1 | /* |
2 | * Copyright (C) 2012 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. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS) |
29 | |
30 | #include "GraphicsLayer.h" |
31 | #include "ScrollingCoordinator.h" |
32 | #include <stdint.h> |
33 | #include <wtf/RefCounted.h> |
34 | #include <wtf/TypeCasts.h> |
35 | #include <wtf/Vector.h> |
36 | |
37 | namespace WTF { |
38 | class TextStream; |
39 | } |
40 | |
41 | namespace WebCore { |
42 | |
43 | class GraphicsLayer; |
44 | class ScrollingStateTree; |
45 | |
46 | // Used to allow ScrollingStateNodes to refer to layers in various contexts: |
47 | // a) Async scrolling, main thread: ScrollingStateNode holds onto a GraphicsLayer, and uses m_layerID |
48 | // to detect whether that GraphicsLayer's underlying PlatformLayer changed. |
49 | // b) Threaded scrolling, commit to scrolling thread: ScrollingStateNode wraps a PlatformLayer, which |
50 | // can be passed to the Scrolling Thread |
51 | // c) Remote scrolling UI process, where LayerRepresentation wraps just a PlatformLayerID. |
52 | class LayerRepresentation { |
53 | public: |
54 | enum Type { |
55 | EmptyRepresentation, |
56 | GraphicsLayerRepresentation, |
57 | PlatformLayerRepresentation, |
58 | PlatformLayerIDRepresentation |
59 | }; |
60 | |
61 | LayerRepresentation() = default; |
62 | |
63 | LayerRepresentation(GraphicsLayer* graphicsLayer) |
64 | : m_graphicsLayer(graphicsLayer) |
65 | , m_layerID(graphicsLayer ? graphicsLayer->primaryLayerID() : 0) |
66 | , m_representation(GraphicsLayerRepresentation) |
67 | { } |
68 | |
69 | LayerRepresentation(PlatformLayer* platformLayer) |
70 | : m_typelessPlatformLayer(makePlatformLayerTypeless(platformLayer)) |
71 | , m_representation(PlatformLayerRepresentation) |
72 | { |
73 | retainPlatformLayer(m_typelessPlatformLayer); |
74 | } |
75 | |
76 | LayerRepresentation(GraphicsLayer::PlatformLayerID layerID) |
77 | : m_layerID(layerID) |
78 | , m_representation(PlatformLayerIDRepresentation) |
79 | { |
80 | } |
81 | |
82 | LayerRepresentation(const LayerRepresentation& other) |
83 | : m_typelessPlatformLayer(other.m_typelessPlatformLayer) |
84 | , m_layerID(other.m_layerID) |
85 | , m_representation(other.m_representation) |
86 | { |
87 | if (m_representation == PlatformLayerRepresentation) |
88 | retainPlatformLayer(m_typelessPlatformLayer); |
89 | } |
90 | |
91 | ~LayerRepresentation() |
92 | { |
93 | if (m_representation == PlatformLayerRepresentation) |
94 | releasePlatformLayer(m_typelessPlatformLayer); |
95 | } |
96 | |
97 | operator GraphicsLayer*() const |
98 | { |
99 | ASSERT(m_representation == GraphicsLayerRepresentation); |
100 | return m_graphicsLayer.get(); |
101 | } |
102 | |
103 | operator PlatformLayer*() const |
104 | { |
105 | ASSERT(m_representation == PlatformLayerRepresentation); |
106 | return makePlatformLayerTyped(m_typelessPlatformLayer); |
107 | } |
108 | |
109 | GraphicsLayer::PlatformLayerID layerID() const |
110 | { |
111 | return m_layerID; |
112 | } |
113 | |
114 | operator GraphicsLayer::PlatformLayerID() const |
115 | { |
116 | ASSERT(m_representation != PlatformLayerRepresentation); |
117 | return m_layerID; |
118 | } |
119 | |
120 | LayerRepresentation& operator=(const LayerRepresentation& other) |
121 | { |
122 | m_graphicsLayer = other.m_graphicsLayer; |
123 | m_typelessPlatformLayer = other.m_typelessPlatformLayer; |
124 | m_layerID = other.m_layerID; |
125 | m_representation = other.m_representation; |
126 | |
127 | if (m_representation == PlatformLayerRepresentation) |
128 | retainPlatformLayer(m_typelessPlatformLayer); |
129 | |
130 | return *this; |
131 | } |
132 | |
133 | bool operator==(const LayerRepresentation& other) const |
134 | { |
135 | if (m_representation != other.m_representation) |
136 | return false; |
137 | switch (m_representation) { |
138 | case EmptyRepresentation: |
139 | return true; |
140 | case GraphicsLayerRepresentation: |
141 | return m_graphicsLayer == other.m_graphicsLayer |
142 | && m_layerID == other.m_layerID; |
143 | case PlatformLayerRepresentation: |
144 | return m_typelessPlatformLayer == other.m_typelessPlatformLayer; |
145 | case PlatformLayerIDRepresentation: |
146 | return m_layerID == other.m_layerID; |
147 | } |
148 | ASSERT_NOT_REACHED(); |
149 | return true; |
150 | } |
151 | |
152 | LayerRepresentation toRepresentation(Type representation) const |
153 | { |
154 | switch (representation) { |
155 | case EmptyRepresentation: |
156 | return LayerRepresentation(); |
157 | case GraphicsLayerRepresentation: |
158 | ASSERT(m_representation == GraphicsLayerRepresentation); |
159 | return LayerRepresentation(m_graphicsLayer.get()); |
160 | case PlatformLayerRepresentation: |
161 | return m_graphicsLayer ? m_graphicsLayer->platformLayer() : nullptr; |
162 | case PlatformLayerIDRepresentation: |
163 | return LayerRepresentation(m_layerID); |
164 | } |
165 | return LayerRepresentation(); |
166 | } |
167 | |
168 | bool representsGraphicsLayer() const { return m_representation == GraphicsLayerRepresentation; } |
169 | bool representsPlatformLayerID() const { return m_representation == PlatformLayerIDRepresentation; } |
170 | |
171 | private: |
172 | WEBCORE_EXPORT static void retainPlatformLayer(void* typelessPlatformLayer); |
173 | WEBCORE_EXPORT static void releasePlatformLayer(void* typelessPlatformLayer); |
174 | WEBCORE_EXPORT static PlatformLayer* makePlatformLayerTyped(void* typelessPlatformLayer); |
175 | WEBCORE_EXPORT static void* makePlatformLayerTypeless(PlatformLayer*); |
176 | |
177 | RefPtr<GraphicsLayer> m_graphicsLayer; |
178 | void* m_typelessPlatformLayer { nullptr }; |
179 | GraphicsLayer::PlatformLayerID m_layerID { 0 }; |
180 | Type m_representation { EmptyRepresentation }; |
181 | }; |
182 | |
183 | class ScrollingStateNode : public RefCounted<ScrollingStateNode> { |
184 | WTF_MAKE_FAST_ALLOCATED; |
185 | public: |
186 | ScrollingStateNode(ScrollingNodeType, ScrollingStateTree&, ScrollingNodeID); |
187 | virtual ~ScrollingStateNode(); |
188 | |
189 | ScrollingNodeType nodeType() const { return m_nodeType; } |
190 | |
191 | bool isFixedNode() const { return m_nodeType == ScrollingNodeType::Fixed; } |
192 | bool isStickyNode() const { return m_nodeType == ScrollingNodeType::Sticky; } |
193 | bool isPositionedNode() const { return m_nodeType == ScrollingNodeType::Positioned; } |
194 | bool isScrollingNode() const { return isFrameScrollingNode() || isOverflowScrollingNode(); } |
195 | bool isFrameScrollingNode() const { return m_nodeType == ScrollingNodeType::MainFrame || m_nodeType == ScrollingNodeType::Subframe; } |
196 | bool isFrameHostingNode() const { return m_nodeType == ScrollingNodeType::FrameHosting; } |
197 | bool isOverflowScrollingNode() const { return m_nodeType == ScrollingNodeType::Overflow; } |
198 | |
199 | virtual Ref<ScrollingStateNode> clone(ScrollingStateTree& adoptiveTree) = 0; |
200 | Ref<ScrollingStateNode> cloneAndReset(ScrollingStateTree& adoptiveTree); |
201 | void cloneAndResetChildren(ScrollingStateNode&, ScrollingStateTree& adoptiveTree); |
202 | |
203 | // FIXME: using an OptionSet<> for these and derived class bits would simplify code. |
204 | enum { |
205 | Layer = 0, |
206 | ChildNodes, |
207 | NumStateNodeBits // This must remain at the last position. |
208 | }; |
209 | typedef uint64_t ChangedProperties; |
210 | |
211 | bool hasChangedProperties() const { return m_changedProperties; } |
212 | bool hasChangedProperty(unsigned propertyBit) const { return m_changedProperties & (static_cast<ChangedProperties>(1) << propertyBit); } |
213 | void resetChangedProperties() { m_changedProperties = 0; } |
214 | void setPropertyChanged(unsigned propertyBit); |
215 | virtual void setAllPropertiesChanged(); |
216 | |
217 | ChangedProperties changedProperties() const { return m_changedProperties; } |
218 | void setChangedProperties(ChangedProperties changedProperties) { m_changedProperties = changedProperties; } |
219 | |
220 | virtual void reconcileLayerPositionForViewportRect(const LayoutRect& /*viewportRect*/, ScrollingLayerPositionAction) { } |
221 | |
222 | const LayerRepresentation& layer() const { return m_layer; } |
223 | WEBCORE_EXPORT void setLayer(const LayerRepresentation&); |
224 | |
225 | ScrollingStateTree& scrollingStateTree() const { return m_scrollingStateTree; } |
226 | |
227 | ScrollingNodeID scrollingNodeID() const { return m_nodeID; } |
228 | |
229 | ScrollingStateNode* parent() const { return m_parent; } |
230 | void setParent(ScrollingStateNode* parent) { m_parent = parent; } |
231 | ScrollingNodeID parentNodeID() const { return m_parent ? m_parent->scrollingNodeID() : 0; } |
232 | |
233 | Vector<RefPtr<ScrollingStateNode>>* children() const { return m_children.get(); } |
234 | std::unique_ptr<Vector<RefPtr<ScrollingStateNode>>> takeChildren() { return WTFMove(m_children); } |
235 | |
236 | void appendChild(Ref<ScrollingStateNode>&&); |
237 | void insertChild(Ref<ScrollingStateNode>&&, size_t index); |
238 | |
239 | // Note that node ownership is via the parent, so these functions can trigger node deletion. |
240 | void removeFromParent(); |
241 | void removeChildAtIndex(size_t index); |
242 | void removeChild(ScrollingStateNode&); |
243 | |
244 | size_t indexOfChild(ScrollingStateNode&) const; |
245 | |
246 | String scrollingStateTreeAsText(ScrollingStateTreeAsTextBehavior = ScrollingStateTreeAsTextBehaviorNormal) const; |
247 | |
248 | protected: |
249 | ScrollingStateNode(const ScrollingStateNode&, ScrollingStateTree&); |
250 | |
251 | virtual void dumpProperties(WTF::TextStream&, ScrollingStateTreeAsTextBehavior) const; |
252 | |
253 | inline void setPropertyChangedBit(unsigned propertyBit); |
254 | |
255 | private: |
256 | void dump(WTF::TextStream&, ScrollingStateTreeAsTextBehavior) const; |
257 | |
258 | const ScrollingNodeType m_nodeType; |
259 | const ScrollingNodeID m_nodeID; |
260 | ChangedProperties m_changedProperties { 0 }; |
261 | |
262 | ScrollingStateTree& m_scrollingStateTree; |
263 | |
264 | ScrollingStateNode* m_parent { nullptr }; |
265 | std::unique_ptr<Vector<RefPtr<ScrollingStateNode>>> m_children; |
266 | |
267 | LayerRepresentation m_layer; |
268 | }; |
269 | |
270 | void ScrollingStateNode::setPropertyChangedBit(unsigned propertyBit) |
271 | { |
272 | m_changedProperties |= (static_cast<ChangedProperties>(1) << propertyBit); |
273 | } |
274 | |
275 | } // namespace WebCore |
276 | |
277 | #define SPECIALIZE_TYPE_TRAITS_SCROLLING_STATE_NODE(ToValueTypeName, predicate) \ |
278 | SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \ |
279 | static bool isType(const WebCore::ScrollingStateNode& node) { return node.predicate; } \ |
280 | SPECIALIZE_TYPE_TRAITS_END() |
281 | |
282 | #endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS) |
283 | |