1/*
2 * Copyright (C) 2017 Apple Inc. 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 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "LayoutUnit.h"
29#include "Timer.h"
30#include <wtf/WeakPtr.h>
31
32namespace WebCore {
33
34class Document;
35class Frame;
36class FrameView;
37class LayoutScope;
38class LayoutSize;
39class RenderBlockFlow;
40class RenderBox;
41class RenderObject;
42class RenderElement;
43class RenderLayoutState;
44class RenderView;
45
46class FrameViewLayoutContext {
47public:
48 FrameViewLayoutContext(FrameView&);
49 ~FrameViewLayoutContext();
50
51 void layout();
52 bool needsLayout() const;
53
54 // We rely on the side-effects of layout, like compositing updates, to update state in various subsystems
55 // whose dependencies are poorly defined. This call triggers such updates.
56 void setNeedsLayoutAfterViewConfigurationChange();
57
58 void scheduleLayout();
59 void scheduleSubtreeLayout(RenderElement& layoutRoot);
60 void unscheduleLayout();
61
62 void startDisallowingLayout() { ++m_layoutDisallowedCount; }
63 void endDisallowingLayout() { ASSERT(m_layoutDisallowedCount > 0); --m_layoutDisallowedCount; }
64
65 void disableSetNeedsLayout();
66 void enableSetNeedsLayout();
67
68 enum class LayoutPhase : uint8_t {
69 OutsideLayout,
70 InPreLayout,
71 InRenderTreeLayout,
72 InViewSizeAdjust,
73 InPostLayout
74 };
75 LayoutPhase layoutPhase() const { return m_layoutPhase; }
76 bool isLayoutNested() const { return m_layoutNestedState == LayoutNestedState::Nested; }
77 bool isLayoutPending() const { return m_layoutTimer.isActive(); }
78 bool isInLayout() const { return layoutPhase() != LayoutPhase::OutsideLayout; }
79 bool isInRenderTreeLayout() const { return layoutPhase() == LayoutPhase::InRenderTreeLayout; }
80 bool inPaintableState() const { return layoutPhase() != LayoutPhase::InRenderTreeLayout && layoutPhase() != LayoutPhase::InViewSizeAdjust && (layoutPhase() != LayoutPhase::InPostLayout || inAsynchronousTasks()); }
81
82 unsigned layoutCount() const { return m_layoutCount; }
83
84 RenderElement* subtreeLayoutRoot() const;
85 void clearSubtreeLayoutRoot() { m_subtreeLayoutRoot.clear(); }
86 void convertSubtreeLayoutToFullLayout();
87
88 void reset();
89 void resetFirstLayoutFlag() { m_firstLayout = true; }
90 bool didFirstLayout() const { return !m_firstLayout; }
91
92 void setNeedsFullRepaint() { m_needsFullRepaint = true; }
93 bool needsFullRepaint() const { return m_needsFullRepaint; }
94
95 void flushAsynchronousTasks();
96
97 RenderLayoutState* layoutState() const PURE_FUNCTION;
98 // Returns true if layoutState should be used for its cached offset and clip.
99 bool isPaintOffsetCacheEnabled() const { return !m_paintOffsetCacheDisableCount && layoutState(); }
100#ifndef NDEBUG
101 void checkLayoutState();
102#endif
103 // layoutDelta is used transiently during layout to store how far an object has moved from its
104 // last layout location, in order to repaint correctly.
105 // If we're doing a full repaint m_layoutState will be 0, but in that case layoutDelta doesn't matter.
106 LayoutSize layoutDelta() const;
107 void addLayoutDelta(const LayoutSize& delta);
108#if !ASSERT_DISABLED
109 bool layoutDeltaMatches(const LayoutSize& delta);
110#endif
111 using LayoutStateStack = Vector<std::unique_ptr<RenderLayoutState>>;
112
113private:
114 friend class LayoutScope;
115 friend class LayoutStateMaintainer;
116 friend class LayoutStateDisabler;
117 friend class SubtreeLayoutStateMaintainer;
118 friend class PaginatedLayoutStateMaintainer;
119
120 bool canPerformLayout() const;
121 bool layoutDisallowed() const { return m_layoutDisallowedCount; }
122 bool isLayoutSchedulingEnabled() const { return m_layoutSchedulingIsEnabled; }
123
124 void layoutTimerFired();
125 void runAsynchronousTasks();
126 void runOrScheduleAsynchronousTasks();
127 bool inAsynchronousTasks() const { return m_inAsynchronousTasks; }
128
129 void setSubtreeLayoutRoot(RenderElement&);
130
131#if ENABLE(TEXT_AUTOSIZING)
132 void applyTextSizingIfNeeded(RenderElement& layoutRoot);
133#endif
134 void updateStyleForLayout();
135
136 bool handleLayoutWithFrameFlatteningIfNeeded();
137 void startLayoutAtMainFrameViewIfNeeded();
138
139 // These functions may only be accessed by LayoutStateMaintainer.
140 // Subtree push/pop
141 void pushLayoutState(RenderElement&);
142 bool pushLayoutStateForPaginationIfNeeded(RenderBlockFlow&);
143 bool pushLayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageHeight = 0_lu, bool pageHeightChanged = false);
144 void popLayoutState();
145
146 // Suspends the LayoutState optimization. Used under transforms that cannot be represented by
147 // LayoutState (common in SVG) and when manipulating the render tree during layout in ways
148 // that can trigger repaint of a non-child (e.g. when a list item moves its list marker around).
149 // Note that even when disabled, LayoutState is still used to store layoutDelta.
150 // These functions may only be accessed by LayoutStateMaintainer or LayoutStateDisabler.
151 void disablePaintOffsetCache() { m_paintOffsetCacheDisableCount++; }
152 void enablePaintOffsetCache() { ASSERT(m_paintOffsetCacheDisableCount > 0); m_paintOffsetCacheDisableCount--; }
153
154 Frame& frame() const;
155 FrameView& view() const;
156 RenderView* renderView() const;
157 Document* document() const;
158
159 FrameView& m_frameView;
160 Timer m_layoutTimer;
161 Timer m_asynchronousTasksTimer;
162 WeakPtr<RenderElement> m_subtreeLayoutRoot;
163
164 bool m_layoutSchedulingIsEnabled { true };
165 bool m_delayedLayout { false };
166 bool m_firstLayout { true };
167 bool m_needsFullRepaint { true };
168 bool m_inAsynchronousTasks { false };
169 bool m_setNeedsLayoutWasDeferred { false };
170 LayoutPhase m_layoutPhase { LayoutPhase::OutsideLayout };
171 enum class LayoutNestedState : uint8_t { NotInLayout, NotNested, Nested };
172 LayoutNestedState m_layoutNestedState { LayoutNestedState::NotInLayout };
173 unsigned m_layoutCount { 0 };
174 unsigned m_disableSetNeedsLayoutCount { 0 };
175 int m_layoutDisallowedCount { 0 };
176 unsigned m_paintOffsetCacheDisableCount { 0 };
177 LayoutStateStack m_layoutStateStack;
178};
179
180} // namespace WebCore
181