[WPE] Implement GStreamer based holepunch
[WebKit.git] / Source / WebCore / platform / graphics / texmap / TextureMapperLayer.cpp
1 /*
2  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Library General Public License for more details.
13
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB.  If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "TextureMapperLayer.h"
22
23 #include "FloatQuad.h"
24 #include "GraphicsLayerTextureMapper.h"
25 #include "Region.h"
26 #include <wtf/MathExtras.h>
27
28 namespace WebCore {
29
30 class TextureMapperPaintOptions {
31 public:
32     TextureMapperPaintOptions(TextureMapper& textureMapper)
33         : textureMapper(textureMapper)
34     { }
35
36     TextureMapper& textureMapper;
37     TransformationMatrix transform;
38     RefPtr<BitmapTexture> surface;
39     float opacity { 1 };
40     IntSize offset;
41 };
42
43 TextureMapperLayer::TextureMapperLayer() = default;
44
45 TextureMapperLayer::~TextureMapperLayer()
46 {
47     for (auto* child : m_children)
48         child->m_parent = nullptr;
49
50     removeFromParent();
51 }
52
53 void TextureMapperLayer::computeTransformsRecursive()
54 {
55     if (m_state.size.isEmpty() && m_state.masksToBounds)
56         return;
57
58     // Compute transforms recursively on the way down to leafs.
59     {
60         TransformationMatrix parentTransform;
61         if (m_parent)
62             parentTransform = m_parent->m_layerTransforms.combinedForChildren;
63         else if (m_effectTarget)
64             parentTransform = m_effectTarget->m_layerTransforms.combined;
65
66         const float originX = m_state.anchorPoint.x() * m_state.size.width();
67         const float originY = m_state.anchorPoint.y() * m_state.size.height();
68
69         m_layerTransforms.combined = parentTransform;
70         m_layerTransforms.combined
71             .translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z())
72             .multiply(m_layerTransforms.localTransform);
73
74         m_layerTransforms.combinedForChildren = m_layerTransforms.combined;
75         m_layerTransforms.combined.translate3d(-originX, -originY, -m_state.anchorPoint.z());
76
77         if (!m_state.preserves3D)
78             m_layerTransforms.combinedForChildren = m_layerTransforms.combinedForChildren.to2dTransform();
79         m_layerTransforms.combinedForChildren.multiply(m_state.childrenTransform);
80         m_layerTransforms.combinedForChildren.translate3d(-originX, -originY, -m_state.anchorPoint.z());
81     }
82
83     m_state.visible = m_state.backfaceVisibility || !m_layerTransforms.combined.isBackFaceVisible();
84
85     if (m_parent && m_parent->m_state.preserves3D)
86         m_centerZ = m_layerTransforms.combined.mapPoint(FloatPoint3D(m_state.size.width() / 2, m_state.size.height() / 2, 0)).z();
87
88     if (m_state.maskLayer)
89         m_state.maskLayer->computeTransformsRecursive();
90     if (m_state.replicaLayer)
91         m_state.replicaLayer->computeTransformsRecursive();
92     for (auto* child : m_children) {
93         ASSERT(child->m_parent == this);
94         child->computeTransformsRecursive();
95     }
96
97     // Reorder children if needed on the way back up.
98     if (m_state.preserves3D)
99         sortByZOrder(m_children);
100 }
101
102 void TextureMapperLayer::paint()
103 {
104     computeTransformsRecursive();
105
106     ASSERT(m_textureMapper);
107     TextureMapperPaintOptions options(*m_textureMapper);
108     options.textureMapper.bindSurface(0);
109
110     paintRecursive(options);
111 }
112
113 static Color blendWithOpacity(const Color& color, float opacity)
114 {
115     if (color.isOpaque() && opacity == 1.)
116         return color;
117
118     return color.colorWithAlphaMultipliedBy(opacity);
119 }
120
121 void TextureMapperLayer::paintSelf(const TextureMapperPaintOptions& options)
122 {
123     if (!m_state.visible || !m_state.contentsVisible)
124         return;
125
126     // We apply the following transform to compensate for painting into a surface, and then apply the offset so that the painting fits in the target rect.
127     TransformationMatrix transform;
128     transform.translate(options.offset.width(), options.offset.height());
129     transform.multiply(options.transform);
130     transform.multiply(m_layerTransforms.combined);
131
132     if (m_state.solidColor.isValid() && !m_state.contentsRect.isEmpty() && m_state.solidColor.isVisible()) {
133         options.textureMapper.drawSolidColor(m_state.contentsRect, transform, blendWithOpacity(m_state.solidColor, options.opacity), true);
134         if (m_state.showDebugBorders)
135             options.textureMapper.drawBorder(m_state.debugBorderColor, m_state.debugBorderWidth, layerRect(), transform);
136         return;
137     }
138
139     options.textureMapper.setWrapMode(TextureMapper::StretchWrap);
140     options.textureMapper.setPatternTransform(TransformationMatrix());
141
142     if (m_backingStore) {
143         FloatRect targetRect = layerRect();
144         ASSERT(!targetRect.isEmpty());
145         m_backingStore->paintToTextureMapper(options.textureMapper, targetRect, transform, options.opacity);
146         if (m_state.showDebugBorders)
147             m_backingStore->drawBorder(options.textureMapper, m_state.debugBorderColor, m_state.debugBorderWidth, targetRect, transform);
148         // Only draw repaint count for the main backing store.
149         if (m_state.showRepaintCounter)
150             m_backingStore->drawRepaintCounter(options.textureMapper, m_state.repaintCount, m_state.debugBorderColor, targetRect, transform);
151     }
152
153     if (!m_contentsLayer)
154         return;
155
156     if (!m_state.contentsTileSize.isEmpty()) {
157         options.textureMapper.setWrapMode(TextureMapper::RepeatWrap);
158
159         auto patternTransform = TransformationMatrix::rectToRect({ { }, m_state.contentsTileSize }, { { }, m_state.contentsRect.size() })
160             .translate(m_state.contentsTilePhase.width() / m_state.contentsRect.width(), m_state.contentsTilePhase.height() / m_state.contentsRect.height());
161         options.textureMapper.setPatternTransform(patternTransform);
162     }
163
164     ASSERT(!layerRect().isEmpty());
165     m_contentsLayer->paintToTextureMapper(options.textureMapper, m_state.contentsRect, transform, options.opacity);
166     if (m_state.showDebugBorders)
167         m_contentsLayer->drawBorder(options.textureMapper, m_state.debugBorderColor, m_state.debugBorderWidth, m_state.contentsRect, transform);
168 }
169
170 void TextureMapperLayer::sortByZOrder(Vector<TextureMapperLayer* >& array)
171 {
172     std::sort(array.begin(), array.end(),
173         [](TextureMapperLayer* a, TextureMapperLayer* b) {
174             return a->m_centerZ < b->m_centerZ;
175         });
176 }
177
178 void TextureMapperLayer::paintSelfAndChildren(const TextureMapperPaintOptions& options)
179 {
180     paintSelf(options);
181
182     if (m_children.isEmpty())
183         return;
184
185     bool shouldClip = m_state.masksToBounds && !m_state.preserves3D;
186     if (shouldClip) {
187         TransformationMatrix clipTransform;
188         clipTransform.translate(options.offset.width(), options.offset.height());
189         clipTransform.multiply(options.transform);
190         clipTransform.multiply(m_layerTransforms.combined);
191         options.textureMapper.beginClip(clipTransform, layerRect());
192
193         // If as a result of beginClip(), the clipping area is empty, it means that the intersection of the previous
194         // clipping area and the current one don't have any pixels in common. In this case we can skip painting the
195         // children as they will be clipped out (see https://bugs.webkit.org/show_bug.cgi?id=181080).
196         if (options.textureMapper.clipBounds().isEmpty()) {
197             options.textureMapper.endClip();
198             return;
199         }
200     }
201
202     for (auto* child : m_children)
203         child->paintRecursive(options);
204
205     if (shouldClip)
206         options.textureMapper.endClip();
207 }
208
209 bool TextureMapperLayer::shouldBlend() const
210 {
211     if (m_state.preserves3D)
212         return false;
213
214     return m_currentOpacity < 1
215         || hasFilters()
216         || m_state.maskLayer
217         || (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer);
218 }
219
220 bool TextureMapperLayer::isVisible() const
221 {
222     if (m_state.size.isEmpty() && (m_state.masksToBounds || m_state.maskLayer || m_children.isEmpty()))
223         return false;
224     if (!m_state.visible && m_children.isEmpty())
225         return false;
226     if (!m_state.contentsVisible && m_children.isEmpty())
227         return false;
228     if (m_currentOpacity < 0.01)
229         return false;
230     return true;
231 }
232
233 void TextureMapperLayer::paintSelfAndChildrenWithReplica(const TextureMapperPaintOptions& options)
234 {
235     if (m_state.replicaLayer) {
236         TextureMapperPaintOptions replicaOptions(options);
237         replicaOptions.transform
238             .multiply(m_state.replicaLayer->m_layerTransforms.combined)
239             .multiply(m_layerTransforms.combined.inverse().valueOr(TransformationMatrix()));
240         paintSelfAndChildren(replicaOptions);
241     }
242
243     paintSelfAndChildren(options);
244 }
245
246 TransformationMatrix TextureMapperLayer::replicaTransform()
247 {
248     return TransformationMatrix(m_state.replicaLayer->m_layerTransforms.combined)
249         .multiply(m_layerTransforms.combined.inverse().valueOr(TransformationMatrix()));
250 }
251
252 static void resolveOverlaps(Region& newRegion, Region& overlapRegion, Region& nonOverlapRegion)
253 {
254     Region newOverlapRegion(newRegion);
255     newOverlapRegion.intersect(nonOverlapRegion);
256     nonOverlapRegion.subtract(newOverlapRegion);
257     overlapRegion.unite(newOverlapRegion);
258     newRegion.subtract(overlapRegion);
259     nonOverlapRegion.unite(newRegion);
260 }
261
262 void TextureMapperLayer::computeOverlapRegions(Region& overlapRegion, Region& nonOverlapRegion, ResolveSelfOverlapMode mode)
263 {
264     if (!m_state.visible || !m_state.contentsVisible)
265         return;
266
267     FloatRect boundingRect;
268     if (m_backingStore || m_state.masksToBounds || m_state.maskLayer || hasFilters())
269         boundingRect = layerRect();
270     else if (m_contentsLayer || m_state.solidColor.isVisible())
271         boundingRect = m_state.contentsRect;
272
273     if (m_currentFilters.hasOutsets()) {
274         FilterOutsets outsets = m_currentFilters.outsets();
275         IntRect unfilteredTargetRect(boundingRect);
276         boundingRect.move(std::max(0, -outsets.left()), std::max(0, -outsets.top()));
277         boundingRect.expand(outsets.left() + outsets.right(), outsets.top() + outsets.bottom());
278         boundingRect.unite(unfilteredTargetRect);
279     }
280
281     TransformationMatrix replicaMatrix;
282     if (m_state.replicaLayer) {
283         replicaMatrix = replicaTransform();
284         boundingRect.unite(replicaMatrix.mapRect(boundingRect));
285     }
286
287     boundingRect = m_layerTransforms.combined.mapRect(boundingRect);
288
289     // Count all masks and filters as overlap layers.
290     if (hasFilters() || m_state.maskLayer || (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer)) {
291         Region newOverlapRegion(enclosingIntRect(boundingRect));
292         nonOverlapRegion.subtract(newOverlapRegion);
293         overlapRegion.unite(newOverlapRegion);
294         return;
295     }
296
297     Region newOverlapRegion;
298     Region newNonOverlapRegion(enclosingIntRect(boundingRect));
299
300     if (!m_state.masksToBounds) {
301         for (auto* child : m_children)
302             child->computeOverlapRegions(newOverlapRegion, newNonOverlapRegion, ResolveSelfOverlapIfNeeded);
303     }
304
305     if (m_state.replicaLayer) {
306         newOverlapRegion.unite(replicaMatrix.mapRect(newOverlapRegion.bounds()));
307         Region replicaRegion(replicaMatrix.mapRect(newNonOverlapRegion.bounds()));
308         resolveOverlaps(replicaRegion, newOverlapRegion, newNonOverlapRegion);
309     }
310
311     if ((mode != ResolveSelfOverlapAlways) && shouldBlend()) {
312         newNonOverlapRegion.unite(newOverlapRegion);
313         newOverlapRegion = Region();
314     }
315
316     overlapRegion.unite(newOverlapRegion);
317     resolveOverlaps(newNonOverlapRegion, overlapRegion, nonOverlapRegion);
318 }
319
320 void TextureMapperLayer::paintUsingOverlapRegions(const TextureMapperPaintOptions& options)
321 {
322     Region overlapRegion;
323     Region nonOverlapRegion;
324     computeOverlapRegions(overlapRegion, nonOverlapRegion, ResolveSelfOverlapAlways);
325     if (overlapRegion.isEmpty()) {
326         paintSelfAndChildrenWithReplica(options);
327         return;
328     }
329
330     // Having both overlap and non-overlap regions carries some overhead. Avoid it if the overlap area
331     // is big anyway.
332     if (overlapRegion.bounds().size().area() > nonOverlapRegion.bounds().size().area()) {
333         overlapRegion.unite(nonOverlapRegion);
334         nonOverlapRegion = Region();
335     }
336
337     nonOverlapRegion.translate(options.offset);
338     Vector<IntRect> rects = nonOverlapRegion.rects();
339
340     for (auto& rect : rects) {
341         if (!rect.intersects(options.textureMapper.clipBounds()))
342             continue;
343
344         options.textureMapper.beginClip(TransformationMatrix(), rect);
345         paintSelfAndChildrenWithReplica(options);
346         options.textureMapper.endClip();
347     }
348
349     rects = overlapRegion.rects();
350     static const size_t OverlapRegionConsolidationThreshold = 4;
351     if (nonOverlapRegion.isEmpty() && rects.size() > OverlapRegionConsolidationThreshold) {
352         rects.clear();
353         rects.append(overlapRegion.bounds());
354     }
355
356     IntSize maxTextureSize = options.textureMapper.maxTextureSize();
357     IntRect adjustedClipBounds(options.textureMapper.clipBounds());
358     adjustedClipBounds.move(-options.offset);
359     for (auto& rect : rects) {
360         for (int x = rect.x(); x < rect.maxX(); x += maxTextureSize.width()) {
361             for (int y = rect.y(); y < rect.maxY(); y += maxTextureSize.height()) {
362                 IntRect tileRect(IntPoint(x, y), maxTextureSize);
363                 tileRect.intersect(rect);
364                 if (!tileRect.intersects(adjustedClipBounds))
365                     continue;
366
367                 paintWithIntermediateSurface(options, tileRect);
368             }
369         }
370     }
371 }
372
373 void TextureMapperLayer::applyMask(const TextureMapperPaintOptions& options)
374 {
375     options.textureMapper.setMaskMode(true);
376     paintSelf(options);
377     options.textureMapper.setMaskMode(false);
378 }
379
380 RefPtr<BitmapTexture> TextureMapperLayer::paintIntoSurface(const TextureMapperPaintOptions& options, const IntSize& size)
381 {
382     RefPtr<BitmapTexture> surface = options.textureMapper.acquireTextureFromPool(size, BitmapTexture::SupportsAlpha);
383     TextureMapperPaintOptions paintOptions(options);
384     paintOptions.surface = surface;
385     options.textureMapper.bindSurface(surface.get());
386     paintSelfAndChildren(paintOptions);
387     if (m_state.maskLayer)
388         m_state.maskLayer->applyMask(options);
389     surface = surface->applyFilters(options.textureMapper, m_currentFilters);
390     options.textureMapper.bindSurface(surface.get());
391     return surface;
392 }
393
394 static void commitSurface(const TextureMapperPaintOptions& options, BitmapTexture& surface, const IntRect& rect, float opacity)
395 {
396     options.textureMapper.bindSurface(options.surface.get());
397     TransformationMatrix targetTransform;
398     targetTransform.translate(options.offset.width(), options.offset.height());
399     targetTransform.multiply(options.transform);
400     options.textureMapper.drawTexture(surface, rect, targetTransform, opacity);
401 }
402
403 void TextureMapperLayer::paintWithIntermediateSurface(const TextureMapperPaintOptions& options, const IntRect& rect)
404 {
405     RefPtr<BitmapTexture> replicaSurface;
406     RefPtr<BitmapTexture> mainSurface;
407     TextureMapperPaintOptions paintOptions(options);
408     paintOptions.offset = -IntSize(rect.x(), rect.y());
409     paintOptions.opacity = 1;
410     paintOptions.transform = TransformationMatrix();
411     if (m_state.replicaLayer) {
412         paintOptions.transform = replicaTransform();
413         replicaSurface = paintIntoSurface(paintOptions, rect.size());
414         paintOptions.transform = TransformationMatrix();
415         if (m_state.replicaLayer->m_state.maskLayer)
416             m_state.replicaLayer->m_state.maskLayer->applyMask(paintOptions);
417     }
418
419     if (replicaSurface && options.opacity == 1) {
420         commitSurface(options, *replicaSurface, rect, 1);
421         replicaSurface = nullptr;
422     }
423
424     mainSurface = paintIntoSurface(paintOptions, rect.size());
425     if (replicaSurface) {
426         options.textureMapper.bindSurface(replicaSurface.get());
427         options.textureMapper.drawTexture(*mainSurface.get(), FloatRect(FloatPoint::zero(), rect.size()));
428         mainSurface = replicaSurface;
429     }
430
431     commitSurface(options, *mainSurface, rect, options.opacity);
432 }
433
434 void TextureMapperLayer::paintRecursive(const TextureMapperPaintOptions& options)
435 {
436     if (!isVisible())
437         return;
438
439     TextureMapperPaintOptions paintOptions(options);
440     paintOptions.opacity *= m_currentOpacity;
441
442     if (!shouldBlend()) {
443         paintSelfAndChildrenWithReplica(paintOptions);
444         return;
445     }
446
447     paintUsingOverlapRegions(paintOptions);
448 }
449
450 #if !USE(COORDINATED_GRAPHICS)
451 void TextureMapperLayer::setChildren(const Vector<GraphicsLayer*>& newChildren)
452 {
453     removeAllChildren();
454     for (auto* child : newChildren)
455         addChild(&downcast<GraphicsLayerTextureMapper>(child)->layer());
456 }
457 #endif
458
459 void TextureMapperLayer::setChildren(const Vector<TextureMapperLayer*>& newChildren)
460 {
461     removeAllChildren();
462     for (auto* child : newChildren)
463         addChild(child);
464 }
465
466 void TextureMapperLayer::addChild(TextureMapperLayer* childLayer)
467 {
468     ASSERT(childLayer != this);
469
470     if (childLayer->m_parent)
471         childLayer->removeFromParent();
472
473     childLayer->m_parent = this;
474     m_children.append(childLayer);
475 }
476
477 void TextureMapperLayer::removeFromParent()
478 {
479     if (m_parent) {
480         size_t index = m_parent->m_children.find(this);
481         ASSERT(index != notFound);
482         m_parent->m_children.remove(index);
483     }
484
485     m_parent = nullptr;
486 }
487
488 void TextureMapperLayer::removeAllChildren()
489 {
490     auto oldChildren = WTFMove(m_children);
491     for (auto* child : oldChildren)
492         child->m_parent = nullptr;
493 }
494
495 void TextureMapperLayer::setMaskLayer(TextureMapperLayer* maskLayer)
496 {
497     if (maskLayer) {
498         maskLayer->m_effectTarget = makeWeakPtr(*this);
499         m_state.maskLayer = makeWeakPtr(*maskLayer);
500     } else
501         m_state.maskLayer = nullptr;
502 }
503
504 void TextureMapperLayer::setReplicaLayer(TextureMapperLayer* replicaLayer)
505 {
506     if (replicaLayer) {
507         replicaLayer->m_effectTarget = makeWeakPtr(*this);
508         m_state.replicaLayer = makeWeakPtr(*replicaLayer);
509     } else
510         m_state.replicaLayer = nullptr;
511 }
512
513 void TextureMapperLayer::setPosition(const FloatPoint& position)
514 {
515     m_state.pos = position;
516 }
517
518 void TextureMapperLayer::setSize(const FloatSize& size)
519 {
520     m_state.size = size;
521 }
522
523 void TextureMapperLayer::setAnchorPoint(const FloatPoint3D& anchorPoint)
524 {
525     m_state.anchorPoint = anchorPoint;
526 }
527
528 void TextureMapperLayer::setPreserves3D(bool preserves3D)
529 {
530     m_state.preserves3D = preserves3D;
531 }
532
533 void TextureMapperLayer::setTransform(const TransformationMatrix& transform)
534 {
535     m_state.transform = transform;
536 }
537
538 void TextureMapperLayer::setChildrenTransform(const TransformationMatrix& childrenTransform)
539 {
540     m_state.childrenTransform = childrenTransform;
541 }
542
543 void TextureMapperLayer::setContentsRect(const FloatRect& contentsRect)
544 {
545     m_state.contentsRect = contentsRect;
546 }
547
548 void TextureMapperLayer::setContentsTileSize(const FloatSize& size)
549 {
550     m_state.contentsTileSize = size;
551 }
552
553 void TextureMapperLayer::setContentsTilePhase(const FloatSize& phase)
554 {
555     m_state.contentsTilePhase = phase;
556 }
557
558 void TextureMapperLayer::setMasksToBounds(bool masksToBounds)
559 {
560     m_state.masksToBounds = masksToBounds;
561 }
562
563 void TextureMapperLayer::setDrawsContent(bool drawsContent)
564 {
565     m_state.drawsContent = drawsContent;
566 }
567
568 void TextureMapperLayer::setContentsVisible(bool contentsVisible)
569 {
570     m_state.contentsVisible = contentsVisible;
571 }
572
573 void TextureMapperLayer::setContentsOpaque(bool contentsOpaque)
574 {
575     m_state.contentsOpaque = contentsOpaque;
576 }
577
578 void TextureMapperLayer::setBackfaceVisibility(bool backfaceVisibility)
579 {
580     m_state.backfaceVisibility = backfaceVisibility;
581 }
582
583 void TextureMapperLayer::setOpacity(float opacity)
584 {
585     m_state.opacity = opacity;
586 }
587
588 void TextureMapperLayer::setSolidColor(const Color& color)
589 {
590     m_state.solidColor = color;
591 }
592
593 void TextureMapperLayer::setFilters(const FilterOperations& filters)
594 {
595     m_state.filters = filters;
596 }
597
598 void TextureMapperLayer::setDebugVisuals(bool showDebugBorders, const Color& debugBorderColor, float debugBorderWidth)
599 {
600     m_state.showDebugBorders = showDebugBorders;
601     m_state.debugBorderColor = debugBorderColor;
602     m_state.debugBorderWidth = debugBorderWidth;
603 }
604
605 void TextureMapperLayer::setRepaintCounter(bool showRepaintCounter, int repaintCount)
606 {
607     m_state.showRepaintCounter = showRepaintCounter;
608     m_state.repaintCount = repaintCount;
609 }
610
611 void TextureMapperLayer::setContentsLayer(TextureMapperPlatformLayer* platformLayer)
612 {
613     m_contentsLayer = platformLayer;
614 }
615
616 void TextureMapperLayer::setAnimations(const TextureMapperAnimations& animations)
617 {
618     m_animations = animations;
619 }
620
621 void TextureMapperLayer::setBackingStore(TextureMapperBackingStore* backingStore)
622 {
623     m_backingStore = backingStore;
624 }
625
626 bool TextureMapperLayer::descendantsOrSelfHaveRunningAnimations() const
627 {
628     if (m_animations.hasRunningAnimations())
629         return true;
630
631     return std::any_of(m_children.begin(), m_children.end(),
632         [](TextureMapperLayer* child) {
633             return child->descendantsOrSelfHaveRunningAnimations();
634         });
635 }
636
637 bool TextureMapperLayer::applyAnimationsRecursively(MonotonicTime time)
638 {
639     bool hasRunningAnimations = syncAnimations(time);
640     for (auto* child : m_children)
641         hasRunningAnimations |= child->applyAnimationsRecursively(time);
642     return hasRunningAnimations;
643 }
644
645 bool TextureMapperLayer::syncAnimations(MonotonicTime time)
646 {
647     TextureMapperAnimation::ApplicationResult applicationResults;
648     m_animations.apply(applicationResults, time);
649
650     m_layerTransforms.localTransform = applicationResults.transform.valueOr(m_state.transform);
651     m_currentOpacity = applicationResults.opacity.valueOr(m_state.opacity);
652     m_currentFilters = applicationResults.filters.valueOr(m_state.filters);
653
654     return applicationResults.hasRunningAnimations;
655 }
656
657 }