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
28namespace WebCore {
29
30class TextureMapperPaintOptions {
31public:
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
43TextureMapperLayer::TextureMapperLayer() = default;
44
45TextureMapperLayer::~TextureMapperLayer()
46{
47 for (auto* child : m_children)
48 child->m_parent = nullptr;
49
50 removeFromParent();
51}
52
53void 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
102void 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
113static 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
121void 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
170void 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
178void 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
209bool 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
220bool 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
233void 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
246TransformationMatrix TextureMapperLayer::replicaTransform()
247{
248 return TransformationMatrix(m_state.replicaLayer->m_layerTransforms.combined)
249 .multiply(m_layerTransforms.combined.inverse().valueOr(TransformationMatrix()));
250}
251
252static 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
262void 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
320void 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 auto 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
373void TextureMapperLayer::applyMask(const TextureMapperPaintOptions& options)
374{
375 options.textureMapper.setMaskMode(true);
376 paintSelf(options);
377 options.textureMapper.setMaskMode(false);
378}
379
380RefPtr<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
394static 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
403void 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
434void 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)
451void TextureMapperLayer::setChildren(const Vector<GraphicsLayer*>& newChildren)
452{
453 removeAllChildren();
454 for (auto* child : newChildren)
455 addChild(&downcast<GraphicsLayerTextureMapper>(child)->layer());
456}
457#endif
458
459void TextureMapperLayer::setChildren(const Vector<TextureMapperLayer*>& newChildren)
460{
461 removeAllChildren();
462 for (auto* child : newChildren)
463 addChild(child);
464}
465
466void 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
477void 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
488void TextureMapperLayer::removeAllChildren()
489{
490 auto oldChildren = WTFMove(m_children);
491 for (auto* child : oldChildren)
492 child->m_parent = nullptr;
493}
494
495void 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
504void 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
513void TextureMapperLayer::setPosition(const FloatPoint& position)
514{
515 m_state.pos = position;
516}
517
518void TextureMapperLayer::setSize(const FloatSize& size)
519{
520 m_state.size = size;
521}
522
523void TextureMapperLayer::setAnchorPoint(const FloatPoint3D& anchorPoint)
524{
525 m_state.anchorPoint = anchorPoint;
526}
527
528void TextureMapperLayer::setPreserves3D(bool preserves3D)
529{
530 m_state.preserves3D = preserves3D;
531}
532
533void TextureMapperLayer::setTransform(const TransformationMatrix& transform)
534{
535 m_state.transform = transform;
536}
537
538void TextureMapperLayer::setChildrenTransform(const TransformationMatrix& childrenTransform)
539{
540 m_state.childrenTransform = childrenTransform;
541}
542
543void TextureMapperLayer::setContentsRect(const FloatRect& contentsRect)
544{
545 m_state.contentsRect = contentsRect;
546}
547
548void TextureMapperLayer::setContentsTileSize(const FloatSize& size)
549{
550 m_state.contentsTileSize = size;
551}
552
553void TextureMapperLayer::setContentsTilePhase(const FloatSize& phase)
554{
555 m_state.contentsTilePhase = phase;
556}
557
558void TextureMapperLayer::setMasksToBounds(bool masksToBounds)
559{
560 m_state.masksToBounds = masksToBounds;
561}
562
563void TextureMapperLayer::setDrawsContent(bool drawsContent)
564{
565 m_state.drawsContent = drawsContent;
566}
567
568void TextureMapperLayer::setContentsVisible(bool contentsVisible)
569{
570 m_state.contentsVisible = contentsVisible;
571}
572
573void TextureMapperLayer::setContentsOpaque(bool contentsOpaque)
574{
575 m_state.contentsOpaque = contentsOpaque;
576}
577
578void TextureMapperLayer::setBackfaceVisibility(bool backfaceVisibility)
579{
580 m_state.backfaceVisibility = backfaceVisibility;
581}
582
583void TextureMapperLayer::setOpacity(float opacity)
584{
585 m_state.opacity = opacity;
586}
587
588void TextureMapperLayer::setSolidColor(const Color& color)
589{
590 m_state.solidColor = color;
591}
592
593void TextureMapperLayer::setFilters(const FilterOperations& filters)
594{
595 m_state.filters = filters;
596}
597
598void 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
605void TextureMapperLayer::setRepaintCounter(bool showRepaintCounter, int repaintCount)
606{
607 m_state.showRepaintCounter = showRepaintCounter;
608 m_state.repaintCount = repaintCount;
609}
610
611void TextureMapperLayer::setContentsLayer(TextureMapperPlatformLayer* platformLayer)
612{
613 m_contentsLayer = platformLayer;
614}
615
616void TextureMapperLayer::setAnimations(const TextureMapperAnimations& animations)
617{
618 m_animations = animations;
619}
620
621void TextureMapperLayer::setBackingStore(TextureMapperBackingStore* backingStore)
622{
623 m_backingStore = backingStore;
624}
625
626bool 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
637bool 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
645bool 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}
658