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#ifndef RenderFlowThread_h
31#define RenderFlowThread_h
32
33
34#include "RenderBlock.h"
35#include <wtf/HashCountedSet.h>
36#include <wtf/ListHashSet.h>
37#include <wtf/PassRefPtr.h>
38
39namespace WebCore {
40
41struct LayerFragment;
42typedef Vector<LayerFragment, 1> LayerFragments;
43class RenderFlowThread;
44class RenderStyle;
45class RenderRegion;
46
47typedef ListHashSet<RenderRegion*> RenderRegionList;
48
49// RenderFlowThread 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, RenderRegion objects will redirect their paint
52// and nodeAtPoint methods to this object. Each RenderRegion will actually be a viewPort
53// of the RenderFlowThread.
54
55class RenderFlowThread: public RenderBlock {
56public:
57    RenderFlowThread();
58    virtual ~RenderFlowThread() { };
59
60    virtual bool isRenderFlowThread() const { return true; }
61
62    virtual void layout();
63
64    // Always create a RenderLayer for the RenderFlowThread so that we
65    // can easily avoid drawing the children directly.
66    virtual bool requiresLayer() const { return true; }
67
68    void removeFlowChildInfo(RenderObject*);
69#ifndef NDEBUG
70    bool hasChildInfo(RenderObject* child) const { return child && child->isBox() && m_regionRangeMap.contains(toRenderBox(child)); }
71#endif
72
73    virtual void addRegionToThread(RenderRegion*);
74    virtual void removeRegionFromThread(RenderRegion*);
75    const RenderRegionList& renderRegionList() const { return m_regionList; }
76
77    virtual void updateLogicalWidth() OVERRIDE;
78    virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE;
79
80    void paintFlowThreadPortionInRegion(PaintInfo&, RenderRegion*, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint&) const;
81    bool hitTestFlowThreadPortionInRegion(RenderRegion*, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const;
82    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
83
84    bool hasRegions() const { return m_regionList.size(); }
85    // Check if the content is flown into at least a region with region styling rules.
86    bool hasRegionsWithStyling() const { return m_hasRegionsWithStyling; }
87    void checkRegionsWithStyling();
88
89    void validateRegions();
90    void invalidateRegions();
91    bool hasValidRegionInfo() const { return !m_regionsInvalidated && !m_regionList.isEmpty(); }
92
93    static PassRefPtr<RenderStyle> createFlowThreadStyle(RenderStyle* parentStyle);
94
95    void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
96
97    void repaintRectangleInRegions(const LayoutRect&, bool immediate) const;
98
99    LayoutPoint adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject&, const LayoutPoint&);
100
101    LayoutUnit pageLogicalTopForOffset(LayoutUnit);
102    LayoutUnit pageLogicalWidthForOffset(LayoutUnit);
103    LayoutUnit pageLogicalHeightForOffset(LayoutUnit);
104    LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary);
105
106    virtual void setPageBreak(LayoutUnit /*offset*/, LayoutUnit /*spaceShortage*/) { }
107    virtual void updateMinimumPageHeight(LayoutUnit /*offset*/, LayoutUnit /*minHeight*/) { }
108
109    enum RegionAutoGenerationPolicy {
110        AllowRegionAutoGeneration,
111        DisallowRegionAutoGeneration,
112    };
113    RenderRegion* regionAtBlockOffset(LayoutUnit, bool extendLastRegion = false, RegionAutoGenerationPolicy = AllowRegionAutoGeneration);
114
115    bool regionsHaveUniformLogicalWidth() const { return m_regionsHaveUniformLogicalWidth; }
116    bool regionsHaveUniformLogicalHeight() const { return m_regionsHaveUniformLogicalHeight; }
117
118    RenderRegion* mapFromFlowToRegion(TransformState&) const;
119
120    void removeRenderBoxRegionInfo(RenderBox*);
121    bool logicalWidthChangedInRegionsForBlock(const RenderBlock*);
122
123    LayoutUnit contentLogicalWidthOfFirstRegion() const;
124    LayoutUnit contentLogicalHeightOfFirstRegion() const;
125    LayoutUnit contentLogicalLeftOfFirstRegion() const;
126
127    RenderRegion* firstRegion() const;
128    RenderRegion* lastRegion() const;
129
130    void setRegionRangeForBox(const RenderBox*, LayoutUnit offsetFromLogicalTopOfFirstPage);
131    void getRegionRangeForBox(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const;
132
133    void clearRenderObjectCustomStyle(const RenderObject*,
134        const RenderRegion* oldStartRegion = 0, const RenderRegion* oldEndRegion = 0,
135        const RenderRegion* newStartRegion = 0, const RenderRegion* newEndRegion = 0);
136
137    void computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge);
138
139    bool overset() const { return m_overset; }
140
141    // Check if the object is in region and the region is part of this flow thread.
142    bool objectInFlowRegion(const RenderObject*, const RenderRegion*) const;
143
144    void markAutoLogicalHeightRegionsForLayout();
145
146    bool addForcedRegionBreak(LayoutUnit, RenderObject* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0);
147    void applyBreakAfterContent(LayoutUnit);
148
149    bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; }
150
151    bool hasAutoLogicalHeightRegions() const { ASSERT(isAutoLogicalHeightRegionsCountConsistent()); return m_autoLogicalHeightRegionsCount; }
152    void incrementAutoLogicalHeightRegions();
153    void decrementAutoLogicalHeightRegions();
154
155#ifndef NDEBUG
156    bool isAutoLogicalHeightRegionsCountConsistent() const;
157#endif
158
159    void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect);
160    LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox);
161
162    void setInConstrainedLayoutPhase(bool value) { m_inConstrainedLayoutPhase = value; }
163    bool inConstrainedLayoutPhase() const { return m_inConstrainedLayoutPhase; }
164
165    bool needsTwoPhasesLayout() const { return m_needsTwoPhasesLayout; }
166    void clearNeedsTwoPhasesLayout() { m_needsTwoPhasesLayout = false; }
167
168    void pushFlowThreadLayoutState(const RenderObject*);
169    void popFlowThreadLayoutState();
170    LayoutUnit offsetFromLogicalTopOfFirstRegion(const RenderBlock*) const;
171
172protected:
173    virtual const char* renderName() const = 0;
174
175    // Overridden by columns/pages to set up an initial logical width of the page width even when
176    // no regions have been generated yet.
177    virtual LayoutUnit initialLogicalWidth() const { return 0; };
178
179    virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
180
181    void updateRegionsFlowThreadPortionRect(const RenderRegion* = 0);
182    bool shouldRepaint(const LayoutRect&) const;
183    bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const;
184
185    LayoutRect computeRegionClippingRect(const LayoutPoint&, const LayoutRect&, const LayoutRect&) const;
186
187    void setDispatchRegionLayoutUpdateEvent(bool value) { m_dispatchRegionLayoutUpdateEvent = value; }
188    bool shouldDispatchRegionLayoutUpdateEvent() { return m_dispatchRegionLayoutUpdateEvent; }
189
190    // Override if the flow thread implementation supports dispatching events when the flow layout is updated (e.g. for named flows)
191    virtual void dispatchRegionLayoutUpdateEvent() { m_dispatchRegionLayoutUpdateEvent = false; }
192
193    void initializeRegionsOverrideLogicalContentHeight(RenderRegion* = 0);
194
195    virtual void autoGenerateRegionsToBlockOffset(LayoutUnit) { };
196
197    inline bool hasCachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*) const;
198    inline LayoutUnit cachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*) const;
199    inline void setOffsetFromLogicalTopOfFirstRegion(const RenderBox*, LayoutUnit);
200    inline void clearOffsetFromLogicalTopOfFirstRegion(const RenderBox*);
201
202    inline const RenderBox* currentActiveRenderBox() const;
203
204    RenderRegionList m_regionList;
205
206    class RenderRegionRange {
207    public:
208        RenderRegionRange()
209        {
210            setRange(0, 0);
211        }
212
213        RenderRegionRange(RenderRegion* start, RenderRegion* end)
214        {
215            setRange(start, end);
216        }
217
218        void setRange(RenderRegion* start, RenderRegion* end)
219        {
220            m_startRegion = start;
221            m_endRegion = end;
222        }
223
224        RenderRegion* startRegion() const { return m_startRegion; }
225        RenderRegion* endRegion() const { return m_endRegion; }
226
227    private:
228        RenderRegion* m_startRegion;
229        RenderRegion* m_endRegion;
230    };
231
232    typedef PODInterval<LayoutUnit, RenderRegion*> RegionInterval;
233    typedef PODIntervalTree<LayoutUnit, RenderRegion*> RegionIntervalTree;
234
235    class RegionSearchAdapter {
236    public:
237        RegionSearchAdapter(LayoutUnit offset)
238            : m_offset(offset)
239            , m_result(0)
240        {
241        }
242
243        const LayoutUnit& lowValue() const { return m_offset; }
244        const LayoutUnit& highValue() const { return m_offset; }
245        void collectIfNeeded(const RegionInterval&);
246
247        RenderRegion* result() const { return m_result; }
248
249    private:
250        LayoutUnit m_offset;
251        RenderRegion* m_result;
252    };
253
254    // A maps from RenderBox
255    typedef HashMap<const RenderBox*, RenderRegionRange> RenderRegionRangeMap;
256    RenderRegionRangeMap m_regionRangeMap;
257
258    typedef HashMap<RenderObject*, RenderRegion*> RenderObjectToRegionMap;
259    RenderObjectToRegionMap m_breakBeforeToRegionMap;
260    RenderObjectToRegionMap m_breakAfterToRegionMap;
261
262    typedef ListHashSet<const RenderObject*> RenderObjectStack;
263    RenderObjectStack m_activeObjectsStack;
264    typedef HashMap<const RenderBox*, LayoutUnit> RenderBoxToOffsetMap;
265    RenderBoxToOffsetMap m_boxesToOffsetMap;
266
267    unsigned m_autoLogicalHeightRegionsCount;
268
269    RegionIntervalTree m_regionIntervalTree;
270
271    bool m_regionsInvalidated : 1;
272    bool m_regionsHaveUniformLogicalWidth : 1;
273    bool m_regionsHaveUniformLogicalHeight : 1;
274    bool m_overset : 1;
275    bool m_hasRegionsWithStyling : 1;
276    bool m_dispatchRegionLayoutUpdateEvent : 1;
277    bool m_pageLogicalSizeChanged : 1;
278    bool m_inConstrainedLayoutPhase : 1;
279    bool m_needsTwoPhasesLayout : 1;
280};
281
282inline RenderFlowThread* toRenderFlowThread(RenderObject* object)
283{
284    ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderFlowThread());
285    return static_cast<RenderFlowThread*>(object);
286}
287
288inline const RenderFlowThread* toRenderFlowThread(const RenderObject* object)
289{
290    ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderFlowThread());
291    return static_cast<const RenderFlowThread*>(object);
292}
293
294// This will catch anyone doing an unnecessary cast.
295void toRenderFlowThread(const RenderFlowThread*);
296
297class CurrentRenderFlowThreadMaintainer {
298    WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadMaintainer);
299public:
300    CurrentRenderFlowThreadMaintainer(RenderFlowThread*);
301    ~CurrentRenderFlowThreadMaintainer();
302private:
303    RenderFlowThread* m_renderFlowThread;
304    RenderFlowThread* m_previousRenderFlowThread;
305};
306
307// These structures are used by PODIntervalTree for debugging.
308#ifndef NDEBUG
309template <> struct ValueToString<LayoutUnit> {
310    static String string(const LayoutUnit value) { return String::number(value.toFloat()); }
311};
312
313template <> struct ValueToString<RenderRegion*> {
314    static String string(const RenderRegion* value) { return String::format("%p", value); }
315};
316#endif
317
318} // namespace WebCore
319
320#endif // RenderFlowThread_h
321