Changeset 207219 in webkit


Ignore:
Timestamp:
Oct 12, 2016 9:45:55 AM (8 years ago)
Author:
Alan Bujtas
Message:

Refactor LineLayoutState's float box handling.
https://bugs.webkit.org/show_bug.cgi?id=163286

Reviewed by David Hyatt.

We keep track of float boxes both per line (RootInlineBox::m_floats) and
per flow block (LineLayoutState::m_floats) during layout.
As we lay out the lines and iterate through RootInlineBox::m_floats, we
increment LineLayoutState::m_floatIndex. This LineLayoutState::m_floatIndex is
later used to find the matching float box in the per-block-flow float list.
This logic works fine as long as the lists and the index manipulation are tightly coded.
However due to the complexity of the line/float layout code, this is no longer the case.

This patch makes float box handling more secure by changing this index based setup
to a list iterator. It helps to eliminate potential vector overflow issues.

LineLayoutState::FloatList (new class) keeps track of all the floats for the block flow.
It groups the float box related functions/members and provides an iterator interface to ensure safer
syncing between this and the line based floats.

No change in functionality.

  • rendering/RenderBlockFlow.h:
  • rendering/RenderBlockLineLayout.cpp:

(WebCore::RenderBlockFlow::appendFloatingObjectToLastLine):
(WebCore::repaintDirtyFloats):
(WebCore::RenderBlockFlow::layoutRunsAndFloats):
(WebCore::RenderBlockFlow::layoutRunsAndFloatsInRange):
(WebCore::RenderBlockFlow::linkToEndLineIfNeeded):
(WebCore::RenderBlockFlow::layoutLineBoxes):
(WebCore::RenderBlockFlow::checkFloatInCleanLine):
(WebCore::RenderBlockFlow::determineStartPosition):
(WebCore::RenderBlockFlow::determineEndPosition):
(WebCore::RenderBlockFlow::repaintDirtyFloats): Deleted.
(WebCore::RenderBlockFlow::checkFloatsInCleanLine): Deleted.

  • rendering/line/LineLayoutState.h:

