1 | /* |
2 | * Copyright (C) 2018 Metrological Group B.V. |
3 | * Copyright (C) 2018 Igalia S.L. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following 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 provided |
14 | * with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #pragma once |
30 | |
31 | #include "Color.h" |
32 | #include "FilterOperations.h" |
33 | #include "FloatPoint.h" |
34 | #include "FloatPoint3D.h" |
35 | #include "FloatRect.h" |
36 | #include "FloatSize.h" |
37 | #include "TextureMapperAnimation.h" |
38 | #include "TransformationMatrix.h" |
39 | #include <wtf/Function.h> |
40 | #include <wtf/Lock.h> |
41 | #include <wtf/ThreadSafeRefCounted.h> |
42 | #include <wtf/TypeCasts.h> |
43 | |
44 | namespace Nicosia { |
45 | |
46 | class PlatformLayer : public ThreadSafeRefCounted<PlatformLayer> { |
47 | public: |
48 | virtual ~PlatformLayer(); |
49 | |
50 | virtual bool isCompositionLayer() const { return false; } |
51 | virtual bool isContentLayer() const { return false; } |
52 | |
53 | using LayerID = uint64_t; |
54 | LayerID id() const { return m_id; } |
55 | |
56 | protected: |
57 | explicit PlatformLayer(uint64_t); |
58 | |
59 | uint64_t m_id; |
60 | |
61 | struct { |
62 | Lock lock; |
63 | } m_state; |
64 | }; |
65 | |
66 | class ContentLayer; |
67 | class BackingStore; |
68 | class ImageBacking; |
69 | |
70 | class CompositionLayer : public PlatformLayer { |
71 | public: |
72 | class Impl { |
73 | public: |
74 | using Factory = WTF::Function<std::unique_ptr<Impl>(uint64_t, CompositionLayer&)>; |
75 | |
76 | virtual ~Impl(); |
77 | virtual bool isTextureMapperImpl() const { return false; } |
78 | }; |
79 | |
80 | static Ref<CompositionLayer> create(uint64_t id, const Impl::Factory& factory) |
81 | { |
82 | return adoptRef(*new CompositionLayer(id, factory)); |
83 | } |
84 | virtual ~CompositionLayer(); |
85 | bool isCompositionLayer() const override { return true; } |
86 | |
87 | Impl& impl() const { return *m_impl; } |
88 | |
89 | struct LayerState { |
90 | struct Delta { |
91 | Delta() = default; |
92 | |
93 | union { |
94 | struct { |
95 | bool positionChanged : 1; |
96 | bool anchorPointChanged : 1; |
97 | bool sizeChanged : 1; |
98 | bool transformChanged : 1; |
99 | bool childrenTransformChanged : 1; |
100 | bool contentsRectChanged : 1; |
101 | bool contentsTilingChanged : 1; |
102 | bool opacityChanged : 1; |
103 | bool solidColorChanged : 1; |
104 | bool filtersChanged : 1; |
105 | bool animationsChanged : 1; |
106 | bool childrenChanged : 1; |
107 | bool maskChanged : 1; |
108 | bool replicaChanged : 1; |
109 | bool flagsChanged : 1; |
110 | bool contentLayerChanged : 1; |
111 | bool backingStoreChanged : 1; |
112 | bool imageBackingChanged : 1; |
113 | bool repaintCounterChanged : 1; |
114 | bool debugBorderChanged : 1; |
115 | }; |
116 | uint32_t value { 0 }; |
117 | }; |
118 | } delta; |
119 | |
120 | struct Flags { |
121 | Flags() |
122 | : contentsVisible(true) |
123 | , backfaceVisible(true) |
124 | { } |
125 | |
126 | union { |
127 | struct { |
128 | bool contentsOpaque : 1; |
129 | bool drawsContent : 1; |
130 | bool contentsVisible : 1; |
131 | bool backfaceVisible : 1; |
132 | bool masksToBounds : 1; |
133 | bool preserves3D : 1; |
134 | }; |
135 | uint32_t value { 0 }; |
136 | }; |
137 | } flags; |
138 | |
139 | WebCore::FloatPoint position; |
140 | WebCore::FloatPoint3D anchorPoint; |
141 | WebCore::FloatSize size; |
142 | |
143 | WebCore::TransformationMatrix transform; |
144 | WebCore::TransformationMatrix childrenTransform; |
145 | |
146 | WebCore::FloatRect contentsRect; |
147 | WebCore::FloatSize contentsTilePhase; |
148 | WebCore::FloatSize contentsTileSize; |
149 | |
150 | float opacity { 0 }; |
151 | WebCore::Color solidColor; |
152 | |
153 | WebCore::FilterOperations filters; |
154 | // FIXME: Despite the name, this implementation is not |
155 | // TextureMapper-specific. Should be renamed when necessary. |
156 | WebCore::TextureMapperAnimations animations; |
157 | |
158 | Vector<RefPtr<CompositionLayer>> children; |
159 | RefPtr<CompositionLayer> replica; |
160 | RefPtr<CompositionLayer> mask; |
161 | |
162 | RefPtr<ContentLayer> contentLayer; |
163 | RefPtr<BackingStore> backingStore; |
164 | RefPtr<ImageBacking> imageBacking; |
165 | |
166 | struct RepaintCounter { |
167 | unsigned count { 0 }; |
168 | bool visible { false }; |
169 | } repaintCounter; |
170 | struct DebugBorder { |
171 | WebCore::Color color; |
172 | float width { 0 }; |
173 | bool visible { false }; |
174 | } debugBorder; |
175 | }; |
176 | |
177 | template<typename T> |
178 | void updateState(const T& functor) |
179 | { |
180 | LockHolder locker(PlatformLayer::m_state.lock); |
181 | functor(m_state.pending); |
182 | } |
183 | |
184 | template<typename T> |
185 | void flushState(const T& functor) |
186 | { |
187 | LockHolder locker(PlatformLayer::m_state.lock); |
188 | auto& pending = m_state.pending; |
189 | auto& staging = m_state.staging; |
190 | |
191 | staging.delta.value |= pending.delta.value; |
192 | |
193 | if (pending.delta.positionChanged) |
194 | staging.position = pending.position; |
195 | if (pending.delta.anchorPointChanged) |
196 | staging.anchorPoint = pending.anchorPoint; |
197 | if (pending.delta.sizeChanged) |
198 | staging.size = pending.size; |
199 | |
200 | if (pending.delta.transformChanged) |
201 | staging.transform = pending.transform; |
202 | if (pending.delta.childrenTransformChanged) |
203 | staging.childrenTransform = pending.childrenTransform; |
204 | |
205 | if (pending.delta.contentsRectChanged) |
206 | staging.contentsRect = pending.contentsRect; |
207 | if (pending.delta.contentsTilingChanged) { |
208 | staging.contentsTilePhase = pending.contentsTilePhase; |
209 | staging.contentsTileSize = pending.contentsTileSize; |
210 | } |
211 | |
212 | if (pending.delta.opacityChanged) |
213 | staging.opacity = pending.opacity; |
214 | if (pending.delta.solidColorChanged) |
215 | staging.solidColor = pending.solidColor; |
216 | |
217 | if (pending.delta.filtersChanged) |
218 | staging.filters = pending.filters; |
219 | if (pending.delta.animationsChanged) |
220 | staging.animations = pending.animations; |
221 | |
222 | if (pending.delta.childrenChanged) |
223 | staging.children = pending.children; |
224 | if (pending.delta.maskChanged) |
225 | staging.mask = pending.mask; |
226 | if (pending.delta.replicaChanged) |
227 | staging.replica = pending.replica; |
228 | |
229 | if (pending.delta.flagsChanged) |
230 | staging.flags.value = pending.flags.value; |
231 | |
232 | if (pending.delta.repaintCounterChanged) |
233 | staging.repaintCounter = pending.repaintCounter; |
234 | if (pending.delta.debugBorderChanged) |
235 | staging.debugBorder = pending.debugBorder; |
236 | |
237 | if (pending.delta.backingStoreChanged) |
238 | staging.backingStore = pending.backingStore; |
239 | if (pending.delta.contentLayerChanged) |
240 | staging.contentLayer = pending.contentLayer; |
241 | if (pending.delta.imageBackingChanged) |
242 | staging.imageBacking = pending.imageBacking; |
243 | |
244 | pending.delta = { }; |
245 | |
246 | functor(staging); |
247 | } |
248 | |
249 | template<typename T> |
250 | void commitState(const T& functor) |
251 | { |
252 | LockHolder locker(PlatformLayer::m_state.lock); |
253 | m_state.committed = m_state.staging; |
254 | m_state.staging.delta = { }; |
255 | |
256 | functor(m_state.committed); |
257 | } |
258 | |
259 | template<typename T> |
260 | void accessCommitted(const T& functor) |
261 | { |
262 | LockHolder locker(PlatformLayer::m_state.lock); |
263 | functor(m_state.committed); |
264 | } |
265 | |
266 | private: |
267 | CompositionLayer(uint64_t, const Impl::Factory&); |
268 | |
269 | std::unique_ptr<Impl> m_impl; |
270 | |
271 | struct { |
272 | LayerState pending; |
273 | LayerState staging; |
274 | LayerState committed; |
275 | } m_state; |
276 | }; |
277 | |
278 | class ContentLayer : public PlatformLayer { |
279 | public: |
280 | class Impl { |
281 | public: |
282 | using Factory = WTF::Function<std::unique_ptr<Impl>(ContentLayer&)>; |
283 | |
284 | virtual ~Impl(); |
285 | virtual bool isTextureMapperImpl() const { return false; } |
286 | }; |
287 | |
288 | static Ref<ContentLayer> create(const Impl::Factory& factory) |
289 | { |
290 | return adoptRef(*new ContentLayer(factory)); |
291 | } |
292 | virtual ~ContentLayer(); |
293 | bool isContentLayer() const override { return true; } |
294 | |
295 | Impl& impl() const { return *m_impl; } |
296 | |
297 | private: |
298 | ContentLayer(const Impl::Factory&); |
299 | |
300 | std::unique_ptr<Impl> m_impl; |
301 | }; |
302 | |
303 | class BackingStore : public ThreadSafeRefCounted<BackingStore> { |
304 | public: |
305 | class Impl { |
306 | public: |
307 | using Factory = WTF::Function<std::unique_ptr<Impl>(BackingStore&)>; |
308 | |
309 | virtual ~Impl(); |
310 | virtual bool isTextureMapperImpl() const { return false; } |
311 | }; |
312 | |
313 | static Ref<BackingStore> create(const Impl::Factory& factory) |
314 | { |
315 | return adoptRef(*new BackingStore(factory)); |
316 | } |
317 | virtual ~BackingStore(); |
318 | |
319 | Impl& impl() const { return *m_impl; } |
320 | |
321 | private: |
322 | BackingStore(const Impl::Factory&); |
323 | |
324 | std::unique_ptr<Impl> m_impl; |
325 | }; |
326 | |
327 | class ImageBacking : public ThreadSafeRefCounted<ImageBacking> { |
328 | public: |
329 | class Impl { |
330 | public: |
331 | using Factory = WTF::Function<std::unique_ptr<Impl>(ImageBacking&)>; |
332 | |
333 | virtual ~Impl(); |
334 | virtual bool isTextureMapperImpl() const { return false; } |
335 | }; |
336 | |
337 | static Ref<ImageBacking> create(const Impl::Factory& factory) |
338 | { |
339 | return adoptRef(*new ImageBacking(factory)); |
340 | } |
341 | virtual ~ImageBacking(); |
342 | |
343 | Impl& impl() const { return *m_impl; } |
344 | |
345 | private: |
346 | ImageBacking(const Impl::Factory&); |
347 | |
348 | std::unique_ptr<Impl> m_impl; |
349 | }; |
350 | |
351 | } // namespace Nicosia |
352 | |
353 | #define SPECIALIZE_TYPE_TRAITS_NICOSIA_PLATFORMLAYER(ToClassName, predicate) \ |
354 | SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \ |
355 | static bool isType(const Nicosia::PlatformLayer& layer) { return layer.predicate; } \ |
356 | SPECIALIZE_TYPE_TRAITS_END() |
357 | |
358 | SPECIALIZE_TYPE_TRAITS_NICOSIA_PLATFORMLAYER(CompositionLayer, isCompositionLayer()); |
359 | SPECIALIZE_TYPE_TRAITS_NICOSIA_PLATFORMLAYER(ContentLayer, isContentLayer()); |
360 | |
361 | #define SPECIALIZE_TYPE_TRAITS_NICOSIA_COMPOSITIONLAYER_IMPL(ToClassName, predicate) \ |
362 | SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \ |
363 | static bool isType(const Nicosia::CompositionLayer::Impl& impl) { return impl.predicate; } \ |
364 | SPECIALIZE_TYPE_TRAITS_END() |
365 | |
366 | #define SPECIALIZE_TYPE_TRAITS_NICOSIA_CONTENTLAYER_IMPL(ToClassName, predicate) \ |
367 | SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \ |
368 | static bool isType(const Nicosia::ContentLayer::Impl& impl) { return impl.predicate; } \ |
369 | SPECIALIZE_TYPE_TRAITS_END() |
370 | |
371 | #define SPECIALIZE_TYPE_TRAITS_NICOSIA_BACKINGSTORE_IMPL(ToClassName, predicate) \ |
372 | SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \ |
373 | static bool isType(const Nicosia::BackingStore::Impl& impl) { return impl.predicate; } \ |
374 | SPECIALIZE_TYPE_TRAITS_END() |
375 | |
376 | #define SPECIALIZE_TYPE_TRAITS_NICOSIA_IMAGEBACKING_IMPL(ToClassName, predicate) \ |
377 | SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \ |
378 | static bool isType(const Nicosia::ImageBacking::Impl& impl) { return impl.predicate; } \ |
379 | SPECIALIZE_TYPE_TRAITS_END() |
380 | |