📄 bidi.cpp
字号:
case QChar::DirCS: break; case QChar::DirET: if(bidi.status.last == QChar::DirEN) { dirCurrent = QChar::DirEN; bidi.eor = bidi.current; bidi.status.eor = dirCurrent; break; } break; // boundary neutrals should be ignored case QChar::DirBN: break; // neutrals case QChar::DirB: // ### what do we do with newline and paragraph seperators that come to here? break; case QChar::DirS: // ### implement rule L1 break; case QChar::DirWS: break; case QChar::DirON: break; default: break; } //cout << " after: dir=" << // dir << " current=" << dirCurrent << " last=" << status.last << " eor=" << status.eor << " lastStrong=" << status.lastStrong << " embedding=" << context->dir << endl; if(bidi.current.atEnd()) break; // set status.last as needed. switch(dirCurrent) { case QChar::DirET: case QChar::DirES: case QChar::DirCS: case QChar::DirS: case QChar::DirWS: case QChar::DirON: switch(bidi.status.last) { case QChar::DirL: case QChar::DirR: case QChar::DirAL: case QChar::DirEN: case QChar::DirAN: bidi.status.last = dirCurrent; break; default: bidi.status.last = QChar::DirON; } break; case QChar::DirNSM: case QChar::DirBN: // ignore these break; case QChar::DirEN: if ( bidi.status.last == QChar::DirL ) { bidi.status.last = QChar::DirL; break; } // fall through default: bidi.status.last = dirCurrent; }#endif if ( atEnd ) break; bidi.last = bidi.current; if ( emptyRun ) { bidi.sor = bidi.current; bidi.eor = bidi.current; emptyRun = false; } // this causes the operator ++ to open and close embedding levels as needed // for the CSS unicode-bidi property adjustEmbedding = true; bidi.current.increment( bidi ); adjustEmbedding = false; if ( bidi.current == end ) { if ( emptyRun ) break; atEnd = true; } }#if BIDI_DEBUG > 0 kdDebug(6041) << "reached end of line current=" << current.obj << "/" << current.pos << ", eor=" << eor.obj << "/" << eor.pos << endl;#endif if ( !emptyRun && bidi.sor != bidi.current ) { bidi.eor = bidi.last; appendRun( bidi ); } // reorder line according to run structure... // first find highest and lowest levels uchar levelLow = 128; uchar levelHigh = 0; BidiRun *r = sFirstBidiRun; while ( r ) { if ( r->level > levelHigh ) levelHigh = r->level; if ( r->level < levelLow ) levelLow = r->level; r = r->nextRun; } // implements reordering of the line (L2 according to Bidi spec): // L2. From the highest level found in the text to the lowest odd level on each line, // reverse any contiguous sequence of characters that are at that level or higher. // reversing is only done up to the lowest odd level if( !(levelLow%2) ) levelLow++;#if BIDI_DEBUG > 0 kdDebug(6041) << "lineLow = " << (uint)levelLow << ", lineHigh = " << (uint)levelHigh << endl; kdDebug(6041) << "logical order is:" << endl; QPtrListIterator<BidiRun> it2(runs); BidiRun *r2; for ( ; (r2 = it2.current()); ++it2 ) kdDebug(6041) << " " << r2 << " start=" << r2->start << " stop=" << r2->stop << " level=" << (uint)r2->level << endl;#endif int count = sBidiRunCount - 1; // do not reverse for visually ordered web sites if(!style()->visuallyOrdered()) { while(levelHigh >= levelLow) { int i = 0; BidiRun* currRun = sFirstBidiRun; while ( i < count ) { while(i < count && currRun && currRun->level < levelHigh) { i++; currRun = currRun->nextRun; } int start = i; while(i <= count && currRun && currRun->level >= levelHigh) { i++; currRun = currRun->nextRun; } int end = i-1; reverseRuns(start, end); i++; if(i >= count) break; } levelHigh--; } }#if BIDI_DEBUG > 0 kdDebug(6041) << "visual order is:" << endl; for (BidiRun* curr = sFirstRun; curr; curr = curr->nextRun) kdDebug(6041) << " " << curr << endl;#endif}static void buildCompactRuns(RenderObject* compactObj, BidiState &bidi){ sBuildingCompactRuns = true; if (!compactObj->isRenderBlock()) { // Just append a run for our object. isLineEmpty = false; addRun(new (compactObj->renderArena()) BidiRun(0, compactObj->length(), compactObj, bidi.context, dir)); } else { // Format the compact like it is its own single line. We build up all the runs for // the little compact and then reorder them for bidi. RenderBlock* compactBlock = static_cast<RenderBlock*>(compactObj); adjustEmbedding = true; BidiIterator start(compactBlock, first(compactBlock, bidi), 0); adjustEmbedding = false; BidiIterator end = start; betweenMidpoints = false; isLineEmpty = true; previousLineBrokeCleanly = true; end = compactBlock->findNextLineBreak(start, bidi); if (!isLineEmpty) compactBlock->bidiReorderLine(start, end, bidi); } sCompactFirstBidiRun = sFirstBidiRun; sCompactLastBidiRun = sLastBidiRun; sCompactBidiRunCount = sBidiRunCount; sNumMidpoints = 0; sCurrMidpoint = 0; betweenMidpoints = false; sBuildingCompactRuns = false;}QRect RenderBlock::layoutInlineChildren(bool relayoutChildren){ BidiState bidi; bool useRepaintRect = false; QRect repaintRect(0,0,0,0); m_overflowHeight = 0; invalidateVerticalPositions();#ifdef DEBUG_LAYOUT QTime qt; qt.start(); kdDebug( 6040 ) << renderName() << " layoutInlineChildren( " << this <<" )" << endl;#endif#if BIDI_DEBUG > 1 || defined( DEBUG_LINEBREAKS ) kdDebug(6041) << " ------- bidi start " << this << " -------" << endl;#endif m_height = borderTop() + paddingTop(); int toAdd = borderBottom() + paddingBottom(); if (includeScrollbarSize()) toAdd += m_layer->horizontalScrollbarHeight(); // Figure out if we should clear out our line boxes. // FIXME: Handle resize eventually! // FIXME: Do something better when floats are present. bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren || containsFloats(); if (fullLayout) deleteLineBoxes(); // Text truncation only kicks in if your overflow isn't visible and your text-overflow-mode isn't // clip. // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely // difficult to figure out (especially in the middle of doing layout), and is really an esoteric pile of nonsense // anyway, so we won't worry about following the draft here. bool hasTextOverflow = style()->textOverflow() && hasOverflowClip(); // Walk all the lines and delete our ellipsis line boxes if they exist. if (hasTextOverflow) deleteEllipsisLineBoxes(); if (firstChild()) { // layout replaced elements bool endOfInline = false; RenderObject *o = first(this, bidi, false); bool hasFloat = false; while (o) { if (o->isReplaced() || o->isFloating() || o->isPositioned()) { if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent()) o->setChildNeedsLayout(true, false); if (o->isPositioned()) o->containingBlock()->insertPositionedObject(o); else { if (o->isFloating()) hasFloat = true; else if (fullLayout || o->needsLayout()) // Replaced elements o->dirtyLineBoxes(fullLayout); o->layoutIfNeeded(); } } else if (o->isText() || (o->isInlineFlow() && !endOfInline)) { if (fullLayout || o->selfNeedsLayout()) o->dirtyLineBoxes(fullLayout); o->setNeedsLayout(false); } o = Bidinext( this, o, bidi, false, &endOfInline); } if (hasFloat) fullLayout = true; // FIXME: Will need to find a way to optimize floats some day. if (fullLayout && !selfNeedsLayout()) { setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like // we're supposed to. if (!document()->view()->needsFullRepaint() && m_layer) { // Because we waited until we were already inside layout to discover // that the block really needed a full layout, we missed our chance to repaint the layer // before layout started. Luckily the layer has cached the repaint rect for its original // position and size, and so we can use that to make a repaint happen now. RenderCanvas* c = canvas(); if (c && !c->printingMode()) c->repaintViewRectangle(m_layer->repaintRect()); } } BidiContext *startEmbed; if( style()->direction() == LTR ) { startEmbed = new BidiContext( 0, QChar::DirL ); bidi.status.eor = QChar::DirL; } else { startEmbed = new BidiContext( 1, QChar::DirR ); bidi.status.eor = QChar::DirR; } startEmbed->ref(); bidi.status.lastStrong = QChar::DirON; bidi.status.last = QChar::DirON; bidi.context = startEmbed; if (!smidpoints) smidpoints = new QMemArray<BidiIterator>; sNumMidpoints = 0; sCurrMidpoint = 0; sCompactFirstBidiRun = sCompactLastBidiRun = 0; sCompactBidiRunCount = 0; // We want to skip ahead to the first dirty line BidiIterator start; RootInlineBox* startLine = determineStartPosition(fullLayout, start, bidi); // We also find the first clean line and extract these lines. We will add them back // if we determine that we're able to synchronize after handling all our dirty lines. BidiIterator cleanLineStart; int endLineYPos; RootInlineBox* endLine = (fullLayout || !startLine) ? 0 : determineEndPosition(startLine, cleanLineStart, endLineYPos); if (startLine) { useRepaintRect = true; repaintRect.setY(m_height); RenderArena* arena = renderArena(); RootInlineBox* box = startLine; while (box) { RootInlineBox* next = box->nextRootBox(); box->deleteLine(arena); box = next; } startLine = 0; } BidiIterator end = start; bool endLineMatched = false; while (!end.atEnd()) { start = end; if (endLine && (endLineMatched = matchedEndLine(start, cleanLineStart, endLine, endLineYPos))) break; betweenMidpoints = false; isLineEmpty = true; if (m_firstLine && firstChild() && firstChild()->isCompact()) { buildCompactRuns(firstChild(), bidi); start.obj = firstChild()->nextSibling(); end = start; } end = findNextLineBreak(start, bidi); if( start.atEnd() ) break; if (!isLineEmpty) { bidiReorderLine(start, end, bidi); // Now that the runs have been ordered, we create the line boxes. // At the same time we figure out where border/padding/margin should be applied for // inline flow boxes. if (sCompactFirstBidiRun) { // We have a compact line sharing this line. Link the compact runs // to our runs to create a single line of runs. sCompactLastBidiRun->nextRun = sFirstBidiRun; sFirstBidiRun = sCompactFirstBidiRun; sBidiRunCount += sCompactBidiRunCount; } RootInlineBox* lineBox = 0; if (sBidiRunCount) { lineBox = constructLine(start, end); if (lineBox) { lineBox->setEndsWithBreak(previousLineBrokeCleanly);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -