2 Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3 Copyright (C) 2010 Apple Inc. All rights reserved.
4 Copyright (C) 2012 Company 100, Inc.
5 Copyright (C) 2012 Intel Corporation. All rights reserved.
6 Copyright (C) 2017 Sony Interactive Entertainment Inc.
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
25 #include "CoordinatedGraphicsLayer.h"
27 #if USE(COORDINATED_GRAPHICS)
29 #include "FloatQuad.h"
30 #include "GraphicsContext.h"
31 #include "GraphicsLayer.h"
32 #include "GraphicsLayerFactory.h"
33 #include "NicosiaBackingStoreTextureMapperImpl.h"
34 #include "NicosiaCompositionLayerTextureMapperImpl.h"
35 #include "NicosiaContentLayerTextureMapperImpl.h"
36 #include "NicosiaImageBackingTextureMapperImpl.h"
37 #include "NicosiaPaintingContext.h"
38 #include "NicosiaPaintingEngine.h"
39 #include "ScrollableArea.h"
40 #include "TextureMapperPlatformLayerProxyProvider.h"
41 #include "TiledBackingStore.h"
43 #include <wtf/SetForScope.h>
45 #include <wtf/text/CString.h>
49 Ref<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, GraphicsLayerClient& client, Type layerType)
52 return adoptRef(*new CoordinatedGraphicsLayer(layerType, client));
54 return factory->createGraphicsLayer(layerType, client);
57 void CoordinatedGraphicsLayer::notifyFlushRequired()
62 if (m_coordinator->isFlushingLayerChanges())
65 client().notifyFlushRequired(this);
68 void CoordinatedGraphicsLayer::didChangeAnimations()
70 m_nicosia.delta.animationsChanged = true;
71 notifyFlushRequired();
74 void CoordinatedGraphicsLayer::didChangeChildren()
76 m_nicosia.delta.childrenChanged = true;
77 notifyFlushRequired();
80 void CoordinatedGraphicsLayer::didChangeFilters()
82 m_nicosia.delta.filtersChanged = true;
83 notifyFlushRequired();
86 void CoordinatedGraphicsLayer::didUpdateTileBuffers()
88 if (!isShowingRepaintCounter())
91 auto repaintCount = incrementRepaintCount();
92 m_nicosia.repaintCounter.count = repaintCount;
93 m_nicosia.delta.repaintCounterChanged = true;
96 void CoordinatedGraphicsLayer::setShouldUpdateVisibleRect()
98 m_shouldUpdateVisibleRect = true;
99 for (auto& child : children())
100 downcast<CoordinatedGraphicsLayer>(child.get()).setShouldUpdateVisibleRect();
102 downcast<CoordinatedGraphicsLayer>(*replicaLayer()).setShouldUpdateVisibleRect();
105 void CoordinatedGraphicsLayer::didChangeGeometry()
107 notifyFlushRequired();
108 setShouldUpdateVisibleRect();
111 CoordinatedGraphicsLayer::CoordinatedGraphicsLayer(Type layerType, GraphicsLayerClient& client)
112 : GraphicsLayer(layerType, client)
116 , m_shouldUpdateVisibleRect(true)
117 , m_movingVisibleRect(false)
118 , m_pendingContentsScaleAdjustment(false)
119 , m_pendingVisibleRectAdjustment(false)
120 , m_shouldUpdatePlatformLayer(false)
122 , m_compositedNativeImagePtr(0)
123 , m_animationStartedTimer(*this, &CoordinatedGraphicsLayer::animationStartedTimerFired)
125 static Nicosia::PlatformLayer::LayerID nextLayerID = 1;
126 m_id = nextLayerID++;
128 m_nicosia.layer = Nicosia::CompositionLayer::create(m_id,
129 Nicosia::CompositionLayerTextureMapperImpl::createFactory());
131 // Enforce a complete flush on the first occasion.
132 m_nicosia.delta.value = UINT_MAX;
135 CoordinatedGraphicsLayer::~CoordinatedGraphicsLayer()
138 purgeBackingStores();
139 m_coordinator->detachLayer(this);
141 ASSERT(!m_nicosia.imageBacking);
142 ASSERT(!m_nicosia.backingStore);
146 bool CoordinatedGraphicsLayer::isCoordinatedGraphicsLayer() const
151 Nicosia::PlatformLayer::LayerID CoordinatedGraphicsLayer::id() const
156 auto CoordinatedGraphicsLayer::primaryLayerID() const -> PlatformLayerID
161 bool CoordinatedGraphicsLayer::setChildren(Vector<Ref<GraphicsLayer>>&& children)
163 bool ok = GraphicsLayer::setChildren(WTFMove(children));
170 void CoordinatedGraphicsLayer::addChild(Ref<GraphicsLayer>&& layer)
172 GraphicsLayer* rawLayer = layer.ptr();
173 GraphicsLayer::addChild(WTFMove(layer));
174 downcast<CoordinatedGraphicsLayer>(*rawLayer).setCoordinatorIncludingSubLayersIfNeeded(m_coordinator);
178 void CoordinatedGraphicsLayer::addChildAtIndex(Ref<GraphicsLayer>&& layer, int index)
180 GraphicsLayer* rawLayer = layer.ptr();
181 GraphicsLayer::addChildAtIndex(WTFMove(layer), index);
182 downcast<CoordinatedGraphicsLayer>(*rawLayer).setCoordinatorIncludingSubLayersIfNeeded(m_coordinator);
186 void CoordinatedGraphicsLayer::addChildAbove(Ref<GraphicsLayer>&& layer, GraphicsLayer* sibling)
188 GraphicsLayer* rawLayer = layer.ptr();
189 GraphicsLayer::addChildAbove(WTFMove(layer), sibling);
190 downcast<CoordinatedGraphicsLayer>(*rawLayer).setCoordinatorIncludingSubLayersIfNeeded(m_coordinator);
194 void CoordinatedGraphicsLayer::addChildBelow(Ref<GraphicsLayer>&& layer, GraphicsLayer* sibling)
196 GraphicsLayer* rawLayer = layer.ptr();
197 GraphicsLayer::addChildBelow(WTFMove(layer), sibling);
198 downcast<CoordinatedGraphicsLayer>(*rawLayer).setCoordinatorIncludingSubLayersIfNeeded(m_coordinator);
202 bool CoordinatedGraphicsLayer::replaceChild(GraphicsLayer* oldChild, Ref<GraphicsLayer>&& newChild)
204 GraphicsLayer* rawLayer = newChild.ptr();
205 bool ok = GraphicsLayer::replaceChild(oldChild, WTFMove(newChild));
208 downcast<CoordinatedGraphicsLayer>(*rawLayer).setCoordinatorIncludingSubLayersIfNeeded(m_coordinator);
213 void CoordinatedGraphicsLayer::removeFromParent()
215 if (CoordinatedGraphicsLayer* parentLayer = downcast<CoordinatedGraphicsLayer>(parent()))
216 parentLayer->didChangeChildren();
217 GraphicsLayer::removeFromParent();
220 void CoordinatedGraphicsLayer::setPosition(const FloatPoint& p)
225 GraphicsLayer::setPosition(p);
226 m_nicosia.delta.positionChanged = true;
230 void CoordinatedGraphicsLayer::setAnchorPoint(const FloatPoint3D& p)
232 if (anchorPoint() == p)
235 GraphicsLayer::setAnchorPoint(p);
236 m_nicosia.delta.anchorPointChanged = true;
240 void CoordinatedGraphicsLayer::setSize(const FloatSize& size)
242 if (this->size() == size)
245 GraphicsLayer::setSize(size);
246 m_nicosia.delta.sizeChanged = true;
249 maskLayer()->setSize(size);
253 void CoordinatedGraphicsLayer::setTransform(const TransformationMatrix& t)
255 if (transform() == t)
258 GraphicsLayer::setTransform(t);
259 m_nicosia.delta.transformChanged = true;
264 void CoordinatedGraphicsLayer::setChildrenTransform(const TransformationMatrix& t)
266 if (childrenTransform() == t)
269 GraphicsLayer::setChildrenTransform(t);
270 m_nicosia.delta.childrenTransformChanged = true;
275 void CoordinatedGraphicsLayer::setPreserves3D(bool b)
277 if (preserves3D() == b)
280 GraphicsLayer::setPreserves3D(b);
281 m_nicosia.delta.flagsChanged = true;
286 void CoordinatedGraphicsLayer::setMasksToBounds(bool b)
288 if (masksToBounds() == b)
290 GraphicsLayer::setMasksToBounds(b);
291 m_nicosia.delta.flagsChanged = true;
296 void CoordinatedGraphicsLayer::setDrawsContent(bool b)
298 if (drawsContent() == b)
300 GraphicsLayer::setDrawsContent(b);
301 m_nicosia.delta.flagsChanged = true;
303 notifyFlushRequired();
306 void CoordinatedGraphicsLayer::setContentsVisible(bool b)
308 if (contentsAreVisible() == b)
310 GraphicsLayer::setContentsVisible(b);
311 m_nicosia.delta.flagsChanged = true;
314 maskLayer()->setContentsVisible(b);
316 notifyFlushRequired();
319 void CoordinatedGraphicsLayer::setContentsOpaque(bool b)
321 if (contentsOpaque() == b)
324 GraphicsLayer::setContentsOpaque(b);
325 m_nicosia.delta.flagsChanged = true;
327 // Demand a repaint of the whole layer.
328 if (!m_needsDisplay.completeLayer) {
329 m_needsDisplay.completeLayer = true;
330 m_needsDisplay.rects.clear();
332 addRepaintRect({ { }, m_size });
335 notifyFlushRequired();
338 void CoordinatedGraphicsLayer::setBackfaceVisibility(bool b)
340 if (backfaceVisibility() == b)
343 GraphicsLayer::setBackfaceVisibility(b);
344 m_nicosia.delta.flagsChanged = true;
346 notifyFlushRequired();
349 void CoordinatedGraphicsLayer::setOpacity(float opacity)
351 if (this->opacity() == opacity)
354 GraphicsLayer::setOpacity(opacity);
355 m_nicosia.delta.opacityChanged = true;
357 notifyFlushRequired();
360 void CoordinatedGraphicsLayer::setContentsRect(const FloatRect& r)
362 if (contentsRect() == r)
365 GraphicsLayer::setContentsRect(r);
366 m_nicosia.delta.contentsRectChanged = true;
368 notifyFlushRequired();
371 void CoordinatedGraphicsLayer::setContentsTileSize(const FloatSize& s)
373 if (contentsTileSize() == s)
376 GraphicsLayer::setContentsTileSize(s);
377 m_nicosia.delta.contentsTilingChanged = true;
378 notifyFlushRequired();
381 void CoordinatedGraphicsLayer::setContentsTilePhase(const FloatSize& p)
383 if (contentsTilePhase() == p)
386 GraphicsLayer::setContentsTilePhase(p);
387 m_nicosia.delta.contentsTilingChanged = true;
388 notifyFlushRequired();
391 bool GraphicsLayer::supportsContentsTiling()
396 void CoordinatedGraphicsLayer::setContentsNeedsDisplay()
398 #if USE(COORDINATED_GRAPHICS_THREADED) && USE(NICOSIA)
399 if (m_nicosia.contentLayer)
400 m_shouldUpdatePlatformLayer = true;
403 notifyFlushRequired();
404 addRepaintRect(contentsRect());
407 void CoordinatedGraphicsLayer::setContentsToPlatformLayer(PlatformLayer* platformLayer, ContentsLayerPurpose)
409 #if USE(COORDINATED_GRAPHICS_THREADED) && USE(NICOSIA)
410 auto* contentLayer = downcast<Nicosia::ContentLayer>(platformLayer);
411 if (m_nicosia.contentLayer != contentLayer) {
412 m_nicosia.contentLayer = contentLayer;
413 m_nicosia.delta.contentLayerChanged = true;
415 notifyFlushRequired();
417 UNUSED_PARAM(platformLayer);
421 bool CoordinatedGraphicsLayer::filtersCanBeComposited(const FilterOperations& filters) const
426 for (const auto& filterOperation : filters.operations()) {
427 if (filterOperation->type() == FilterOperation::REFERENCE)
434 bool CoordinatedGraphicsLayer::setFilters(const FilterOperations& newFilters)
436 bool canCompositeFilters = filtersCanBeComposited(newFilters);
437 if (filters() == newFilters)
438 return canCompositeFilters;
440 if (canCompositeFilters) {
441 if (!GraphicsLayer::setFilters(newFilters))
444 } else if (filters().size()) {
449 return canCompositeFilters;
452 void CoordinatedGraphicsLayer::setContentsToSolidColor(const Color& color)
454 if (m_solidColor == color)
457 m_solidColor = color;
458 m_nicosia.delta.solidColorChanged = true;
460 notifyFlushRequired();
463 void CoordinatedGraphicsLayer::setShowDebugBorder(bool show)
465 if (isShowingDebugBorder() == show)
468 GraphicsLayer::setShowDebugBorder(show);
469 m_nicosia.debugBorder.visible = show;
470 m_nicosia.delta.debugBorderChanged = true;
472 if (m_nicosia.debugBorder.visible)
473 updateDebugIndicators();
475 notifyFlushRequired();
478 void CoordinatedGraphicsLayer::setShowRepaintCounter(bool show)
480 if (isShowingRepaintCounter() == show)
483 GraphicsLayer::setShowRepaintCounter(show);
484 m_nicosia.repaintCounter.visible = show;
485 m_nicosia.delta.repaintCounterChanged = true;
487 notifyFlushRequired();
490 void CoordinatedGraphicsLayer::setContentsToImage(Image* image)
492 NativeImagePtr nativeImagePtr = image ? image->nativeImageForCurrentFrame() : nullptr;
493 if (m_compositedImage == image && m_compositedNativeImagePtr == nativeImagePtr)
496 m_compositedImage = image;
497 m_compositedNativeImagePtr = nativeImagePtr;
499 GraphicsLayer::setContentsToImage(image);
500 notifyFlushRequired();
503 void CoordinatedGraphicsLayer::setMaskLayer(RefPtr<GraphicsLayer>&& layer)
505 if (layer == maskLayer())
508 GraphicsLayer* rawLayer = layer.get();
509 GraphicsLayer::setMaskLayer(WTFMove(layer));
514 rawLayer->setSize(size());
515 rawLayer->setContentsVisible(contentsAreVisible());
517 m_nicosia.delta.maskChanged = true;
519 notifyFlushRequired();
522 bool CoordinatedGraphicsLayer::shouldDirectlyCompositeImage(Image* image) const
524 if (!image || !image->isBitmapImage())
527 enum { MaxDimenstionForDirectCompositing = 2000 };
528 if (image->width() > MaxDimenstionForDirectCompositing || image->height() > MaxDimenstionForDirectCompositing)
534 void CoordinatedGraphicsLayer::setReplicatedByLayer(RefPtr<GraphicsLayer>&& layer)
536 if (layer == replicaLayer())
539 GraphicsLayer::setReplicatedByLayer(WTFMove(layer));
540 m_nicosia.delta.replicaChanged = true;
541 notifyFlushRequired();
544 void CoordinatedGraphicsLayer::setNeedsDisplay()
546 if (!drawsContent() || !contentsAreVisible() || m_size.isEmpty() || m_needsDisplay.completeLayer)
549 m_needsDisplay.completeLayer = true;
550 m_needsDisplay.rects.clear();
552 notifyFlushRequired();
553 addRepaintRect({ { }, m_size });
556 void CoordinatedGraphicsLayer::setNeedsDisplayInRect(const FloatRect& initialRect, ShouldClipToLayer shouldClip)
558 if (!drawsContent() || !contentsAreVisible() || m_size.isEmpty() || m_needsDisplay.completeLayer)
561 auto rect = initialRect;
562 if (shouldClip == ClipToLayer)
563 rect.intersect({ { }, m_size });
568 auto& rects = m_needsDisplay.rects;
569 bool alreadyRecorded = std::any_of(rects.begin(), rects.end(),
570 [&](auto& dirtyRect) { return dirtyRect.contains(rect); });
574 if (rects.size() < 32)
577 rects[0].unite(rect);
579 notifyFlushRequired();
580 addRepaintRect(rect);
583 void CoordinatedGraphicsLayer::flushCompositingState(const FloatRect& rect)
585 if (CoordinatedGraphicsLayer* mask = downcast<CoordinatedGraphicsLayer>(maskLayer()))
586 mask->flushCompositingStateForThisLayerOnly();
588 if (CoordinatedGraphicsLayer* replica = downcast<CoordinatedGraphicsLayer>(replicaLayer()))
589 replica->flushCompositingStateForThisLayerOnly();
591 flushCompositingStateForThisLayerOnly();
593 for (auto& child : children())
594 child->flushCompositingState(rect);
597 void CoordinatedGraphicsLayer::setDebugBorder(const Color& color, float width)
599 ASSERT(m_nicosia.debugBorder.visible);
600 if (m_nicosia.debugBorder.color != color) {
601 m_nicosia.debugBorder.color = color;
602 m_nicosia.delta.debugBorderChanged = true;
605 if (m_nicosia.debugBorder.width != width) {
606 m_nicosia.debugBorder.width = width;
607 m_nicosia.delta.debugBorderChanged = true;
611 void CoordinatedGraphicsLayer::updatePlatformLayer()
613 if (!m_shouldUpdatePlatformLayer)
616 m_shouldUpdatePlatformLayer = false;
617 #if USE(COORDINATED_GRAPHICS_THREADED) && USE(NICOSIA)
618 if (m_nicosia.contentLayer)
619 downcast<Nicosia::ContentLayerTextureMapperImpl>(m_nicosia.contentLayer->impl()).swapBuffersIfNeeded();
623 void CoordinatedGraphicsLayer::flushCompositingStateForThisLayerOnly()
625 // When we have a transform animation, we need to update visible rect every frame to adjust the visible rect of a backing store.
626 bool hasActiveTransformAnimation = selfOrAncestorHasActiveTransformAnimation();
627 if (hasActiveTransformAnimation)
628 m_movingVisibleRect = true;
631 computePixelAlignment(m_adjustedPosition, m_adjustedSize, m_adjustedAnchorPoint, m_pixelAlignmentOffset);
633 computeTransformedVisibleRect();
634 updatePlatformLayer();
636 // Only unset m_movingVisibleRect after we have updated the visible rect after the animation stopped.
637 if (!hasActiveTransformAnimation)
638 m_movingVisibleRect = false;
640 // Determine the backing store presence. Content is painted later, in the updateContentBuffers() traversal.
641 if (shouldHaveBackingStore()) {
642 if (!m_nicosia.backingStore) {
643 m_nicosia.backingStore = Nicosia::BackingStore::create(Nicosia::BackingStoreTextureMapperImpl::createFactory());
644 m_nicosia.delta.backingStoreChanged = true;
646 } else if (m_nicosia.backingStore) {
647 auto& layerState = downcast<Nicosia::BackingStoreTextureMapperImpl>(m_nicosia.backingStore->impl()).layerState();
648 layerState.isPurging = true;
649 layerState.mainBackingStore = nullptr;
650 layerState.previousBackingStore = nullptr;
652 m_nicosia.backingStore = nullptr;
653 m_nicosia.delta.backingStoreChanged = true;
656 // Determine image backing presence according to the composited image source.
657 if (m_compositedNativeImagePtr) {
658 ASSERT(m_compositedImage);
659 auto& image = *m_compositedImage;
660 uintptr_t imageID = reinterpret_cast<uintptr_t>(&image);
661 uintptr_t nativeImageID = reinterpret_cast<uintptr_t>(m_compositedNativeImagePtr.get());
663 // Respawn the ImageBacking object if the underlying image changed.
664 if (m_nicosia.imageBacking) {
665 auto& impl = downcast<Nicosia::ImageBackingTextureMapperImpl>(m_nicosia.imageBacking->impl());
666 if (impl.layerState().imageID != imageID) {
667 impl.layerState().update = Nicosia::ImageBackingTextureMapperImpl::Update { };
668 m_nicosia.imageBacking = nullptr;
671 if (!m_nicosia.imageBacking) {
672 m_nicosia.imageBacking = Nicosia::ImageBacking::create(Nicosia::ImageBackingTextureMapperImpl::createFactory());
673 m_nicosia.delta.imageBackingChanged = true;
676 // Update the image contents only when the image layer is visible and the native image changed.
677 auto& impl = downcast<Nicosia::ImageBackingTextureMapperImpl>(m_nicosia.imageBacking->impl());
678 auto& layerState = impl.layerState();
679 layerState.imageID = imageID;
680 layerState.update.isVisible = transformedVisibleRect().intersects(IntRect(contentsRect()));
681 if (layerState.update.isVisible && layerState.nativeImageID != nativeImageID) {
682 auto buffer = Nicosia::Buffer::create(IntSize(image.size()),
683 !image.currentFrameKnownToBeOpaque() ? Nicosia::Buffer::SupportsAlpha : Nicosia::Buffer::NoFlags);
684 Nicosia::PaintingContext::paint(buffer,
685 [&image](GraphicsContext& context)
687 IntRect rect { { }, IntSize { image.size() } };
688 context.drawImage(image, rect, rect, ImagePaintingOptions(CompositeCopy));
690 layerState.nativeImageID = nativeImageID;
691 layerState.update.buffer = WTFMove(buffer);
692 m_nicosia.delta.imageBackingChanged = true;
694 } else if (m_nicosia.imageBacking) {
695 auto& layerState = downcast<Nicosia::ImageBackingTextureMapperImpl>(m_nicosia.imageBacking->impl()).layerState();
696 layerState.update = Nicosia::ImageBackingTextureMapperImpl::Update { };
697 m_nicosia.imageBacking = nullptr;
698 m_nicosia.delta.imageBackingChanged = true;
702 m_nicosia.layer->updateState(
703 [this](Nicosia::CompositionLayer::LayerState& state)
705 // OR the local delta value into the layer's pending state delta. After that,
706 // go through each local change and update the pending state accordingly.
707 auto& localDelta = m_nicosia.delta;
708 state.delta.value |= localDelta.value;
710 if (localDelta.positionChanged)
711 state.position = m_adjustedPosition;
712 if (localDelta.anchorPointChanged)
713 state.anchorPoint = m_adjustedAnchorPoint;
714 if (localDelta.sizeChanged)
715 state.size = m_adjustedSize;
717 if (localDelta.transformChanged)
718 state.transform = transform();
719 if (localDelta.childrenTransformChanged)
720 state.childrenTransform = childrenTransform();
722 if (localDelta.contentsRectChanged)
723 state.contentsRect = contentsRect();
724 if (localDelta.contentsTilingChanged) {
725 state.contentsTilePhase = contentsTilePhase();
726 state.contentsTileSize = contentsTileSize();
729 if (localDelta.opacityChanged)
730 state.opacity = opacity();
731 if (localDelta.solidColorChanged)
732 state.solidColor = m_solidColor;
734 if (localDelta.filtersChanged)
735 state.filters = filters();
736 if (localDelta.animationsChanged)
737 state.animations = m_animations.getActiveAnimations();
739 if (localDelta.childrenChanged) {
740 state.children = WTF::map(children(),
743 return downcast<CoordinatedGraphicsLayer>(child.get()).m_nicosia.layer;
747 if (localDelta.maskChanged) {
748 auto* mask = downcast<CoordinatedGraphicsLayer>(maskLayer());
749 state.mask = mask ? mask->m_nicosia.layer : nullptr;
752 if (localDelta.replicaChanged) {
753 auto* replica = downcast<CoordinatedGraphicsLayer>(replicaLayer());
754 state.replica = replica ? replica->m_nicosia.layer : nullptr;
757 if (localDelta.flagsChanged) {
758 state.flags.contentsOpaque = contentsOpaque();
759 state.flags.drawsContent = drawsContent();
760 state.flags.contentsVisible = contentsAreVisible();
761 state.flags.backfaceVisible = backfaceVisibility();
762 state.flags.masksToBounds = masksToBounds();
763 state.flags.preserves3D = preserves3D();
766 if (localDelta.repaintCounterChanged)
767 state.repaintCounter = m_nicosia.repaintCounter;
768 if (localDelta.debugBorderChanged)
769 state.debugBorder = m_nicosia.debugBorder;
771 if (localDelta.backingStoreChanged)
772 state.backingStore = m_nicosia.backingStore;
773 if (localDelta.contentLayerChanged)
774 state.contentLayer = m_nicosia.contentLayer;
775 if (localDelta.imageBackingChanged)
776 state.imageBacking = m_nicosia.imageBacking;
778 m_nicosia.performLayerSync = !!m_nicosia.delta.value;
779 m_nicosia.delta = { };
783 void CoordinatedGraphicsLayer::syncPendingStateChangesIncludingSubLayers()
785 if (m_nicosia.performLayerSync)
786 m_coordinator->syncLayerState();
787 m_nicosia.performLayerSync = false;
790 downcast<CoordinatedGraphicsLayer>(*maskLayer()).syncPendingStateChangesIncludingSubLayers();
792 for (auto& child : children())
793 downcast<CoordinatedGraphicsLayer>(child.get()).syncPendingStateChangesIncludingSubLayers();
796 void CoordinatedGraphicsLayer::deviceOrPageScaleFactorChanged()
798 if (shouldHaveBackingStore())
799 m_pendingContentsScaleAdjustment = true;
802 float CoordinatedGraphicsLayer::effectiveContentsScale()
804 return selfOrAncestorHaveNonAffineTransforms() ? 1 : deviceScaleFactor() * pageScaleFactor();
807 static void clampToContentsRectIfRectIsInfinite(FloatRect& rect, const FloatSize& contentsSize)
809 if (rect.width() >= LayoutUnit::nearlyMax() || rect.width() <= LayoutUnit::nearlyMin()) {
811 rect.setWidth(contentsSize.width());
814 if (rect.height() >= LayoutUnit::nearlyMax() || rect.height() <= LayoutUnit::nearlyMin()) {
816 rect.setHeight(contentsSize.height());
820 IntRect CoordinatedGraphicsLayer::transformedVisibleRect()
822 // Non-invertible layers are not visible.
823 if (!m_layerTransform.combined().isInvertible())
826 // Return a projection of the visible rect (surface coordinates) onto the layer's plane (layer coordinates).
827 // The resulting quad might be squewed and the visible rect is the bounding box of this quad,
828 // so it might spread further than the real visible area (and then even more amplified by the cover rect multiplier).
829 ASSERT(m_cachedInverseTransform == m_layerTransform.combined().inverse().value_or(TransformationMatrix()));
830 FloatRect rect = m_cachedInverseTransform.clampedBoundsOfProjectedQuad(FloatQuad(m_coordinator->visibleContentsRect()));
831 clampToContentsRectIfRectIsInfinite(rect, size());
832 return enclosingIntRect(rect);
835 void CoordinatedGraphicsLayer::updateContentBuffersIncludingSubLayers()
837 if (CoordinatedGraphicsLayer* mask = downcast<CoordinatedGraphicsLayer>(maskLayer()))
838 mask->updateContentBuffers();
840 if (CoordinatedGraphicsLayer* replica = downcast<CoordinatedGraphicsLayer>(replicaLayer()))
841 replica->updateContentBuffers();
843 updateContentBuffers();
845 for (auto& child : children())
846 downcast<CoordinatedGraphicsLayer>(child.get()).updateContentBuffersIncludingSubLayers();
849 void CoordinatedGraphicsLayer::updateContentBuffers()
851 if (!m_nicosia.backingStore)
854 // Prepare for painting on the impl-contained backing store. isFlushing is used there
855 // for internal sanity checks.
856 auto& impl = downcast<Nicosia::BackingStoreTextureMapperImpl>(m_nicosia.backingStore->impl());
857 auto& layerState = impl.layerState();
858 layerState.isFlushing = true;
860 // Helper lambda that finished the flush update and determines layer sync necessity.
862 [this, &layerState] {
863 auto& update = layerState.update;
864 m_nicosia.performLayerSync = !update.tilesToCreate.isEmpty()
865 || !update.tilesToRemove.isEmpty() || !update.tilesToUpdate.isEmpty();
866 layerState.isFlushing = false;
869 // Address the content scale adjustment.
870 // FIXME: the previousBackingStore logic is likely possible to remove.
871 // https://bugs.webkit.org/show_bug.cgi?id=188693
872 if (m_pendingContentsScaleAdjustment) {
873 if (layerState.mainBackingStore && layerState.mainBackingStore->contentsScale() != effectiveContentsScale()) {
874 // Between creating the new backing store and painting the content, we do not
875 // want to drop the previous one as that might result in briefly seeing flickering
876 // as the old tiles may be dropped before something replaces them.
877 layerState.previousBackingStore = WTFMove(layerState.mainBackingStore);
879 // No reason to save the previous backing store for non-visible areas.
880 layerState.previousBackingStore->removeAllNonVisibleTiles(transformedVisibleRect(), IntRect(0, 0, size().width(), size().height()));
882 m_pendingContentsScaleAdjustment = false;
885 // Ensure the TiledBackingStore object, and enforce a complete repaint if it's not been present yet.
886 if (!layerState.mainBackingStore) {
887 layerState.mainBackingStore = std::make_unique<TiledBackingStore>(impl, effectiveContentsScale());
888 m_pendingVisibleRectAdjustment = true;
891 // Bail if there's no painting recorded or enforced.
892 if (!m_pendingVisibleRectAdjustment && !m_needsDisplay.completeLayer && m_needsDisplay.rects.isEmpty()) {
897 if (!m_needsDisplay.completeLayer) {
898 for (auto& rect : m_needsDisplay.rects)
899 layerState.mainBackingStore->invalidate(IntRect { rect });
901 layerState.mainBackingStore->invalidate({ { }, IntSize { m_size } });
903 m_needsDisplay.completeLayer = false;
904 m_needsDisplay.rects.clear();
906 if (m_pendingVisibleRectAdjustment) {
907 m_pendingVisibleRectAdjustment = false;
908 layerState.mainBackingStore->createTilesIfNeeded(transformedVisibleRect(), IntRect(0, 0, m_size.width(), m_size.height()));
911 ASSERT(m_coordinator && m_coordinator->isFlushingLayerChanges());
913 // With all the affected tiles created and/or invalidated, we can finally paint them.
914 auto dirtyTiles = layerState.mainBackingStore->dirtyTiles();
915 if (!dirtyTiles.isEmpty()) {
916 bool didUpdateTiles = false;
918 for (auto& tileReference : dirtyTiles) {
919 auto& tile = tileReference.get();
922 auto& tileRect = tile.rect();
923 auto& dirtyRect = tile.dirtyRect();
925 auto coordinatedBuffer = Nicosia::Buffer::create(dirtyRect.size(), contentsOpaque() ? Nicosia::Buffer::NoFlags : Nicosia::Buffer::SupportsAlpha);
926 SurfaceUpdateInfo updateInfo;
927 updateInfo.updateRect = dirtyRect;
928 updateInfo.updateRect.move(-tileRect.x(), -tileRect.y());
929 updateInfo.buffer = coordinatedBuffer.copyRef();
931 if (!m_coordinator->paintingEngine().paint(*this, WTFMove(coordinatedBuffer),
932 dirtyRect, layerState.mainBackingStore->mapToContents(dirtyRect),
933 IntRect { { 0, 0 }, dirtyRect.size() }, layerState.mainBackingStore->contentsScale()))
936 impl.updateTile(tile.tileID(), updateInfo, tileRect);
939 didUpdateTiles |= true;
943 didUpdateTileBuffers();
946 // The previous backing store is kept around to avoid flickering between
947 // removing the existing tiles and painting the new ones. The first time
948 // the visibleRect is full painted we remove the previous backing store.
949 if (layerState.previousBackingStore && layerState.mainBackingStore->visibleAreaIsCovered())
950 layerState.previousBackingStore = nullptr;
952 // Request a second update immediately if some tiles are still pending creation.
953 if (layerState.hasPendingTileCreation) {
954 setNeedsVisibleRectAdjustment();
955 notifyFlushRequired();
961 void CoordinatedGraphicsLayer::purgeBackingStores()
964 SetForScope<bool> updateModeProtector(m_isPurging, true);
966 if (m_nicosia.backingStore) {
967 auto& layerState = downcast<Nicosia::BackingStoreTextureMapperImpl>(m_nicosia.backingStore->impl()).layerState();
968 layerState.isPurging = true;
969 layerState.mainBackingStore = nullptr;
970 layerState.previousBackingStore = nullptr;
972 m_nicosia.backingStore = nullptr;
975 if (m_nicosia.imageBacking) {
976 auto& layerState = downcast<Nicosia::ImageBackingTextureMapperImpl>(m_nicosia.imageBacking->impl()).layerState();
977 layerState.imageID = 0;
978 layerState.nativeImageID = 0;
979 layerState.update = { };
981 m_nicosia.imageBacking = nullptr;
984 notifyFlushRequired();
987 void CoordinatedGraphicsLayer::setCoordinator(CoordinatedGraphicsLayerClient* coordinator)
989 m_coordinator = coordinator;
992 void CoordinatedGraphicsLayer::setCoordinatorIncludingSubLayersIfNeeded(CoordinatedGraphicsLayerClient* coordinator)
994 if (m_coordinator == coordinator)
997 // If the coordinators are different it means that we are attaching a layer that was created by a different
998 // CompositingCoordinator than the current one. This happens because the layer was taken out of the tree
999 // and then added back after AC was disabled and enabled again. We need to set the new coordinator to the
1000 // layer and its children.
1002 // During each layer flush, the state stores the values that have changed since the previous one, and these
1003 // are updated once in the scene. When adding CoordinatedGraphicsLayers back to the tree, the fields that
1004 // are not updated during the next flush won't be sent to the scene, so they won't be updated there and the
1005 // rendering will fail.
1007 // For example the drawsContent flag. This is set when the layer is created and is not updated anymore (unless
1008 // the content changes). When the layer is added back to the tree, the state won't reflect any change in the
1009 // flag value, so the scene won't update it and the layer won't be rendered.
1011 // We need to update here the layer changeMask so the scene gets all the current values.
1012 m_nicosia.delta.value = UINT_MAX;
1014 coordinator->attachLayer(this);
1015 for (auto& child : children())
1016 downcast<CoordinatedGraphicsLayer>(child.get()).setCoordinatorIncludingSubLayersIfNeeded(coordinator);
1019 const RefPtr<Nicosia::CompositionLayer>& CoordinatedGraphicsLayer::compositionLayer() const
1021 return m_nicosia.layer;
1024 void CoordinatedGraphicsLayer::setNeedsVisibleRectAdjustment()
1026 if (shouldHaveBackingStore())
1027 m_pendingVisibleRectAdjustment = true;
1030 static inline bool isIntegral(float value)
1032 return static_cast<int>(value) == value;
1035 FloatPoint CoordinatedGraphicsLayer::computePositionRelativeToBase()
1038 for (const GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent())
1039 offset += currLayer->position();
1044 void CoordinatedGraphicsLayer::computePixelAlignment(FloatPoint& position, FloatSize& size, FloatPoint3D& anchorPoint, FloatSize& alignmentOffset)
1046 if (isIntegral(effectiveContentsScale())) {
1047 position = m_position;
1049 anchorPoint = m_anchorPoint;
1050 alignmentOffset = FloatSize();
1054 FloatPoint positionRelativeToBase = computePositionRelativeToBase();
1056 FloatRect baseRelativeBounds(positionRelativeToBase, m_size);
1057 FloatRect scaledBounds = baseRelativeBounds;
1059 // Scale by the effective scale factor to compute the screen-relative bounds.
1060 scaledBounds.scale(effectiveContentsScale());
1062 // Round to integer boundaries.
1063 // NOTE: When using enclosingIntRect (as mac) it will have different sizes depending on position.
1064 FloatRect alignedBounds = enclosingIntRect(scaledBounds);
1066 // Convert back to layer coordinates.
1067 alignedBounds.scale(1 / effectiveContentsScale());
1069 // Convert back to layer coordinates.
1070 alignmentOffset = baseRelativeBounds.location() - alignedBounds.location();
1072 position = m_position - alignmentOffset;
1073 size = alignedBounds.size();
1075 // Now we have to compute a new anchor point which compensates for rounding.
1076 float anchorPointX = m_anchorPoint.x();
1077 float anchorPointY = m_anchorPoint.y();
1079 if (alignedBounds.width())
1080 anchorPointX = (baseRelativeBounds.width() * anchorPointX + alignmentOffset.width()) / alignedBounds.width();
1082 if (alignedBounds.height())
1083 anchorPointY = (baseRelativeBounds.height() * anchorPointY + alignmentOffset.height()) / alignedBounds.height();
1085 anchorPoint = FloatPoint3D(anchorPointX, anchorPointY, m_anchorPoint.z() * effectiveContentsScale());
1088 void CoordinatedGraphicsLayer::computeTransformedVisibleRect()
1090 if (!m_shouldUpdateVisibleRect && !m_movingVisibleRect)
1093 m_shouldUpdateVisibleRect = false;
1094 TransformationMatrix currentTransform = transform();
1095 if (m_movingVisibleRect)
1096 client().getCurrentTransform(this, currentTransform);
1097 m_layerTransform.setLocalTransform(currentTransform);
1099 m_layerTransform.setAnchorPoint(m_adjustedAnchorPoint);
1100 m_layerTransform.setPosition(m_adjustedPosition);
1101 m_layerTransform.setSize(m_adjustedSize);
1103 m_layerTransform.setFlattening(!preserves3D());
1104 m_layerTransform.setChildrenTransform(childrenTransform());
1105 m_layerTransform.combineTransforms(parent() ? downcast<CoordinatedGraphicsLayer>(*parent()).m_layerTransform.combinedForChildren() : TransformationMatrix());
1107 m_cachedInverseTransform = m_layerTransform.combined().inverse().value_or(TransformationMatrix());
1109 // The combined transform will be used in tiledBackingStoreVisibleRect.
1110 setNeedsVisibleRectAdjustment();
1113 bool CoordinatedGraphicsLayer::shouldHaveBackingStore() const
1115 return drawsContent() && contentsAreVisible() && !m_size.isEmpty();
1118 bool CoordinatedGraphicsLayer::selfOrAncestorHasActiveTransformAnimation() const
1120 if (m_animations.hasActiveAnimationsOfType(AnimatedPropertyTransform))
1126 return downcast<CoordinatedGraphicsLayer>(*parent()).selfOrAncestorHasActiveTransformAnimation();
1129 bool CoordinatedGraphicsLayer::selfOrAncestorHaveNonAffineTransforms()
1131 if (!m_layerTransform.combined().isAffine())
1137 return downcast<CoordinatedGraphicsLayer>(*parent()).selfOrAncestorHaveNonAffineTransforms();
1140 bool CoordinatedGraphicsLayer::addAnimation(const KeyframeValueList& valueList, const FloatSize& boxSize, const Animation* anim, const String& keyframesName, double delayAsNegativeTimeOffset)
1142 ASSERT(!keyframesName.isEmpty());
1144 if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2 || (valueList.property() != AnimatedPropertyTransform && valueList.property() != AnimatedPropertyOpacity && valueList.property() != AnimatedPropertyFilter))
1147 if (valueList.property() == AnimatedPropertyFilter) {
1148 int listIndex = validateFilterOperations(valueList);
1152 const auto& filters = static_cast<const FilterAnimationValue&>(valueList.at(listIndex)).value();
1153 if (!filtersCanBeComposited(filters))
1157 bool listsMatch = false;
1158 bool ignoredHasBigRotation;
1160 if (valueList.property() == AnimatedPropertyTransform)
1161 listsMatch = validateTransformOperations(valueList, ignoredHasBigRotation) >= 0;
1163 m_lastAnimationStartTime = MonotonicTime::now() - Seconds(delayAsNegativeTimeOffset);
1164 m_animations.add(TextureMapperAnimation(keyframesName, valueList, boxSize, *anim, listsMatch, m_lastAnimationStartTime, 0_s, TextureMapperAnimation::AnimationState::Playing));
1165 m_animationStartedTimer.startOneShot(0_s);
1166 didChangeAnimations();
1170 void CoordinatedGraphicsLayer::pauseAnimation(const String& animationName, double time)
1172 m_animations.pause(animationName, Seconds(time));
1173 didChangeAnimations();
1176 void CoordinatedGraphicsLayer::removeAnimation(const String& animationName)
1178 m_animations.remove(animationName);
1179 didChangeAnimations();
1182 void CoordinatedGraphicsLayer::suspendAnimations(MonotonicTime time)
1184 m_animations.suspend(time);
1185 didChangeAnimations();
1188 void CoordinatedGraphicsLayer::resumeAnimations()
1190 m_animations.resume();
1191 didChangeAnimations();
1194 void CoordinatedGraphicsLayer::animationStartedTimerFired()
1196 client().notifyAnimationStarted(this, "", m_lastAnimationStartTime);
1199 bool CoordinatedGraphicsLayer::usesContentsLayer() const
1201 return m_nicosia.contentLayer || m_compositedImage;
1204 } // namespace WebCore
1206 #endif // USE(COORDINATED_GRAPHICS)