Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1328)

Unified Diff: Source/core/layout/LayoutMultiColumnFlowThread.cpp

Issue 1163603002: Out-of-flow objects inside multicol may not establish column sets. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « LayoutTests/fast/multicol/dynamic/remove-column-content-next-to-abspos-between-spanners-expected.html ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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)
« no previous file with comments | « LayoutTests/fast/multicol/dynamic/remove-column-content-next-to-abspos-between-spanners-expected.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698