📄 bidi.cpp
字号:
return QChar::DirON;
RenderText *renderTxt = static_cast<RenderText *>( obj );
if ( pos >= renderTxt->stringLength() )
return QChar::DirON;
return renderTxt->text()[pos].direction();
}
// -------------------------------------------------------------------------------------------------
static void addRun(BidiRun* bidiRun)
{
if (!sFirstBidiRun)
sFirstBidiRun = sLastBidiRun = bidiRun;
else {
sLastBidiRun->nextRun = bidiRun;
sLastBidiRun = bidiRun;
}
sBidiRunCount++;
bidiRun->compact = sBuildingCompactRuns;
// Compute the number of spaces in this run,
if (bidiRun->obj && bidiRun->obj->isText()) {
RenderText* text = static_cast<RenderText*>(bidiRun->obj);
if (text->text()) {
for (int i = bidiRun->start; i < bidiRun->stop; i++) {
const QChar c = text->text()[i];
if (c == ' ' || c == '\n')
numSpaces++;
}
}
}
}
static void reverseRuns(int start, int end)
{
if (start >= end)
return;
assert(start >= 0 && end < sBidiRunCount);
// Get the item before the start of the runs to reverse and put it in
// |beforeStart|. |curr| should point to the first run to reverse.
BidiRun* curr = sFirstBidiRun;
BidiRun* beforeStart = 0;
int i = 0;
while (i < start) {
i++;
beforeStart = curr;
curr = curr->nextRun;
}
BidiRun* startRun = curr;
while (i < end) {
i++;
curr = curr->nextRun;
}
BidiRun* endRun = curr;
BidiRun* afterEnd = curr->nextRun;
i = start;
curr = startRun;
BidiRun* newNext = afterEnd;
while (i <= end) {
// Do the reversal.
BidiRun* next = curr->nextRun;
curr->nextRun = newNext;
newNext = curr;
curr = next;
i++;
}
// Now hook up beforeStart and afterEnd to the newStart and newEnd.
if (beforeStart)
beforeStart->nextRun = endRun;
else
sFirstBidiRun = endRun;
startRun->nextRun = afterEnd;
if (!afterEnd)
sLastBidiRun = startRun;
}
static void chopMidpointsAt(RenderObject* obj, uint pos)
{
if (!sNumMidpoints) return;
BidiIterator* midpoints = smidpoints->data();
for (uint i = 0; i < sNumMidpoints; i++) {
const BidiIterator& point = midpoints[i];
if (point.obj == obj && point.pos == pos) {
sNumMidpoints = i;
break;
}
}
}
static void checkMidpoints(BidiIterator& lBreak, BidiState &bidi)
{
// Check to see if our last midpoint is a start point beyond the line break. If so,
// shave it off the list, and shave off a trailing space if the previous end point isn't
// white-space: pre.
if (lBreak.obj && sNumMidpoints && sNumMidpoints%2 == 0) {
BidiIterator* midpoints = smidpoints->data();
BidiIterator& endpoint = midpoints[sNumMidpoints-2];
const BidiIterator& startpoint = midpoints[sNumMidpoints-1];
BidiIterator currpoint = endpoint;
while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
currpoint.increment( bidi );
if (currpoint == lBreak) {
// We hit the line break before the start point. Shave off the start point.
sNumMidpoints--;
if (endpoint.obj->style()->whiteSpace() != PRE) {
if (endpoint.obj->isText()) {
// Don't shave a character off the endpoint if it was from a soft hyphen.
RenderText* textObj = static_cast<RenderText*>(endpoint.obj);
if (endpoint.pos+1 < textObj->length() &&
textObj->text()[endpoint.pos+1].unicode() == SOFT_HYPHEN)
return;
}
endpoint.pos--;
}
}
}
}
static void addMidpoint(const BidiIterator& midpoint)
{
if (!smidpoints)
return;
if (smidpoints->size() <= sNumMidpoints)
smidpoints->resize(sNumMidpoints+10);
BidiIterator* midpoints = smidpoints->data();
midpoints[sNumMidpoints++] = midpoint;
}
static void appendRunsForObject(int start, int end, RenderObject* obj, BidiState &bidi)
{
if (start > end || obj->isFloating() ||
(obj->isPositioned() && !obj->hasStaticX() && !obj->hasStaticY() && !obj->container()->isInlineFlow()))
return;
bool haveNextMidpoint = (smidpoints && sCurrMidpoint < sNumMidpoints);
BidiIterator nextMidpoint;
if (haveNextMidpoint)
nextMidpoint = smidpoints->at(sCurrMidpoint);
if (betweenMidpoints) {
if (!(haveNextMidpoint && nextMidpoint.obj == obj))
return;
// This is a new start point. Stop ignoring objects and
// adjust our start.
betweenMidpoints = false;
start = nextMidpoint.pos;
sCurrMidpoint++;
if (start < end)
return appendRunsForObject(start, end, obj, bidi);
}
else {
if (!smidpoints || !haveNextMidpoint || (obj != nextMidpoint.obj)) {
addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context, dir));
return;
}
// An end midpoint has been encountered within our object. We
// need to go ahead and append a run with our endpoint.
if (int(nextMidpoint.pos+1) <= end) {
betweenMidpoints = true;
sCurrMidpoint++;
if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
addRun(new (obj->renderArena())
BidiRun(start, nextMidpoint.pos+1, obj, bidi.context, dir));
return appendRunsForObject(nextMidpoint.pos+1, end, obj, bidi);
}
}
else
addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context, dir));
}
}
static void appendRun( BidiState &bidi )
{
if ( emptyRun ) return;
#if BIDI_DEBUG > 1
kdDebug(6041) << "appendRun: dir="<<(int)dir<<endl;
#endif
bool b = adjustEmbedding;
adjustEmbedding = false;
int start = bidi.sor.pos;
RenderObject *obj = bidi.sor.obj;
while( obj && obj != bidi.eor.obj ) {
appendRunsForObject(start, obj->length(), obj, bidi);
start = 0;
obj = Bidinext( bidi.sor.par, obj, bidi );
}
if (obj)
appendRunsForObject(start, bidi.eor.pos+1, obj, bidi);
bidi.eor.increment( bidi );
bidi.sor = bidi.eor;
dir = QChar::DirON;
bidi.status.eor = QChar::DirON;
adjustEmbedding = b;
}
static void embed( QChar::Direction d, BidiState &bidi )
{
#if BIDI_DEBUG > 1
qDebug("*** embed dir=%d emptyrun=%d", d, emptyRun );
#endif
bool b = adjustEmbedding ;
adjustEmbedding = false;
if ( d == QChar::DirPDF ) {
BidiContext *c = bidi.context->parent;
if (c) {
if ( bidi.eor != bidi.last ) {
appendRun( bidi );
bidi.eor = bidi.last;
}
appendRun( bidi );
emptyRun = true;
bidi.status.last = bidi.context->dir;
bidi.context->deref();
bidi.context = c;
if(bidi.context->override)
dir = bidi.context->dir;
else
dir = QChar::DirON;
bidi.status.lastStrong = bidi.context->dir;
}
} else {
QChar::Direction runDir;
if( d == QChar::DirRLE || d == QChar::DirRLO )
runDir = QChar::DirR;
else
runDir = QChar::DirL;
bool override;
if( d == QChar::DirLRO || d == QChar::DirRLO )
override = true;
else
override = false;
unsigned char level = bidi.context->level;
if ( runDir == QChar::DirR ) {
if(level%2) // we have an odd level
level += 2;
else
level++;
} else {
if(level%2) // we have an odd level
level++;
else
level += 2;
}
if(level < 61) {
if ( bidi.eor != bidi.last ) {
appendRun( bidi );
bidi.eor = bidi.last;
}
appendRun( bidi );
emptyRun = true;
bidi.context = new BidiContext(level, runDir, bidi.context, override);
bidi.context->ref();
if ( override )
dir = runDir;
bidi.status.last = runDir;
bidi.status.lastStrong = runDir;
}
}
adjustEmbedding = b;
}
InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj)
{
// See if we have an unconstructed line box for this object that is also
// the last item on the line.
KHTMLAssert(obj->isInlineFlow() || obj == this);
RenderFlow* flow = static_cast<RenderFlow*>(obj);
// Get the last box we made for this render object.
InlineFlowBox* box = flow->lastLineBox();
// If this box is constructed then it is from a previous line, and we need
// to make a new box for our line. If this box is unconstructed but it has
// something following it on the line, then we know we have to make a new box
// as well. In this situation our inline has actually been split in two on
// the same line (this can happen with very fancy language mixtures).
if (!box || box->isConstructed() || box->nextOnLine()) {
// We need to make a new box for this render object. Once
// made, we need to place it at the end of the current line.
InlineBox* newBox = obj->createInlineBox(false, obj == this);
KHTMLAssert(newBox->isInlineFlowBox());
box = static_cast<InlineFlowBox*>(newBox);
box->setFirstLineStyleBit(m_firstLine);
// We have a new box. Append it to the inline box we get by constructing our
// parent. If we have hit the block itself, then |box| represents the root
// inline box for the line, and it doesn't have to be appended to any parent
// inline.
if (obj != this) {
InlineFlowBox* parentBox = createLineBoxes(obj->parent());
parentBox->addToLine(box);
}
}
return box;
}
RootInlineBox* RenderBlock::constructLine(const BidiIterator &start, const BidiIterator &end)
{
if (!sFirstBidiRun)
return 0; // We had no runs. Don't make a root inline box at all. The line is empty.
InlineFlowBox* parentBox = 0;
for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) {
// Create a box for our object.
r->box = r->obj->createInlineBox(r->obj->isPositioned(), false, sBidiRunCount == 1);
if (r->box) {
// If we have no parent box yet, or if the run is not simply a sibling,
// then we need to construct inline boxes as necessary to properly enclose the
// run's inline box.
if (!parentBox || (parentBox->object() != r->obj->parent()))
// Create new inline boxes all the way back to the appropriate insertion point.
parentBox = createLineBoxes(r->obj->parent());
// Append the inline box to this line.
parentBox->addToLine(r->box);
}
}
// We should have a root inline box. It should be unconstructed and
// be the last continuation of our line list.
KHTMLAssert(lastLineBox() && !lastLineBox()->isConstructed());
// Set bits on our inline flow boxes that indicate which sides should
// paint borders/margins/padding. This knowledge will ultimately be used when
// we determine the horizontal positions and widths of all the inline boxes on
// the line.
RenderObject* endObject = 0;
bool lastLine = !end.obj;
if (end.obj && end.pos == 0)
endObject = end.obj;
lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject);
// Now mark the line boxes as being constructed.
lastLineBox()->setConstructed();
// Return the last line.
return lastRootBox();
}
void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiState &bidi)
{
// First determine our total width.
int availableWidth = lineWidth(m_height);
int totWidth = lineBox->getFlowSpacingWidth();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -