Changeset 57030 in webkit


Ignore:
Timestamp:
Apr 2, 2010 4:21:35 PM (14 years ago)
Author:
jamesr@google.com
Message:

2010-04-02 James Robinson <jamesr@chromium.org>

Reviewed by Darin Adler.

Splits RenderBlock::layoutInline into smaller functions
https://bugs.webkit.org/show_bug.cgi?id=36921

RenderBlock::layoutInlineChildren is 351 lines long and very difficult
to comprehend or edit safely. This patch splits it up into a few
slightly smaller functions. Most of the code is now in the 241 line
layoutRunsAndFloats() which is a slight improvement.

Perf neutral on the page cyclers. This doesn't introduce any function
calls into the hottest layout paths inside layoutRunsAndFloats and
findNextLineBreak.

No change in behavior, no new tests.

  • rendering/RenderBlock.h: (WebCore::RenderBlock::FloatWithRect::FloatWithRect):
  • rendering/RenderBlockLineLayout.cpp: (WebCore::RenderBlock::layoutReplacedElements): (WebCore::RenderBlock::createLineBoxesForResolver): (WebCore::RenderBlock::layoutRunsAndFloats): (WebCore::RenderBlock::layoutInlineChildren):
Location:
trunk/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r57028 r57030  
     12010-04-02  James Robinson  <jamesr@chromium.org>
     2
     3        Reviewed by Darin Adler.
     4
     5        Splits RenderBlock::layoutInline into smaller functions
     6        https://bugs.webkit.org/show_bug.cgi?id=36921
     7
     8        RenderBlock::layoutInlineChildren is 351 lines long and very difficult
     9        to comprehend or edit safely. This patch splits it up into a few
     10        slightly smaller functions.  Most of the code is now in the 241 line
     11        layoutRunsAndFloats() which is a slight improvement.
     12
     13        Perf neutral on the page cyclers.  This doesn't introduce any function
     14        calls into the hottest layout paths inside layoutRunsAndFloats and
     15        findNextLineBreak.
     16
     17        No change in behavior, no new tests.
     18
     19        * rendering/RenderBlock.h:
     20        (WebCore::RenderBlock::FloatWithRect::FloatWithRect):
     21        * rendering/RenderBlockLineLayout.cpp:
     22        (WebCore::RenderBlock::layoutReplacedElements):
     23        (WebCore::RenderBlock::createLineBoxesForResolver):
     24        (WebCore::RenderBlock::layoutRunsAndFloats):
     25        (WebCore::RenderBlock::layoutInlineChildren):
     26
    1272010-04-02  Evan Stade  <estade@chromium.org>
    228
  • trunk/WebCore/rendering/RenderBlock.h

    r55890 r57030  
    484484    // End helper functions and structs used by layoutBlockChildren.
    485485
     486    // Helper functions for layoutInlineChildren()
     487    bool layoutReplacedElements(bool relayoutChildren, bool fullLayout, Vector<FloatWithRect>&);
     488    RootInlineBox* createLineBoxesForResolver(const InlineBidiResolver&, const InlineIterator& position, bool firstLine, bool previousLineBrokeCleanly, BidiRun* trailingSpaceRun);
     489    void layoutRunsAndFloats(bool fullLayout, Vector<FloatWithRect>&, int& repaintTop, int& repaintBottom);
     490
    486491    typedef ListHashSet<RenderBox*>::const_iterator Iterator;
    487492    DeprecatedPtrList<FloatingObject>* m_floatingObjects;
  • trunk/WebCore/rendering/RenderBlockLineLayout.cpp

    r56186 r57030  
    515515}
    516516
    517 void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom)
    518 {
     517// This is a helper for RenderBlock::layoutInlineChildren.  It iterates through a RenderBlock's inline children
     518// in bidi order and:
     519//  - calls layoutIfNeeded() on all replaced children
     520//  - assembles a list of floats
     521//  - adds all positioned children to their containing block's positioned object set
     522//  - dirties line boxes on inline children if fullLayout is set
     523bool RenderBlock::layoutReplacedElements(bool relayoutChildren, bool fullLayout, Vector<FloatWithRect>& floats)
     524{
     525    bool endOfInline = false;
     526    bool hasInlineChild = false;
     527    // FIXME: Use a more descriptive variable name and use a for loop instead of while here.
     528    RenderObject* o = bidiFirst(this, 0, false);
     529    while (o) {
     530        if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
     531            RenderBox* box = toRenderBox(o);
     532           
     533            if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent())
     534                o->setChildNeedsLayout(true, false);
     535               
     536            // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
     537            if (relayoutChildren && (o->style()->paddingLeft().isPercent() || o->style()->paddingRight().isPercent()))
     538                o->setPrefWidthsDirty(true, false);
     539       
     540            if (o->isPositioned())
     541                o->containingBlock()->insertPositionedObject(box);
     542            else {
     543                if (o->isFloating())
     544                    floats.append(RenderBlock::FloatWithRect(box));
     545                else if (fullLayout || o->needsLayout()) // Replaced elements
     546                    toRenderBox(o)->dirtyLineBoxes(fullLayout);
     547
     548                o->layoutIfNeeded();
     549            }
     550        } else if (o->isText() || (o->isRenderInline() && !endOfInline)) {
     551            hasInlineChild = true;
     552            if (fullLayout || o->selfNeedsLayout())
     553                dirtyLineBoxesForRenderer(o, fullLayout);
     554            o->setNeedsLayout(false);
     555            if (!o->isText())
     556                toRenderInline(o)->invalidateVerticalPosition(); // FIXME: Should do better here and not always invalidate everything.
     557        }
     558        o = bidiNext(this, o, 0, false, &endOfInline);
     559    }
     560    return hasInlineChild;
     561}
     562
     563// This function constructs line boxes for all of the text runs in the resolver and computes their position.
     564RootInlineBox* RenderBlock::createLineBoxesForResolver(const InlineBidiResolver& resolver, const InlineIterator& position, bool firstLine, bool previousLineBrokeCleanly, BidiRun* trailingSpaceRun)
     565{
     566    RootInlineBox* lineBox = 0;
     567    if (resolver.runCount()) {
     568        lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), firstLine, !position.obj, position.obj && !position.pos ? position.obj : 0);
     569        if (lineBox) {
     570            lineBox->setEndsWithBreak(previousLineBrokeCleanly);
     571
     572            // Now we position all of our text runs horizontally.
     573            computeHorizontalPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, position.atEnd());
     574
     575            // Now position our text runs vertically.
     576            computeVerticalPositionsForLine(lineBox, resolver.firstRun());
     577
     578#if ENABLE(SVG)
     579            // Special SVG text layout code
     580            lineBox->computePerCharacterLayoutInformation();
     581#endif
     582
     583#if PLATFORM(MAC)
     584            // Highlight acts as an overflow inflation.
     585            if (style()->highlight() != nullAtom)
     586                lineBox->addHighlightOverflow();
     587#endif
     588        }
     589    }
     590
     591    return lineBox;
     592}
     593
     594void RenderBlock::layoutRunsAndFloats(bool fullLayout, Vector<FloatWithRect>& floats, int& repaintTop, int& repaintBottom)
     595{
     596    // We want to skip ahead to the first dirty line
     597    InlineBidiResolver resolver;
     598    unsigned floatIndex;
     599    bool firstLine = true;
     600    bool previousLineBrokeCleanly = true;
    519601    bool useRepaintBounds = false;
    520602   
     603    RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex);
     604
     605    FloatingObject* lastFloat = m_floatingObjects ? m_floatingObjects->last() : 0;
     606
     607    LineMidpointState& lineMidpointState = resolver.midpointState();
     608
     609    // We also find the first clean line and extract these lines.  We will add them back
     610    // if we determine that we're able to synchronize after handling all our dirty lines.
     611    InlineIterator cleanLineStart;
     612    BidiStatus cleanLineBidiStatus;
     613    int endLineYPos = 0;
     614    RootInlineBox* endLine = (fullLayout || !startLine) ?
     615                             0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineYPos);
     616
     617    if (startLine) {
     618        useRepaintBounds = true;
     619        repaintTop = height();
     620        repaintBottom = height();
     621        RenderArena* arena = renderArena();
     622        RootInlineBox* box = startLine;
     623        while (box) {
     624            repaintTop = min(repaintTop, box->topVisibleOverflow());
     625            repaintBottom = max(repaintBottom, box->bottomVisibleOverflow());
     626            RootInlineBox* next = box->nextRootBox();
     627            box->deleteLine(arena);
     628            box = next;
     629        }
     630    }
     631
     632    InlineIterator currentPosition = resolver.position();
     633
     634    if (!fullLayout && lastRootBox() && lastRootBox()->endsWithBreak()) {
     635        // If the last line before the start line ends with a line break that clear floats,
     636        // adjust the height accordingly.
     637        // A line break can be either the first or the last object on a line, depending on its direction.
     638        if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
     639            RenderObject* lastObject = lastLeafChild->renderer();
     640            if (!lastObject->isBR())
     641                lastObject = lastRootBox()->firstLeafChild()->renderer();
     642            if (lastObject->isBR()) {
     643                EClear clear = lastObject->style()->clear();
     644                if (clear != CNONE)
     645                    newLine(clear);
     646            }
     647        }
     648    }
     649
     650    bool endLineMatched = false;
     651    bool checkForEndLineMatch = endLine;
     652    bool checkForFloatsFromLastLine = false;
     653
     654    bool isLineEmpty = true;
     655
     656    while (!currentPosition.atEnd()) {
     657        // FIXME: Is this check necessary before the first iteration or can it be moved to the end?
     658        if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineYPos, repaintBottom, repaintTop)))
     659            break;
     660
     661        lineMidpointState.reset();
     662       
     663        isLineEmpty = true;
     664       
     665        EClear clear = CNONE;
     666        currentPosition = findNextLineBreak(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, &clear);
     667        if (resolver.position().atEnd()) {
     668            resolver.deleteRuns();
     669            checkForFloatsFromLastLine = true;
     670            break;
     671        }
     672        ASSERT(currentPosition != resolver.position());
     673
     674        if (!isLineEmpty) {
     675            bidiReorderLine(resolver, currentPosition, previousLineBrokeCleanly);
     676            ASSERT(resolver.position() == currentPosition);
     677
     678            BidiRun* trailingSpaceRun = 0;
     679            if (!previousLineBrokeCleanly && resolver.runCount() && resolver.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()
     680                    && resolver.logicallyLastRun()->m_object->style()->autoWrap()) {
     681                trailingSpaceRun = resolver.logicallyLastRun();
     682                RenderObject* lastObject = trailingSpaceRun->m_object;
     683                if (lastObject->isText()) {
     684                    RenderText* lastText = toRenderText(lastObject);
     685                    const UChar* characters = lastText->characters();
     686                    int firstSpace = trailingSpaceRun->stop();
     687                    while (firstSpace > trailingSpaceRun->start()) {
     688                        UChar current = characters[firstSpace - 1];
     689                        if (!isCollapsibleSpace(current, lastText))
     690                            break;
     691                        firstSpace--;
     692                    }
     693                    if (firstSpace == trailingSpaceRun->stop())
     694                        trailingSpaceRun = 0;
     695                    else {
     696                        TextDirection direction = style()->direction();
     697                        bool shouldReorder = trailingSpaceRun != (direction == LTR ? resolver.lastRun() : resolver.firstRun());
     698                        if (firstSpace != trailingSpaceRun->start()) {
     699                            BidiContext* baseContext = resolver.context();
     700                            while (BidiContext* parent = baseContext->parent())
     701                                baseContext = parent;
     702
     703                            BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral);
     704                            trailingSpaceRun->m_stop = firstSpace;
     705                            if (direction == LTR)
     706                                resolver.addRun(newTrailingRun);
     707                            else
     708                                resolver.prependRun(newTrailingRun);
     709                            trailingSpaceRun = newTrailingRun;
     710                            shouldReorder = false;
     711                        }
     712                        if (shouldReorder) {
     713                            if (direction == LTR) {
     714                                resolver.moveRunToEnd(trailingSpaceRun);
     715                                trailingSpaceRun->m_level = 0;
     716                            } else {
     717                                resolver.moveRunToBeginning(trailingSpaceRun);
     718                                trailingSpaceRun->m_level = 1;
     719                            }
     720                        }
     721                    }
     722                } else
     723                    trailingSpaceRun = 0;
     724            }
     725
     726            // Now that the runs have been ordered, we create the line boxes.
     727            RootInlineBox* lineBox = createLineBoxesForResolver(resolver, currentPosition, firstLine, previousLineBrokeCleanly, trailingSpaceRun);
     728            resolver.deleteRuns();
     729
     730            // At the same time we figure out where border/padding/margin should be applied for
     731            // inline flow boxes.
     732            if (lineBox) {
     733                lineBox->setLineBreakInfo(currentPosition.obj, currentPosition.pos, resolver.status());
     734                if (useRepaintBounds) {
     735                    repaintTop = min(repaintTop, lineBox->topVisibleOverflow());
     736                    repaintBottom = max(repaintBottom, lineBox->bottomVisibleOverflow());
     737                }
     738            }
     739
     740            firstLine = false;
     741            newLine(clear);
     742        }
     743
     744        if (m_floatingObjects && lastRootBox()) {
     745            if (lastFloat) {
     746                for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
     747                }
     748                m_floatingObjects->next();
     749            } else
     750                m_floatingObjects->first();
     751            for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) {
     752                lastRootBox()->floats().append(f->m_renderer);
     753                ASSERT(f->m_renderer == floats[floatIndex].object);
     754                // If a float's geometry has changed, give up on syncing with clean lines.
     755                if (floats[floatIndex].rect != IntRect(f->m_left, f->m_top, f->m_width, f->m_bottom - f->m_top))
     756                    checkForEndLineMatch = false;
     757                floatIndex++;
     758            }
     759            lastFloat = m_floatingObjects->last();
     760        }
     761
     762        lineMidpointState.reset();
     763        resolver.setPosition(currentPosition);
     764    }
     765
     766    if (endLine) {
     767        if (endLineMatched) {
     768            // Attach all the remaining lines, and then adjust their y-positions as needed.
     769            int delta = height() - endLineYPos;
     770            for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
     771                line->attachLine();
     772                if (delta) {
     773                    repaintTop = min(repaintTop, line->topVisibleOverflow() + min(delta, 0));
     774                    repaintBottom = max(repaintBottom, line->bottomVisibleOverflow() + max(delta, 0));
     775                    line->adjustPosition(0, delta);
     776                }
     777                if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
     778                    Vector<RenderBox*>::iterator end = cleanLineFloats->end();
     779                    for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
     780                        int floatTop = (*f)->y() - (*f)->marginTop();
     781                        insertFloatingObject(*f);
     782                        setHeight(floatTop + delta);
     783                        positionNewFloats();
     784                    }
     785                }
     786            }
     787            setHeight(lastRootBox()->blockHeight());
     788        } else {
     789            // Delete all the remaining lines.
     790            RootInlineBox* line = endLine;
     791            RenderArena* arena = renderArena();
     792            while (line) {
     793                repaintTop = min(repaintTop, line->topVisibleOverflow());
     794                repaintBottom = max(repaintBottom, line->bottomVisibleOverflow());
     795                RootInlineBox* next = line->nextRootBox();
     796                line->deleteLine(arena);
     797                line = next;
     798            }
     799        }
     800    }
     801    if (m_floatingObjects && (checkForFloatsFromLastLine || positionNewFloats()) && lastRootBox()) {
     802        // In case we have a float on the last line, it might not be positioned up to now.
     803        // This has to be done before adding in the bottom border/padding, or the float will
     804        // include the padding incorrectly. -dwh
     805        if (checkForFloatsFromLastLine) {
     806            int bottomVisualOverflow = lastRootBox()->bottomVisualOverflow();
     807            int bottomLayoutOverflow = lastRootBox()->bottomLayoutOverflow();
     808            TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this);
     809            m_lineBoxes.appendLineBox(trailingFloatsLineBox);
     810            trailingFloatsLineBox->setConstructed();
     811            trailingFloatsLineBox->verticallyAlignBoxes(height());
     812            trailingFloatsLineBox->setVerticalOverflowPositions(height(), bottomLayoutOverflow, height(), bottomVisualOverflow, 0);
     813            trailingFloatsLineBox->setBlockHeight(height());
     814        }
     815        if (lastFloat) {
     816            for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
     817            }
     818            m_floatingObjects->next();
     819        } else
     820            m_floatingObjects->first();
     821        for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next())
     822            lastRootBox()->floats().append(f->m_renderer);
     823        lastFloat = m_floatingObjects->last();
     824    }
     825    // Floats that did not have layout did not repaint when we laid them out. They would have
     826    // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
     827    // painted.
     828    size_t floatCount = floats.size();
     829    for (size_t i = 0; i < floatCount; ++i) {
     830        if (!floats[i].everHadLayout) {
     831            RenderBox* f = floats[i].object;
     832            if (!f->x() && !f->y() && f->checkForRepaintDuringLayout())
     833                f->repaint();
     834        }
     835    }
     836}
     837
     838void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom)
     839{
    521840    m_overflow.clear();
    522841       
     
    542861
    543862    if (firstChild()) {
    544         // layout replaced elements
    545         bool endOfInline = false;
    546         RenderObject* o = bidiFirst(this, 0, false);
    547863        Vector<FloatWithRect> floats;
    548         bool hasInlineChild = false;
    549         while (o) {
    550             if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
    551                 RenderBox* box = toRenderBox(o);
    552                
    553                 if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent())
    554                     o->setChildNeedsLayout(true, false);
    555                    
    556                 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
    557                 if (relayoutChildren && (o->style()->paddingLeft().isPercent() || o->style()->paddingRight().isPercent()))
    558                     o->setPrefWidthsDirty(true, false);
    559            
    560                 if (o->isPositioned())
    561                     o->containingBlock()->insertPositionedObject(box);
    562                 else {
    563                     if (o->isFloating())
    564                         floats.append(FloatWithRect(box));
    565                     else if (fullLayout || o->needsLayout()) // Replaced elements
    566                         toRenderBox(o)->dirtyLineBoxes(fullLayout);
    567 
    568                     o->layoutIfNeeded();
    569                 }
    570             } else if (o->isText() || (o->isRenderInline() && !endOfInline)) {
    571                 hasInlineChild = true;
    572                 if (fullLayout || o->selfNeedsLayout())
    573                     dirtyLineBoxesForRenderer(o, fullLayout);
    574                 o->setNeedsLayout(false);
    575                 if (!o->isText())
    576                     toRenderInline(o)->invalidateVerticalPosition(); // FIXME: Should do better here and not always invalidate everything.
    577             }
    578             o = bidiNext(this, o, 0, false, &endOfInline);
    579         }
    580 
    581         // We want to skip ahead to the first dirty line
    582         InlineBidiResolver resolver;
    583         unsigned floatIndex;
    584         bool firstLine = true;
    585         bool previousLineBrokeCleanly = true;
    586         RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex);
     864        bool hasInlineChild = layoutReplacedElements(relayoutChildren, fullLayout, floats);
    587865
    588866        if (fullLayout && hasInlineChild && !selfNeedsLayout()) {
    589             setNeedsLayout(true, false);  // Mark ourselves as needing a full layout. This way we'll repaint like
    590                                           // we're supposed to.
     867            setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
     868                                         // we're supposed to.
    591869            RenderView* v = view();
    592870            if (v && !v->doingFullRepaint() && hasLayer()) {
     
    599877        }
    600878
    601         FloatingObject* lastFloat = m_floatingObjects ? m_floatingObjects->last() : 0;
    602 
    603         LineMidpointState& lineMidpointState = resolver.midpointState();
    604 
    605         // We also find the first clean line and extract these lines.  We will add them back
    606         // if we determine that we're able to synchronize after handling all our dirty lines.
    607         InlineIterator cleanLineStart;
    608         BidiStatus cleanLineBidiStatus;
    609         int endLineYPos = 0;
    610         RootInlineBox* endLine = (fullLayout || !startLine) ?
    611                                  0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineYPos);
    612 
    613         if (startLine) {
    614             useRepaintBounds = true;
    615             repaintTop = height();
    616             repaintBottom = height();
    617             RenderArena* arena = renderArena();
    618             RootInlineBox* box = startLine;
    619             while (box) {
    620                 repaintTop = min(repaintTop, box->topVisibleOverflow());
    621                 repaintBottom = max(repaintBottom, box->bottomVisibleOverflow());
    622                 RootInlineBox* next = box->nextRootBox();
    623                 box->deleteLine(arena);
    624                 box = next;
    625             }
    626         }
    627 
    628         InlineIterator end = resolver.position();
    629 
    630         if (!fullLayout && lastRootBox() && lastRootBox()->endsWithBreak()) {
    631             // If the last line before the start line ends with a line break that clear floats,
    632             // adjust the height accordingly.
    633             // A line break can be either the first or the last object on a line, depending on its direction.
    634             if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
    635                 RenderObject* lastObject = lastLeafChild->renderer();
    636                 if (!lastObject->isBR())
    637                     lastObject = lastRootBox()->firstLeafChild()->renderer();
    638                 if (lastObject->isBR()) {
    639                     EClear clear = lastObject->style()->clear();
    640                     if (clear != CNONE)
    641                         newLine(clear);
    642                 }
    643             }
    644         }
    645 
    646         bool endLineMatched = false;
    647         bool checkForEndLineMatch = endLine;
    648         bool checkForFloatsFromLastLine = false;
    649 
    650         bool isLineEmpty = true;
    651 
    652         while (!end.atEnd()) {
    653             // FIXME: Is this check necessary before the first iteration or can it be moved to the end?
    654             if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineYPos, repaintBottom, repaintTop)))
    655                 break;
    656 
    657             lineMidpointState.reset();
    658            
    659             isLineEmpty = true;
    660            
    661             EClear clear = CNONE;
    662             end = findNextLineBreak(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, &clear);
    663             if (resolver.position().atEnd()) {
    664                 resolver.deleteRuns();
    665                 checkForFloatsFromLastLine = true;
    666                 break;
    667             }
    668             ASSERT(end != resolver.position());
    669 
    670             if (!isLineEmpty) {
    671                 bidiReorderLine(resolver, end, previousLineBrokeCleanly);
    672                 ASSERT(resolver.position() == end);
    673 
    674                 BidiRun* trailingSpaceRun = 0;
    675                 if (!previousLineBrokeCleanly && resolver.runCount() && resolver.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()
    676                         && resolver.logicallyLastRun()->m_object->style()->autoWrap()) {
    677                     trailingSpaceRun = resolver.logicallyLastRun();
    678                     RenderObject* lastObject = trailingSpaceRun->m_object;
    679                     if (lastObject->isText()) {
    680                         RenderText* lastText = toRenderText(lastObject);
    681                         const UChar* characters = lastText->characters();
    682                         int firstSpace = trailingSpaceRun->stop();
    683                         while (firstSpace > trailingSpaceRun->start()) {
    684                             UChar current = characters[firstSpace - 1];
    685                             if (!isCollapsibleSpace(current, lastText))
    686                                 break;
    687                             firstSpace--;
    688                         }
    689                         if (firstSpace == trailingSpaceRun->stop())
    690                             trailingSpaceRun = 0;
    691                         else {
    692                             TextDirection direction = style()->direction();
    693                             bool shouldReorder = trailingSpaceRun != (direction == LTR ? resolver.lastRun() : resolver.firstRun());
    694                             if (firstSpace != trailingSpaceRun->start()) {
    695                                 BidiContext* baseContext = resolver.context();
    696                                 while (BidiContext* parent = baseContext->parent())
    697                                     baseContext = parent;
    698 
    699                                 BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral);
    700                                 trailingSpaceRun->m_stop = firstSpace;
    701                                 if (direction == LTR)
    702                                     resolver.addRun(newTrailingRun);
    703                                 else
    704                                     resolver.prependRun(newTrailingRun);
    705                                 trailingSpaceRun = newTrailingRun;
    706                                 shouldReorder = false;
    707                             }
    708                             if (shouldReorder) {
    709                                 if (direction == LTR) {
    710                                     resolver.moveRunToEnd(trailingSpaceRun);
    711                                     trailingSpaceRun->m_level = 0;
    712                                 } else {
    713                                     resolver.moveRunToBeginning(trailingSpaceRun);
    714                                     trailingSpaceRun->m_level = 1;
    715                                 }
    716                             }
    717                         }
    718                     } else
    719                         trailingSpaceRun = 0;
    720                 }
    721 
    722                 // Now that the runs have been ordered, we create the line boxes.
    723                 // At the same time we figure out where border/padding/margin should be applied for
    724                 // inline flow boxes.
    725 
    726                 RootInlineBox* lineBox = 0;
    727                 if (resolver.runCount()) {
    728                     lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), firstLine, !end.obj, end.obj && !end.pos ? end.obj : 0);
    729                     if (lineBox) {
    730                         lineBox->setEndsWithBreak(previousLineBrokeCleanly);
    731 
    732                         // Now we position all of our text runs horizontally.
    733                         computeHorizontalPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, end.atEnd());
    734 
    735                         // Now position our text runs vertically.
    736                         computeVerticalPositionsForLine(lineBox, resolver.firstRun());
    737 
    738 #if ENABLE(SVG)
    739                         // Special SVG text layout code
    740                         lineBox->computePerCharacterLayoutInformation();
    741 #endif
    742 
    743 #if PLATFORM(MAC)
    744                         // Highlight acts as an overflow inflation.
    745                         if (style()->highlight() != nullAtom)
    746                             lineBox->addHighlightOverflow();
    747 #endif
    748                     }
    749                 }
    750 
    751                 resolver.deleteRuns();
    752 
    753                 if (lineBox) {
    754                     lineBox->setLineBreakInfo(end.obj, end.pos, resolver.status());
    755                     if (useRepaintBounds) {
    756                         repaintTop = min(repaintTop, lineBox->topVisibleOverflow());
    757                         repaintBottom = max(repaintBottom, lineBox->bottomVisibleOverflow());
    758                     }
    759                 }
    760 
    761                 firstLine = false;
    762                 newLine(clear);
    763             }
    764 
    765             if (m_floatingObjects && lastRootBox()) {
    766                 if (lastFloat) {
    767                     for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
    768                     }
    769                     m_floatingObjects->next();
    770                 } else
    771                     m_floatingObjects->first();
    772                 for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) {
    773                     lastRootBox()->floats().append(f->m_renderer);
    774                     ASSERT(f->m_renderer == floats[floatIndex].object);
    775                     // If a float's geometry has changed, give up on syncing with clean lines.
    776                     if (floats[floatIndex].rect != IntRect(f->m_left, f->m_top, f->m_width, f->m_bottom - f->m_top))
    777                         checkForEndLineMatch = false;
    778                     floatIndex++;
    779                 }
    780                 lastFloat = m_floatingObjects->last();
    781             }
    782 
    783             lineMidpointState.reset();
    784             resolver.setPosition(end);
    785         }
    786 
    787         if (endLine) {
    788             if (endLineMatched) {
    789                 // Attach all the remaining lines, and then adjust their y-positions as needed.
    790                 int delta = height() - endLineYPos;
    791                 for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
    792                     line->attachLine();
    793                     if (delta) {
    794                         repaintTop = min(repaintTop, line->topVisibleOverflow() + min(delta, 0));
    795                         repaintBottom = max(repaintBottom, line->bottomVisibleOverflow() + max(delta, 0));
    796                         line->adjustPosition(0, delta);
    797                     }
    798                     if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
    799                         Vector<RenderBox*>::iterator end = cleanLineFloats->end();
    800                         for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
    801                             int floatTop = (*f)->y() - (*f)->marginTop();
    802                             insertFloatingObject(*f);
    803                             setHeight(floatTop + delta);
    804                             positionNewFloats();
    805                         }
    806                     }
    807                 }
    808                 setHeight(lastRootBox()->blockHeight());
    809             } else {
    810                 // Delete all the remaining lines.
    811                 RootInlineBox* line = endLine;
    812                 RenderArena* arena = renderArena();
    813                 while (line) {
    814                     repaintTop = min(repaintTop, line->topVisibleOverflow());
    815                     repaintBottom = max(repaintBottom, line->bottomVisibleOverflow());
    816                     RootInlineBox* next = line->nextRootBox();
    817                     line->deleteLine(arena);
    818                     line = next;
    819                 }
    820             }
    821         }
    822         if (m_floatingObjects && (checkForFloatsFromLastLine || positionNewFloats()) && lastRootBox()) {
    823             // In case we have a float on the last line, it might not be positioned up to now.
    824             // This has to be done before adding in the bottom border/padding, or the float will
    825             // include the padding incorrectly. -dwh
    826             if (checkForFloatsFromLastLine) {
    827                 int bottomVisualOverflow = lastRootBox()->bottomVisualOverflow();
    828                 int bottomLayoutOverflow = lastRootBox()->bottomLayoutOverflow();
    829                 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this);
    830                 m_lineBoxes.appendLineBox(trailingFloatsLineBox);
    831                 trailingFloatsLineBox->setConstructed();
    832                 trailingFloatsLineBox->verticallyAlignBoxes(height());
    833                 trailingFloatsLineBox->setVerticalOverflowPositions(height(), bottomLayoutOverflow, height(), bottomVisualOverflow, 0);
    834                 trailingFloatsLineBox->setBlockHeight(height());
    835             }
    836             if (lastFloat) {
    837                 for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
    838                 }
    839                 m_floatingObjects->next();
    840             } else
    841                 m_floatingObjects->first();
    842             for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next())
    843                 lastRootBox()->floats().append(f->m_renderer);
    844             lastFloat = m_floatingObjects->last();
    845         }
    846         size_t floatCount = floats.size();
    847         // Floats that did not have layout did not repaint when we laid them out. They would have
    848         // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
    849         // painted.
    850         for (size_t i = 0; i < floatCount; ++i) {
    851             if (!floats[i].everHadLayout) {
    852                 RenderBox* f = floats[i].object;
    853                 if (!f->x() && !f->y() && f->checkForRepaintDuringLayout())
    854                     f->repaint();
    855             }
    856         }
     879        layoutRunsAndFloats(fullLayout, floats, repaintTop, repaintBottom);
    857880    }
    858881
Note: See TracChangeset for help on using the changeset viewer.