2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials
14 * provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include "core/layout/LayoutFlowThread.h"
34 #include "core/layout/LayoutMultiColumnSet.h"
35 #include "core/layout/LayoutView.h"
39 LayoutFlowThread::LayoutFlowThread()
40 : LayoutBlockFlow(nullptr)
41 , m_columnSetsInvalidated(false)
42 , m_pageLogicalSizeChanged(false)
46 LayoutFlowThread
* LayoutFlowThread::locateFlowThreadContainingBlockOf(const LayoutObject
& descendant
)
48 ASSERT(descendant
.isInsideFlowThread());
49 LayoutObject
* curr
= const_cast<LayoutObject
*>(&descendant
);
51 if (curr
->isSVG() && !curr
->isSVGRoot())
53 if (curr
->isLayoutFlowThread())
54 return toLayoutFlowThread(curr
);
55 LayoutObject
* container
= curr
->container();
56 curr
= curr
->parent();
57 while (curr
!= container
) {
58 if (curr
->isLayoutFlowThread()) {
59 // The nearest ancestor flow thread isn't in our containing block chain. Then we
60 // aren't really part of any flow thread, and we should stop looking. This happens
61 // when there are out-of-flow objects or column spanners.
64 curr
= curr
->parent();
70 void LayoutFlowThread::removeColumnSetFromThread(LayoutMultiColumnSet
* columnSet
)
73 m_multiColumnSetList
.remove(columnSet
);
74 invalidateColumnSets();
75 // Clear the interval tree right away, instead of leaving it around with dead objects. Not that
76 // anyone _should_ try to access the interval tree when the column sets are marked as invalid,
77 // but this is actually possible if other parts of the engine has bugs that cause us to not lay
78 // out everything that was marked for layout, so that LayoutObject::assertLaidOut() (and a LOT
79 // of other assertions) fails.
80 m_multiColumnSetIntervalTree
.clear();
83 void LayoutFlowThread::invalidateColumnSets()
85 if (m_columnSetsInvalidated
) {
86 ASSERT(selfNeedsLayout());
90 setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::ColumnsChanged
);
92 m_columnSetsInvalidated
= true;
95 void LayoutFlowThread::validateColumnSets()
97 m_columnSetsInvalidated
= false;
98 updateLogicalWidth(); // Called to get the maximum logical width for the columnSet.
99 generateColumnSetIntervalTree();
102 void LayoutFlowThread::mapRectToPaintInvalidationBacking(const LayoutBoxModelObject
* paintInvalidationContainer
, LayoutRect
& rect
, const PaintInvalidationState
* paintInvalidationState
) const
104 ASSERT(paintInvalidationContainer
!= this); // A flow thread should never be an invalidation container.
105 // |rect| is a layout rectangle, where the block direction coordinate is flipped for writing
106 // mode. fragmentsBoundingBox(), on the other hand, works on physical rectangles, so we need to
107 // flip the rectangle before and after calling it.
108 flipForWritingMode(rect
);
109 rect
= fragmentsBoundingBox(rect
);
110 flipForWritingMode(rect
);
111 LayoutBlockFlow::mapRectToPaintInvalidationBacking(paintInvalidationContainer
, rect
, paintInvalidationState
);
114 void LayoutFlowThread::layout()
116 m_pageLogicalSizeChanged
= m_columnSetsInvalidated
&& everHadLayout();
117 LayoutBlockFlow::layout();
118 m_pageLogicalSizeChanged
= false;
121 void LayoutFlowThread::computeLogicalHeight(LayoutUnit
, LayoutUnit logicalTop
, LogicalExtentComputedValues
& computedValues
) const
123 computedValues
.m_position
= logicalTop
;
124 computedValues
.m_extent
= 0;
126 for (LayoutMultiColumnSetList::const_iterator iter
= m_multiColumnSetList
.begin(); iter
!= m_multiColumnSetList
.end(); ++iter
) {
127 LayoutMultiColumnSet
* columnSet
= *iter
;
128 computedValues
.m_extent
+= columnSet
->logicalHeightInFlowThread();
132 bool LayoutFlowThread::nodeAtPoint(HitTestResult
& result
, const HitTestLocation
& locationInContainer
, const LayoutPoint
& accumulatedOffset
, HitTestAction hitTestAction
)
134 if (hitTestAction
== HitTestBlockBackground
)
136 return LayoutBlockFlow::nodeAtPoint(result
, locationInContainer
, accumulatedOffset
, hitTestAction
);
139 LayoutUnit
LayoutFlowThread::pageLogicalHeightForOffset(LayoutUnit offset
)
141 LayoutMultiColumnSet
* columnSet
= columnSetAtBlockOffset(offset
);
145 return columnSet
->pageLogicalHeightForOffset(offset
);
148 LayoutUnit
LayoutFlowThread::pageRemainingLogicalHeightForOffset(LayoutUnit offset
, PageBoundaryRule pageBoundaryRule
)
150 LayoutMultiColumnSet
* columnSet
= columnSetAtBlockOffset(offset
);
154 return columnSet
->pageRemainingLogicalHeightForOffset(offset
, pageBoundaryRule
);
157 void LayoutFlowThread::generateColumnSetIntervalTree()
159 // FIXME: Optimize not to clear the interval all the time. This implies manually managing the tree nodes lifecycle.
160 m_multiColumnSetIntervalTree
.clear();
161 m_multiColumnSetIntervalTree
.initIfNeeded();
162 for (auto columnSet
: m_multiColumnSetList
)
163 m_multiColumnSetIntervalTree
.add(MultiColumnSetIntervalTree::createInterval(columnSet
->logicalTopInFlowThread(), columnSet
->logicalBottomInFlowThread(), columnSet
));
166 void LayoutFlowThread::collectLayerFragments(DeprecatedPaintLayerFragments
& layerFragments
, const LayoutRect
& layerBoundingBox
, const LayoutRect
& dirtyRectInFlowThread
)
168 ASSERT(!m_columnSetsInvalidated
);
170 LayoutRect
dirtyRectInMulticolContainer(dirtyRectInFlowThread
);
171 dirtyRectInMulticolContainer
.moveBy(location());
173 for (LayoutMultiColumnSetList::const_iterator iter
= m_multiColumnSetList
.begin(); iter
!= m_multiColumnSetList
.end(); ++iter
) {
174 LayoutMultiColumnSet
* columnSet
= *iter
;
175 columnSet
->collectLayerFragments(layerFragments
, layerBoundingBox
, dirtyRectInMulticolContainer
);
179 LayoutRect
LayoutFlowThread::fragmentsBoundingBox(const LayoutRect
& layerBoundingBox
) const
181 ASSERT(!RuntimeEnabledFeatures::slimmingPaintV2Enabled() || !m_columnSetsInvalidated
);
184 for (auto* columnSet
: m_multiColumnSetList
)
185 result
.unite(columnSet
->fragmentsBoundingBox(layerBoundingBox
));
190 void LayoutFlowThread::MultiColumnSetSearchAdapter::collectIfNeeded(const MultiColumnSetInterval
& interval
)
194 if (interval
.low() <= m_offset
&& interval
.high() > m_offset
)
195 m_result
= interval
.data();