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
37namespace WebCore {
38
39class CurrentRenderFragmentContainerMaintainer;
40class RenderFragmentedFlow;
41class RenderStyle;
42class RenderFragmentContainer;
43class RootInlineBox;
44
45typedef ListHashSet<RenderFragmentContainer*> RenderFragmentContainerList;
46typedef Vector<RenderLayer*> RenderLayerList;
47typedef 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
55class RenderFragmentedFlow: public RenderBlockFlow {
56 WTF_MAKE_ISO_ALLOCATED(RenderFragmentedFlow);
57public:
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
176private:
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
181protected:
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
280namespace WTF {
281
282// This structure is used by PODIntervalTree for debugging.
283template <> struct ValueToString<WebCore::RenderFragmentContainer*> {
284 static String string(const WebCore::RenderFragmentContainer* value) { return value->debugString(); }
285};
286template <> 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
294SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderFragmentedFlow, isRenderFragmentedFlow())
295