Index: Source/core/layout/LayoutMultiColumnFlowThread.cpp |
diff --git a/Source/core/layout/LayoutMultiColumnFlowThread.cpp b/Source/core/layout/LayoutMultiColumnFlowThread.cpp |
index 51c0a42890106bbebbbca8f4a0e21e259904a6d8..cdf34ad28f26926e46eb2c659f61770218db209d 100644 |
--- a/Source/core/layout/LayoutMultiColumnFlowThread.cpp |
+++ b/Source/core/layout/LayoutMultiColumnFlowThread.cpp |
@@ -73,6 +73,44 @@ LayoutMultiColumnSet* LayoutMultiColumnFlowThread::lastMultiColumnSet() const |
return 0; |
} |
+static LayoutObject* nextInPreOrderAfterChildrenSkippingOutOfFlow(LayoutMultiColumnFlowThread* flowThread, LayoutObject* descendant) |
+{ |
+ ASSERT(descendant->isDescendantOf(flowThread)); |
+ LayoutObject* object = descendant->nextInPreOrderAfterChildren(flowThread); |
+ while (object) { |
+ // Walk through the siblings and find the first one which is either in-flow or has this |
+ // flow thread as its containing block flow thread. |
+ if (!object->isOutOfFlowPositioned()) |
+ break; |
+ if (object->containingBlock()->flowThreadContainingBlock() == flowThread) { |
+ // This out-of-flow object is still part of the flow thread, because its containing |
+ // block (probably relatively positioned) is part of the flow thread. |
+ break; |
+ } |
+ object = object->nextInPreOrderAfterChildren(flowThread); |
+ } |
+ return object; |
+} |
+ |
+static LayoutObject* previousInPreOrderSkippingOutOfFlow(LayoutMultiColumnFlowThread* flowThread, LayoutObject* descendant) |
+{ |
+ ASSERT(descendant->isDescendantOf(flowThread)); |
+ LayoutObject* object = descendant->previousInPreOrder(flowThread); |
+ while (object && object != flowThread) { |
+ // Walk through the siblings and find the first one which is either in-flow or has this |
+ // flow thread as its containing block flow thread. |
+ if (!object->isOutOfFlowPositioned()) |
+ break; |
+ if (object->containingBlock()->flowThreadContainingBlock() == flowThread) { |
+ // This out-of-flow object is still part of the flow thread, because its containing |
+ // block (probably relatively positioned) is part of the flow thread. |
+ break; |
+ } |
+ object = object->previousInPreOrder(flowThread); |
+ } |
+ return object && object != flowThread ? object : nullptr; |
+} |
+ |
static LayoutObject* firstLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) |
{ |
LayoutBox* sibling = multicolSet->previousSiblingMultiColumnBox(); |
@@ -81,7 +119,8 @@ static LayoutObject* firstLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) |
// Adjacent column content sets should not occur. We would have no way of figuring out what each |
// of them contains then. |
ASSERT(sibling->isLayoutMultiColumnSpannerPlaceholder()); |
- return toLayoutMultiColumnSpannerPlaceholder(sibling)->layoutObjectInFlowThread()->nextInPreOrderAfterChildren(multicolSet->flowThread()); |
+ LayoutBox* spanner = toLayoutMultiColumnSpannerPlaceholder(sibling)->layoutObjectInFlowThread(); |
+ return nextInPreOrderAfterChildrenSkippingOutOfFlow(multicolSet->multiColumnFlowThread(), spanner); |
} |
static LayoutObject* lastLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) |
@@ -92,7 +131,8 @@ static LayoutObject* lastLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) |
// Adjacent column content sets should not occur. We would have no way of figuring out what each |
// of them contains then. |
ASSERT(sibling->isLayoutMultiColumnSpannerPlaceholder()); |
- return toLayoutMultiColumnSpannerPlaceholder(sibling)->layoutObjectInFlowThread()->previousInPreOrder(multicolSet->flowThread()); |
+ LayoutBox* spanner = toLayoutMultiColumnSpannerPlaceholder(sibling)->layoutObjectInFlowThread(); |
+ return previousInPreOrderSkippingOutOfFlow(multicolSet->multiColumnFlowThread(), spanner); |
} |
LayoutMultiColumnSet* LayoutMultiColumnFlowThread::mapDescendantToColumnSet(LayoutObject* layoutObject) const |
@@ -100,6 +140,7 @@ LayoutMultiColumnSet* LayoutMultiColumnFlowThread::mapDescendantToColumnSet(Layo |
ASSERT(!containingColumnSpannerPlaceholder(layoutObject)); // should not be used for spanners or content inside them. |
ASSERT(layoutObject != this); |
ASSERT(layoutObject->isDescendantOf(this)); |
+ ASSERT(layoutObject->containingBlock()->isDescendantOf(this)); // Out-of-flow objects don't belong in column sets. |
LayoutMultiColumnSet* multicolSet = firstMultiColumnSet(); |
if (!multicolSet) |
return 0; |
@@ -453,7 +494,7 @@ LayoutUnit LayoutMultiColumnFlowThread::skipColumnSpanner(LayoutBox* layoutObjec |
// When processing layout objects to remove or when processing layout objects that have just been |
// inserted, certain types of objects should be skipped. |
-static bool shouldSkipInsertedOrRemovedChild(const LayoutObject& child) |
+static bool shouldSkipInsertedOrRemovedChild(LayoutMultiColumnFlowThread* flowThread, const LayoutObject& child) |
{ |
if (child.isSVG() && !child.isSVGRoot()) { |
// Don't descend into SVG objects. What's in there is of no interest, and there might even |
@@ -469,21 +510,25 @@ static bool shouldSkipInsertedOrRemovedChild(const LayoutObject& child) |
// flow thread. |
return true; |
} |
+ if (child.isOutOfFlowPositioned() && child.containingBlock()->flowThreadContainingBlock() != flowThread) { |
+ // Out-of-flow with its containing block on the outside of the multicol container. |
+ return true; |
+ } |
return false; |
} |
void LayoutMultiColumnFlowThread::flowThreadDescendantWasInserted(LayoutObject* descendant) |
{ |
ASSERT(!m_isBeingEvacuated); |
- LayoutObject* objectAfterSubtree = descendant->nextInPreOrderAfterChildren(this); |
// This method ensures that the list of column sets and spanner placeholders reflects the |
// multicol content after having inserted a descendant (or descendant subtree). See the header |
// file for more information. Go through the subtree that was just inserted and create column |
// sets (needed by regular column content) and spanner placeholders (one needed by each spanner) |
// where needed. |
+ LayoutObject* objectAfterSubtree = nextInPreOrderAfterChildrenSkippingOutOfFlow(this, descendant); |
LayoutObject* next; |
for (LayoutObject* layoutObject = descendant; layoutObject; layoutObject = next) { |
- if (shouldSkipInsertedOrRemovedChild(*layoutObject)) { |
+ if (shouldSkipInsertedOrRemovedChild(this, *layoutObject)) { |
next = layoutObject->nextInPreOrderAfterChildren(descendant); |
continue; |
} |
@@ -502,7 +547,7 @@ void LayoutMultiColumnFlowThread::flowThreadDescendantWasInserted(LayoutObject* |
if (!insertBefore) { |
// The next layoutObject isn't a spanner; it's regular column content. Examine what |
// comes right before us in the flow thread, then. |
- LayoutObject* previousLayoutObject = layoutObject->previousInPreOrder(this); |
+ LayoutObject* previousLayoutObject = previousInPreOrderSkippingOutOfFlow(this, layoutObject); |
if (!previousLayoutObject || previousLayoutObject == this) { |
// The spanner is inserted as the first child of the multicol container, |
// which means that we simply insert a new spanner placeholder at the |
@@ -531,21 +576,6 @@ void LayoutMultiColumnFlowThread::flowThreadDescendantWasInserted(LayoutObject* |
continue; |
} |
// This layoutObject is regular column content (i.e. not a spanner). Create a set if necessary. |
- while (objectAfterSubtree) { |
- // Walk through the siblings and find the first one which is either in-flow or has this |
- // flow thread as its containing block flow thread. |
- if (!objectAfterSubtree->isOutOfFlowPositioned()) { |
- // In-flow objects are always part of the flow thread (unless it's a spanner - but |
- // we'll deal with that further below). |
- break; |
- } |
- if (objectAfterSubtree->containingBlock()->flowThreadContainingBlock() == this) { |
- // This out-of-flow object is still part of the flow thread, because its containing |
- // block (probably relatively positioned) is part of the flow thread. |
- break; |
- } |
- objectAfterSubtree = objectAfterSubtree->nextInPreOrderAfterChildren(this); |
- } |
if (objectAfterSubtree) { |
if (LayoutMultiColumnSpannerPlaceholder* placeholder = objectAfterSubtree->spannerPlaceholder()) { |
// If inserted right before a spanner, we need to make sure that there's a set for us there. |
@@ -580,7 +610,7 @@ void LayoutMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(LayoutObject |
LayoutObject* next; |
// Remove spanner placeholders that are no longer needed, and merge column sets around them. |
for (LayoutObject* layoutObject = descendant; layoutObject; layoutObject = next) { |
- if (shouldSkipInsertedOrRemovedChild(*layoutObject)) { |
+ if (shouldSkipInsertedOrRemovedChild(this, *layoutObject)) { |
next = layoutObject->nextInPreOrderAfterChildren(descendant); |
continue; |
} |
@@ -608,14 +638,14 @@ void LayoutMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(LayoutObject |
// Column content will be removed. Does this mean that we should destroy a column set? |
LayoutMultiColumnSpannerPlaceholder* adjacentPreviousSpannerPlaceholder = 0; |
- LayoutObject* previousLayoutObject = descendant->previousInPreOrder(this); |
+ LayoutObject* previousLayoutObject = previousInPreOrderSkippingOutOfFlow(this, descendant); |
if (previousLayoutObject && previousLayoutObject != this) { |
adjacentPreviousSpannerPlaceholder = containingColumnSpannerPlaceholder(previousLayoutObject); |
if (!adjacentPreviousSpannerPlaceholder) |
return; // Preceded by column content. Set still needed. |
} |
LayoutMultiColumnSpannerPlaceholder* adjacentNextSpannerPlaceholder = 0; |
- LayoutObject* nextLayoutObject = descendant->nextInPreOrderAfterChildren(this); |
+ LayoutObject* nextLayoutObject = nextInPreOrderAfterChildrenSkippingOutOfFlow(this, descendant); |
if (nextLayoutObject) { |
adjacentNextSpannerPlaceholder = containingColumnSpannerPlaceholder(nextLayoutObject); |
if (!adjacentNextSpannerPlaceholder) |