Changeset 228682 in webkit


Ignore:
Timestamp:
Feb 19, 2018 7:16:45 AM (6 years ago)
Author:
Carlos Garcia Campos
Message:

Merge r228320 - [RenderTreeBuilder] Move multicolumn spanner mutation logic to RenderTreeBuilder
https://bugs.webkit.org/show_bug.cgi?id=182627
<rdar://problem/37367284>

Reviewed by Antti Koivisto.

Move spanner triggered mutation logic to RenderTreeBuilder.

No change in functionality.

  • rendering/RenderFragmentedFlow.h:
  • rendering/RenderMultiColumnFlow.cpp:

(WebCore::RenderMultiColumnFlow::isColumnSpanningDescendant const):
(WebCore::findSetRendering): Deleted.
(WebCore::isValidColumnSpanner): Deleted.
(WebCore::spannerPlacehoderCandidate): Deleted.
(WebCore::RenderMultiColumnFlow::processPossibleSpannerDescendant): Deleted.
(WebCore::RenderMultiColumnFlow::fragmentedFlowDescendantInserted): Deleted.

  • rendering/RenderMultiColumnFlow.h:
  • rendering/RenderObject.cpp:

(WebCore::RenderObject::insertedIntoTree):

  • rendering/updating/RenderTreeBuilder.cpp:

(WebCore::RenderTreeBuilder::multiColumnDescendantInserted):

  • rendering/updating/RenderTreeBuilder.h:
  • rendering/updating/RenderTreeBuilderMultiColumn.cpp:

(WebCore::findSetRendering):
(WebCore::spannerPlacehoderCandidate):
(WebCore::isValidColumnSpanner):
(WebCore::RenderTreeBuilder::MultiColumn::multiColumnDescendantInserted):
(WebCore::RenderTreeBuilder::MultiColumn::processPossibleSpannerDescendant):

  • rendering/updating/RenderTreeBuilderMultiColumn.h:
Location:
releases/WebKitGTK/webkit-2.20/Source/WebCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • releases/WebKitGTK/webkit-2.20/Source/WebCore/ChangeLog

    r228681 r228682  
     12018-02-09  Zalan Bujtas  <zalan@apple.com>
     2
     3        [RenderTreeBuilder] Move multicolumn spanner mutation logic to RenderTreeBuilder
     4        https://bugs.webkit.org/show_bug.cgi?id=182627
     5        <rdar://problem/37367284>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Move spanner triggered mutation logic to RenderTreeBuilder.
     10
     11        No change in functionality.
     12
     13        * rendering/RenderFragmentedFlow.h:
     14        * rendering/RenderMultiColumnFlow.cpp:
     15        (WebCore::RenderMultiColumnFlow::isColumnSpanningDescendant const):
     16        (WebCore::findSetRendering): Deleted.
     17        (WebCore::isValidColumnSpanner): Deleted.
     18        (WebCore::spannerPlacehoderCandidate): Deleted.
     19        (WebCore::RenderMultiColumnFlow::processPossibleSpannerDescendant): Deleted.
     20        (WebCore::RenderMultiColumnFlow::fragmentedFlowDescendantInserted): Deleted.
     21        * rendering/RenderMultiColumnFlow.h:
     22        * rendering/RenderObject.cpp:
     23        (WebCore::RenderObject::insertedIntoTree):
     24        * rendering/updating/RenderTreeBuilder.cpp:
     25        (WebCore::RenderTreeBuilder::multiColumnDescendantInserted):
     26        * rendering/updating/RenderTreeBuilder.h:
     27        * rendering/updating/RenderTreeBuilderMultiColumn.cpp:
     28        (WebCore::findSetRendering):
     29        (WebCore::spannerPlacehoderCandidate):
     30        (WebCore::isValidColumnSpanner):
     31        (WebCore::RenderTreeBuilder::MultiColumn::multiColumnDescendantInserted):
     32        (WebCore::RenderTreeBuilder::MultiColumn::processPossibleSpannerDescendant):
     33        * rendering/updating/RenderTreeBuilderMultiColumn.h:
     34
    1352018-02-09  Javier Fernandez  <jfernandez@igalia.com>
    236
  • releases/WebKitGTK/webkit-2.20/Source/WebCore/rendering/RenderFragmentedFlow.h

    r227903 r228682  
    8787    virtual bool singleFragmentHasUniformLogicalHeight() const { return true; }
    8888   
    89     // Called when a descendant of the flow thread has been inserted.
    90     virtual void fragmentedFlowDescendantInserted(RenderObject&) { }
    9189    // Called when a sibling or descendant of the flow thread is about to be removed.
    9290    virtual void fragmentedFlowRelativeWillBeRemoved(RenderObject&) { }
  • releases/WebKitGTK/webkit-2.20/Source/WebCore/rendering/RenderMultiColumnFlow.cpp

    r227977 r228682  
    4141WTF_MAKE_ISO_ALLOCATED_IMPL(RenderMultiColumnFlow);
    4242
    43 bool RenderMultiColumnFlow::gShiftingSpanner = false;
    44 
    4543RenderMultiColumnFlow::RenderMultiColumnFlow(Document& document, RenderStyle&& style)
    4644    : RenderFragmentedFlow(document, WTFMove(style))
     
    136134}
    137135
    138 static RenderMultiColumnSet* findSetRendering(const RenderMultiColumnFlow& fragmentedFlow, const RenderObject& renderer)
    139 {
    140     // Find the set inside which the specified renderer would be rendered.
    141     for (auto* multicolSet = fragmentedFlow.firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
    142         if (multicolSet->containsRendererInFragmentedFlow(renderer))
    143             return multicolSet;
    144     }
    145     return nullptr;
     136bool RenderMultiColumnFlow::isColumnSpanningDescendant(const RenderBox& descendantBox) const
     137{
     138    return descendantBox.style().columnSpan() == ColumnSpanAll;
    146139}
    147140
     
    168161}
    169162
    170 bool RenderMultiColumnFlow::isColumnSpanningDescendant(const RenderBox& descendantBox) const
    171 {
    172     return descendantBox.style().columnSpan() == ColumnSpanAll;
    173 }
    174 
    175 static bool isValidColumnSpanner(const RenderMultiColumnFlow& fragmentedFlow, const RenderObject& descendant)
    176 {
    177     // We assume that we're inside the flow thread. This function is not to be called otherwise.
    178     ASSERT(descendant.isDescendantOf(&fragmentedFlow));
    179     // First make sure that the renderer itself has the right properties for becoming a spanner.
    180     if (!is<RenderBox>(descendant))
    181         return false;
    182 
    183     auto& descendantBox = downcast<RenderBox>(descendant);
    184     if (descendantBox.isFloatingOrOutOfFlowPositioned())
    185         return false;
    186 
    187     if (!fragmentedFlow.isColumnSpanningDescendant(descendantBox))
    188         return false;
    189 
    190     auto* parent = descendantBox.parent();
    191     if (!is<RenderBlockFlow>(*parent) || parent->childrenInline()) {
    192         // Needs to be block-level.
    193         return false;
    194     }
    195    
    196     // We need to have the flow thread as the containing block. A spanner cannot break out of the flow thread.
    197     auto* enclosingFragmentedFlow = descendantBox.enclosingFragmentedFlow();
    198     if (enclosingFragmentedFlow != &fragmentedFlow)
    199         return false;
    200 
    201     // This looks like a spanner, but if we're inside something unbreakable, it's not to be treated as one.
    202     for (auto* ancestor = descendantBox.containingBlock(); ancestor; ancestor = ancestor->containingBlock()) {
    203         if (is<RenderView>(*ancestor))
    204             return false;
    205         if (is<RenderFragmentedFlow>(*ancestor)) {
    206             // Don't allow any intervening non-multicol fragmentation contexts. The spec doesn't say
    207             // anything about disallowing this, but it's just going to be too complicated to
    208             // implement (not to mention specify behavior).
    209             return ancestor == &fragmentedFlow;
    210         }
    211         // This ancestor (descendent of the fragmentedFlow) will create columns later. The spanner belongs to it.
    212         if (is<RenderBlockFlow>(*ancestor) && downcast<RenderBlockFlow>(*ancestor).willCreateColumns())
    213             return false;
    214         ASSERT(ancestor->style().columnSpan() != ColumnSpanAll || !isValidColumnSpanner(fragmentedFlow, *ancestor));
    215         if (ancestor->isUnsplittableForPagination())
    216             return false;
    217     }
    218     ASSERT_NOT_REACHED();
    219     return false;
    220 }
    221 
    222 static RenderObject* spannerPlacehoderCandidate(const RenderObject& renderer, const RenderMultiColumnFlow& stayWithin)
    223 {
    224     // Spanner candidate is a next sibling/ancestor's next child within the flow thread and
    225     // it is in the same inflow/out-of-flow layout context.
    226     if (renderer.isOutOfFlowPositioned())
    227         return nullptr;
    228 
    229     ASSERT(renderer.isDescendantOf(&stayWithin));
    230     auto* current = &renderer;
    231     while (true) {
    232         // Skip to the first in-flow sibling.
    233         auto* nextSibling = current->nextSibling();
    234         while (nextSibling && nextSibling->isOutOfFlowPositioned())
    235             nextSibling = nextSibling->nextSibling();
    236         if (nextSibling)
    237             return nextSibling;
    238         // No sibling candidate, jump to the parent and check its siblings.
    239         current = current->parent();
    240         if (!current || current == &stayWithin || current->isOutOfFlowPositioned())
    241             return nullptr;
    242     }
    243     return nullptr;
    244 }
    245 
    246 RenderObject* RenderMultiColumnFlow::processPossibleSpannerDescendant(RenderObject*& subtreeRoot, RenderObject& descendant)
    247 {
    248     RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
    249     RenderObject* nextRendererInFragmentedFlow = spannerPlacehoderCandidate(descendant, *this);
    250     RenderObject* insertBeforeMulticolChild = nullptr;
    251     RenderObject* nextDescendant = &descendant;
    252 
    253     if (isValidColumnSpanner(*this, descendant)) {
    254         // This is a spanner (column-span:all). Such renderers are moved from where they would
    255         // otherwise occur in the render tree to becoming a direct child of the multicol container,
    256         // so that they live among the column sets. This simplifies the layout implementation, and
    257         // basically just relies on regular block layout done by the RenderBlockFlow that
    258         // establishes the multicol container.
    259         RenderBlockFlow* container = downcast<RenderBlockFlow>(descendant.parent());
    260         RenderMultiColumnSet* setToSplit = nullptr;
    261         if (nextRendererInFragmentedFlow) {
    262             setToSplit = findSetRendering(*this, descendant);
    263             if (setToSplit) {
    264                 setToSplit->setNeedsLayout();
    265                 insertBeforeMulticolChild = setToSplit->nextSibling();
    266             }
    267         }
    268         // Moving a spanner's renderer so that it becomes a sibling of the column sets requires us
    269         // to insert an anonymous placeholder in the tree where the spanner's renderer otherwise
    270         // would have been. This is needed for a two reasons: We need a way of separating inline
    271         // content before and after the spanner, so that it becomes separate line boxes. Secondly,
    272         // this placeholder serves as a break point for column sets, so that, when encountered, we
    273         // end flowing one column set and move to the next one.
    274         auto newPlaceholder = RenderMultiColumnSpannerPlaceholder::createAnonymous(*this, downcast<RenderBox>(descendant), container->style());
    275         auto& placeholder = *newPlaceholder;
    276         RenderTreeBuilder::current()->insertChild(*container, WTFMove(newPlaceholder), descendant.nextSibling());
    277         auto takenDescendant = container->takeChild(*RenderTreeBuilder::current(), descendant);
    278        
    279         // This is a guard to stop an ancestor flow thread from processing the spanner.
    280         gShiftingSpanner = true;
    281         RenderTreeBuilder::current()->insertChildToRenderBlock(*multicolContainer, WTFMove(takenDescendant), insertBeforeMulticolChild);
    282         gShiftingSpanner = false;
    283        
    284         // The spanner has now been moved out from the flow thread, but we don't want to
    285         // examine its children anyway. They are all part of the spanner and shouldn't trigger
    286         // creation of column sets or anything like that. Continue at its original position in
    287         // the tree, i.e. where the placeholder was just put.
    288         if (subtreeRoot == &descendant)
    289             subtreeRoot = &placeholder;
    290         nextDescendant = &placeholder;
    291     } else {
    292         // This is regular multicol content, i.e. not part of a spanner.
    293         if (is<RenderMultiColumnSpannerPlaceholder>(nextRendererInFragmentedFlow)) {
    294             // Inserted right before a spanner. Is there a set for us there?
    295             RenderMultiColumnSpannerPlaceholder& placeholder = downcast<RenderMultiColumnSpannerPlaceholder>(*nextRendererInFragmentedFlow);
    296             if (RenderObject* previous = placeholder.spanner()->previousSibling()) {
    297                 if (is<RenderMultiColumnSet>(*previous))
    298                     return nextDescendant; // There's already a set there. Nothing to do.
    299             }
    300             insertBeforeMulticolChild = placeholder.spanner();
    301         } else if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) {
    302             // This child is not an immediate predecessor of a spanner, which means that if this
    303             // child precedes a spanner at all, there has to be a column set created for us there
    304             // already. If it doesn't precede any spanner at all, on the other hand, we need a
    305             // column set at the end of the multicol container. We don't really check here if the
    306             // child inserted precedes any spanner or not (as that's an expensive operation). Just
    307             // make sure we have a column set at the end. It's no big deal if it remains unused.
    308             if (!lastSet->nextSibling())
    309                 return nextDescendant;
    310         }
    311     }
    312     // Need to create a new column set when there's no set already created. We also always insert
    313     // another column set after a spanner. Even if it turns out that there are no renderers
    314     // following the spanner, there may be bottom margins there, which take up space.
    315     auto newSet = createMultiColumnSet(RenderStyle::createAnonymousStyleWithDisplay(multicolContainer->style(), BLOCK));
    316     newSet->initializeStyle();
    317     auto& set = *newSet;
    318     RenderTreeBuilder::current()->insertChildToRenderBlock(*multicolContainer, WTFMove(newSet), insertBeforeMulticolChild);
    319     invalidateFragments();
    320 
    321     // We cannot handle immediate column set siblings at the moment (and there's no need for
    322     // it, either). There has to be at least one spanner separating them.
    323     ASSERT_UNUSED(set, !previousColumnSetOrSpannerSiblingOf(&set) || !previousColumnSetOrSpannerSiblingOf(&set)->isRenderMultiColumnSet());
    324     ASSERT(!nextColumnSetOrSpannerSiblingOf(&set) || !nextColumnSetOrSpannerSiblingOf(&set)->isRenderMultiColumnSet());
    325    
    326     return nextDescendant;
    327 }
    328 
    329163RenderPtr<RenderMultiColumnSet> RenderMultiColumnFlow::createMultiColumnSet(RenderStyle&& style)
    330164{
    331165    return createRenderer<RenderMultiColumnSet>(*this, WTFMove(style));
    332 }
    333 
    334 void RenderMultiColumnFlow::fragmentedFlowDescendantInserted(RenderObject& newDescendant)
    335 {
    336     if (gShiftingSpanner || newDescendant.isInFlowRenderFragmentedFlow())
    337         return;
    338 
    339     auto* subtreeRoot = &newDescendant;
    340     auto* descendant = subtreeRoot;
    341     while (descendant) {
    342         // Skip nested multicolumn flows.
    343         if (is<RenderMultiColumnFlow>(*descendant)) {
    344             descendant = descendant->nextSibling();
    345             continue;
    346         }
    347         if (is<RenderMultiColumnSpannerPlaceholder>(*descendant)) {
    348             // A spanner's placeholder has been inserted. The actual spanner renderer is moved from
    349             // where it would otherwise occur (if it weren't a spanner) to becoming a sibling of the
    350             // column sets.
    351             RenderMultiColumnSpannerPlaceholder& placeholder = downcast<RenderMultiColumnSpannerPlaceholder>(*descendant);
    352             ASSERT(!spannerMap().get(placeholder.spanner()));
    353             spannerMap().add(placeholder.spanner(), makeWeakPtr(downcast<RenderMultiColumnSpannerPlaceholder>(descendant)));
    354             ASSERT(!placeholder.firstChild()); // There should be no children here, but if there are, we ought to skip them.
    355         } else
    356             descendant = processPossibleSpannerDescendant(subtreeRoot, *descendant);
    357         if (descendant)
    358             descendant = descendant->nextInPreOrder(subtreeRoot);
    359     }
    360166}
    361167
  • releases/WebKitGTK/webkit-2.20/Source/WebCore/rendering/RenderMultiColumnFlow.h

    r227903 r228682  
    101101    virtual bool isColumnSpanningDescendant(const RenderBox&) const;
    102102
    103 protected:
    104103    virtual RenderPtr<RenderMultiColumnSet> createMultiColumnSet(RenderStyle&&);
    105104
     
    109108    void addFragmentToThread(RenderFragmentContainer*) override;
    110109    void willBeRemovedFromTree() override;
    111     void fragmentedFlowDescendantInserted(RenderObject&) override;
    112110    void fragmentedFlowRelativeWillBeRemoved(RenderObject&) override;
    113111    void fragmentedFlowDescendantBoxLaidOut(RenderBox*) override;
     
    122120
    123121    void handleSpannerRemoval(RenderObject& spanner);
    124     RenderObject* processPossibleSpannerDescendant(RenderObject*& subtreeRoot, RenderObject& descendant);
    125122
    126123private:
     
    142139    bool m_progressionIsInline;
    143140    bool m_progressionIsReversed;
    144    
    145     static bool gShiftingSpanner;
    146141};
    147142
  • releases/WebKitGTK/webkit-2.20/Source/WebCore/rendering/RenderObject.cpp

    r228655 r228682  
    14601460        parent()->dirtyLinesFromChangedChild(*this);
    14611461
    1462     if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
    1463         fragmentedFlow->fragmentedFlowDescendantInserted(*this);
     1462    auto* fragmentedFlow = enclosingFragmentedFlow();
     1463    if (is<RenderMultiColumnFlow>(fragmentedFlow))
     1464        RenderTreeBuilder::current()->multiColumnDescendantInserted(downcast<RenderMultiColumnFlow>(*fragmentedFlow), *this);
    14641465}
    14651466
  • releases/WebKitGTK/webkit-2.20/Source/WebCore/rendering/updating/RenderTreeBuilder.cpp

    r228668 r228682  
    353353}
    354354
     355void RenderTreeBuilder::multiColumnDescendantInserted(RenderMultiColumnFlow& flow, RenderObject& newDescendant)
     356{
     357    multiColumnBuilder().multiColumnDescendantInserted(flow, newDescendant);
     358}
     359
    355360static bool isAnonymousAndSafeToDelete(RenderElement& element)
    356361{
  • releases/WebKitGTK/webkit-2.20/Source/WebCore/rendering/updating/RenderTreeBuilder.h

    r228665 r228682  
    8080    RenderObject* resolveMovedChildForMultiColumnFlow(RenderFragmentedFlow& enclosingFragmentedFlow, RenderObject* beforeChild);
    8181    void removeFromParentAndDestroyCleaningUpAnonymousWrappers(RenderObject& child);
     82    void multiColumnDescendantInserted(RenderMultiColumnFlow&, RenderObject& newDescendant);
    8283
    8384private:
  • releases/WebKitGTK/webkit-2.20/Source/WebCore/rendering/updating/RenderTreeBuilderMultiColumn.cpp

    r228668 r228682  
    3535namespace WebCore {
    3636
     37static RenderMultiColumnSet* findSetRendering(const RenderMultiColumnFlow& fragmentedFlow, const RenderObject& renderer)
     38{
     39    // Find the set inside which the specified renderer would be rendered.
     40    for (auto* multicolSet = fragmentedFlow.firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
     41        if (multicolSet->containsRendererInFragmentedFlow(renderer))
     42            return multicolSet;
     43    }
     44    return nullptr;
     45}
     46
     47static RenderObject* spannerPlacehoderCandidate(const RenderObject& renderer, const RenderMultiColumnFlow& stayWithin)
     48{
     49    // Spanner candidate is a next sibling/ancestor's next child within the flow thread and
     50    // it is in the same inflow/out-of-flow layout context.
     51    if (renderer.isOutOfFlowPositioned())
     52        return nullptr;
     53
     54    ASSERT(renderer.isDescendantOf(&stayWithin));
     55    auto* current = &renderer;
     56    while (true) {
     57        // Skip to the first in-flow sibling.
     58        auto* nextSibling = current->nextSibling();
     59        while (nextSibling && nextSibling->isOutOfFlowPositioned())
     60            nextSibling = nextSibling->nextSibling();
     61        if (nextSibling)
     62            return nextSibling;
     63        // No sibling candidate, jump to the parent and check its siblings.
     64        current = current->parent();
     65        if (!current || current == &stayWithin || current->isOutOfFlowPositioned())
     66            return nullptr;
     67    }
     68    return nullptr;
     69}
     70
     71static bool isValidColumnSpanner(const RenderMultiColumnFlow& fragmentedFlow, const RenderObject& descendant)
     72{
     73    // We assume that we're inside the flow thread. This function is not to be called otherwise.
     74    ASSERT(descendant.isDescendantOf(&fragmentedFlow));
     75    // First make sure that the renderer itself has the right properties for becoming a spanner.
     76    if (!is<RenderBox>(descendant))
     77        return false;
     78
     79    auto& descendantBox = downcast<RenderBox>(descendant);
     80    if (descendantBox.isFloatingOrOutOfFlowPositioned())
     81        return false;
     82
     83    if (!fragmentedFlow.isColumnSpanningDescendant(descendantBox))
     84        return false;
     85
     86    auto* parent = descendantBox.parent();
     87    if (!is<RenderBlockFlow>(*parent) || parent->childrenInline()) {
     88        // Needs to be block-level.
     89        return false;
     90    }
     91
     92    // We need to have the flow thread as the containing block. A spanner cannot break out of the flow thread.
     93    auto* enclosingFragmentedFlow = descendantBox.enclosingFragmentedFlow();
     94    if (enclosingFragmentedFlow != &fragmentedFlow)
     95        return false;
     96
     97    // This looks like a spanner, but if we're inside something unbreakable, it's not to be treated as one.
     98    for (auto* ancestor = descendantBox.containingBlock(); ancestor; ancestor = ancestor->containingBlock()) {
     99        if (is<RenderView>(*ancestor))
     100            return false;
     101        if (is<RenderFragmentedFlow>(*ancestor)) {
     102            // Don't allow any intervening non-multicol fragmentation contexts. The spec doesn't say
     103            // anything about disallowing this, but it's just going to be too complicated to
     104            // implement (not to mention specify behavior).
     105            return ancestor == &fragmentedFlow;
     106        }
     107        // This ancestor (descendent of the fragmentedFlow) will create columns later. The spanner belongs to it.
     108        if (is<RenderBlockFlow>(*ancestor) && downcast<RenderBlockFlow>(*ancestor).willCreateColumns())
     109            return false;
     110        ASSERT(ancestor->style().columnSpan() != ColumnSpanAll || !isValidColumnSpanner(fragmentedFlow, *ancestor));
     111        if (ancestor->isUnsplittableForPagination())
     112            return false;
     113    }
     114    ASSERT_NOT_REACHED();
     115    return false;
     116}
     117
    37118RenderTreeBuilder::MultiColumn::MultiColumn(RenderTreeBuilder& builder)
    38119    : m_builder(builder)
     
    172253}
    173254
    174 }
     255static bool gShiftingSpanner = false;
     256
     257void RenderTreeBuilder::MultiColumn::multiColumnDescendantInserted(RenderMultiColumnFlow& flow, RenderObject& newDescendant)
     258{
     259    if (gShiftingSpanner || newDescendant.isInFlowRenderFragmentedFlow())
     260        return;
     261
     262    auto* subtreeRoot = &newDescendant;
     263    auto* descendant = subtreeRoot;
     264    while (descendant) {
     265        // Skip nested multicolumn flows.
     266        if (is<RenderMultiColumnFlow>(*descendant)) {
     267            descendant = descendant->nextSibling();
     268            continue;
     269        }
     270        if (is<RenderMultiColumnSpannerPlaceholder>(*descendant)) {
     271            // A spanner's placeholder has been inserted. The actual spanner renderer is moved from
     272            // where it would otherwise occur (if it weren't a spanner) to becoming a sibling of the
     273            // column sets.
     274            RenderMultiColumnSpannerPlaceholder& placeholder = downcast<RenderMultiColumnSpannerPlaceholder>(*descendant);
     275            ASSERT(!flow.spannerMap().get(placeholder.spanner()));
     276            flow.spannerMap().add(placeholder.spanner(), makeWeakPtr(downcast<RenderMultiColumnSpannerPlaceholder>(descendant)));
     277            ASSERT(!placeholder.firstChild()); // There should be no children here, but if there are, we ought to skip them.
     278        } else
     279            descendant = processPossibleSpannerDescendant(flow, subtreeRoot, *descendant);
     280        if (descendant)
     281            descendant = descendant->nextInPreOrder(subtreeRoot);
     282    }
     283}
     284
     285RenderObject* RenderTreeBuilder::MultiColumn::processPossibleSpannerDescendant(RenderMultiColumnFlow& flow, RenderObject*& subtreeRoot, RenderObject& descendant)
     286{
     287    RenderBlockFlow* multicolContainer = flow.multiColumnBlockFlow();
     288    RenderObject* nextRendererInFragmentedFlow = spannerPlacehoderCandidate(descendant, flow);
     289    RenderObject* insertBeforeMulticolChild = nullptr;
     290    RenderObject* nextDescendant = &descendant;
     291
     292    if (isValidColumnSpanner(flow, descendant)) {
     293        // This is a spanner (column-span:all). Such renderers are moved from where they would
     294        // otherwise occur in the render tree to becoming a direct child of the multicol container,
     295        // so that they live among the column sets. This simplifies the layout implementation, and
     296        // basically just relies on regular block layout done by the RenderBlockFlow that
     297        // establishes the multicol container.
     298        RenderBlockFlow* container = downcast<RenderBlockFlow>(descendant.parent());
     299        RenderMultiColumnSet* setToSplit = nullptr;
     300        if (nextRendererInFragmentedFlow) {
     301            setToSplit = findSetRendering(flow, descendant);
     302            if (setToSplit) {
     303                setToSplit->setNeedsLayout();
     304                insertBeforeMulticolChild = setToSplit->nextSibling();
     305            }
     306        }
     307        // Moving a spanner's renderer so that it becomes a sibling of the column sets requires us
     308        // to insert an anonymous placeholder in the tree where the spanner's renderer otherwise
     309        // would have been. This is needed for a two reasons: We need a way of separating inline
     310        // content before and after the spanner, so that it becomes separate line boxes. Secondly,
     311        // this placeholder serves as a break point for column sets, so that, when encountered, we
     312        // end flowing one column set and move to the next one.
     313        auto newPlaceholder = RenderMultiColumnSpannerPlaceholder::createAnonymous(flow, downcast<RenderBox>(descendant), container->style());
     314        auto& placeholder = *newPlaceholder;
     315        m_builder.insertChild(*container, WTFMove(newPlaceholder), descendant.nextSibling());
     316        auto takenDescendant = container->takeChild(m_builder, descendant);
     317
     318        // This is a guard to stop an ancestor flow thread from processing the spanner.
     319        gShiftingSpanner = true;
     320        m_builder.insertChildToRenderBlock(*multicolContainer, WTFMove(takenDescendant), insertBeforeMulticolChild);
     321        gShiftingSpanner = false;
     322
     323        // The spanner has now been moved out from the flow thread, but we don't want to
     324        // examine its children anyway. They are all part of the spanner and shouldn't trigger
     325        // creation of column sets or anything like that. Continue at its original position in
     326        // the tree, i.e. where the placeholder was just put.
     327        if (subtreeRoot == &descendant)
     328            subtreeRoot = &placeholder;
     329        nextDescendant = &placeholder;
     330    } else {
     331        // This is regular multicol content, i.e. not part of a spanner.
     332        if (is<RenderMultiColumnSpannerPlaceholder>(nextRendererInFragmentedFlow)) {
     333            // Inserted right before a spanner. Is there a set for us there?
     334            RenderMultiColumnSpannerPlaceholder& placeholder = downcast<RenderMultiColumnSpannerPlaceholder>(*nextRendererInFragmentedFlow);
     335            if (RenderObject* previous = placeholder.spanner()->previousSibling()) {
     336                if (is<RenderMultiColumnSet>(*previous))
     337                    return nextDescendant; // There's already a set there. Nothing to do.
     338            }
     339            insertBeforeMulticolChild = placeholder.spanner();
     340        } else if (RenderMultiColumnSet* lastSet = flow.lastMultiColumnSet()) {
     341            // This child is not an immediate predecessor of a spanner, which means that if this
     342            // child precedes a spanner at all, there has to be a column set created for us there
     343            // already. If it doesn't precede any spanner at all, on the other hand, we need a
     344            // column set at the end of the multicol container. We don't really check here if the
     345            // child inserted precedes any spanner or not (as that's an expensive operation). Just
     346            // make sure we have a column set at the end. It's no big deal if it remains unused.
     347            if (!lastSet->nextSibling())
     348                return nextDescendant;
     349        }
     350    }
     351    // Need to create a new column set when there's no set already created. We also always insert
     352    // another column set after a spanner. Even if it turns out that there are no renderers
     353    // following the spanner, there may be bottom margins there, which take up space.
     354    auto newSet = flow.createMultiColumnSet(RenderStyle::createAnonymousStyleWithDisplay(multicolContainer->style(), BLOCK));
     355    newSet->initializeStyle();
     356    auto& set = *newSet;
     357    m_builder.insertChildToRenderBlock(*multicolContainer, WTFMove(newSet), insertBeforeMulticolChild);
     358    flow.invalidateFragments();
     359
     360    // We cannot handle immediate column set siblings at the moment (and there's no need for
     361    // it, either). There has to be at least one spanner separating them.
     362    ASSERT_UNUSED(set, !RenderMultiColumnFlow::previousColumnSetOrSpannerSiblingOf(&set)
     363        || !RenderMultiColumnFlow::previousColumnSetOrSpannerSiblingOf(&set)->isRenderMultiColumnSet());
     364    ASSERT(!RenderMultiColumnFlow::nextColumnSetOrSpannerSiblingOf(&set)
     365        || !RenderMultiColumnFlow::nextColumnSetOrSpannerSiblingOf(&set)->isRenderMultiColumnSet());
     366
     367    return nextDescendant;
     368}
     369
     370}
  • releases/WebKitGTK/webkit-2.20/Source/WebCore/rendering/updating/RenderTreeBuilderMultiColumn.h

    r227903 r228682  
    4141    // location in the tree.
    4242    RenderObject* resolveMovedChild(RenderFragmentedFlow& enclosingFragmentedFlow, RenderObject* beforeChild);
     43    void multiColumnDescendantInserted(RenderMultiColumnFlow&, RenderObject& newDescendant);
    4344
    4445private:
    4546    void createFragmentedFlow(RenderBlockFlow&);
    4647    void destroyFragmentedFlow(RenderBlockFlow&);
     48    RenderObject* processPossibleSpannerDescendant(RenderMultiColumnFlow&, RenderObject*& subtreeRoot, RenderObject& descendant);
    4749
    4850    RenderTreeBuilder& m_builder;
Note: See TracChangeset for help on using the changeset viewer.