(WebCore::FloatWithRect::create):
(WebCore::FloatWithRect::renderer):
(WebCore::FloatWithRect::rect):
(WebCore::FloatWithRect::everHadLayout):
(WebCore::FloatWithRect::adjustRect):
(WebCore::FloatWithRect::FloatWithRect):
(WebCore::LineLayoutState::FloatList::append):
(WebCore::LineLayoutState::FloatList::setLastFloat):
(WebCore::LineLayoutState::FloatList::lastFloat):
(WebCore::LineLayoutState::FloatList::setLastCleanFloat):
(WebCore::LineLayoutState::FloatList::lastCleanFloat):
(WebCore::LineLayoutState::FloatList::floatWithRect):
(WebCore::LineLayoutState::FloatList::begin):
(WebCore::LineLayoutState::FloatList::end):
(WebCore::LineLayoutState::FloatList::find):
(WebCore::LineLayoutState::FloatList::isEmpty):
(WebCore::LineLayoutState::LineLayoutState):
(WebCore::LineLayoutState::floatList):
(WebCore::LineLayoutState::lastFloat): Deleted.
(WebCore::LineLayoutState::setLastFloat): Deleted.
(WebCore::LineLayoutState::floats): Deleted.
(WebCore::LineLayoutState::floatIndex): Deleted.
(WebCore::LineLayoutState::setFloatIndex): Deleted.

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r207216 r207219  
     12016-10-12  Zalan Bujtas  <zalan@apple.com>
     2
     3        Refactor LineLayoutState's float box handling.
     4        https://bugs.webkit.org/show_bug.cgi?id=163286
     5
     6        Reviewed by David Hyatt.
     7       
     8        We keep track of float boxes both per line (RootInlineBox::m_floats) and
     9        per flow block (LineLayoutState::m_floats) during layout.
     10        As we lay out the lines and iterate through RootInlineBox::m_floats, we
     11        increment LineLayoutState::m_floatIndex. This LineLayoutState::m_floatIndex is
     12        later used to find the matching float box in the per-block-flow float list.
     13        This logic works fine as long as the lists and the index manipulation are tightly coded.
     14        However due to the complexity of the line/float layout code, this is no longer the case.
     15
     16        This patch makes float box handling more secure by changing this index based setup
     17        to a list iterator. It helps to eliminate potential vector overflow issues.
     18
     19        LineLayoutState::FloatList (new class) keeps track of all the floats for the block flow.
     20        It groups the float box related functions/members and provides an iterator interface to ensure safer
     21        syncing between this and the line based floats.
     22
     23        No change in functionality.
     24
     25        * rendering/RenderBlockFlow.h:
     26        * rendering/RenderBlockLineLayout.cpp:
     27        (WebCore::RenderBlockFlow::appendFloatingObjectToLastLine):
     28        (WebCore::repaintDirtyFloats):
     29        (WebCore::RenderBlockFlow::layoutRunsAndFloats):
     30        (WebCore::RenderBlockFlow::layoutRunsAndFloatsInRange):
     31        (WebCore::RenderBlockFlow::linkToEndLineIfNeeded):
     32        (WebCore::RenderBlockFlow::layoutLineBoxes):
     33        (WebCore::RenderBlockFlow::checkFloatInCleanLine):
     34        (WebCore::RenderBlockFlow::determineStartPosition):
     35        (WebCore::RenderBlockFlow::determineEndPosition):
     36        (WebCore::RenderBlockFlow::repaintDirtyFloats): Deleted.
     37        (WebCore::RenderBlockFlow::checkFloatsInCleanLine): Deleted.
     38        * rendering/line/LineLayoutState.h:
     39        (WebCore::FloatWithRect::create):
     40        (WebCore::FloatWithRect::renderer):
     41        (WebCore::FloatWithRect::rect):
     42        (WebCore::FloatWithRect::everHadLayout):
     43        (WebCore::FloatWithRect::adjustRect):
     44        (WebCore::FloatWithRect::FloatWithRect):
     45        (WebCore::LineLayoutState::FloatList::append):
     46        (WebCore::LineLayoutState::FloatList::setLastFloat):
     47        (WebCore::LineLayoutState::FloatList::lastFloat):
     48        (WebCore::LineLayoutState::FloatList::setLastCleanFloat):
     49        (WebCore::LineLayoutState::FloatList::lastCleanFloat):
     50        (WebCore::LineLayoutState::FloatList::floatWithRect):
     51        (WebCore::LineLayoutState::FloatList::begin):
     52        (WebCore::LineLayoutState::FloatList::end):
     53        (WebCore::LineLayoutState::FloatList::find):
     54        (WebCore::LineLayoutState::FloatList::isEmpty):
     55        (WebCore::LineLayoutState::LineLayoutState):
     56        (WebCore::LineLayoutState::floatList):
     57        (WebCore::LineLayoutState::lastFloat): Deleted.
     58        (WebCore::LineLayoutState::setLastFloat): Deleted.
     59        (WebCore::LineLayoutState::floats): Deleted.
     60        (WebCore::LineLayoutState::floatIndex): Deleted.
     61        (WebCore::LineLayoutState::setFloatIndex): Deleted.
     62
    1632016-10-12  Said Abou-Hallawa  <sabouhallawa@apple.com>
    264
  • trunk/Source/WebCore/rendering/RenderBlockFlow.h

    r206395 r207219  
    3434namespace WebCore {
    3535
     36class FloatWithRect;
    3637class LayoutStateMaintainer;
    3738class LineBreaker;
     
    4243class RenderRubyRun;
    4344
    44 struct FloatWithRect;
    4545struct WordMeasurement;
    4646
     
    567567    void computeBlockDirectionPositionsForLine(RootInlineBox*, BidiRun*, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&);
    568568    BidiRun* handleTrailingSpaces(BidiRunList<BidiRun>&, BidiContext*);
    569     void appendFloatingObjectToLastLine(FloatingObject*);
     569    void appendFloatingObjectToLastLine(FloatingObject&);
    570570    // Helper function for layoutInlineChildren()
    571571    RootInlineBox* createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>&, const InlineIterator& end, LineInfo&, VerticalPositionCache&, BidiRun* trailingSpaceRun, WordMeasurements&);
     
    575575    void reattachCleanLineFloats(RootInlineBox& cleanLine, LayoutUnit delta, bool isFirstCleanLine);
    576576    void linkToEndLineIfNeeded(LineLayoutState&);
    577     static void repaintDirtyFloats(Vector<FloatWithRect>& floats);
    578     void checkFloatsInCleanLine(RootInlineBox*, Vector<FloatWithRect>&, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat);
     577    void checkFloatInCleanLine(RootInlineBox& cleanLine, RenderBox& floatBoxOnCleanLine, FloatWithRect& matchingFloatWithRect,
     578        bool& encounteredNewFloat, bool& dirtiedByFloat);
    579579    RootInlineBox* determineStartPosition(LineLayoutState&, InlineBidiResolver&);
    580580    void determineEndPosition(LineLayoutState&, RootInlineBox* startBox, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus);
  • trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp

    r205186 r207219  
    11011101}
    11021102
    1103 void RenderBlockFlow::appendFloatingObjectToLastLine(FloatingObject* floatingObject)
    1104 {
    1105     ASSERT_WITH_SECURITY_IMPLICATION(!floatingObject->originatingLine());
    1106     floatingObject->setOriginatingLine(lastRootBox());
    1107     lastRootBox()->appendFloat(floatingObject->renderer());
     1103void RenderBlockFlow::appendFloatingObjectToLastLine(FloatingObject& floatingObject)
     1104{
     1105    ASSERT_WITH_SECURITY_IMPLICATION(!floatingObject.originatingLine());
     1106    floatingObject.setOriginatingLine(lastRootBox());
     1107    lastRootBox()->appendFloat(floatingObject.renderer());
    11081108}
    11091109
     
    12501250}
    12511251
     1252static void repaintDirtyFloats(LineLayoutState::FloatList& floats)
     1253{
     1254    // Floats that did not have layout did not repaint when we laid them out. They would have
     1255    // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
     1256    // painted.
     1257    for (auto& floatBox : floats) {
     1258        if (floatBox->everHadLayout())
     1259            continue;
     1260        auto& box = floatBox->renderer();
     1261        if (!box.x() && !box.y() && box.checkForRepaintDuringLayout())
     1262            box.repaint();
     1263    }
     1264}
     1265
    12521266void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool hasInlineChild)
    12531267{
     
    12801294
    12811295    if (containsFloats())
    1282         layoutState.setLastFloat(m_floatingObjects->set().last().get());
     1296        layoutState.floatList().setLastFloat(m_floatingObjects->set().last().get());
    12831297
    12841298    // We also find the first clean line and extract these lines.  We will add them back
     
    13131327    layoutRunsAndFloatsInRange(layoutState, resolver, cleanLineStart, cleanLineBidiStatus, consecutiveHyphenatedLines);
    13141328    linkToEndLineIfNeeded(layoutState);
    1315     repaintDirtyFloats(layoutState.floats());
     1329    repaintDirtyFloats(layoutState.floatList());
    13161330}
    13171331
     
    14801494            auto it = floatingObjectSet.begin();
    14811495            auto end = floatingObjectSet.end();
    1482             if (layoutState.lastFloat()) {
    1483                 auto lastFloatIterator = floatingObjectSet.find<FloatingObject&, FloatingObjectHashTranslator>(*layoutState.lastFloat());
     1496            if (auto* lastFloat = layoutState.floatList().lastFloat()) {
     1497                auto lastFloatIterator = floatingObjectSet.find<FloatingObject&, FloatingObjectHashTranslator>(*lastFloat);
    14841498                ASSERT(lastFloatIterator != end);
    14851499                ++lastFloatIterator;
     
    14871501            }
    14881502            for (; it != end; ++it) {
    1489                 FloatingObject* f = it->get();
    1490                 appendFloatingObjectToLastLine(f);
    1491                 ASSERT(&f->renderer() == &layoutState.floats()[layoutState.floatIndex()].object);
     1503                auto& floatingObject = *it;
     1504                appendFloatingObjectToLastLine(*floatingObject);
    14921505                // If a float's geometry has changed, give up on syncing with clean lines.
    1493                 if (layoutState.floats()[layoutState.floatIndex()].rect != f->frameRect())
     1506                auto* floatWithRect = layoutState.floatList().floatWithRect(floatingObject->renderer());
     1507                if (!floatWithRect || floatWithRect->rect() != floatingObject->frameRect())
    14941508                    checkForEndLineMatch = false;
    1495                 layoutState.setFloatIndex(layoutState.floatIndex() + 1);
    1496             }
    1497             layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : nullptr);
     1509            }
     1510            layoutState.floatList().setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : nullptr);
    14981511        }
    14991512
     
    16421655        auto it = floatingObjectSet.begin();
    16431656        auto end = floatingObjectSet.end();
    1644         if (layoutState.lastFloat()) {
    1645             auto lastFloatIterator = floatingObjectSet.find<FloatingObject&, FloatingObjectHashTranslator>(*layoutState.lastFloat());
     1657        if (auto* lastFloat = layoutState.floatList().lastFloat()) {
     1658            auto lastFloatIterator = floatingObjectSet.find<FloatingObject&, FloatingObjectHashTranslator>(*lastFloat);
    16461659            ASSERT(lastFloatIterator != end);
    16471660            ++lastFloatIterator;
     
    16491662        }
    16501663        for (; it != end; ++it)
    1651             appendFloatingObjectToLastLine(it->get());
    1652         layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : nullptr);
    1653     }
    1654 }
    1655 
    1656 void RenderBlockFlow::repaintDirtyFloats(Vector<FloatWithRect>& floats)
    1657 {
    1658     size_t floatCount = floats.size();
    1659     // Floats that did not have layout did not repaint when we laid them out. They would have
    1660     // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
    1661     // painted.
    1662     for (size_t i = 0; i < floatCount; ++i) {
    1663         if (!floats[i].everHadLayout) {
    1664             RenderBox& box = floats[i].object;
    1665             if (!box.x() && !box.y() && box.checkForRepaintDuringLayout())
    1666                 box.repaint();
    1667         }
     1664            appendFloatingObjectToLastLine(**it);
     1665        layoutState.floatList().setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : nullptr);
    16681666    }
    16691667}
     
    17301728                    box.containingBlock()->insertPositionedObject(box);
    17311729                else if (box.isFloating())
    1732                     layoutState.floats().append(FloatWithRect(box));
     1730                    layoutState.floatList().append(FloatWithRect::create(box));
    17331731                else if (isFullLayout || box.needsLayout()) {
    17341732                    // Replaced element.
     
    17861784}
    17871785
    1788 void RenderBlockFlow::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRect>& floats, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat)
    1789 {
    1790     Vector<RenderBox*>* cleanLineFloats = line->floatsPtr();
    1791     if (!cleanLineFloats)
    1792         return;
    1793    
    1794     if (!floats.size()) {
     1786void RenderBlockFlow::checkFloatInCleanLine(RootInlineBox& cleanLine, RenderBox& floatBoxOnCleanLine, FloatWithRect& matchingFloatWithRect,
     1787    bool& encounteredNewFloat, bool& dirtiedByFloat)
     1788{
     1789    ASSERT_WITH_SECURITY_IMPLICATION(!floatBoxOnCleanLine.style().deletionHasBegun());
     1790    if (&matchingFloatWithRect.renderer() != &floatBoxOnCleanLine) {
    17951791        encounteredNewFloat = true;
    17961792        return;
    17971793    }
    1798 
    1799     for (auto it = cleanLineFloats->begin(), end = cleanLineFloats->end(); it != end; ++it) {
    1800         RenderBox* floatingBox = *it;
    1801         ASSERT_WITH_SECURITY_IMPLICATION(!floatingBox->style().deletionHasBegun());
    1802         floatingBox->layoutIfNeeded();
    1803         LayoutSize newSize(floatingBox->width() + floatingBox->horizontalMarginExtent(), floatingBox->height() + floatingBox->verticalMarginExtent());
    1804         ASSERT_WITH_SECURITY_IMPLICATION(floatIndex < floats.size());
    1805         if (&floats[floatIndex].object != floatingBox) {
    1806             encounteredNewFloat = true;
    1807             return;
    1808         }
     1794    floatBoxOnCleanLine.layoutIfNeeded();
     1795    LayoutRect originalFloatRect = matchingFloatWithRect.rect();
     1796    LayoutSize newSize(
     1797        floatBoxOnCleanLine.width() + floatBoxOnCleanLine.horizontalMarginExtent(),
     1798        floatBoxOnCleanLine.height() + floatBoxOnCleanLine.verticalMarginExtent());
    18091799   
    1810         // We have to reset the cap-height alignment done by the first-letter floats when initial-letter is set, so just always treat first-letter floats
    1811         // as dirty.
    1812         if (floats[floatIndex].rect.size() != newSize || (floatingBox->style().styleType() == FIRST_LETTER && floatingBox->style().initialLetterDrop() > 0)) {
    1813             LayoutUnit floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
    1814             LayoutUnit floatHeight = isHorizontalWritingMode() ? std::max(floats[floatIndex].rect.height(), newSize.height()) : std::max(floats[floatIndex].rect.width(), newSize.width());
    1815             floatHeight = std::min(floatHeight, LayoutUnit::max() - floatTop);
    1816             line->markDirty();
    1817             markLinesDirtyInBlockRange(line->lineBottomWithLeading(), floatTop + floatHeight, line);
    1818             floats[floatIndex].rect.setSize(newSize);
    1819             dirtiedByFloat = true;
    1820         }
    1821         floatIndex++;
    1822     }
     1800    // We have to reset the cap-height alignment done by the first-letter floats when initial-letter is set, so just always treat first-letter floats as dirty.
     1801    if (originalFloatRect.size() == newSize && (floatBoxOnCleanLine.style().styleType() != FIRST_LETTER || !floatBoxOnCleanLine.style().initialLetterDrop()))
     1802        return;
     1803
     1804    LayoutUnit floatTop = isHorizontalWritingMode() ? originalFloatRect.y() : originalFloatRect.x();
     1805    LayoutUnit floatHeight = isHorizontalWritingMode() ? std::max(originalFloatRect.height(), newSize.height())
     1806        : std::max(originalFloatRect.width(), newSize.width());
     1807    floatHeight = std::min(floatHeight, LayoutUnit::max() - floatTop);
     1808    cleanLine.markDirty();
     1809    markLinesDirtyInBlockRange(cleanLine.lineBottomWithLeading(), floatTop + floatHeight, &cleanLine);
     1810    LayoutRect newFloatRect = originalFloatRect;
     1811    newFloatRect.setSize(newSize);
     1812    matchingFloatWithRect.adjustRect(newFloatRect);
     1813    dirtiedByFloat = true;
    18231814}
    18241815
    18251816RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutState, InlineBidiResolver& resolver)
    18261817{
    1827     RootInlineBox* curr = 0;
    1828     RootInlineBox* last = 0;
     1818    RootInlineBox* currentLine = nullptr;
     1819    RootInlineBox* lastLine = nullptr;
    18291820
    18301821    // FIXME: This entire float-checking block needs to be broken into a new function.
     1822    auto& floats = layoutState.floatList();
    18311823    bool dirtiedByFloat = false;
    18321824    if (!layoutState.isFullLayout()) {
     
    18341826        bool paginated = view().layoutState() && view().layoutState()->isPaginated();
    18351827        LayoutUnit paginationDelta = 0;
    1836         size_t floatIndex = 0;
    1837         for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
     1828        auto floatsIterator = floats.begin();
     1829        auto end = floats.end();
     1830        for (currentLine = firstRootBox(); currentLine && !currentLine->isDirty(); currentLine = currentLine->nextRootBox()) {
    18381831            if (paginated) {
    1839                 if (lineWidthForPaginatedLineChanged(curr, 0, layoutState.flowThread())) {
    1840                     curr->markDirty();
     1832                if (lineWidthForPaginatedLineChanged(currentLine, 0, layoutState.flowThread())) {
     1833                    currentLine->markDirty();
    18411834                    break;
    18421835                }
    1843                 paginationDelta -= curr->paginationStrut();
     1836                paginationDelta -= currentLine->paginationStrut();
    18441837                bool overflowsRegion;
    1845                 adjustLinePositionForPagination(curr, paginationDelta, overflowsRegion, layoutState.flowThread());
     1838                adjustLinePositionForPagination(currentLine, paginationDelta, overflowsRegion, layoutState.flowThread());
    18461839                if (paginationDelta) {
    1847                     if (containsFloats() || !layoutState.floats().isEmpty()) {
     1840                    if (containsFloats() || !floats.isEmpty()) {
    18481841                        // FIXME: Do better eventually.  For now if we ever shift because of pagination and floats are present just go to a full layout.
    18491842                        layoutState.markForFullLayout();
     
    18511844                    }
    18521845
    1853                     layoutState.updateRepaintRangeFromBox(curr, paginationDelta);
    1854                     curr->adjustBlockDirectionPosition(paginationDelta);
     1846                    layoutState.updateRepaintRangeFromBox(currentLine, paginationDelta);
     1847                    currentLine->adjustBlockDirectionPosition(paginationDelta);
    18551848                }
    18561849                if (layoutState.flowThread())
    1857                     updateRegionForLine(curr);
    1858             }
    1859 
    1860             // If a new float has been inserted before this line or before its last known float, just do a full layout.
    1861             bool encounteredNewFloat = false;
    1862             checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
    1863             if (encounteredNewFloat)
    1864                 layoutState.markForFullLayout();
    1865 
    1866             if (dirtiedByFloat || layoutState.isFullLayout())
    1867                 break;
     1850                    updateRegionForLine(currentLine);
     1851            }
     1852
     1853            if (auto* cleanLineFloats = currentLine->floatsPtr()) {
     1854                // If a new float has been inserted before this line or before its last known float, just do a full layout.
     1855                bool encounteredNewFloat = false;
     1856                for (auto* floatBoxOnCleanLine : *cleanLineFloats) {
     1857                    ASSERT(floatsIterator != end);
     1858                    checkFloatInCleanLine(*currentLine, *floatBoxOnCleanLine, *floatsIterator, encounteredNewFloat, dirtiedByFloat);
     1859                    ++floatsIterator;
     1860                    if (floatsIterator == end || encounteredNewFloat) {
     1861                        layoutState.markForFullLayout();
     1862                        break;
     1863                    }
     1864                }
     1865                if (dirtiedByFloat || encounteredNewFloat)
     1866                    break;
     1867            }
    18681868        }
    18691869        // Check if a new float has been inserted after the last known float.
    1870         if (!curr && floatIndex < layoutState.floats().size())
     1870        if (!currentLine && floatsIterator != end)
    18711871            layoutState.markForFullLayout();
    18721872    }
     
    18741874    if (layoutState.isFullLayout()) {
    18751875        m_lineBoxes.deleteLineBoxTree();
    1876         curr = 0;
    1877 
     1876        currentLine = nullptr;
    18781877        ASSERT(!firstRootBox() && !lastRootBox());
    18791878    } else {
    1880         if (curr) {
     1879        if (currentLine) {
    18811880            // We have a dirty line.
    1882             if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
     1881            if (RootInlineBox* prevRootBox = currentLine->prevRootBox()) {
    18831882                // We have a previous line.
    1884                 if (!dirtiedByFloat && !curr->hasAnonymousInlineBlock() && (!prevRootBox->endsWithBreak() || !prevRootBox->lineBreakObj() || (is<RenderText>(*prevRootBox->lineBreakObj()) && prevRootBox->lineBreakPos() >= downcast<RenderText>(*prevRootBox->lineBreakObj()).textLength()))) {
     1883                if (!dirtiedByFloat && !currentLine->hasAnonymousInlineBlock() && (!prevRootBox->endsWithBreak()
     1884                    || !prevRootBox->lineBreakObj()
     1885                    || (is<RenderText>(*prevRootBox->lineBreakObj())
     1886                    && prevRootBox->lineBreakPos() >= downcast<RenderText>(*prevRootBox->lineBreakObj()).textLength()))) {
    18851887                    // The previous line didn't break cleanly or broke at a newline
    18861888                    // that has been deleted, so treat it as dirty too.
    1887                     curr = prevRootBox;
     1889                    currentLine = prevRootBox;
    18881890                }
    18891891            }
    18901892        }
    18911893        // If we have no dirty lines, then last is just the last root box.
    1892         last = curr ? curr->prevRootBox() : lastRootBox();
    1893     }
    1894 
    1895     unsigned numCleanFloats = 0;
    1896     if (!layoutState.floats().isEmpty()) {
     1894        lastLine = currentLine ? currentLine->prevRootBox() : lastRootBox();
     1895    }
     1896
     1897    if (!floats.isEmpty()) {
    18971898        LayoutUnit savedLogicalHeight = logicalHeight();
    18981899        // Restore floats from clean lines.
    18991900        RootInlineBox* line = firstRootBox();
    1900         while (line != curr) {
     1901        while (line != currentLine) {
    19011902            if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
    19021903                for (auto it = cleanLineFloats->begin(), end = cleanLineFloats->end(); it != end; ++it) {
    1903                     RenderBox* floatingBox = *it;
    1904                     FloatingObject* floatingObject = insertFloatingObject(*floatingBox);
     1904                    auto* floatingBox = *it;
     1905                    auto* floatingObject = insertFloatingObject(*floatingBox);
    19051906                    ASSERT_WITH_SECURITY_IMPLICATION(!floatingObject->originatingLine());
    19061907                    floatingObject->setOriginatingLine(line);
    19071908                    setLogicalHeight(logicalTopForChild(*floatingBox) - marginBeforeForChild(*floatingBox));
    19081909                    positionNewFloats();
    1909                     ASSERT(&layoutState.floats()[numCleanFloats].object == floatingBox);
    1910                     numCleanFloats++;
     1910                    floats.setLastCleanFloat(*floatingBox);
    19111911                }
    19121912            }
     
    19151915        setLogicalHeight(savedLogicalHeight);
    19161916    }
    1917     layoutState.setFloatIndex(numCleanFloats);
    1918 
    1919     layoutState.lineInfo().setFirstLine(!last);
    1920     layoutState.lineInfo().setPreviousLineBrokeCleanly(!last || last->endsWithBreak());
    1921 
    1922     if (last) {
    1923         setLogicalHeight(last->lineBottomWithLeading());
    1924         InlineIterator iter = InlineIterator(this, last->lineBreakObj(), last->lineBreakPos());
     1917
     1918    layoutState.lineInfo().setFirstLine(!lastLine);
     1919    layoutState.lineInfo().setPreviousLineBrokeCleanly(!lastLine || lastLine->endsWithBreak());
     1920
     1921    if (lastLine) {
     1922        setLogicalHeight(lastLine->lineBottomWithLeading());
     1923        InlineIterator iter = InlineIterator(this, lastLine->lineBreakObj(), lastLine->lineBreakPos());
    19251924        resolver.setPosition(iter, numberOfIsolateAncestors(iter));
    1926         resolver.setStatus(last->lineBreakBidiStatus());
     1925        resolver.setStatus(lastLine->lineBreakBidiStatus());
    19271926    } else {
    19281927        TextDirection direction = style().direction();
     
    19331932        resolver.setPosition(iter, numberOfIsolateAncestors(iter));
    19341933    }
    1935     return curr;
     1934    return currentLine;
    19361935}
    19371936
    19381937void RenderBlockFlow::determineEndPosition(LineLayoutState& layoutState, RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus)
    19391938{
     1939    auto iteratorForFirstDirtyFloat = [](LineLayoutState::FloatList& floats) {
     1940        auto lastCleanFloat = floats.lastCleanFloat();
     1941        if (!lastCleanFloat)
     1942            return floats.begin();
     1943        auto* lastCleanFloatWithRect = floats.floatWithRect(*lastCleanFloat);
     1944        ASSERT(lastCleanFloatWithRect);
     1945        return ++floats.find(*lastCleanFloatWithRect);
     1946    };
     1947
    19401948    ASSERT(!layoutState.endLine());
    1941     size_t floatIndex = layoutState.floatIndex();
    1942     RootInlineBox* last = 0;
    1943     for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
    1944         if (!curr->isDirty()) {
    1945             bool encounteredNewFloat = false;
    1946             bool dirtiedByFloat = false;
    1947             checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
    1948             if (encounteredNewFloat)
    1949                 return;
    1950         }
    1951         if (curr->isDirty())
    1952             last = 0;
    1953         else if (!last)
    1954             last = curr;
    1955     }
    1956 
    1957     if (!last)
     1949    auto floatsIterator = iteratorForFirstDirtyFloat(layoutState.floatList());
     1950    auto end = layoutState.floatList().end();
     1951    RootInlineBox* lastLine = nullptr;
     1952    for (RootInlineBox* currentLine = startLine->nextRootBox(); currentLine; currentLine = currentLine->nextRootBox()) {
     1953        if (!currentLine->isDirty()) {
     1954            if (auto* cleanLineFloats = currentLine->floatsPtr()) {
     1955                bool encounteredNewFloat = false;
     1956                bool dirtiedByFloat = false;
     1957                for (auto* floatBoxOnCleanLine : *cleanLineFloats) {
     1958                    ASSERT(floatsIterator != end);
     1959                    checkFloatInCleanLine(*currentLine, *floatBoxOnCleanLine, *floatsIterator, encounteredNewFloat, dirtiedByFloat);
     1960                    ++floatsIterator;
     1961                    if (floatsIterator == end || encounteredNewFloat)
     1962                        return;
     1963                }
     1964            }
     1965        }
     1966        if (currentLine->isDirty())
     1967            lastLine = nullptr;
     1968        else if (!lastLine)
     1969            lastLine = currentLine;
     1970    }
     1971
     1972    if (!lastLine)
    19581973        return;
    19591974
    19601975    // At this point, |last| is the first line in a run of clean lines that ends with the last line
    19611976    // in the block.
    1962 
    1963     RootInlineBox* prev = last->prevRootBox();
    1964     cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
    1965     cleanLineBidiStatus = prev->lineBreakBidiStatus();
    1966     layoutState.setEndLineLogicalTop(prev->lineBottomWithLeading());
    1967 
    1968     for (RootInlineBox* line = last; line; line = line->nextRootBox())
    1969         line->extractLine(); // Disconnect all line boxes from their render objects while preserving
    1970                              // their connections to one another.
    1971 
    1972     layoutState.setEndLine(last);
     1977    RootInlineBox* previousLine = lastLine->prevRootBox();
     1978    cleanLineStart = InlineIterator(this, previousLine->lineBreakObj(), previousLine->lineBreakPos());
     1979    cleanLineBidiStatus = previousLine->lineBreakBidiStatus();
     1980    layoutState.setEndLineLogicalTop(previousLine->lineBottomWithLeading());
     1981
     1982    for (RootInlineBox* line = lastLine; line; line = line->nextRootBox()) {
     1983        // Disconnect all line boxes from their render objects while preserving their connections to one another.
     1984        line->extractLine();
     1985    }
     1986    layoutState.setEndLine(lastLine);
    19731987}
    19741988
  • trunk/Source/WebCore/rendering/line/LineLayoutState.h

    r189817 r207219  
    3737#include "LayoutRect.h"
    3838#include "RenderBlockFlow.h"
     39#include <wtf/RefCounted.h>
    3940
    4041namespace WebCore {
    4142
    42 struct FloatWithRect {
    43     FloatWithRect(RenderBox& f)
    44         : object(f)
    45         , rect(LayoutRect(f.x() - f.marginLeft(), f.y() - f.marginTop(), f.width() + f.horizontalMarginExtent(), f.height() + f.verticalMarginExtent()))
    46         , everHadLayout(f.everHadLayout())
     43class FloatWithRect : public RefCounted<FloatWithRect> {
     44    WTF_MAKE_FAST_ALLOCATED;
     45public:
     46    static Ref<FloatWithRect> create(RenderBox& renderer)
     47    {
     48        return adoptRef(*new FloatWithRect(renderer));
     49    }
     50   
     51    RenderBox& renderer() const { return m_renderer; }
     52    LayoutRect rect() const { return m_rect; }
     53    bool everHadLayout() const { return m_everHadLayout; }
     54
     55    void adjustRect(const LayoutRect& rect) { m_rect = rect; }
     56
     57private:
     58    FloatWithRect() = default;
     59   
     60    FloatWithRect(RenderBox& renderer)
     61        : m_renderer(renderer)
     62        , m_rect(LayoutRect(renderer.x() - renderer.marginLeft(), renderer.y() - renderer.marginTop(), renderer.width() + renderer.horizontalMarginExtent(), renderer.height() + renderer.verticalMarginExtent()))
     63        , m_everHadLayout(renderer.everHadLayout())
    4764    {
    4865    }
    49 
    50     RenderBox& object;
    51     LayoutRect rect;
    52     bool everHadLayout;
     66   
     67    RenderBox& m_renderer;
     68    LayoutRect m_rect;
     69    bool m_everHadLayout { false };
    5370};
    5471
     
    5774class LineLayoutState {
    5875public:
     76    class FloatList {
     77    public:
     78        void append(Ref<FloatWithRect>&& floatWithRect)
     79        {
     80            m_floats.add(floatWithRect.copyRef());
     81            m_floatWithRectMap.add(&floatWithRect->renderer(), WTFMove(floatWithRect));
     82        }
     83        void setLastFloat(FloatingObject* lastFloat) { m_lastFloat = lastFloat; }
     84        FloatingObject* lastFloat() const { return m_lastFloat; }
     85
     86        void setLastCleanFloat(RenderBox& floatBox) { m_lastCleanFloat = &floatBox; }
     87        RenderBox* lastCleanFloat() const { return m_lastCleanFloat; }
     88
     89        FloatWithRect* floatWithRect(RenderBox& floatBox) const { return m_floatWithRectMap.get(&floatBox); }
     90
     91        using Iterator = ListHashSet<Ref<FloatWithRect>>::iterator;
     92        Iterator begin() { return m_floats.begin(); }
     93        Iterator end() { return m_floats.end(); }
     94        Iterator find(FloatWithRect& floatBoxWithRect) { return m_floats.find(floatBoxWithRect); }
     95        bool isEmpty() const { return m_floats.isEmpty(); }
     96
     97    private:
     98        ListHashSet<Ref<FloatWithRect>> m_floats;
     99        HashMap<RenderBox*, Ref<FloatWithRect>> m_floatWithRectMap;
     100        FloatingObject* m_lastFloat { nullptr };
     101        RenderBox* m_lastCleanFloat { nullptr };
     102    };
     103
    59104    LineLayoutState(const RenderBlockFlow& blockFlow, bool fullLayout, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, RenderFlowThread* flowThread)
    60         : m_endLineLogicalTop(0)
    61         , m_endLine(0)
    62         , m_lastFloat(0)
    63         , m_floatIndex(0)
    64         , m_adjustedLogicalLineTop(0)
    65         , m_flowThread(flowThread)
     105        : m_flowThread(flowThread)
    66106        , m_repaintLogicalTop(repaintLogicalTop)
    67107        , m_repaintLogicalBottom(repaintLogicalBottom)
     
    82122    RootInlineBox* endLine() const { return m_endLine; }
    83123    void setEndLine(RootInlineBox* line) { m_endLine = line; }
    84 
    85     FloatingObject* lastFloat() const { return m_lastFloat; }
    86     void setLastFloat(FloatingObject* lastFloat) { m_lastFloat = lastFloat; }
    87 
    88     Vector<FloatWithRect>& floats() { return m_floats; }
    89 
    90     unsigned floatIndex() const { return m_floatIndex; }
    91     void setFloatIndex(unsigned floatIndex) { m_floatIndex = floatIndex; }
    92124
    93125    LayoutUnit adjustedLogicalLineTop() const { return m_adjustedLogicalLineTop; }
     
    125157    LayoutUnit& maxFloatBottomFromAnonymousInlineBlock() { return m_maxFloatBottomFromAnonymousInlineBlock; }
    126158
     159    FloatList& floatList() { return m_floatList; }
     160
    127161private:
    128162    LineInfo m_lineInfo;
    129163    LayoutUnit m_endLineLogicalTop;
    130     RootInlineBox* m_endLine;
    131 
    132     FloatingObject* m_lastFloat;
    133     Vector<FloatWithRect> m_floats;
    134     unsigned m_floatIndex;
     164    RootInlineBox* m_endLine { nullptr };
    135165
    136166    LayoutUnit m_adjustedLogicalLineTop;
    137167
    138     RenderFlowThread* m_flowThread;
     168    RenderFlowThread* m_flowThread { nullptr };
    139169
     170    FloatList m_floatList;
    140171    // FIXME: Should this be a range object instead of two ints?
    141172    LayoutUnit& m_repaintLogicalTop;
Note: See TracChangeset for help on using the changeset viewer.