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 "LayerFragment.h"
33 #include "RenderBlockFlow.h"
34 #include <wtf/ListHashSet.h>
38 class CurrentRenderRegionMaintainer;
39 class RenderFlowThread;
40 class RenderNamedFlowFragment;
45 typedef ListHashSet<RenderRegion*> RenderRegionList;
46 typedef Vector<RenderLayer*> RenderLayerList;
47 typedef HashMap<RenderNamedFlowFragment*, RenderLayerList> RegionToLayerListMap;
48 typedef HashMap<RenderLayer*, RenderNamedFlowFragment*> LayerToRegionMap;
49 typedef HashMap<const RootInlineBox*, RenderRegion*> ContainingRegionMap;
51 // RenderFlowThread is used to collect all the render objects that participate in a
52 // flow thread. It will also help in doing the layout. However, it will not render
53 // directly to screen. Instead, RenderRegion objects will redirect their paint
54 // and nodeAtPoint methods to this object. Each RenderRegion will actually be a viewPort
55 // of the RenderFlowThread.
57 class RenderFlowThread: public RenderBlockFlow {
59 virtual ~RenderFlowThread() { }
61 virtual void removeFlowChildInfo(RenderElement&);
63 bool hasChildInfo(RenderObject* child) const { return is<RenderBox>(child) && m_regionRangeMap.contains(downcast<RenderBox>(child)); }
66 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
67 bool checkLinesConsistency(const RenderBlockFlow&) const;
70 void deleteLines() override;
72 virtual void addRegionToThread(RenderRegion*) = 0;
73 virtual void removeRegionFromThread(RenderRegion*);
74 const RenderRegionList& renderRegionList() const { return m_regionList; }
76 void updateLogicalWidth() final;
77 LogicalExtentComputedValues computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop) const override;
79 bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
81 bool hasRegions() const { return m_regionList.size(); }
82 virtual void regionChangedWritingMode(RenderRegion*) { }
84 void validateRegions();
85 void invalidateRegions(MarkingBehavior = MarkContainingBlockChain);
86 bool hasValidRegionInfo() const { return !m_regionsInvalidated && !m_regionList.isEmpty(); }
88 // Some renderers (column spanners) are moved out of the flow thread to live among column
89 // sets. If |child| is such a renderer, resolve it to the placeholder that lives at the original
90 // location in the tree.
91 virtual RenderObject* resolveMovedChild(RenderObject* child) const { return child; }
92 // Called when a descendant of the flow thread has been inserted.
93 virtual void flowThreadDescendantInserted(RenderObject&) { }
94 // Called when a sibling or descendant of the flow thread is about to be removed.
95 virtual void flowThreadRelativeWillBeRemoved(RenderObject&) { }
96 // Called when a descendant box's layout is finished and it has been positioned within its container.
97 virtual void flowThreadDescendantBoxLaidOut(RenderBox*) { }
99 static RenderStyle createFlowThreadStyle(const RenderStyle* parentStyle);
101 void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override;
103 void repaintRectangleInRegions(const LayoutRect&) const;
105 LayoutPoint adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject&, const LayoutPoint&) const;
107 LayoutUnit pageLogicalTopForOffset(LayoutUnit) const;
108 LayoutUnit pageLogicalWidthForOffset(LayoutUnit) const;
109 LayoutUnit pageLogicalHeightForOffset(LayoutUnit) const;
110 LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary) const;
112 virtual void setPageBreak(const RenderBlock*, LayoutUnit /*offset*/, LayoutUnit /*spaceShortage*/) { }
113 virtual void updateMinimumPageHeight(const RenderBlock*, LayoutUnit /*offset*/, LayoutUnit /*minHeight*/) { }
115 virtual RenderRegion* regionAtBlockOffset(const RenderBox*, LayoutUnit, bool extendLastRegion = false) const;
117 bool regionsHaveUniformLogicalWidth() const { return m_regionsHaveUniformLogicalWidth; }
118 bool regionsHaveUniformLogicalHeight() const { return m_regionsHaveUniformLogicalHeight; }
120 virtual RenderRegion* mapFromFlowToRegion(TransformState&) const;
122 void logicalWidthChangedInRegionsForBlock(const RenderBlock*, bool&);
124 LayoutUnit contentLogicalWidthOfFirstRegion() const;
125 LayoutUnit contentLogicalHeightOfFirstRegion() const;
126 LayoutUnit contentLogicalLeftOfFirstRegion() const;
128 RenderRegion* firstRegion() const;
129 RenderRegion* lastRegion() const;
131 bool previousRegionCountChanged() const { return m_previousRegionCount != m_regionList.size(); };
132 void updatePreviousRegionCount() { m_previousRegionCount = m_regionList.size(); };
134 virtual void setRegionRangeForBox(const RenderBox&, RenderRegion*, RenderRegion*);
135 bool getRegionRangeForBox(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const;
136 bool computedRegionRangeForBox(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const;
137 bool hasCachedRegionRangeForBox(const RenderBox&) const;
139 // Check if the object is in region and the region is part of this flow thread.
140 bool objectInFlowRegion(const RenderObject*, const RenderRegion*) const;
142 // Check if the object should be painted in this region and if the region is part of this flow thread.
143 bool objectShouldFragmentInFlowRegion(const RenderObject*, const RenderRegion*) const;
145 void markAutoLogicalHeightRegionsForLayout();
146 void markRegionsForOverflowLayoutIfNeeded();
148 virtual bool addForcedRegionBreak(const RenderBlock*, LayoutUnit, RenderBox* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0);
149 virtual void applyBreakAfterContent(LayoutUnit) { }
151 virtual bool isPageLogicalHeightKnown() const { return true; }
152 bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; }
154 bool hasAutoLogicalHeightRegions() const { ASSERT(isAutoLogicalHeightRegionsCountConsistent()); return m_autoLogicalHeightRegionsCount; }
155 void incrementAutoLogicalHeightRegions();
156 void decrementAutoLogicalHeightRegions();
159 bool isAutoLogicalHeightRegionsCountConsistent() const;
162 void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect);
163 LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox);
165 // A flow thread goes through different states during layout.
167 LayoutPhaseMeasureContent = 0, // The initial phase, used to measure content for the auto-height regions.
168 LayoutPhaseConstrained, // In this phase the regions are laid out using the sizes computed in the normal phase.
169 LayoutPhaseOverflow, // In this phase the layout overflow is propagated from the content to the regions.
170 LayoutPhaseFinal // In case scrollbars have resized the regions, content is laid out one last time to respect the change.
172 bool inMeasureContentLayoutPhase() const { return m_layoutPhase == LayoutPhaseMeasureContent; }
173 bool inConstrainedLayoutPhase() const { return m_layoutPhase == LayoutPhaseConstrained; }
174 bool inOverflowLayoutPhase() const { return m_layoutPhase == LayoutPhaseOverflow; }
175 bool inFinalLayoutPhase() const { return m_layoutPhase == LayoutPhaseFinal; }
176 void setLayoutPhase(LayoutPhase phase) { m_layoutPhase = phase; }
178 bool needsTwoPhasesLayout() const { return m_needsTwoPhasesLayout; }
179 void clearNeedsTwoPhasesLayout() { m_needsTwoPhasesLayout = false; }
181 // Whether any of the regions has a compositing descendant.
182 bool hasCompositingRegionDescendant() const;
184 void setNeedsLayerToRegionMappingsUpdate() { m_layersToRegionMappingsDirty = true; }
185 void updateAllLayerToRegionMappingsIfNeeded()
187 if (m_layersToRegionMappingsDirty)
188 updateAllLayerToRegionMappings();
191 const RenderLayerList* getLayerListForRegion(RenderNamedFlowFragment*) const;
193 RenderNamedFlowFragment* regionForCompositedLayer(RenderLayer&) const; // By means of getRegionRangeForBox or regionAtBlockOffset.
194 RenderNamedFlowFragment* cachedRegionForCompositedLayer(RenderLayer&) const;
196 virtual bool collectsGraphicsLayersUnderRegions() const;
198 void pushFlowThreadLayoutState(const RenderObject&);
199 void popFlowThreadLayoutState();
200 LayoutUnit offsetFromLogicalTopOfFirstRegion(const RenderBlock*) const;
201 void clearRenderBoxRegionInfoAndCustomStyle(const RenderBox&, const RenderRegion*, const RenderRegion*, const RenderRegion*, const RenderRegion*);
203 void addRegionsVisualEffectOverflow(const RenderBox*);
204 void addRegionsVisualOverflowFromTheme(const RenderBlock*);
205 void addRegionsOverflowFromChild(const RenderBox*, const RenderBox*, const LayoutSize&);
206 void addRegionsLayoutOverflow(const RenderBox*, const LayoutRect&);
207 void addRegionsVisualOverflow(const RenderBox*, const LayoutRect&);
208 void clearRegionsOverflow(const RenderBox*);
210 LayoutRect mapFromFlowThreadToLocal(const RenderBox*, const LayoutRect&) const;
211 LayoutRect mapFromLocalToFlowThread(const RenderBox*, const LayoutRect&) const;
213 void flipForWritingModeLocalCoordinates(LayoutRect&) const;
215 // Used to estimate the maximum height of the flow thread.
216 static LayoutUnit maxLogicalHeight() { return LayoutUnit::max() / 2; }
218 bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const;
220 virtual bool absoluteQuadsForBox(Vector<FloatQuad>&, bool*, const RenderBox*, float, float) const { return false; }
222 void layout() override;
224 void setCurrentRegionMaintainer(CurrentRenderRegionMaintainer* currentRegionMaintainer) { m_currentRegionMaintainer = currentRegionMaintainer; }
225 RenderRegion* currentRegion() const;
227 ContainingRegionMap& containingRegionMap();
229 bool cachedFlowThreadContainingBlockNeedsUpdate() const override { return false; }
231 // FIXME: Eventually as column and region flow threads start nesting, this may end up changing.
232 virtual bool shouldCheckColumnBreaks() const { return false; }
235 // Always create a RenderLayer for the RenderFlowThread so that we
236 // can easily avoid drawing the children directly.
237 bool requiresLayer() const final { return true; }
240 RenderFlowThread(Document&, RenderStyle&&);
242 RenderFlowThread* locateFlowThreadContainingBlock() const override { return const_cast<RenderFlowThread*>(this); }
244 const char* renderName() const override = 0;
246 // Overridden by columns/pages to set up an initial logical width of the page width even when
247 // no regions have been generated yet.
248 virtual LayoutUnit initialLogicalWidth() const { return 0; };
250 void clearLinesToRegionMap();
251 void willBeDestroyed() override;
253 void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const override;
255 void updateRegionsFlowThreadPortionRect(const RenderRegion* = nullptr);
256 bool shouldRepaint(const LayoutRect&) const;
258 bool updateAllLayerToRegionMappings();
260 // Triggers a layers' update if a layer has moved from a region to another since the last update.
261 void updateLayerToRegionMappings(RenderLayer&, LayerToRegionMap&, RegionToLayerListMap&, bool& needsLayerUpdate);
262 void updateRegionForRenderLayer(RenderLayer*, LayerToRegionMap&, RegionToLayerListMap&, bool& needsLayerUpdate);
264 void initializeRegionsComputedAutoHeight(RenderRegion* = nullptr);
266 inline bool hasCachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*) const;
267 inline LayoutUnit cachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*) const;
268 inline void setOffsetFromLogicalTopOfFirstRegion(const RenderBox*, LayoutUnit);
269 inline void clearOffsetFromLogicalTopOfFirstRegion(const RenderBox*);
271 inline const RenderBox* currentActiveRenderBox() const;
273 bool getRegionRangeForBoxFromCachedInfo(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const;
275 void removeRenderBoxRegionInfo(RenderBox&);
276 void removeLineRegionInfo(const RenderBlockFlow&);
278 RenderRegionList m_regionList;
279 unsigned short m_previousRegionCount;
281 class RenderRegionRange {
285 setRange(nullptr, nullptr);
288 RenderRegionRange(RenderRegion* start, RenderRegion* end)
290 setRange(start, end);
293 void setRange(RenderRegion* start, RenderRegion* end)
295 m_startRegion = start;
297 m_rangeInvalidated = true;
300 RenderRegion* startRegion() const { return m_startRegion; }
301 RenderRegion* endRegion() const { return m_endRegion; }
302 bool rangeInvalidated() const { return m_rangeInvalidated; }
303 void clearRangeInvalidated() { m_rangeInvalidated = false; }
306 RenderRegion* m_startRegion;
307 RenderRegion* m_endRegion;
308 bool m_rangeInvalidated;
311 typedef PODInterval<LayoutUnit, RenderRegion*> RegionInterval;
312 typedef PODIntervalTree<LayoutUnit, RenderRegion*> RegionIntervalTree;
314 class RegionSearchAdapter {
316 RegionSearchAdapter(LayoutUnit offset)
322 const LayoutUnit& lowValue() const { return m_offset; }
323 const LayoutUnit& highValue() const { return m_offset; }
324 void collectIfNeeded(const RegionInterval&);
326 RenderRegion* result() const { return m_result; }
330 RenderRegion* m_result;
333 // Map a layer to the region in which the layer is painted.
334 std::unique_ptr<LayerToRegionMap> m_layerToRegionMap;
336 // Map a region to the list of layers that paint in that region.
337 std::unique_ptr<RegionToLayerListMap> m_regionToLayerListMap;
339 // Map a line to its containing region.
340 std::unique_ptr<ContainingRegionMap> m_lineToRegionMap;
342 // Map a box to the list of regions in which the box is rendered.
343 typedef HashMap<const RenderBox*, RenderRegionRange> RenderRegionRangeMap;
344 RenderRegionRangeMap m_regionRangeMap;
346 // Map a box with a region break to the auto height region affected by that break.
347 typedef HashMap<RenderBox*, RenderRegion*> RenderBoxToRegionMap;
348 RenderBoxToRegionMap m_breakBeforeToRegionMap;
349 RenderBoxToRegionMap m_breakAfterToRegionMap;
351 typedef Vector<const RenderObject*> RenderObjectStack;
352 RenderObjectStack m_activeObjectsStack;
354 typedef HashMap<const RenderBox*, LayoutUnit> RenderBoxToOffsetMap;
355 RenderBoxToOffsetMap m_boxesToOffsetMap;
357 unsigned m_autoLogicalHeightRegionsCount;
359 RegionIntervalTree m_regionIntervalTree;
361 CurrentRenderRegionMaintainer* m_currentRegionMaintainer;
363 bool m_regionsInvalidated : 1;
364 bool m_regionsHaveUniformLogicalWidth : 1;
365 bool m_regionsHaveUniformLogicalHeight : 1;
366 bool m_pageLogicalSizeChanged : 1;
367 unsigned m_layoutPhase : 2;
368 bool m_needsTwoPhasesLayout : 1;
369 bool m_layersToRegionMappingsDirty : 1;
372 } // namespace WebCore
374 // This structure is used by PODIntervalTree for debugging.
378 template <> struct ValueToString<WebCore::RenderRegion*> {
379 static String string(const WebCore::RenderRegion* value) { return String::format("%p", value); }
385 SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderFlowThread, isRenderFlowThread())