174e210cbe2b058b395882c0b33bdc60d11dee43
[WebKit-https.git] / Source / WebCore / rendering / RenderFlowThread.h
1 /*
2  * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above
9  *    copyright notice, this list of conditions and the following
10  *    disclaimer.
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.
15  * 
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
27  * SUCH DAMAGE.
28  */
29
30 #pragma once
31
32 #include "LayerFragment.h"
33 #include "RenderBlockFlow.h"
34 #include <wtf/ListHashSet.h>
35
36 namespace WebCore {
37
38 class CurrentRenderRegionMaintainer;
39 class RenderFlowThread;
40 class RenderNamedFlowFragment;
41 class RenderStyle;
42 class RenderRegion;
43 class RootInlineBox;
44
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;
50
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.
56
57 class RenderFlowThread: public RenderBlockFlow {
58 public:
59     virtual ~RenderFlowThread() { }
60
61     virtual void removeFlowChildInfo(RenderElement&);
62 #ifndef NDEBUG
63     bool hasChildInfo(RenderObject* child) const { return is<RenderBox>(child) && m_regionRangeMap.contains(downcast<RenderBox>(child)); }
64 #endif
65
66 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
67     bool checkLinesConsistency(const RenderBlockFlow&) const;
68 #endif
69     
70     void deleteLines() override;
71
72     virtual void addRegionToThread(RenderRegion*) = 0;
73     virtual void removeRegionFromThread(RenderRegion*);
74     const RenderRegionList& renderRegionList() const { return m_regionList; }
75
76     void updateLogicalWidth() final;
77     LogicalExtentComputedValues computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop) const override;
78
79     bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
80
81     bool hasRegions() const { return m_regionList.size(); }
82     virtual void regionChangedWritingMode(RenderRegion*) { }
83
84     void validateRegions();
85     void invalidateRegions(MarkingBehavior = MarkContainingBlockChain);
86     bool hasValidRegionInfo() const { return !m_regionsInvalidated && !m_regionList.isEmpty(); }
87
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*) { }
98
99     static RenderStyle createFlowThreadStyle(const RenderStyle* parentStyle);
100
101     void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override;
102
103     void repaintRectangleInRegions(const LayoutRect&) const;
104     
105     LayoutPoint adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject&, const LayoutPoint&) const;
106
107     LayoutUnit pageLogicalTopForOffset(LayoutUnit) const;
108     LayoutUnit pageLogicalWidthForOffset(LayoutUnit) const;
109     LayoutUnit pageLogicalHeightForOffset(LayoutUnit) const;
110     LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary) const;
111
112     virtual void setPageBreak(const RenderBlock*, LayoutUnit /*offset*/, LayoutUnit /*spaceShortage*/) { }
113     virtual void updateMinimumPageHeight(const RenderBlock*, LayoutUnit /*offset*/, LayoutUnit /*minHeight*/) { }
114
115     virtual RenderRegion* regionAtBlockOffset(const RenderBox*, LayoutUnit, bool extendLastRegion = false) const;
116
117     bool regionsHaveUniformLogicalWidth() const { return m_regionsHaveUniformLogicalWidth; }
118     bool regionsHaveUniformLogicalHeight() const { return m_regionsHaveUniformLogicalHeight; }
119
120     virtual RenderRegion* mapFromFlowToRegion(TransformState&) const;
121
122     void logicalWidthChangedInRegionsForBlock(const RenderBlock*, bool&);
123
124     LayoutUnit contentLogicalWidthOfFirstRegion() const;
125     LayoutUnit contentLogicalHeightOfFirstRegion() const;
126     LayoutUnit contentLogicalLeftOfFirstRegion() const;
127     
128     RenderRegion* firstRegion() const;
129     RenderRegion* lastRegion() const;
130
131     bool previousRegionCountChanged() const { return m_previousRegionCount != m_regionList.size(); };
132     void updatePreviousRegionCount() { m_previousRegionCount = m_regionList.size(); };
133
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;
138
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;
141     
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;
144
145     void markAutoLogicalHeightRegionsForLayout();
146     void markRegionsForOverflowLayoutIfNeeded();
147
148     virtual bool addForcedRegionBreak(const RenderBlock*, LayoutUnit, RenderBox* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0);
149     virtual void applyBreakAfterContent(LayoutUnit) { }
150
151     virtual bool isPageLogicalHeightKnown() const { return true; }
152     bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; }
153
154     bool hasAutoLogicalHeightRegions() const { ASSERT(isAutoLogicalHeightRegionsCountConsistent()); return m_autoLogicalHeightRegionsCount; }
155     void incrementAutoLogicalHeightRegions();
156     void decrementAutoLogicalHeightRegions();
157
158 #ifndef NDEBUG
159     bool isAutoLogicalHeightRegionsCountConsistent() const;
160 #endif
161
162     void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect);
163     LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox);
164
165     // A flow thread goes through different states during layout.
166     enum LayoutPhase {
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.
171     };
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; }
177
178     bool needsTwoPhasesLayout() const { return m_needsTwoPhasesLayout; }
179     void clearNeedsTwoPhasesLayout() { m_needsTwoPhasesLayout = false; }
180
181     // Whether any of the regions has a compositing descendant.
182     bool hasCompositingRegionDescendant() const;
183
184     void setNeedsLayerToRegionMappingsUpdate() { m_layersToRegionMappingsDirty = true; }
185     void updateAllLayerToRegionMappingsIfNeeded()
186     {
187         if (m_layersToRegionMappingsDirty)
188             updateAllLayerToRegionMappings();
189     }
190
191     const RenderLayerList* getLayerListForRegion(RenderNamedFlowFragment*) const;
192
193     RenderNamedFlowFragment* regionForCompositedLayer(RenderLayer&) const; // By means of getRegionRangeForBox or regionAtBlockOffset.
194     RenderNamedFlowFragment* cachedRegionForCompositedLayer(RenderLayer&) const;
195
196     virtual bool collectsGraphicsLayersUnderRegions() const;
197
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*);
202
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*);
209
210     LayoutRect mapFromFlowThreadToLocal(const RenderBox*, const LayoutRect&) const;
211     LayoutRect mapFromLocalToFlowThread(const RenderBox*, const LayoutRect&) const;
212
213     void flipForWritingModeLocalCoordinates(LayoutRect&) const;
214
215     // Used to estimate the maximum height of the flow thread.
216     static LayoutUnit maxLogicalHeight() { return LayoutUnit::max() / 2; }
217
218     bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const;
219
220     virtual bool absoluteQuadsForBox(Vector<FloatQuad>&, bool*, const RenderBox*, float, float) const { return false; }
221
222     void layout() override;
223
224     void setCurrentRegionMaintainer(CurrentRenderRegionMaintainer* currentRegionMaintainer) { m_currentRegionMaintainer = currentRegionMaintainer; }
225     RenderRegion* currentRegion() const;
226
227     ContainingRegionMap& containingRegionMap();
228
229     bool cachedFlowThreadContainingBlockNeedsUpdate() const override { return false; }
230
231     // FIXME: Eventually as column and region flow threads start nesting, this may end up changing.
232     virtual bool shouldCheckColumnBreaks() const { return false; }
233
234 private:
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; }
238
239 protected:
240     RenderFlowThread(Document&, RenderStyle&&);
241
242     RenderFlowThread* locateFlowThreadContainingBlock() const override { return const_cast<RenderFlowThread*>(this); }
243
244     const char* renderName() const override = 0;
245
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; };
249     
250     void clearLinesToRegionMap();
251     void willBeDestroyed() override;
252
253     void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const override;
254
255     void updateRegionsFlowThreadPortionRect(const RenderRegion* = nullptr);
256     bool shouldRepaint(const LayoutRect&) const;
257
258     bool updateAllLayerToRegionMappings();
259
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);
263
264     void initializeRegionsComputedAutoHeight(RenderRegion* = nullptr);
265
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*);
270
271     inline const RenderBox* currentActiveRenderBox() const;
272
273     bool getRegionRangeForBoxFromCachedInfo(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const;
274
275     void removeRenderBoxRegionInfo(RenderBox&);
276     void removeLineRegionInfo(const RenderBlockFlow&);
277
278     RenderRegionList m_regionList;
279     unsigned short m_previousRegionCount;
280
281     class RenderRegionRange {
282     public:
283         RenderRegionRange()
284         {
285             setRange(nullptr, nullptr);
286         }
287
288         RenderRegionRange(RenderRegion* start, RenderRegion* end)
289         {
290             setRange(start, end);
291         }
292         
293         void setRange(RenderRegion* start, RenderRegion* end)
294         {
295             m_startRegion = start;
296             m_endRegion = end;
297             m_rangeInvalidated = true;
298         }
299
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; }
304
305     private:
306         RenderRegion* m_startRegion;
307         RenderRegion* m_endRegion;
308         bool m_rangeInvalidated;
309     };
310
311     typedef PODInterval<LayoutUnit, RenderRegion*> RegionInterval;
312     typedef PODIntervalTree<LayoutUnit, RenderRegion*> RegionIntervalTree;
313
314     class RegionSearchAdapter {
315     public:
316         RegionSearchAdapter(LayoutUnit offset)
317             : m_offset(offset)
318             , m_result(nullptr)
319         {
320         }
321         
322         const LayoutUnit& lowValue() const { return m_offset; }
323         const LayoutUnit& highValue() const { return m_offset; }
324         void collectIfNeeded(const RegionInterval&);
325
326         RenderRegion* result() const { return m_result; }
327
328     private:
329         LayoutUnit m_offset;
330         RenderRegion* m_result;
331     };
332
333     // Map a layer to the region in which the layer is painted.
334     std::unique_ptr<LayerToRegionMap> m_layerToRegionMap;
335
336     // Map a region to the list of layers that paint in that region.
337     std::unique_ptr<RegionToLayerListMap> m_regionToLayerListMap;
338
339     // Map a line to its containing region.
340     std::unique_ptr<ContainingRegionMap> m_lineToRegionMap;
341
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;
345
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;
350
351     typedef Vector<const RenderObject*> RenderObjectStack;
352     RenderObjectStack m_activeObjectsStack;
353
354     typedef HashMap<const RenderBox*, LayoutUnit> RenderBoxToOffsetMap;
355     RenderBoxToOffsetMap m_boxesToOffsetMap;
356
357     unsigned m_autoLogicalHeightRegionsCount;
358
359     RegionIntervalTree m_regionIntervalTree;
360
361     CurrentRenderRegionMaintainer* m_currentRegionMaintainer;
362
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;
370 };
371
372 // This structure is used by PODIntervalTree for debugging.
373 #ifndef NDEBUG
374 template <> struct ValueToString<RenderRegion*> {
375     static String string(const RenderRegion* value) { return String::format("%p", value); }
376 };
377 #endif
378
379 } // namespace WebCore
380
381 SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderFlowThread, isRenderFlowThread())