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

Unified Diff: Source/core/rendering/RenderMultiColumnFlowThread.cpp

Issue 712553003: [New Multicolumn] Actual support for layout of column-span:all. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Code review. Camelize. Created 6 years 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
Index: Source/core/rendering/RenderMultiColumnFlowThread.cpp
diff --git a/Source/core/rendering/RenderMultiColumnFlowThread.cpp b/Source/core/rendering/RenderMultiColumnFlowThread.cpp
index 6eaed6f174181af1b3308840f9bf3bb3b990256a..1a847a502deb6d974b9eb5f0053e3af95dbacf48 100644
--- a/Source/core/rendering/RenderMultiColumnFlowThread.cpp
+++ b/Source/core/rendering/RenderMultiColumnFlowThread.cpp
@@ -32,11 +32,13 @@
namespace blink {
RenderMultiColumnFlowThread::RenderMultiColumnFlowThread()
- : m_columnCount(1)
+ : m_lastSetWorkedOn(0)
+ , m_columnCount(1)
, m_columnHeightAvailable(0)
, m_inBalancingPass(false)
, m_needsColumnHeightsRecalculation(false)
, m_progressionIsInline(true)
+ , m_isBeingEvacuated(false)
{
setFlowThreadState(InsideInFlowThread);
}
@@ -102,6 +104,7 @@ void RenderMultiColumnFlowThread::populate()
void RenderMultiColumnFlowThread::evacuateAndDestroy()
{
RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
+ m_isBeingEvacuated = true;
// Remove all sets.
while (RenderMultiColumnSet* columnSet = firstMultiColumnSet())
@@ -146,11 +149,33 @@ bool RenderMultiColumnFlowThread::needsNewWidth() const
return newWidth != logicalWidth();
}
+RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(LayoutUnit offset) const
+{
+ if (m_lastSetWorkedOn) {
+ // Layout in progress. We are calculating the set heights as we speak, so the column set range
+ // information is not up-to-date.
+ return m_lastSetWorkedOn;
+ }
+
+ ASSERT(!m_regionsInvalidated);
+ if (offset <= 0)
+ return m_multiColumnSetList.isEmpty() ? 0 : m_multiColumnSetList.first();
+
+ MultiColumnSetSearchAdapter adapter(offset);
+ m_multiColumnSetIntervalTree.allOverlapsWithAdapter<MultiColumnSetSearchAdapter>(adapter);
+
+ // If no set was found, the offset is in the flow thread overflow.
+ if (!adapter.result() && !m_multiColumnSetList.isEmpty())
+ return m_multiColumnSetList.last();
+ return adapter.result();
+}
+
void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLayoutScope& layoutScope)
{
if (relayoutChildren)
layoutScope.setChildNeedsLayout(this);
+ m_needsColumnHeightsRecalculation = false;
if (!needsLayout()) {
// Just before the multicol container (our parent RenderBlockFlow) finishes laying out, it
// will call recalculateColumnHeights() on us unconditionally, but we only want that method
@@ -158,7 +183,6 @@ void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa
// machinery would kick in needlessly, and trigger additional layout passes. Furthermore, we
// actually depend on a proper flowthread layout pass in order to do balancing, since it's
// flowthread layout that sets up content runs.
- m_needsColumnHeightsRecalculation = false;
return;
}
@@ -168,10 +192,11 @@ void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa
// typically have changed.
columnSet->resetColumnHeight();
}
+ if (!m_needsColumnHeightsRecalculation)
+ m_needsColumnHeightsRecalculation = columnSet->isRenderMultiColumnSpannerSet() || columnSet->heightIsAuto();
}
invalidateRegions();
- m_needsColumnHeightsRecalculation = heightIsAuto();
layout();
}
@@ -316,8 +341,71 @@ void RenderMultiColumnFlowThread::willBeRemovedFromTree()
RenderFlowThread::willBeRemovedFromTree();
}
+bool RenderMultiColumnFlowThread::isColumnSpanner(const RenderObject* descendant) const
+{
+ ASSERT(descendant->isDescendantOf(this));
+ return m_spannerMap.get(descendant);
+}
+
+bool RenderMultiColumnFlowThread::isInsideColumnSpanner(const RenderObject* descendant) const
+{
+ ASSERT(descendant->isDescendantOf(this));
+ return containingColumnSpannerSet(descendant);
+}
+
+LayoutUnit RenderMultiColumnFlowThread::enterColumnSpannerBeforeLayout(RenderBox* renderer, LayoutUnit logicalTop, SubtreeLayoutScope& layoutScope)
+{
+ ASSERT(isColumnSpanner(renderer));
+ RenderMultiColumnSpannerSet* spannerSet = m_spannerMap.get(renderer);
+
+ // FIXME: it's really only necessary to mark the spanner set for layout when the height of
+ // |renderer| changes.
+ spannerSet->setChildNeedsLayout(MarkOnlyThis, &layoutScope);
+
+ RenderMultiColumnSet* previousSet = spannerSet->previousSiblingMultiColumnSet();
+ if (!previousSet) {
+ // The first set is entered at the beginning of flow thread layout. If the first set happens
+ // to be a spanner, we have nothing more to do here.
+ return LayoutUnit();
+ }
+
+ LayoutUnit logicalTopInFlowThread = renderer->parentBlock()->offsetFromLogicalTopOfFirstPage() + logicalTop;
+ LayoutUnit adjustment;
+ if (!previousSet->isRenderMultiColumnSpannerSet() && previousSet->pageLogicalHeight()) {
+ // Pad flow thread offset to a column boundary, so that any content that's supposed to come
+ // after the spanner (or the spanner itself) doesn't bleed into the column preceding the
+ // spanner.
+ LayoutUnit columnLogicalTopInFlowThread = previousSet->pageLogicalTopForOffset(logicalTopInFlowThread);
+ if (columnLogicalTopInFlowThread != logicalTopInFlowThread) {
+ adjustment = columnLogicalTopInFlowThread + previousSet->pageLogicalHeight() - logicalTopInFlowThread;
+ logicalTopInFlowThread += adjustment;
+ }
+ }
+
+ if (!previousSet->isRenderMultiColumnSpannerSet())
+ previousSet->endFlow(logicalTopInFlowThread);
+ spannerSet->beginFlow(logicalTopInFlowThread);
+
+ m_lastSetWorkedOn = spannerSet;
+ return adjustment;
+}
+
+void RenderMultiColumnFlowThread::exitColumnSpannerAfterLayout(RenderBox* renderer, LayoutUnit logicalBottom)
+{
+ ASSERT(m_lastSetWorkedOn == m_spannerMap.get(renderer));
+
+ LayoutUnit logicalBottomInFlowThread = renderer->parentBlock()->offsetFromLogicalTopOfFirstPage() + logicalBottom;
+ m_lastSetWorkedOn->endFlow(logicalBottomInFlowThread);
+ if (RenderMultiColumnSet* nextSet = m_lastSetWorkedOn->nextSiblingMultiColumnSet()) {
+ m_lastSetWorkedOn = nextSet;
+ if (!m_lastSetWorkedOn->isRenderMultiColumnSpannerSet())
+ m_lastSetWorkedOn->beginFlow(logicalBottomInFlowThread);
+ }
+}
+
void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant)
{
+ ASSERT(!m_isBeingEvacuated);
// Go through the subtree that was just inserted and create column sets (needed by regular
// column content) and spanner sets (one needed by each spanner).
for (RenderObject* renderer = descendant; renderer; renderer = renderer->nextInPreOrder(descendant)) {
@@ -335,6 +423,34 @@ void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject*
}
}
+void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject* descendant)
+{
+ if (m_isBeingEvacuated)
+ return;
+ RenderObject* next;
+ // Remove spanner sets that are no longer needed, and merge column sets around them.
+ for (RenderObject* renderer = descendant; renderer; renderer = next) {
+ RenderMultiColumnSpannerSet* spanner = m_spannerMap.get(renderer);
+ if (!spanner) {
+ next = renderer->nextInPreOrder(descendant);
+ continue;
+ }
+ next = renderer->nextInPreOrderAfterChildren(descendant); // It's a spanner. Its children are of no interest to us.
+ if (RenderMultiColumnSet* nextSet = spanner->nextSiblingMultiColumnSet()) {
+ RenderMultiColumnSet* previousSet = spanner->previousSiblingMultiColumnSet();
+ if (nextSet && !nextSet->isRenderMultiColumnSpannerSet()
+ && previousSet && !previousSet->isRenderMultiColumnSpannerSet()) {
+ // Need to merge two column sets.
+ nextSet->destroy();
+ previousSet->setNeedsLayout();
+ invalidateRegions();
+ }
+ }
+ m_spannerMap.remove(renderer);
+ spanner->destroy();
+ }
+}
+
void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
{
// We simply remain at our intrinsic height.
@@ -351,9 +467,17 @@ void RenderMultiColumnFlowThread::updateLogicalWidth()
void RenderMultiColumnFlowThread::layout()
{
+ ASSERT(!m_lastSetWorkedOn);
+ m_lastSetWorkedOn = firstMultiColumnSet();
+ if (m_lastSetWorkedOn)
+ m_lastSetWorkedOn->beginFlow(LayoutUnit());
RenderFlowThread::layout();
- if (RenderMultiColumnSet* lastSet = lastMultiColumnSet())
+ if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) {
+ ASSERT(lastSet == m_lastSetWorkedOn);
+ lastSet->endFlow(logicalHeight());
lastSet->expandToEncompassFlowThreadContentsIfNeeded();
+ }
+ m_lastSetWorkedOn = 0;
}
void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
@@ -375,12 +499,6 @@ void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay
multicolSet->updateMinimumColumnHeight(minHeight);
}
-RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(LayoutUnit /*offset*/) const
-{
- // For now there's only one column set, so this is easy:
- return firstMultiColumnSet();
-}
-
bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, RenderObject* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment)
{
if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) {
@@ -394,8 +512,10 @@ bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render
bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const
{
- if (RenderMultiColumnSet* columnSet = lastMultiColumnSet())
- return columnSet->pageLogicalHeight();
+ for (RenderMultiColumnSet* columnSet = lastMultiColumnSet(); columnSet; columnSet = columnSet->previousSiblingMultiColumnSet()) {
+ if (!columnSet->isRenderMultiColumnSpannerSet())
+ return columnSet->pageLogicalHeight();
+ }
return false;
}
« no previous file with comments | « Source/core/rendering/RenderMultiColumnFlowThread.h ('k') | Source/core/rendering/RenderMultiColumnFlowThreadTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698