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
44namespace Nicosia {
45
46class PlatformLayer : public ThreadSafeRefCounted<PlatformLayer> {
47public:
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
56protected:
57 explicit PlatformLayer(uint64_t);
58
59 uint64_t m_id;
60
61 struct {
62 Lock lock;
63 } m_state;
64};
65
66class ContentLayer;
67class BackingStore;
68class ImageBacking;
69
70class CompositionLayer : public PlatformLayer {
71public:
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
266private:
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
278class ContentLayer : public PlatformLayer {
279public:
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
297private:
298 ContentLayer(const Impl::Factory&);
299
300 std::unique_ptr<Impl> m_impl;
301};
302
303class BackingStore : public ThreadSafeRefCounted<BackingStore> {
304public:
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
321private:
322 BackingStore(const Impl::Factory&);
323
324 std::unique_ptr<Impl> m_impl;
325};
326
327class ImageBacking : public ThreadSafeRefCounted<ImageBacking> {
328public:
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
345private:
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
358SPECIALIZE_TYPE_TRAITS_NICOSIA_PLATFORMLAYER(CompositionLayer, isCompositionLayer());
359SPECIALIZE_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