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 "RenderFragmentContainer.h" |
35 | #include <wtf/ListHashSet.h> |
36 | |
37 | namespace WebCore { |
38 | |
39 | class CurrentRenderFragmentContainerMaintainer; |
40 | class RenderFragmentedFlow; |
41 | class RenderStyle; |
42 | class RenderFragmentContainer; |
43 | class RootInlineBox; |
44 | |
45 | typedef ListHashSet<RenderFragmentContainer*> RenderFragmentContainerList; |
46 | typedef Vector<RenderLayer*> RenderLayerList; |
47 | typedef HashMap<const RootInlineBox*, RenderFragmentContainer*> ContainingFragmentMap; |
48 | |
49 | // RenderFragmentedFlow is used to collect all the render objects that participate in a |
50 | // flow thread. It will also help in doing the layout. However, it will not render |
51 | // directly to screen. Instead, RenderFragmentContainer objects will redirect their paint |
52 | // and nodeAtPoint methods to this object. Each RenderFragmentContainer will actually be a viewPort |
53 | // of the RenderFragmentedFlow. |
54 | |
55 | class RenderFragmentedFlow: public RenderBlockFlow { |
56 | WTF_MAKE_ISO_ALLOCATED(RenderFragmentedFlow); |
57 | public: |
58 | virtual ~RenderFragmentedFlow() = default; |
59 | |
60 | virtual void removeFlowChildInfo(RenderElement&); |
61 | #ifndef NDEBUG |
62 | bool hasChildInfo(RenderObject* child) const { return is<RenderBox>(child) && m_fragmentRangeMap.contains(downcast<RenderBox>(child)); } |
63 | #endif |
64 | |
65 | #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
66 | bool checkLinesConsistency(const RenderBlockFlow&) const; |
67 | #endif |
68 | |
69 | void deleteLines() override; |
70 | |
71 | virtual void addFragmentToThread(RenderFragmentContainer*) = 0; |
72 | virtual void removeFragmentFromThread(RenderFragmentContainer*); |
73 | const RenderFragmentContainerList& renderFragmentContainerList() const { return m_fragmentList; } |
74 | |
75 | void updateLogicalWidth() final; |
76 | LogicalExtentComputedValues computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop) const override; |
77 | |
78 | bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; |
79 | |
80 | bool hasFragments() const { return m_fragmentList.size(); } |
81 | virtual void fragmentChangedWritingMode(RenderFragmentContainer*) { } |
82 | |
83 | void validateFragments(); |
84 | void invalidateFragments(MarkingBehavior = MarkContainingBlockChain); |
85 | bool hasValidFragmentInfo() const { return !m_fragmentsInvalidated && !m_fragmentList.isEmpty(); } |
86 | |
87 | // Called when a descendant box's layout is finished and it has been positioned within its container. |
88 | virtual void fragmentedFlowDescendantBoxLaidOut(RenderBox*) { } |
89 | |
90 | void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; |
91 | |
92 | void repaintRectangleInFragments(const LayoutRect&) const; |
93 | |
94 | LayoutPoint adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject&, const LayoutPoint&) const; |
95 | |
96 | LayoutUnit pageLogicalTopForOffset(LayoutUnit) const; |
97 | LayoutUnit pageLogicalWidthForOffset(LayoutUnit) const; |
98 | LayoutUnit pageLogicalHeightForOffset(LayoutUnit) const; |
99 | LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary) const; |
100 | |
101 | virtual void setPageBreak(const RenderBlock*, LayoutUnit /*offset*/, LayoutUnit /*spaceShortage*/) { } |
102 | virtual void updateMinimumPageHeight(const RenderBlock*, LayoutUnit /*offset*/, LayoutUnit /*minHeight*/) { } |
103 | |
104 | virtual RenderFragmentContainer* fragmentAtBlockOffset(const RenderBox*, LayoutUnit, bool extendLastFragment = false) const; |
105 | |
106 | bool fragmentsHaveUniformLogicalWidth() const { return m_fragmentsHaveUniformLogicalWidth; } |
107 | bool fragmentsHaveUniformLogicalHeight() const { return m_fragmentsHaveUniformLogicalHeight; } |
108 | |
109 | virtual RenderFragmentContainer* mapFromFlowToFragment(TransformState&) const; |
110 | |
111 | void logicalWidthChangedInFragmentsForBlock(const RenderBlock*, bool&); |
112 | |
113 | LayoutUnit contentLogicalWidthOfFirstFragment() const; |
114 | LayoutUnit contentLogicalHeightOfFirstFragment() const; |
115 | LayoutUnit contentLogicalLeftOfFirstFragment() const; |
116 | |
117 | RenderFragmentContainer* firstFragment() const; |
118 | RenderFragmentContainer* lastFragment() const; |
119 | |
120 | virtual void setFragmentRangeForBox(const RenderBox&, RenderFragmentContainer*, RenderFragmentContainer*); |
121 | bool getFragmentRangeForBox(const RenderBox*, RenderFragmentContainer*& startFragment, RenderFragmentContainer*& endFragment) const; |
122 | bool computedFragmentRangeForBox(const RenderBox*, RenderFragmentContainer*& startFragment, RenderFragmentContainer*& endFragment) const; |
123 | bool hasCachedFragmentRangeForBox(const RenderBox&) const; |
124 | |
125 | // Check if the object is in fragment and the fragment is part of this flow thread. |
126 | bool objectInFlowFragment(const RenderObject*, const RenderFragmentContainer*) const; |
127 | |
128 | // Check if the object should be painted in this fragment and if the fragment is part of this flow thread. |
129 | bool objectShouldFragmentInFlowFragment(const RenderObject*, const RenderFragmentContainer*) const; |
130 | |
131 | void markFragmentsForOverflowLayoutIfNeeded(); |
132 | |
133 | virtual bool addForcedFragmentBreak(const RenderBlock*, LayoutUnit, RenderBox* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0); |
134 | virtual void applyBreakAfterContent(LayoutUnit) { } |
135 | |
136 | virtual bool isPageLogicalHeightKnown() const { return true; } |
137 | bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; } |
138 | |
139 | void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect); |
140 | LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox); |
141 | |
142 | LayoutUnit offsetFromLogicalTopOfFirstFragment(const RenderBlock*) const; |
143 | void clearRenderBoxFragmentInfoAndCustomStyle(const RenderBox&, const RenderFragmentContainer*, const RenderFragmentContainer*, const RenderFragmentContainer*, const RenderFragmentContainer*); |
144 | |
145 | void addFragmentsVisualEffectOverflow(const RenderBox*); |
146 | void addFragmentsVisualOverflowFromTheme(const RenderBlock*); |
147 | void addFragmentsOverflowFromChild(const RenderBox*, const RenderBox*, const LayoutSize&); |
148 | void addFragmentsLayoutOverflow(const RenderBox*, const LayoutRect&); |
149 | void addFragmentsVisualOverflow(const RenderBox*, const LayoutRect&); |
150 | void clearFragmentsOverflow(const RenderBox*); |
151 | |
152 | LayoutRect mapFromFragmentedFlowToLocal(const RenderBox*, const LayoutRect&) const; |
153 | LayoutRect mapFromLocalToFragmentedFlow(const RenderBox*, const LayoutRect&) const; |
154 | |
155 | void flipForWritingModeLocalCoordinates(LayoutRect&) const; |
156 | |
157 | // Used to estimate the maximum height of the flow thread. |
158 | static LayoutUnit maxLogicalHeight() { return LayoutUnit::max() / 2; } |
159 | |
160 | bool fragmentInRange(const RenderFragmentContainer* targetFragment, const RenderFragmentContainer* startFragment, const RenderFragmentContainer* endFragment) const; |
161 | |
162 | virtual bool absoluteQuadsForBox(Vector<FloatQuad>&, bool*, const RenderBox*, float, float) const { return false; } |
163 | |
164 | void layout() override; |
165 | |
166 | void setCurrentFragmentMaintainer(CurrentRenderFragmentContainerMaintainer* currentFragmentMaintainer) { m_currentFragmentMaintainer = currentFragmentMaintainer; } |
167 | RenderFragmentContainer* currentFragment() const; |
168 | |
169 | ContainingFragmentMap& containingFragmentMap(); |
170 | |
171 | bool cachedEnclosingFragmentedFlowNeedsUpdate() const override { return false; } |
172 | |
173 | // FIXME: Eventually as column and fragment flow threads start nesting, this may end up changing. |
174 | virtual bool shouldCheckColumnBreaks() const { return false; } |
175 | |
176 | private: |
177 | // Always create a RenderLayer for the RenderFragmentedFlow so that we |
178 | // can easily avoid drawing the children directly. |
179 | bool requiresLayer() const final { return true; } |
180 | |
181 | protected: |
182 | RenderFragmentedFlow(Document&, RenderStyle&&); |
183 | |
184 | RenderFragmentedFlow* locateEnclosingFragmentedFlow() const override { return const_cast<RenderFragmentedFlow*>(this); } |
185 | |
186 | const char* renderName() const override = 0; |
187 | |
188 | // Overridden by columns/pages to set up an initial logical width of the page width even when |
189 | // no fragments have been generated yet. |
190 | virtual LayoutUnit initialLogicalWidth() const { return 0; }; |
191 | |
192 | void clearLinesToFragmentMap(); |
193 | void willBeDestroyed() override; |
194 | |
195 | void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const override; |
196 | |
197 | void updateFragmentsFragmentedFlowPortionRect(); |
198 | bool shouldRepaint(const LayoutRect&) const; |
199 | |
200 | bool getFragmentRangeForBoxFromCachedInfo(const RenderBox*, RenderFragmentContainer*& startFragment, RenderFragmentContainer*& endFragment) const; |
201 | |
202 | void removeRenderBoxFragmentInfo(RenderBox&); |
203 | void removeLineFragmentInfo(const RenderBlockFlow&); |
204 | |
205 | RenderFragmentContainerList m_fragmentList; |
206 | |
207 | class RenderFragmentContainerRange { |
208 | public: |
209 | RenderFragmentContainerRange() = default; |
210 | RenderFragmentContainerRange(RenderFragmentContainer* start, RenderFragmentContainer* end) |
211 | { |
212 | setRange(start, end); |
213 | } |
214 | |
215 | void setRange(RenderFragmentContainer* start, RenderFragmentContainer* end) |
216 | { |
217 | m_startFragment = makeWeakPtr(start); |
218 | m_endFragment = makeWeakPtr(end); |
219 | m_rangeInvalidated = true; |
220 | } |
221 | |
222 | RenderFragmentContainer* startFragment() const { return m_startFragment.get(); } |
223 | RenderFragmentContainer* endFragment() const { return m_endFragment.get(); } |
224 | bool rangeInvalidated() const { return m_rangeInvalidated; } |
225 | void clearRangeInvalidated() { m_rangeInvalidated = false; } |
226 | |
227 | private: |
228 | WeakPtr<RenderFragmentContainer> m_startFragment; |
229 | WeakPtr<RenderFragmentContainer> m_endFragment; |
230 | bool m_rangeInvalidated; |
231 | }; |
232 | |
233 | typedef PODInterval<LayoutUnit, WeakPtr<RenderFragmentContainer>> FragmentInterval; |
234 | typedef PODIntervalTree<LayoutUnit, WeakPtr<RenderFragmentContainer>> FragmentIntervalTree; |
235 | |
236 | class FragmentSearchAdapter { |
237 | public: |
238 | FragmentSearchAdapter(LayoutUnit offset) |
239 | : m_offset(offset) |
240 | { |
241 | } |
242 | |
243 | const LayoutUnit& lowValue() const { return m_offset; } |
244 | const LayoutUnit& highValue() const { return m_offset; } |
245 | void collectIfNeeded(const FragmentInterval&); |
246 | |
247 | RenderFragmentContainer* result() const { return m_result.get(); } |
248 | |
249 | private: |
250 | LayoutUnit m_offset; |
251 | WeakPtr<RenderFragmentContainer> m_result; |
252 | }; |
253 | |
254 | // Map a line to its containing fragment. |
255 | std::unique_ptr<ContainingFragmentMap> m_lineToFragmentMap; |
256 | |
257 | // Map a box to the list of fragments in which the box is rendered. |
258 | typedef HashMap<const RenderBox*, RenderFragmentContainerRange> RenderFragmentContainerRangeMap; |
259 | RenderFragmentContainerRangeMap m_fragmentRangeMap; |
260 | |
261 | // Map a box with a fragment break to the auto height fragment affected by that break. |
262 | typedef HashMap<RenderBox*, RenderFragmentContainer*> RenderBoxToFragmentMap; |
263 | RenderBoxToFragmentMap m_breakBeforeToFragmentMap; |
264 | RenderBoxToFragmentMap m_breakAfterToFragmentMap; |
265 | |
266 | FragmentIntervalTree m_fragmentIntervalTree; |
267 | |
268 | CurrentRenderFragmentContainerMaintainer* m_currentFragmentMaintainer; |
269 | |
270 | bool m_fragmentsInvalidated : 1; |
271 | bool m_fragmentsHaveUniformLogicalWidth : 1; |
272 | bool m_fragmentsHaveUniformLogicalHeight : 1; |
273 | bool m_pageLogicalSizeChanged : 1; |
274 | }; |
275 | |
276 | } // namespace WebCore |
277 | |
278 | #ifndef NDEBUG |
279 | |
280 | namespace WTF { |
281 | |
282 | // This structure is used by PODIntervalTree for debugging. |
283 | template <> struct ValueToString<WebCore::RenderFragmentContainer*> { |
284 | static String string(const WebCore::RenderFragmentContainer* value) { return value->debugString(); } |
285 | }; |
286 | template <> struct ValueToString<WeakPtr<WebCore::RenderFragmentContainer>> { |
287 | static String string(const WeakPtr<WebCore::RenderFragmentContainer>& value) { return value ? value->debugString() : String { }; } |
288 | }; |
289 | |
290 | } // namespace WTF |
291 | |
292 | #endif |
293 | |
294 | SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderFragmentedFlow, isRenderFragmentedFlow()) |
295 | |