2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "GraphicsLayerCA.h"
30 #include "Animation.h"
31 #include "FloatConversion.h"
32 #include "FloatRect.h"
33 #include "GraphicsLayerFactory.h"
35 #include "PlatformCAFilters.h"
36 #include "PlatformCALayer.h"
37 #include "RotateTransformOperation.h"
38 #include "ScaleTransformOperation.h"
39 #include "TextStream.h"
40 #include "TiledBacking.h"
41 #include "TransformState.h"
42 #include "TranslateTransformOperation.h"
43 #include <QuartzCore/CATransform3D.h>
45 #include <wtf/CurrentTime.h>
46 #include <wtf/MathExtras.h>
47 #include <wtf/TemporaryChange.h>
48 #include <wtf/text/WTFString.h>
51 #include "SystemMemory.h"
52 #include "WebCoreThread.h"
56 #include "PlatformCAAnimationMac.h"
57 #include "PlatformCALayerMac.h"
58 #include "WebCoreSystemInterface.h"
62 #include "PlatformCAAnimationWin.h"
63 #include "PlatformCALayerWin.h"
68 // The threshold width or height above which a tiled layer will be used. This should be
69 // large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL
70 // texture size limit on all supported hardware.
72 static const int cMaxPixelDimension = 1280;
73 static const int cMaxPixelDimensionLowMemory = 1024;
74 static const int cMemoryLevelToUseSmallerPixelDimension = 35;
76 static const int cMaxPixelDimension = 2000;
79 // Derived empirically: <rdar://problem/13401861>
80 static const int cMaxLayerTreeDepth = 250;
82 // If we send a duration of 0 to CA, then it will use the default duration
83 // of 250ms. So send a very small value instead.
84 static const float cAnimationAlmostZeroDuration = 1e-3f;
86 static bool isTransformTypeTransformationMatrix(TransformOperation::OperationType transformType)
88 switch (transformType) {
89 case TransformOperation::SKEW_X:
90 case TransformOperation::SKEW_Y:
91 case TransformOperation::SKEW:
92 case TransformOperation::MATRIX:
93 case TransformOperation::ROTATE_3D:
94 case TransformOperation::MATRIX_3D:
95 case TransformOperation::PERSPECTIVE:
96 case TransformOperation::IDENTITY:
97 case TransformOperation::NONE:
104 static bool isTransformTypeFloatPoint3D(TransformOperation::OperationType transformType)
106 switch (transformType) {
107 case TransformOperation::SCALE:
108 case TransformOperation::SCALE_3D:
109 case TransformOperation::TRANSLATE:
110 case TransformOperation::TRANSLATE_3D:
117 static bool isTransformTypeNumber(TransformOperation::OperationType transformType)
119 return !isTransformTypeTransformationMatrix(transformType) && !isTransformTypeFloatPoint3D(transformType);
122 static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const FloatSize& size, float& value)
124 switch (transformType) {
125 case TransformOperation::ROTATE:
126 case TransformOperation::ROTATE_X:
127 case TransformOperation::ROTATE_Y:
128 value = transformOp ? narrowPrecisionToFloat(deg2rad(downcast<RotateTransformOperation>(*transformOp).angle())) : 0;
130 case TransformOperation::SCALE_X:
131 value = transformOp ? narrowPrecisionToFloat(downcast<ScaleTransformOperation>(*transformOp).x()) : 1;
133 case TransformOperation::SCALE_Y:
134 value = transformOp ? narrowPrecisionToFloat(downcast<ScaleTransformOperation>(*transformOp).y()) : 1;
136 case TransformOperation::SCALE_Z:
137 value = transformOp ? narrowPrecisionToFloat(downcast<ScaleTransformOperation>(*transformOp).z()) : 1;
139 case TransformOperation::TRANSLATE_X:
140 value = transformOp ? narrowPrecisionToFloat(downcast<TranslateTransformOperation>(*transformOp).x(size)) : 0;
142 case TransformOperation::TRANSLATE_Y:
143 value = transformOp ? narrowPrecisionToFloat(downcast<TranslateTransformOperation>(*transformOp).y(size)) : 0;
145 case TransformOperation::TRANSLATE_Z:
146 value = transformOp ? narrowPrecisionToFloat(downcast<TranslateTransformOperation>(*transformOp).z(size)) : 0;
153 static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const FloatSize& size, FloatPoint3D& value)
155 switch (transformType) {
156 case TransformOperation::SCALE:
157 case TransformOperation::SCALE_3D: {
158 const auto* scaleTransformOp = downcast<ScaleTransformOperation>(transformOp);
159 value.setX(scaleTransformOp ? narrowPrecisionToFloat(scaleTransformOp->x()) : 1);
160 value.setY(scaleTransformOp ? narrowPrecisionToFloat(scaleTransformOp->y()) : 1);
161 value.setZ(scaleTransformOp ? narrowPrecisionToFloat(scaleTransformOp->z()) : 1);
164 case TransformOperation::TRANSLATE:
165 case TransformOperation::TRANSLATE_3D: {
166 const auto* translateTransformOp = downcast<TranslateTransformOperation>(transformOp);
167 value.setX(translateTransformOp ? narrowPrecisionToFloat(translateTransformOp->x(size)) : 0);
168 value.setY(translateTransformOp ? narrowPrecisionToFloat(translateTransformOp->y(size)) : 0);
169 value.setZ(translateTransformOp ? narrowPrecisionToFloat(translateTransformOp->z(size)) : 0);
177 static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const FloatSize& size, TransformationMatrix& value)
179 switch (transformType) {
180 case TransformOperation::SKEW_X:
181 case TransformOperation::SKEW_Y:
182 case TransformOperation::SKEW:
183 case TransformOperation::MATRIX:
184 case TransformOperation::ROTATE_3D:
185 case TransformOperation::MATRIX_3D:
186 case TransformOperation::PERSPECTIVE:
187 case TransformOperation::IDENTITY:
188 case TransformOperation::NONE:
190 transformOp->apply(value, size);
192 value.makeIdentity();
199 static PlatformCAAnimation::ValueFunctionType getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType)
201 // Use literal strings to avoid link-time dependency on those symbols.
202 switch (transformType) {
203 case TransformOperation::ROTATE_X:
204 return PlatformCAAnimation::RotateX;
205 case TransformOperation::ROTATE_Y:
206 return PlatformCAAnimation::RotateY;
207 case TransformOperation::ROTATE:
208 return PlatformCAAnimation::RotateZ;
209 case TransformOperation::SCALE_X:
210 return PlatformCAAnimation::ScaleX;
211 case TransformOperation::SCALE_Y:
212 return PlatformCAAnimation::ScaleY;
213 case TransformOperation::SCALE_Z:
214 return PlatformCAAnimation::ScaleZ;
215 case TransformOperation::TRANSLATE_X:
216 return PlatformCAAnimation::TranslateX;
217 case TransformOperation::TRANSLATE_Y:
218 return PlatformCAAnimation::TranslateY;
219 case TransformOperation::TRANSLATE_Z:
220 return PlatformCAAnimation::TranslateZ;
221 case TransformOperation::SCALE:
222 case TransformOperation::SCALE_3D:
223 return PlatformCAAnimation::Scale;
224 case TransformOperation::TRANSLATE:
225 case TransformOperation::TRANSLATE_3D:
226 return PlatformCAAnimation::Translate;
228 return PlatformCAAnimation::NoValueFunction;
232 static ASCIILiteral propertyIdToString(AnimatedPropertyID property)
235 case AnimatedPropertyTransform:
236 return ASCIILiteral("transform");
237 case AnimatedPropertyOpacity:
238 return ASCIILiteral("opacity");
239 case AnimatedPropertyBackgroundColor:
240 return ASCIILiteral("backgroundColor");
241 case AnimatedPropertyWebkitFilter:
242 return ASCIILiteral("filters");
243 #if ENABLE(FILTERS_LEVEL_2)
244 case AnimatedPropertyWebkitBackdropFilter:
245 return ASCIILiteral("backdropFilters");
247 case AnimatedPropertyInvalid:
248 ASSERT_NOT_REACHED();
250 ASSERT_NOT_REACHED();
251 return ASCIILiteral("");
254 static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index, int subIndex)
256 return animationName + '_' + String::number(property) + '_' + String::number(index) + '_' + String::number(subIndex);
259 static bool animationHasStepsTimingFunction(const KeyframeValueList& valueList, const Animation* anim)
261 if (anim->timingFunction()->isStepsTimingFunction())
264 for (unsigned i = 0; i < valueList.size(); ++i) {
265 if (const TimingFunction* timingFunction = valueList.at(i).timingFunction()) {
266 if (timingFunction->isStepsTimingFunction())
274 static inline bool supportsAcceleratedFilterAnimations()
283 bool GraphicsLayer::supportsLayerType(Type type)
287 case Type::PageTiledBacking:
288 case Type::Scrolling:
292 // FIXME: we can use shaper layers on Windows when PlatformCALayerMac::setShapePath() etc are implemented.
298 ASSERT_NOT_REACHED();
302 bool GraphicsLayer::supportsBackgroundColorContent()
307 std::unique_ptr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, GraphicsLayerClient& client, Type layerType)
309 std::unique_ptr<GraphicsLayer> graphicsLayer;
311 graphicsLayer = std::make_unique<GraphicsLayerCA>(layerType, client);
313 graphicsLayer = factory->createGraphicsLayer(layerType, client);
315 graphicsLayer->initialize(layerType);
317 return graphicsLayer;
320 bool GraphicsLayerCA::filtersCanBeComposited(const FilterOperations& filters)
323 return PlatformCALayerMac::filtersCanBeComposited(filters);
325 return PlatformCALayerWin::filtersCanBeComposited(filters);
329 PassRefPtr<PlatformCALayer> GraphicsLayerCA::createPlatformCALayer(PlatformCALayer::LayerType layerType, PlatformCALayerClient* owner)
332 return PlatformCALayerMac::create(layerType, owner);
334 return PlatformCALayerWin::create(layerType, owner);
338 PassRefPtr<PlatformCALayer> GraphicsLayerCA::createPlatformCALayer(PlatformLayer* platformLayer, PlatformCALayerClient* owner)
341 return PlatformCALayerMac::create(platformLayer, owner);
343 return PlatformCALayerWin::create(platformLayer, owner);
347 PassRefPtr<PlatformCAAnimation> GraphicsLayerCA::createPlatformCAAnimation(PlatformCAAnimation::AnimationType type, const String& keyPath)
350 return PlatformCAAnimationMac::create(type, keyPath);
352 return PlatformCAAnimationWin::create(type, keyPath);
356 GraphicsLayerCA::GraphicsLayerCA(Type layerType, GraphicsLayerClient& client)
357 : GraphicsLayer(layerType, client)
358 , m_needsFullRepaint(false)
359 , m_usingBackdropLayerType(false)
360 , m_allowsBackingStoreDetachment(true)
361 , m_intersectsCoverageRect(false)
365 void GraphicsLayerCA::initialize(Type layerType)
367 PlatformCALayer::LayerType platformLayerType;
370 platformLayerType = PlatformCALayer::LayerType::LayerTypeWebLayer;
372 case Type::PageTiledBacking:
373 platformLayerType = PlatformCALayer::LayerType::LayerTypePageTiledBackingLayer;
375 case Type::Scrolling:
376 platformLayerType = PlatformCALayer::LayerType::LayerTypeScrollingLayer;
379 platformLayerType = PlatformCALayer::LayerType::LayerTypeShapeLayer;
382 m_layer = createPlatformCALayer(platformLayerType, this);
383 noteLayerPropertyChanged(ContentsScaleChanged);
386 GraphicsLayerCA::~GraphicsLayerCA()
388 // Do cleanup while we can still safely call methods on the derived class.
392 void GraphicsLayerCA::willBeDestroyed()
394 // We release our references to the PlatformCALayers here, but do not actively unparent them,
395 // since that will cause a commit and break our batched commit model. The layers will
396 // get released when the rootmost modified GraphicsLayerCA rebuilds its child layers.
398 // Clean up the layer.
400 m_layer->setOwner(nullptr);
403 m_contentsLayer->setOwner(nullptr);
405 if (m_contentsClippingLayer)
406 m_contentsClippingLayer->setOwner(nullptr);
408 if (m_contentsShapeMaskLayer)
409 m_contentsShapeMaskLayer->setOwner(nullptr);
411 if (m_shapeMaskLayer)
412 m_shapeMaskLayer->setOwner(nullptr);
414 if (m_structuralLayer)
415 m_structuralLayer->setOwner(nullptr);
418 m_backdropLayer->setOwner(nullptr);
422 GraphicsLayer::willBeDestroyed();
425 void GraphicsLayerCA::setName(const String& name)
427 String caLayerDescription;
429 if (!m_layer->isPlatformCALayerRemote())
430 caLayerDescription = String::format("CALayer(%p) ", m_layer->platformLayer());
432 String longName = caLayerDescription + String::format("GraphicsLayer(%p, %llu) ", this, primaryLayerID()) + name;
433 GraphicsLayer::setName(longName);
434 noteLayerPropertyChanged(NameChanged);
437 GraphicsLayer::PlatformLayerID GraphicsLayerCA::primaryLayerID() const
439 return primaryLayer()->layerID();
442 PlatformLayer* GraphicsLayerCA::platformLayer() const
444 return primaryLayer()->platformLayer();
447 bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children)
449 bool childrenChanged = GraphicsLayer::setChildren(children);
451 noteSublayersChanged();
453 return childrenChanged;
456 void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
458 GraphicsLayer::addChild(childLayer);
459 noteSublayersChanged();
462 void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
464 GraphicsLayer::addChildAtIndex(childLayer, index);
465 noteSublayersChanged();
468 void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
470 GraphicsLayer::addChildBelow(childLayer, sibling);
471 noteSublayersChanged();
474 void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
476 GraphicsLayer::addChildAbove(childLayer, sibling);
477 noteSublayersChanged();
480 bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
482 if (GraphicsLayer::replaceChild(oldChild, newChild)) {
483 noteSublayersChanged();
489 void GraphicsLayerCA::removeFromParent()
492 downcast<GraphicsLayerCA>(*m_parent).noteSublayersChanged();
493 GraphicsLayer::removeFromParent();
496 void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer)
498 if (layer == m_maskLayer)
501 GraphicsLayer::setMaskLayer(layer);
502 noteLayerPropertyChanged(MaskLayerChanged);
504 propagateLayerChangeToReplicas();
506 if (m_replicatedLayer)
507 downcast<GraphicsLayerCA>(*m_replicatedLayer).propagateLayerChangeToReplicas();
510 void GraphicsLayerCA::setReplicatedLayer(GraphicsLayer* layer)
512 if (layer == m_replicatedLayer)
515 GraphicsLayer::setReplicatedLayer(layer);
516 noteLayerPropertyChanged(ReplicatedLayerChanged);
519 void GraphicsLayerCA::setReplicatedByLayer(GraphicsLayer* layer)
521 if (layer == m_replicaLayer)
524 GraphicsLayer::setReplicatedByLayer(layer);
525 noteSublayersChanged();
526 noteLayerPropertyChanged(ReplicatedLayerChanged);
529 void GraphicsLayerCA::setPosition(const FloatPoint& point)
531 if (point == m_position)
534 GraphicsLayer::setPosition(point);
535 noteLayerPropertyChanged(GeometryChanged);
538 void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
540 if (point == m_anchorPoint)
543 GraphicsLayer::setAnchorPoint(point);
544 noteLayerPropertyChanged(GeometryChanged);
547 void GraphicsLayerCA::setSize(const FloatSize& size)
552 GraphicsLayer::setSize(size);
553 noteLayerPropertyChanged(GeometryChanged);
556 void GraphicsLayerCA::setBoundsOrigin(const FloatPoint& origin)
558 if (origin == m_boundsOrigin)
561 GraphicsLayer::setBoundsOrigin(origin);
562 noteLayerPropertyChanged(GeometryChanged);
565 void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
567 if (t == m_transform)
570 GraphicsLayer::setTransform(t);
571 noteLayerPropertyChanged(TransformChanged);
574 void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
576 if (t == m_childrenTransform)
579 GraphicsLayer::setChildrenTransform(t);
580 noteLayerPropertyChanged(ChildrenTransformChanged);
583 void GraphicsLayerCA::moveOrCopyLayerAnimation(MoveOrCopy operation, const String& animationIdentifier, PlatformCALayer *fromLayer, PlatformCALayer *toLayer)
585 RefPtr<PlatformCAAnimation> anim = fromLayer->animationForKey(animationIdentifier);
591 fromLayer->removeAnimationForKey(animationIdentifier);
592 toLayer->addAnimationForKey(animationIdentifier, *anim);
596 toLayer->addAnimationForKey(animationIdentifier, *anim);
601 void GraphicsLayerCA::moveOrCopyAnimations(MoveOrCopy operation, PlatformCALayer *fromLayer, PlatformCALayer *toLayer)
603 // Look for running animations affecting this property.
604 AnimationsMap::const_iterator end = m_runningAnimations.end();
605 for (AnimationsMap::const_iterator it = m_runningAnimations.begin(); it != end; ++it) {
606 const Vector<LayerPropertyAnimation>& propertyAnimations = it->value;
607 size_t numAnimations = propertyAnimations.size();
608 for (size_t i = 0; i < numAnimations; ++i) {
609 const LayerPropertyAnimation& currAnimation = propertyAnimations[i];
611 if (currAnimation.m_property == AnimatedPropertyTransform
612 || currAnimation.m_property == AnimatedPropertyOpacity
613 || currAnimation.m_property == AnimatedPropertyBackgroundColor
614 || currAnimation.m_property == AnimatedPropertyWebkitFilter)
615 moveOrCopyLayerAnimation(operation, animationIdentifier(currAnimation.m_name, currAnimation.m_property, currAnimation.m_index, currAnimation.m_subIndex), fromLayer, toLayer);
620 void GraphicsLayerCA::setPreserves3D(bool preserves3D)
622 if (preserves3D == m_preserves3D)
625 GraphicsLayer::setPreserves3D(preserves3D);
626 noteLayerPropertyChanged(Preserves3DChanged);
629 void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
631 if (masksToBounds == m_masksToBounds)
634 GraphicsLayer::setMasksToBounds(masksToBounds);
635 noteLayerPropertyChanged(MasksToBoundsChanged | DebugIndicatorsChanged);
638 void GraphicsLayerCA::setDrawsContent(bool drawsContent)
640 if (drawsContent == m_drawsContent)
643 GraphicsLayer::setDrawsContent(drawsContent);
644 noteLayerPropertyChanged(DrawsContentChanged | DebugIndicatorsChanged);
647 void GraphicsLayerCA::setContentsVisible(bool contentsVisible)
649 if (contentsVisible == m_contentsVisible)
652 GraphicsLayer::setContentsVisible(contentsVisible);
653 noteLayerPropertyChanged(ContentsVisibilityChanged);
654 // Visibility affects whether the contentsLayer is parented.
656 noteSublayersChanged();
659 void GraphicsLayerCA::setAcceleratesDrawing(bool acceleratesDrawing)
661 if (acceleratesDrawing == m_acceleratesDrawing)
664 GraphicsLayer::setAcceleratesDrawing(acceleratesDrawing);
665 noteLayerPropertyChanged(AcceleratesDrawingChanged);
668 void GraphicsLayerCA::setBackgroundColor(const Color& color)
670 if (m_backgroundColor == color)
673 GraphicsLayer::setBackgroundColor(color);
674 noteLayerPropertyChanged(BackgroundColorChanged);
677 void GraphicsLayerCA::setContentsOpaque(bool opaque)
679 if (m_contentsOpaque == opaque)
682 GraphicsLayer::setContentsOpaque(opaque);
683 noteLayerPropertyChanged(ContentsOpaqueChanged);
686 void GraphicsLayerCA::setBackfaceVisibility(bool visible)
688 if (m_backfaceVisibility == visible)
691 GraphicsLayer::setBackfaceVisibility(visible);
692 noteLayerPropertyChanged(BackfaceVisibilityChanged);
695 void GraphicsLayerCA::setOpacity(float opacity)
697 float clampedOpacity = std::max(0.0f, std::min(opacity, 1.0f));
699 if (clampedOpacity == m_opacity)
702 GraphicsLayer::setOpacity(clampedOpacity);
703 noteLayerPropertyChanged(OpacityChanged);
706 bool GraphicsLayerCA::setFilters(const FilterOperations& filterOperations)
708 bool canCompositeFilters = filtersCanBeComposited(filterOperations);
710 if (m_filters == filterOperations)
711 return canCompositeFilters;
713 // Filters cause flattening, so we should never have filters on a layer with preserves3D().
714 ASSERT(!filterOperations.size() || !preserves3D());
716 if (canCompositeFilters) {
717 GraphicsLayer::setFilters(filterOperations);
718 noteLayerPropertyChanged(FiltersChanged);
719 } else if (filters().size()) {
720 // In this case filters are rendered in software, so we need to remove any
721 // previously attached hardware filters.
723 noteLayerPropertyChanged(FiltersChanged);
725 return canCompositeFilters;
728 bool GraphicsLayerCA::setBackdropFilters(const FilterOperations& filterOperations)
730 bool canCompositeFilters = filtersCanBeComposited(filterOperations);
732 if (m_backdropFilters == filterOperations)
733 return canCompositeFilters;
735 // Filters cause flattening, so we should never have filters on a layer with preserves3D().
736 ASSERT(!filterOperations.size() || !preserves3D());
738 if (canCompositeFilters)
739 GraphicsLayer::setBackdropFilters(filterOperations);
741 // FIXME: This would clear the backdrop filters if we had a software implementation.
742 clearBackdropFilters();
744 noteLayerPropertyChanged(BackdropFiltersChanged);
745 return canCompositeFilters;
748 void GraphicsLayerCA::setBackdropFiltersRect(const FloatRect& backdropFiltersRect)
750 if (backdropFiltersRect == m_backdropFiltersRect)
753 GraphicsLayer::setBackdropFiltersRect(backdropFiltersRect);
754 noteLayerPropertyChanged(BackdropFiltersRectChanged);
757 #if ENABLE(CSS_COMPOSITING)
758 void GraphicsLayerCA::setBlendMode(BlendMode blendMode)
760 if (GraphicsLayer::blendMode() == blendMode)
763 GraphicsLayer::setBlendMode(blendMode);
764 noteLayerPropertyChanged(BlendModeChanged);
768 void GraphicsLayerCA::setNeedsDisplay()
773 m_needsFullRepaint = true;
774 m_dirtyRects.clear();
775 noteLayerPropertyChanged(DirtyRectsChanged);
776 addRepaintRect(FloatRect(FloatPoint(), m_size));
779 void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& r, ShouldClipToLayer shouldClip)
784 if (m_needsFullRepaint)
788 if (shouldClip == ClipToLayer) {
789 FloatRect layerBounds(FloatPoint(), m_size);
790 rect.intersect(layerBounds);
796 const size_t maxDirtyRects = 32;
798 for (size_t i = 0; i < m_dirtyRects.size(); ++i) {
799 if (m_dirtyRects[i].contains(rect))
803 if (m_dirtyRects.size() < maxDirtyRects)
804 m_dirtyRects.append(rect);
806 m_dirtyRects[0].unite(rect);
808 noteLayerPropertyChanged(DirtyRectsChanged);
810 addRepaintRect(rect);
813 void GraphicsLayerCA::setContentsNeedsDisplay()
815 noteLayerPropertyChanged(ContentsNeedsDisplay);
818 void GraphicsLayerCA::setContentsRect(const FloatRect& rect)
820 if (rect == m_contentsRect)
823 GraphicsLayer::setContentsRect(rect);
824 noteLayerPropertyChanged(ContentsRectsChanged);
827 void GraphicsLayerCA::setContentsClippingRect(const FloatRoundedRect& rect)
829 if (rect == m_contentsClippingRect)
832 GraphicsLayer::setContentsClippingRect(rect);
833 noteLayerPropertyChanged(ContentsRectsChanged);
836 bool GraphicsLayerCA::setMasksToBoundsRect(const FloatRoundedRect& roundedRect)
838 if (roundedRect == m_masksToBoundsRect)
841 GraphicsLayer::setMasksToBoundsRect(roundedRect);
842 noteLayerPropertyChanged(MasksToBoundsRectChanged);
846 void GraphicsLayerCA::setShapeLayerPath(const Path& path)
848 // FIXME: need to check for path equality. No bool Path::operator==(const Path&)!.
849 GraphicsLayer::setShapeLayerPath(path);
850 noteLayerPropertyChanged(ShapeChanged);
853 void GraphicsLayerCA::setShapeLayerWindRule(WindRule windRule)
855 if (windRule == m_shapeLayerWindRule)
858 GraphicsLayer::setShapeLayerWindRule(windRule);
859 noteLayerPropertyChanged(WindRuleChanged);
862 bool GraphicsLayerCA::shouldRepaintOnSizeChange() const
864 return drawsContent() && !tiledBacking();
867 bool GraphicsLayerCA::animationCanBeAccelerated(const KeyframeValueList& valueList, const Animation* anim) const
869 if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
872 if (animationHasStepsTimingFunction(valueList, anim))
875 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
876 // If there is a trigger that depends on the scroll position, we cannot accelerate the animation.
877 if (anim->trigger()->isScrollAnimationTrigger()) {
878 ScrollAnimationTrigger& scrollTrigger = downcast<ScrollAnimationTrigger>(*anim->trigger().get());
879 if (scrollTrigger.hasEndValue())
887 bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const FloatSize& boxSize, const Animation* anim, const String& animationName, double timeOffset)
889 ASSERT(!animationName.isEmpty());
891 if (!animationCanBeAccelerated(valueList, anim))
894 bool createdAnimations = false;
895 if (valueList.property() == AnimatedPropertyTransform)
896 createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize);
897 else if (valueList.property() == AnimatedPropertyWebkitFilter) {
898 if (supportsAcceleratedFilterAnimations())
899 createdAnimations = createFilterAnimationsFromKeyframes(valueList, anim, animationName, timeOffset);
901 #if ENABLE(FILTERS_LEVEL_2)
902 else if (valueList.property() == AnimatedPropertyWebkitBackdropFilter) {
903 if (supportsAcceleratedFilterAnimations())
904 createdAnimations = createFilterAnimationsFromKeyframes(valueList, anim, animationName, timeOffset);
908 createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset);
910 if (createdAnimations)
911 noteLayerPropertyChanged(AnimationChanged);
913 return createdAnimations;
916 void GraphicsLayerCA::pauseAnimation(const String& animationName, double timeOffset)
918 if (!animationIsRunning(animationName))
921 AnimationsToProcessMap::iterator it = m_animationsToProcess.find(animationName);
922 if (it != m_animationsToProcess.end()) {
923 AnimationProcessingAction& processingInfo = it->value;
924 // If an animation is scheduled to be removed, don't change the remove to a pause.
925 if (processingInfo.action != Remove)
926 processingInfo.action = Pause;
928 m_animationsToProcess.add(animationName, AnimationProcessingAction(Pause, timeOffset));
930 noteLayerPropertyChanged(AnimationChanged);
933 void GraphicsLayerCA::removeAnimation(const String& animationName)
935 if (!animationIsRunning(animationName))
938 m_animationsToProcess.add(animationName, AnimationProcessingAction(Remove));
939 noteLayerPropertyChanged(AnimationChanged);
942 void GraphicsLayerCA::platformCALayerAnimationStarted(const String& animationKey, CFTimeInterval startTime)
944 client().notifyAnimationStarted(this, animationKey, startTime);
947 void GraphicsLayerCA::platformCALayerAnimationEnded(const String& animationKey)
949 client().notifyAnimationEnded(this, animationKey);
952 void GraphicsLayerCA::setContentsToSolidColor(const Color& color)
954 if (color == m_contentsSolidColor)
957 m_contentsSolidColor = color;
959 bool contentsLayerChanged = false;
961 if (m_contentsSolidColor.isValid() && m_contentsSolidColor.alpha()) {
962 if (!m_contentsLayer || m_contentsLayerPurpose != ContentsLayerForBackgroundColor) {
963 m_contentsLayerPurpose = ContentsLayerForBackgroundColor;
964 m_contentsLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
966 m_contentsLayer->setName(String::format("Background Color Layer %llu", m_contentsLayer->layerID()));
968 contentsLayerChanged = true;
971 contentsLayerChanged = m_contentsLayer;
972 m_contentsLayerPurpose = NoContentsLayer;
973 m_contentsLayer = nullptr;
976 if (contentsLayerChanged)
977 noteSublayersChanged();
979 noteLayerPropertyChanged(ContentsColorLayerChanged);
982 void GraphicsLayerCA::setContentsToImage(Image* image)
985 CGImageRef newImage = image->nativeImageForCurrentFrame();
989 // Check to see if the image changed; we have to do this because the call to
990 // CGImageCreateCopyWithColorSpace() below can create a new image every time.
991 if (m_uncorrectedContentsImage && m_uncorrectedContentsImage.get() == newImage)
994 m_uncorrectedContentsImage = newImage;
995 m_pendingContentsImage = newImage;
997 #if !PLATFORM(WIN) && !PLATFORM(IOS)
998 CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get());
1000 static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
1001 if (colorSpace && CFEqual(colorSpace, deviceRGB)) {
1002 // CoreGraphics renders images tagged with DeviceRGB using the color space of the main display. When we hand such
1003 // images to CA we need to tag them similarly so CA rendering matches CG rendering.
1004 static CGColorSpaceRef genericRGB = CGDisplayCopyColorSpace(kCGDirectMainDisplay);
1005 m_pendingContentsImage = adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB));
1008 m_contentsLayerPurpose = ContentsLayerForImage;
1009 if (!m_contentsLayer)
1010 noteSublayersChanged();
1012 m_uncorrectedContentsImage = nullptr;
1013 m_pendingContentsImage = nullptr;
1014 m_contentsLayerPurpose = NoContentsLayer;
1015 if (m_contentsLayer)
1016 noteSublayersChanged();
1019 noteLayerPropertyChanged(ContentsImageChanged);
1022 void GraphicsLayerCA::setContentsToPlatformLayer(PlatformLayer* platformLayer, ContentsLayerPurpose purpose)
1024 if (m_contentsLayer && platformLayer == m_contentsLayer->platformLayer())
1027 if (m_contentsClippingLayer && m_contentsLayer)
1028 m_contentsLayer->removeFromSuperlayer();
1030 // FIXME: The passed in layer might be a raw layer or an externally created
1031 // PlatformCALayer. To determine this we attempt to get the
1032 // PlatformCALayer pointer. If this returns a null pointer we assume it's
1033 // raw. This test might be invalid if the raw layer is, for instance, the
1034 // PlatformCALayer is using a user data pointer in the raw layer, and
1035 // the creator of the raw layer is using it for some other purpose.
1036 // For now we don't support such a case.
1037 PlatformCALayer* platformCALayer = PlatformCALayer::platformCALayer(platformLayer);
1038 m_contentsLayer = platformLayer ? (platformCALayer ? platformCALayer : createPlatformCALayer(platformLayer, this)) : nullptr;
1039 m_contentsLayerPurpose = platformLayer ? purpose : NoContentsLayer;
1041 if (m_contentsClippingLayer && m_contentsLayer)
1042 m_contentsClippingLayer->appendSublayer(*m_contentsLayer);
1044 noteSublayersChanged();
1045 noteLayerPropertyChanged(ContentsPlatformLayerChanged);
1049 PlatformLayer* GraphicsLayerCA::contentsLayerForMedia() const
1051 return m_contentsLayerPurpose == ContentsLayerForMedia ? m_contentsLayer->platformLayer() : nullptr;
1055 void GraphicsLayerCA::layerDidDisplay(PlatformCALayer* layer)
1057 LayerMap* layerCloneMap;
1059 if (layer == m_layer)
1060 layerCloneMap = m_layerClones.get();
1061 else if (layer == m_contentsLayer)
1062 layerCloneMap = m_contentsLayerClones.get();
1066 if (layerCloneMap) {
1067 LayerMap::const_iterator end = layerCloneMap->end();
1068 for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1069 PlatformCALayer* currClone = it->value.get();
1073 currClone->copyContentsFromLayer(layer);
1078 FloatPoint GraphicsLayerCA::computePositionRelativeToBase(float& pageScale) const
1083 for (const GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) {
1084 if (currLayer->appliesPageScale()) {
1085 pageScale = currLayer->pageScaleFactor();
1089 offset += currLayer->position();
1092 return FloatPoint();
1095 void GraphicsLayerCA::flushCompositingState(const FloatRect& clipRect)
1097 TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
1098 FloatQuad coverageQuad(clipRect);
1099 state.setSecondaryQuad(&coverageQuad);
1100 recursiveCommitChanges(CommitState(), state);
1103 void GraphicsLayerCA::flushCompositingStateForThisLayerOnly()
1105 float pageScaleFactor;
1106 bool hadChanges = m_uncommittedChanges;
1108 CommitState commitState;
1110 FloatPoint offset = computePositionRelativeToBase(pageScaleFactor);
1111 commitLayerChangesBeforeSublayers(commitState, pageScaleFactor, offset);
1112 commitLayerChangesAfterSublayers(commitState);
1115 client().didCommitChangesForLayer(this);
1118 static inline bool accumulatesTransform(const GraphicsLayerCA& layer)
1120 return layer.preserves3D() || (layer.parent() && layer.parent()->preserves3D());
1123 bool GraphicsLayerCA::recursiveVisibleRectChangeRequiresFlush(const TransformState& state) const
1125 TransformState localState = state;
1127 // This may be called at times when layout has not been updated, so we want to avoid calling out to the client
1128 // for animating transforms.
1129 VisibleAndCoverageRects rects = computeVisibleAndCoverageRect(localState, accumulatesTransform(*this), 0);
1130 adjustCoverageRect(rects, m_visibleRect);
1132 if (rects.coverageRect != m_coverageRect) {
1133 if (TiledBacking* tiledBacking = this->tiledBacking()) {
1134 if (tiledBacking->tilesWouldChangeForCoverageRect(rects.coverageRect))
1140 GraphicsLayerCA& maskLayerCA = downcast<GraphicsLayerCA>(*m_maskLayer);
1141 if (maskLayerCA.recursiveVisibleRectChangeRequiresFlush(localState))
1145 const Vector<GraphicsLayer*>& childLayers = children();
1146 size_t numChildren = childLayers.size();
1148 for (size_t i = 0; i < numChildren; ++i) {
1149 GraphicsLayerCA& currentChild = downcast<GraphicsLayerCA>(*childLayers[i]);
1150 if (currentChild.recursiveVisibleRectChangeRequiresFlush(localState))
1155 if (downcast<GraphicsLayerCA>(*m_replicaLayer).recursiveVisibleRectChangeRequiresFlush(localState))
1161 bool GraphicsLayerCA::visibleRectChangeRequiresFlush(const FloatRect& clipRect) const
1163 TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
1164 return recursiveVisibleRectChangeRequiresFlush(state);
1167 TiledBacking* GraphicsLayerCA::tiledBacking() const
1169 return m_layer->tiledBacking();
1172 TransformationMatrix GraphicsLayerCA::layerTransform(const FloatPoint& position, const TransformationMatrix* customTransform) const
1174 TransformationMatrix transform;
1175 transform.translate(position.x(), position.y());
1177 TransformationMatrix currentTransform = customTransform ? *customTransform : m_transform;
1179 if (!currentTransform.isIdentity()) {
1180 FloatPoint3D absoluteAnchorPoint(anchorPoint());
1181 absoluteAnchorPoint.scale(size().width(), size().height(), 1);
1182 transform.translate3d(absoluteAnchorPoint.x(), absoluteAnchorPoint.y(), absoluteAnchorPoint.z());
1183 transform.multiply(currentTransform);
1184 transform.translate3d(-absoluteAnchorPoint.x(), -absoluteAnchorPoint.y(), -absoluteAnchorPoint.z());
1187 if (GraphicsLayer* parentLayer = parent()) {
1188 if (!parentLayer->childrenTransform().isIdentity()) {
1189 FloatPoint3D parentAnchorPoint(parentLayer->anchorPoint());
1190 parentAnchorPoint.scale(parentLayer->size().width(), parentLayer->size().height(), 1);
1192 transform.translateRight3d(-parentAnchorPoint.x(), -parentAnchorPoint.y(), -parentAnchorPoint.z());
1193 transform = parentLayer->childrenTransform() * transform;
1194 transform.translateRight3d(parentAnchorPoint.x(), parentAnchorPoint.y(), parentAnchorPoint.z());
1201 GraphicsLayerCA::VisibleAndCoverageRects GraphicsLayerCA::computeVisibleAndCoverageRect(TransformState& state, bool preserves3D, ComputeVisibleRectFlags flags) const
1203 FloatPoint position = m_position;
1204 client().customPositionForVisibleRectComputation(this, position);
1206 TransformationMatrix layerTransform;
1207 TransformationMatrix currentTransform;
1208 if ((flags & RespectAnimatingTransforms) && client().getCurrentTransform(this, currentTransform))
1209 layerTransform = this->layerTransform(position, ¤tTransform);
1211 layerTransform = this->layerTransform(position);
1213 bool applyWasClamped;
1214 TransformState::TransformAccumulation accumulation = preserves3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform;
1215 state.applyTransform(layerTransform, accumulation, &applyWasClamped);
1218 FloatRect clipRectForChildren = state.mappedQuad(&mapWasClamped).boundingBox();
1219 FloatPoint boundsOrigin = m_boundsOrigin;
1221 // In WK1, UIKit may be changing layer bounds behind our back in overflow-scroll layers, so use the layer's origin.
1222 if (m_layer->isPlatformCALayerMac())
1223 boundsOrigin = m_layer->bounds().location();
1225 clipRectForChildren.move(boundsOrigin.x(), boundsOrigin.y());
1227 FloatRect clipRectForSelf(boundsOrigin, m_size);
1228 if (!applyWasClamped && !mapWasClamped)
1229 clipRectForSelf.intersect(clipRectForChildren);
1231 if (masksToBounds()) {
1232 ASSERT(accumulation == TransformState::FlattenTransform);
1233 // Flatten, and replace the quad in the TransformState with one that is clipped to this layer's bounds.
1235 state.setQuad(clipRectForSelf);
1236 if (state.isMappingSecondaryQuad()) {
1237 FloatQuad secondaryQuad(clipRectForSelf);
1238 state.setSecondaryQuad(&secondaryQuad);
1242 FloatRect coverageRect = clipRectForSelf;
1243 std::unique_ptr<FloatQuad> quad = state.mappedSecondaryQuad(&mapWasClamped);
1244 if (quad && !mapWasClamped && !applyWasClamped)
1245 coverageRect = quad->boundingBox();
1247 return VisibleAndCoverageRects(clipRectForSelf, coverageRect);
1250 bool GraphicsLayerCA::adjustCoverageRect(VisibleAndCoverageRects& rects, const FloatRect& oldVisibleRect) const
1252 FloatRect coverageRect = rects.coverageRect;
1254 // FIXME: TileController's computeTileCoverageRect() code should move here, and we should unify these different
1255 // ways of computing coverage.
1257 case Type::PageTiledBacking:
1258 coverageRect = tiledBacking()->computeTileCoverageRect(size(), oldVisibleRect, rects.visibleRect, pageScaleFactor() * deviceScaleFactor());
1261 if (m_layer->layerType() == PlatformCALayer::LayerTypeTiledBackingLayer)
1262 coverageRect.unite(adjustTiledLayerVisibleRect(tiledBacking(), oldVisibleRect, rects.visibleRect, m_sizeAtLastCoverageRectUpdate, m_size));
1268 if (rects.coverageRect == coverageRect)
1271 rects.coverageRect = coverageRect;
1275 void GraphicsLayerCA::setVisibleAndCoverageRects(const VisibleAndCoverageRects& rects, bool allowBackingStoreDetachment)
1277 bool visibleRectChanged = rects.visibleRect != m_visibleRect;
1278 bool coverageRectChanged = rects.coverageRect != m_coverageRect;
1279 if (!visibleRectChanged && !coverageRectChanged)
1282 // FIXME: we need to take reflections into account when determining whether this layer intersects the coverage rect.
1283 bool intersectsCoverageRect = !allowBackingStoreDetachment || rects.coverageRect.intersects(FloatRect(m_boundsOrigin, size()));
1284 if (intersectsCoverageRect != m_intersectsCoverageRect) {
1285 m_uncommittedChanges |= CoverageRectChanged;
1286 m_intersectsCoverageRect = intersectsCoverageRect;
1288 if (GraphicsLayerCA* maskLayer = downcast<GraphicsLayerCA>(m_maskLayer)) {
1289 maskLayer->m_uncommittedChanges |= CoverageRectChanged;
1290 maskLayer->m_intersectsCoverageRect = intersectsCoverageRect;
1294 if (visibleRectChanged) {
1295 m_uncommittedChanges |= CoverageRectChanged;
1296 m_visibleRect = rects.visibleRect;
1298 if (GraphicsLayerCA* maskLayer = downcast<GraphicsLayerCA>(m_maskLayer)) {
1299 // FIXME: this assumes that the mask layer has the same geometry as this layer (which is currently always true).
1300 maskLayer->m_uncommittedChanges |= CoverageRectChanged;
1301 maskLayer->m_visibleRect = rects.visibleRect;
1305 if (coverageRectChanged) {
1306 m_uncommittedChanges |= CoverageRectChanged;
1307 m_coverageRect = rects.coverageRect;
1309 if (GraphicsLayerCA* maskLayer = downcast<GraphicsLayerCA>(m_maskLayer)) {
1310 maskLayer->m_uncommittedChanges |= CoverageRectChanged;
1311 maskLayer->m_coverageRect = rects.coverageRect;
1316 // rootRelativeTransformForScaling is a transform from the root, but for layers with transform animations, it cherry-picked the state of the
1317 // animation that contributes maximally to the scale (on every layer with animations down the hierarchy).
1318 void GraphicsLayerCA::recursiveCommitChanges(const CommitState& commitState, const TransformState& state, float pageScaleFactor, const FloatPoint& positionRelativeToBase, bool affectedByPageScale)
1320 TransformState localState = state;
1321 CommitState childCommitState = commitState;
1322 bool affectedByTransformAnimation = commitState.ancestorHasTransformAnimation;
1324 bool accumulateTransform = accumulatesTransform(*this);
1325 VisibleAndCoverageRects rects = computeVisibleAndCoverageRect(localState, accumulateTransform);
1326 if (adjustCoverageRect(rects, m_visibleRect)) {
1327 if (state.isMappingSecondaryQuad()) {
1328 FloatQuad secondaryQuad(rects.coverageRect);
1329 localState.setLastPlanarSecondaryQuad(&secondaryQuad);
1332 setVisibleAndCoverageRects(rects, m_allowsBackingStoreDetachment && commitState.ancestorsAllowBackingStoreDetachment);
1334 #ifdef VISIBLE_TILE_WASH
1335 // Use having a transform as a key to making the tile wash layer. If every layer gets a wash,
1336 // they start to obscure useful information.
1337 if ((!m_transform.isIdentity() || m_usingTiledBacking) && !m_visibleTileWashLayer) {
1338 static Color washFillColor(255, 0, 0, 50);
1339 static Color washBorderColor(255, 0, 0, 100);
1341 m_visibleTileWashLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
1342 String name = String::format("Visible Tile Wash Layer %p", m_visibleTileWashLayer->platformLayer());
1343 m_visibleTileWashLayer->setName(name);
1344 m_visibleTileWashLayer->setAnchorPoint(FloatPoint3D(0, 0, 0));
1345 m_visibleTileWashLayer->setBorderColor(washBorderColor);
1346 m_visibleTileWashLayer->setBorderWidth(8);
1347 m_visibleTileWashLayer->setBackgroundColor(washFillColor);
1348 noteSublayersChanged(DontScheduleFlush);
1351 if (m_visibleTileWashLayer) {
1352 m_visibleTileWashLayer->setPosition(m_visibleRect.location());
1353 m_visibleTileWashLayer->setBounds(FloatRect(FloatPoint(), m_visibleRect.size()));
1357 bool hadChanges = m_uncommittedChanges;
1359 if (appliesPageScale()) {
1360 pageScaleFactor = this->pageScaleFactor();
1361 affectedByPageScale = true;
1364 // Accumulate an offset from the ancestral pixel-aligned layer.
1365 FloatPoint baseRelativePosition = positionRelativeToBase;
1366 if (affectedByPageScale)
1367 baseRelativePosition += m_position;
1369 commitLayerChangesBeforeSublayers(childCommitState, pageScaleFactor, baseRelativePosition);
1371 if (isRunningTransformAnimation()) {
1372 childCommitState.ancestorHasTransformAnimation = true;
1373 affectedByTransformAnimation = true;
1376 childCommitState.ancestorsAllowBackingStoreDetachment &= m_allowsBackingStoreDetachment;
1378 if (GraphicsLayerCA* maskLayer = downcast<GraphicsLayerCA>(m_maskLayer))
1379 maskLayer->commitLayerChangesBeforeSublayers(childCommitState, pageScaleFactor, baseRelativePosition);
1381 const Vector<GraphicsLayer*>& childLayers = children();
1382 size_t numChildren = childLayers.size();
1384 for (size_t i = 0; i < numChildren; ++i) {
1385 GraphicsLayerCA& currentChild = downcast<GraphicsLayerCA>(*childLayers[i]);
1386 currentChild.recursiveCommitChanges(childCommitState, localState, pageScaleFactor, baseRelativePosition, affectedByPageScale);
1389 if (GraphicsLayerCA* replicaLayer = downcast<GraphicsLayerCA>(m_replicaLayer))
1390 replicaLayer->recursiveCommitChanges(childCommitState, localState, pageScaleFactor, baseRelativePosition, affectedByPageScale);
1392 if (GraphicsLayerCA* maskLayer = downcast<GraphicsLayerCA>(m_maskLayer))
1393 maskLayer->commitLayerChangesAfterSublayers(childCommitState);
1395 commitLayerChangesAfterSublayers(childCommitState);
1397 if (affectedByTransformAnimation && m_layer->layerType() == PlatformCALayer::LayerTypeTiledBackingLayer)
1398 client().notifyFlushBeforeDisplayRefresh(this);
1401 client().didCommitChangesForLayer(this);
1404 bool GraphicsLayerCA::platformCALayerShowRepaintCounter(PlatformCALayer* platformLayer) const
1406 // The repaint counters are painted into the TileController tiles (which have no corresponding platform layer),
1407 // so we don't want to overpaint the repaint counter when called with the TileController's own layer.
1408 if (isPageTiledBackingLayer() && platformLayer)
1411 return isShowingRepaintCounter();
1414 void GraphicsLayerCA::platformCALayerPaintContents(PlatformCALayer*, GraphicsContext& context, const FloatRect& clip)
1416 paintGraphicsLayerContents(context, clip);
1419 void GraphicsLayerCA::platformCALayerSetNeedsToRevalidateTiles()
1421 noteLayerPropertyChanged(TilingAreaChanged, m_isCommittingChanges ? DontScheduleFlush : ScheduleFlush);
1424 float GraphicsLayerCA::platformCALayerDeviceScaleFactor() const
1426 return deviceScaleFactor();
1429 float GraphicsLayerCA::platformCALayerContentsScaleMultiplierForNewTiles(PlatformCALayer*) const
1431 return client().contentsScaleMultiplierForNewTiles(this);
1434 bool GraphicsLayerCA::platformCALayerShouldAggressivelyRetainTiles(PlatformCALayer*) const
1436 return client().shouldAggressivelyRetainTiles(this);
1439 bool GraphicsLayerCA::platformCALayerShouldTemporarilyRetainTileCohorts(PlatformCALayer*) const
1441 return client().shouldTemporarilyRetainTileCohorts(this);
1444 static PlatformCALayer::LayerType layerTypeForCustomBackdropAppearance(GraphicsLayer::CustomAppearance appearance)
1446 return appearance == GraphicsLayer::LightBackdropAppearance ? PlatformCALayer::LayerTypeLightSystemBackdropLayer : PlatformCALayer::LayerTypeDarkSystemBackdropLayer;
1449 static bool isCustomBackdropLayerType(PlatformCALayer::LayerType layerType)
1451 return layerType == PlatformCALayer::LayerTypeLightSystemBackdropLayer || layerType == PlatformCALayer::LayerTypeDarkSystemBackdropLayer;
1454 void GraphicsLayerCA::commitLayerChangesBeforeSublayers(CommitState& commitState, float pageScaleFactor, const FloatPoint& positionRelativeToBase)
1456 TemporaryChange<bool> committingChangesChange(m_isCommittingChanges, true);
1458 ++commitState.treeDepth;
1459 if (m_structuralLayer)
1460 ++commitState.treeDepth;
1462 if (!m_uncommittedChanges) {
1463 // Ensure that we cap layer depth in commitLayerChangesAfterSublayers().
1464 if (commitState.treeDepth > cMaxLayerTreeDepth)
1465 m_uncommittedChanges |= ChildrenChanged;
1468 bool needTiledLayer = requiresTiledLayer(pageScaleFactor);
1469 bool needBackdropLayerType = (customAppearance() == LightBackdropAppearance || customAppearance() == DarkBackdropAppearance);
1470 PlatformCALayer::LayerType neededLayerType = m_layer->layerType();
1472 if (needBackdropLayerType)
1473 neededLayerType = layerTypeForCustomBackdropAppearance(customAppearance());
1474 else if (needTiledLayer)
1475 neededLayerType = PlatformCALayer::LayerTypeTiledBackingLayer;
1476 else if (isCustomBackdropLayerType(m_layer->layerType()) || m_usingTiledBacking)
1477 neededLayerType = PlatformCALayer::LayerTypeWebLayer;
1479 if (neededLayerType != m_layer->layerType())
1480 changeLayerTypeTo(neededLayerType);
1482 // Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to
1483 if (m_uncommittedChanges & (Preserves3DChanged | ReplicatedLayerChanged | BackdropFiltersChanged))
1484 updateStructuralLayer();
1486 if (m_uncommittedChanges & GeometryChanged)
1487 updateGeometry(pageScaleFactor, positionRelativeToBase);
1489 if (m_uncommittedChanges & DrawsContentChanged)
1490 updateDrawsContent();
1492 if (m_uncommittedChanges & NameChanged)
1495 if (m_uncommittedChanges & ContentsImageChanged) // Needs to happen before ChildrenChanged
1496 updateContentsImage();
1498 if (m_uncommittedChanges & ContentsPlatformLayerChanged) // Needs to happen before ChildrenChanged
1499 updateContentsPlatformLayer();
1501 if (m_uncommittedChanges & ContentsColorLayerChanged) // Needs to happen before ChildrenChanged
1502 updateContentsColorLayer();
1504 if (m_uncommittedChanges & BackgroundColorChanged)
1505 updateBackgroundColor();
1507 if (m_uncommittedChanges & TransformChanged)
1510 if (m_uncommittedChanges & ChildrenTransformChanged)
1511 updateChildrenTransform();
1513 if (m_uncommittedChanges & MasksToBoundsChanged)
1514 updateMasksToBounds();
1516 if (m_uncommittedChanges & ContentsVisibilityChanged)
1517 updateContentsVisibility();
1519 // Note that contentsScale can affect whether the layer can be opaque.
1520 if (m_uncommittedChanges & ContentsOpaqueChanged)
1521 updateContentsOpaque(pageScaleFactor);
1523 if (m_uncommittedChanges & BackfaceVisibilityChanged)
1524 updateBackfaceVisibility();
1526 if (m_uncommittedChanges & OpacityChanged)
1527 updateOpacityOnLayer();
1529 if (m_uncommittedChanges & FiltersChanged)
1532 if (m_uncommittedChanges & BackdropFiltersChanged)
1533 updateBackdropFilters();
1535 if (m_uncommittedChanges & BackdropFiltersRectChanged)
1536 updateBackdropFiltersRect();
1538 #if ENABLE(CSS_COMPOSITING)
1539 if (m_uncommittedChanges & BlendModeChanged)
1543 if (m_uncommittedChanges & ShapeChanged)
1546 if (m_uncommittedChanges & WindRuleChanged)
1549 if (m_uncommittedChanges & AnimationChanged)
1552 // Updating the contents scale can cause parts of the layer to be invalidated,
1553 // so make sure to update the contents scale before updating the dirty rects.
1554 if (m_uncommittedChanges & ContentsScaleChanged)
1555 updateContentsScale(pageScaleFactor);
1557 if (m_uncommittedChanges & CoverageRectChanged)
1560 if (m_uncommittedChanges & TilingAreaChanged) // Needs to happen after CoverageRectChanged, ContentsScaleChanged
1563 if (m_uncommittedChanges & DirtyRectsChanged)
1564 repaintLayerDirtyRects();
1566 if (m_uncommittedChanges & ContentsRectsChanged) // Needs to happen before ChildrenChanged
1567 updateContentsRects();
1569 if (m_uncommittedChanges & MasksToBoundsRectChanged) // Needs to happen before ChildrenChanged
1570 updateMasksToBoundsRect();
1572 if (m_uncommittedChanges & MaskLayerChanged) {
1574 // If the mask layer becomes tiled it can set this flag again. Clear the flag so that
1575 // commitLayerChangesAfterSublayers doesn't update the mask again in the normal case.
1576 m_uncommittedChanges &= ~MaskLayerChanged;
1579 if (m_uncommittedChanges & ContentsNeedsDisplay)
1580 updateContentsNeedsDisplay();
1582 if (m_uncommittedChanges & AcceleratesDrawingChanged)
1583 updateAcceleratesDrawing();
1585 if (m_uncommittedChanges & DebugIndicatorsChanged)
1586 updateDebugBorder();
1588 if (m_uncommittedChanges & CustomAppearanceChanged)
1589 updateCustomAppearance();
1591 if (m_uncommittedChanges & ChildrenChanged) {
1592 updateSublayerList();
1593 // Sublayers may set this flag again, so clear it to avoid always updating sublayers in commitLayerChangesAfterSublayers().
1594 m_uncommittedChanges &= ~ChildrenChanged;
1597 // Ensure that we cap layer depth in commitLayerChangesAfterSublayers().
1598 if (commitState.treeDepth > cMaxLayerTreeDepth)
1599 m_uncommittedChanges |= ChildrenChanged;
1602 void GraphicsLayerCA::commitLayerChangesAfterSublayers(CommitState& commitState)
1604 if (!m_uncommittedChanges)
1607 TemporaryChange<bool> committingChangesChange(m_isCommittingChanges, true);
1609 if (m_uncommittedChanges & MaskLayerChanged)
1612 if (m_uncommittedChanges & ChildrenChanged)
1613 updateSublayerList(commitState.treeDepth > cMaxLayerTreeDepth);
1615 if (m_uncommittedChanges & ReplicatedLayerChanged)
1616 updateReplicatedLayers();
1618 m_uncommittedChanges = NoChange;
1621 void GraphicsLayerCA::updateNames()
1623 switch (structuralLayerPurpose()) {
1624 case StructuralLayerForPreserves3D:
1625 m_structuralLayer->setName("Transform layer " + name());
1627 case StructuralLayerForReplicaFlattening:
1628 m_structuralLayer->setName("Replica flattening layer " + name());
1630 case StructuralLayerForBackdrop:
1631 m_structuralLayer->setName("Backdrop hosting layer " + name());
1633 case NoStructuralLayer:
1636 m_layer->setName(name());
1639 void GraphicsLayerCA::updateSublayerList(bool maxLayerDepthReached)
1641 if (maxLayerDepthReached) {
1642 m_layer->setSublayers(PlatformCALayerList());
1646 const PlatformCALayerList* customSublayers = m_layer->customSublayers();
1648 PlatformCALayerList structuralLayerChildren;
1649 PlatformCALayerList primaryLayerChildren;
1651 PlatformCALayerList& childListForSublayers = m_structuralLayer ? structuralLayerChildren : primaryLayerChildren;
1653 if (customSublayers)
1654 primaryLayerChildren.appendVector(*customSublayers);
1656 if (m_structuralLayer) {
1657 if (m_backdropLayer)
1658 structuralLayerChildren.append(m_backdropLayer);
1661 structuralLayerChildren.append(downcast<GraphicsLayerCA>(*m_replicaLayer).primaryLayer());
1663 structuralLayerChildren.append(m_layer);
1666 if (m_contentsLayer && m_contentsVisible) {
1667 // FIXME: add the contents layer in the correct order with negative z-order children.
1668 // This does not cause visible rendering issues because currently contents layers are only used
1669 // for replaced elements that don't have children.
1670 primaryLayerChildren.append(m_contentsClippingLayer ? m_contentsClippingLayer : m_contentsLayer);
1673 const Vector<GraphicsLayer*>& childLayers = children();
1674 size_t numChildren = childLayers.size();
1675 for (size_t i = 0; i < numChildren; ++i) {
1676 GraphicsLayerCA& currentChild = downcast<GraphicsLayerCA>(*childLayers[i]);
1677 PlatformCALayer* childLayer = currentChild.layerForSuperlayer();
1678 childListForSublayers.append(childLayer);
1681 #ifdef VISIBLE_TILE_WASH
1682 if (m_visibleTileWashLayer)
1683 childListForSublayers.append(m_visibleTileWashLayer);
1686 if (m_structuralLayer)
1687 m_structuralLayer->setSublayers(structuralLayerChildren);
1689 m_layer->setSublayers(primaryLayerChildren);
1692 void GraphicsLayerCA::updateGeometry(float pageScaleFactor, const FloatPoint& positionRelativeToBase)
1694 FloatPoint scaledPosition = m_position;
1695 FloatPoint3D scaledAnchorPoint = m_anchorPoint;
1696 FloatSize scaledSize = m_size;
1697 FloatSize pixelAlignmentOffset;
1699 // FIXME: figure out if we really need to pixel align the graphics layer here.
1700 if (m_client.needsPixelAligment() && !WTF::isIntegral(pageScaleFactor) && m_drawsContent && !m_masksToBounds)
1701 computePixelAlignment(pageScaleFactor, positionRelativeToBase, scaledPosition, scaledAnchorPoint, pixelAlignmentOffset);
1704 // Position is offset on the layer by the layer anchor point.
1705 FloatPoint adjustedPosition(scaledPosition.x() + scaledAnchorPoint.x() * scaledSize.width(), scaledPosition.y() + scaledAnchorPoint.y() * scaledSize.height());
1707 if (m_structuralLayer) {
1708 FloatPoint layerPosition(m_position.x() + m_anchorPoint.x() * m_size.width(), m_position.y() + m_anchorPoint.y() * m_size.height());
1709 FloatRect layerBounds(m_boundsOrigin, m_size);
1711 m_structuralLayer->setPosition(layerPosition);
1712 m_structuralLayer->setBounds(layerBounds);
1713 m_structuralLayer->setAnchorPoint(m_anchorPoint);
1715 if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) {
1716 for (auto& clone : *layerCloneMap) {
1717 PlatformCALayer* cloneLayer = clone.value.get();
1718 FloatPoint clonePosition = layerPosition;
1720 if (m_replicaLayer && isReplicatedRootClone(clone.key)) {
1721 // Maintain the special-case position for the root of a clone subtree,
1722 // which we set up in replicatedLayerRoot().
1723 clonePosition = positionForCloneRootLayer();
1726 cloneLayer->setPosition(clonePosition);
1727 cloneLayer->setBounds(layerBounds);
1728 cloneLayer->setAnchorPoint(m_anchorPoint);
1732 // If we have a structural layer, we just use 0.5, 0.5 for the anchor point of the main layer.
1733 scaledAnchorPoint = FloatPoint(0.5f, 0.5f);
1734 adjustedPosition = FloatPoint(scaledAnchorPoint.x() * scaledSize.width() - pixelAlignmentOffset.width(), scaledAnchorPoint.y() * scaledSize.height() - pixelAlignmentOffset.height());
1737 m_pixelAlignmentOffset = pixelAlignmentOffset;
1739 // Push the layer to device pixel boundary (setPosition()), but move the content back to its original position (setBounds())
1740 m_layer->setPosition(adjustedPosition);
1741 FloatRect adjustedBounds = FloatRect(FloatPoint(m_boundsOrigin - pixelAlignmentOffset), m_size);
1742 m_layer->setBounds(adjustedBounds);
1743 m_layer->setAnchorPoint(scaledAnchorPoint);
1745 if (LayerMap* layerCloneMap = m_layerClones.get()) {
1746 for (auto& clone : *layerCloneMap) {
1747 PlatformCALayer* cloneLayer = clone.value.get();
1748 FloatPoint clonePosition = adjustedPosition;
1750 if (!m_structuralLayer && m_replicaLayer && isReplicatedRootClone(clone.key)) {
1751 // Maintain the special-case position for the root of a clone subtree,
1752 // which we set up in replicatedLayerRoot().
1753 clonePosition = positionForCloneRootLayer();
1756 cloneLayer->setPosition(clonePosition);
1757 cloneLayer->setBounds(adjustedBounds);
1758 cloneLayer->setAnchorPoint(scaledAnchorPoint);
1763 void GraphicsLayerCA::updateTransform()
1765 primaryLayer()->setTransform(m_transform);
1767 if (LayerMap* layerCloneMap = primaryLayerClones()) {
1768 for (auto& clone : *layerCloneMap) {
1769 PlatformCALayer* currLayer = clone.value.get();
1770 if (m_replicaLayer && isReplicatedRootClone(clone.key)) {
1771 // Maintain the special-case transform for the root of a clone subtree,
1772 // which we set up in replicatedLayerRoot().
1773 currLayer->setTransform(TransformationMatrix());
1775 currLayer->setTransform(m_transform);
1780 void GraphicsLayerCA::updateChildrenTransform()
1782 primaryLayer()->setSublayerTransform(m_childrenTransform);
1784 if (LayerMap* layerCloneMap = primaryLayerClones()) {
1785 for (auto & layer : layerCloneMap->values())
1786 layer->setSublayerTransform(m_childrenTransform);
1790 void GraphicsLayerCA::updateMasksToBounds()
1792 m_layer->setMasksToBounds(m_masksToBounds);
1794 if (LayerMap* layerCloneMap = m_layerClones.get()) {
1795 for (auto & layer : layerCloneMap->values())
1796 layer->setMasksToBounds(m_masksToBounds);
1800 void GraphicsLayerCA::updateContentsVisibility()
1802 // Note that m_contentsVisible also affects whether m_contentsLayer is parented.
1803 if (m_contentsVisible) {
1805 m_layer->setNeedsDisplay();
1807 m_layer->setContents(nullptr);
1809 if (LayerMap* layerCloneMap = m_layerClones.get()) {
1810 for (auto & layer : layerCloneMap->values())
1811 layer->setContents(nullptr);
1816 void GraphicsLayerCA::updateContentsOpaque(float pageScaleFactor)
1818 bool contentsOpaque = m_contentsOpaque;
1819 if (contentsOpaque) {
1820 float contentsScale = pageScaleFactor * deviceScaleFactor();
1821 if (!WTF::isIntegral(contentsScale) && !m_client.paintsOpaquelyAtNonIntegralScales(this))
1822 contentsOpaque = false;
1825 m_layer->setOpaque(contentsOpaque);
1827 if (LayerMap* layerCloneMap = m_layerClones.get()) {
1828 for (auto & layer : layerCloneMap->values())
1829 layer->setOpaque(contentsOpaque);
1833 void GraphicsLayerCA::updateBackfaceVisibility()
1835 if (m_structuralLayer && structuralLayerPurpose() == StructuralLayerForReplicaFlattening) {
1836 m_structuralLayer->setDoubleSided(m_backfaceVisibility);
1838 if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) {
1839 for (auto& layer : layerCloneMap->values())
1840 layer->setDoubleSided(m_backfaceVisibility);
1844 m_layer->setDoubleSided(m_backfaceVisibility);
1846 if (LayerMap* layerCloneMap = m_layerClones.get()) {
1847 for (auto& layer : layerCloneMap->values())
1848 layer->setDoubleSided(m_backfaceVisibility);
1852 void GraphicsLayerCA::updateFilters()
1854 m_layer->setFilters(m_filters);
1856 if (LayerMap* layerCloneMap = m_layerClones.get()) {
1857 for (auto& clone : *layerCloneMap) {
1858 if (m_replicaLayer && isReplicatedRootClone(clone.key))
1861 clone.value->setFilters(m_filters);
1866 void GraphicsLayerCA::updateBackdropFilters()
1868 if (m_backdropFilters.isEmpty()) {
1869 if (m_backdropLayer) {
1870 m_backdropLayer->removeFromSuperlayer();
1871 m_backdropLayer->setOwner(nullptr);
1872 m_backdropLayer = nullptr;
1877 if (!m_backdropLayer) {
1878 m_backdropLayer = createPlatformCALayer(PlatformCALayer::LayerTypeBackdropLayer, this);
1879 m_backdropLayer->setAnchorPoint(FloatPoint3D());
1880 m_backdropLayer->setMasksToBounds(true);
1882 m_backdropLayer->setFilters(m_backdropFilters);
1885 void GraphicsLayerCA::updateBackdropFiltersRect()
1887 if (!m_backdropLayer)
1889 FloatRect contentBounds(0, 0, m_backdropFiltersRect.width(), m_backdropFiltersRect.height());
1890 m_backdropLayer->setBounds(contentBounds);
1891 m_backdropLayer->setPosition(m_backdropFiltersRect.location());
1894 #if ENABLE(CSS_COMPOSITING)
1895 void GraphicsLayerCA::updateBlendMode()
1897 primaryLayer()->setBlendMode(m_blendMode);
1899 if (LayerMap* layerCloneMap = primaryLayerClones()) {
1900 for (auto& clone : *layerCloneMap) {
1901 if (m_replicaLayer && isReplicatedRootClone(clone.key))
1903 clone.value->setBlendMode(m_blendMode);
1909 void GraphicsLayerCA::updateShape()
1911 m_layer->setShapePath(m_shapeLayerPath);
1914 void GraphicsLayerCA::updateWindRule()
1916 m_layer->setShapeWindRule(m_shapeLayerWindRule);
1919 void GraphicsLayerCA::updateStructuralLayer()
1921 ensureStructuralLayer(structuralLayerPurpose());
1924 void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose)
1926 const LayerChangeFlags structuralLayerChangeFlags = NameChanged
1929 | ChildrenTransformChanged
1931 | BackfaceVisibilityChanged
1933 | BackdropFiltersChanged
1936 if (purpose == NoStructuralLayer) {
1937 if (m_structuralLayer) {
1938 // Replace the transformLayer in the parent with this layer.
1939 m_layer->removeFromSuperlayer();
1941 // If m_layer doesn't have a parent, it means it's the root layer and
1942 // is likely hosted by something that is not expecting to be changed
1943 ASSERT(m_structuralLayer->superlayer());
1944 m_structuralLayer->superlayer()->replaceSublayer(*m_structuralLayer, *m_layer);
1946 moveAnimations(m_structuralLayer.get(), m_layer.get());
1948 // Release the structural layer.
1949 m_structuralLayer = nullptr;
1951 m_uncommittedChanges |= structuralLayerChangeFlags;
1956 bool structuralLayerChanged = false;
1958 if (purpose == StructuralLayerForPreserves3D) {
1959 if (m_structuralLayer && m_structuralLayer->layerType() != PlatformCALayer::LayerTypeTransformLayer)
1960 m_structuralLayer = nullptr;
1962 if (!m_structuralLayer) {
1963 m_structuralLayer = createPlatformCALayer(PlatformCALayer::LayerTypeTransformLayer, this);
1964 structuralLayerChanged = true;
1967 if (m_structuralLayer && m_structuralLayer->layerType() != PlatformCALayer::LayerTypeLayer)
1968 m_structuralLayer = nullptr;
1970 if (!m_structuralLayer) {
1971 m_structuralLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
1972 structuralLayerChanged = true;
1976 if (!structuralLayerChanged)
1979 m_uncommittedChanges |= structuralLayerChangeFlags;
1981 // We've changed the layer that our parent added to its sublayer list, so tell it to update
1982 // sublayers again in its commitLayerChangesAfterSublayers().
1983 downcast<GraphicsLayerCA>(*parent()).noteSublayersChanged(DontScheduleFlush);
1985 // Set properties of m_layer to their default values, since these are expressed on on the structural layer.
1986 FloatPoint point(m_size.width() / 2.0f, m_size.height() / 2.0f);
1987 FloatPoint3D anchorPoint(0.5f, 0.5f, 0);
1988 m_layer->setPosition(point);
1989 m_layer->setAnchorPoint(anchorPoint);
1990 m_layer->setTransform(TransformationMatrix());
1991 m_layer->setOpacity(1);
1992 if (m_layerClones) {
1993 LayerMap::const_iterator end = m_layerClones->end();
1994 for (LayerMap::const_iterator it = m_layerClones->begin(); it != end; ++it) {
1995 PlatformCALayer* currLayer = it->value.get();
1996 currLayer->setPosition(point);
1997 currLayer->setAnchorPoint(anchorPoint);
1998 currLayer->setTransform(TransformationMatrix());
1999 currLayer->setOpacity(1);
2003 moveAnimations(m_layer.get(), m_structuralLayer.get());
2006 GraphicsLayerCA::StructuralLayerPurpose GraphicsLayerCA::structuralLayerPurpose() const
2009 return StructuralLayerForPreserves3D;
2012 return StructuralLayerForReplicaFlattening;
2014 if (needsBackdrop())
2015 return StructuralLayerForBackdrop;
2017 return NoStructuralLayer;
2020 void GraphicsLayerCA::updateDrawsContent()
2023 m_layer->setNeedsDisplay();
2025 m_layer->setContents(0);
2026 if (m_layerClones) {
2027 LayerMap::const_iterator end = m_layerClones->end();
2028 for (LayerMap::const_iterator it = m_layerClones->begin(); it != end; ++it)
2029 it->value->setContents(0);
2034 void GraphicsLayerCA::updateCoverage()
2036 // FIXME: Need to set coverage on clone layers too.
2037 if (TiledBacking* backing = tiledBacking()) {
2038 backing->setVisibleRect(m_visibleRect);
2039 backing->setCoverageRect(m_coverageRect);
2042 m_layer->setBackingStoreAttached(m_intersectsCoverageRect);
2043 if (m_layerClones) {
2044 LayerMap::const_iterator end = m_layerClones->end();
2045 for (LayerMap::const_iterator it = m_layerClones->begin(); it != end; ++it)
2046 it->value->setBackingStoreAttached(m_intersectsCoverageRect);
2049 m_sizeAtLastCoverageRectUpdate = m_size;
2052 void GraphicsLayerCA::updateAcceleratesDrawing()
2054 m_layer->setAcceleratesDrawing(m_acceleratesDrawing);
2057 static void setLayerDebugBorder(PlatformCALayer& layer, Color borderColor, float borderWidth)
2059 layer.setBorderColor(borderColor);
2060 layer.setBorderWidth(borderColor.isValid() ? borderWidth : 0);
2063 static const float contentsLayerBorderWidth = 4;
2064 static Color contentsLayerDebugBorderColor(bool showingBorders)
2066 return showingBorders ? Color(0, 0, 128, 180) : Color();
2069 static const float cloneLayerBorderWidth = 2;
2070 static Color cloneLayerDebugBorderColor(bool showingBorders)
2072 return showingBorders ? Color(255, 122, 251) : Color();
2075 void GraphicsLayerCA::updateDebugBorder()
2080 bool showDebugBorders = isShowingDebugBorder();
2081 if (showDebugBorders)
2082 getDebugBorderInfo(borderColor, width);
2084 setLayerDebugBorder(*m_layer, borderColor, width);
2085 if (m_contentsLayer)
2086 setLayerDebugBorder(*m_contentsLayer, contentsLayerDebugBorderColor(showDebugBorders), contentsLayerBorderWidth);
2088 if (m_layerClones) {
2089 for (auto& clone : m_layerClones->values())
2090 setLayerDebugBorder(*clone, borderColor, width);
2093 if (m_structuralLayerClones) {
2094 Color cloneLayerBorderColor = cloneLayerDebugBorderColor(showDebugBorders);
2095 for (auto& clone : m_structuralLayerClones->values())
2096 setLayerDebugBorder(*clone, cloneLayerBorderColor, cloneLayerBorderWidth);
2099 if (m_contentsLayerClones) {
2100 Color contentsLayerBorderColor = contentsLayerDebugBorderColor(showDebugBorders);
2101 for (auto& contentsLayerClone : m_contentsLayerClones->values())
2102 setLayerDebugBorder(*contentsLayerClone, contentsLayerBorderColor, contentsLayerBorderWidth);
2106 FloatRect GraphicsLayerCA::adjustTiledLayerVisibleRect(TiledBacking* tiledBacking, const FloatRect& oldVisibleRect, const FloatRect& newVisibleRect, const FloatSize& oldSize, const FloatSize& newSize)
2108 // If the old visible rect is empty, we have no information about how the visible area is changing
2109 // (maybe the layer was just created), so don't attempt to expand. Also don't attempt to expand
2110 // if the size changed or the rects don't overlap.
2111 if (oldVisibleRect.isEmpty() || newSize != oldSize || !newVisibleRect.intersects(oldVisibleRect))
2112 return newVisibleRect;
2114 const float paddingMultiplier = 2;
2116 float leftEdgeDelta = paddingMultiplier * (newVisibleRect.x() - oldVisibleRect.x());
2117 float rightEdgeDelta = paddingMultiplier * (newVisibleRect.maxX() - oldVisibleRect.maxX());
2119 float topEdgeDelta = paddingMultiplier * (newVisibleRect.y() - oldVisibleRect.y());
2120 float bottomEdgeDelta = paddingMultiplier * (newVisibleRect.maxY() - oldVisibleRect.maxY());
2122 FloatRect existingTileBackingRect = tiledBacking->visibleRect();
2123 FloatRect expandedRect = newVisibleRect;
2125 // More exposed on left side.
2126 if (leftEdgeDelta < 0) {
2127 float newLeft = expandedRect.x() + leftEdgeDelta;
2128 // Pad to the left, but don't reduce padding that's already in the backing store (since we're still exposing to the left).
2129 if (newLeft < existingTileBackingRect.x())
2130 expandedRect.shiftXEdgeTo(newLeft);
2132 expandedRect.shiftXEdgeTo(existingTileBackingRect.x());
2135 // More exposed on right.
2136 if (rightEdgeDelta > 0) {
2137 float newRight = expandedRect.maxX() + rightEdgeDelta;
2138 // Pad to the right, but don't reduce padding that's already in the backing store (since we're still exposing to the right).
2139 if (newRight > existingTileBackingRect.maxX())
2140 expandedRect.setWidth(newRight - expandedRect.x());
2142 expandedRect.setWidth(existingTileBackingRect.maxX() - expandedRect.x());
2145 // More exposed at top.
2146 if (topEdgeDelta < 0) {
2147 float newTop = expandedRect.y() + topEdgeDelta;
2148 if (newTop < existingTileBackingRect.y())
2149 expandedRect.shiftYEdgeTo(newTop);
2151 expandedRect.shiftYEdgeTo(existingTileBackingRect.y());
2154 // More exposed on bottom.
2155 if (bottomEdgeDelta > 0) {
2156 float newBottom = expandedRect.maxY() + bottomEdgeDelta;
2157 if (newBottom > existingTileBackingRect.maxY())
2158 expandedRect.setHeight(newBottom - expandedRect.y());
2160 expandedRect.setHeight(existingTileBackingRect.maxY() - expandedRect.y());
2163 expandedRect.intersect(tiledBacking->boundsWithoutMargin());
2164 return expandedRect;
2167 void GraphicsLayerCA::updateTiles()
2169 if (!m_layer->usesTiledBackingLayer())
2172 tiledBacking()->revalidateTiles();
2175 void GraphicsLayerCA::updateBackgroundColor()
2177 m_layer->setBackgroundColor(m_backgroundColor);
2180 void GraphicsLayerCA::updateContentsImage()
2182 if (m_pendingContentsImage) {
2183 if (!m_contentsLayer.get()) {
2184 m_contentsLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
2186 m_contentsLayer->setName(String::format("Image Layer %llu", m_contentsLayer->layerID()));
2188 setupContentsLayer(m_contentsLayer.get());
2189 // m_contentsLayer will be parented by updateSublayerList
2192 // FIXME: maybe only do trilinear if the image is being scaled down,
2193 // but then what if the layer size changes?
2194 m_contentsLayer->setMinificationFilter(PlatformCALayer::Trilinear);
2195 m_contentsLayer->setContents(m_pendingContentsImage.get());
2196 m_pendingContentsImage = 0;
2198 if (m_contentsLayerClones) {
2199 LayerMap::const_iterator end = m_contentsLayerClones->end();
2200 for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it)
2201 it->value->setContents(m_contentsLayer->contents());
2204 updateContentsRects();
2207 // m_contentsLayer will be removed via updateSublayerList.
2208 m_contentsLayer = 0;
2212 void GraphicsLayerCA::updateContentsPlatformLayer()
2214 if (!m_contentsLayer)
2217 // Platform layer was set as m_contentsLayer, and will get parented in updateSublayerList().
2218 setupContentsLayer(m_contentsLayer.get());
2220 if (m_contentsLayerPurpose == ContentsLayerForCanvas)
2221 m_contentsLayer->setNeedsDisplay();
2223 updateContentsRects();
2226 void GraphicsLayerCA::updateContentsColorLayer()
2228 // Color layer was set as m_contentsLayer, and will get parented in updateSublayerList().
2229 if (!m_contentsLayer || m_contentsLayerPurpose != ContentsLayerForBackgroundColor)
2232 setupContentsLayer(m_contentsLayer.get());
2233 updateContentsRects();
2234 ASSERT(m_contentsSolidColor.isValid());
2235 m_contentsLayer->setBackgroundColor(m_contentsSolidColor);
2237 if (m_contentsLayerClones) {
2238 LayerMap::const_iterator end = m_contentsLayerClones->end();
2239 for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it)
2240 it->value->setBackgroundColor(m_contentsSolidColor);
2244 // The clipping strategy depends on whether the rounded rect has equal corner radii.
2245 void GraphicsLayerCA::updateClippingStrategy(PlatformCALayer& clippingLayer, RefPtr<PlatformCALayer>& shapeMaskLayer, const FloatRoundedRect& roundedRect)
2247 if (roundedRect.radii().isUniformCornerRadius()) {
2248 clippingLayer.setMask(nullptr);
2249 if (shapeMaskLayer) {
2250 shapeMaskLayer->setOwner(nullptr);
2251 shapeMaskLayer = nullptr;
2254 clippingLayer.setMasksToBounds(true);
2255 clippingLayer.setCornerRadius(roundedRect.radii().topLeft().width());
2259 if (!shapeMaskLayer) {
2260 shapeMaskLayer = createPlatformCALayer(PlatformCALayer::LayerTypeShapeLayer, this);
2261 shapeMaskLayer->setAnchorPoint(FloatPoint3D());
2264 shapeMaskLayer->setPosition(FloatPoint());
2265 shapeMaskLayer->setBounds(clippingLayer.bounds());
2267 clippingLayer.setCornerRadius(0);
2268 clippingLayer.setMask(shapeMaskLayer.get());
2270 FloatRoundedRect offsetRoundedRect(clippingLayer.bounds(), roundedRect.radii());
2271 shapeMaskLayer->setShapeRoundedRect(offsetRoundedRect);
2274 void GraphicsLayerCA::updateContentsRects()
2276 if (!m_contentsLayer)
2279 FloatPoint contentOrigin;
2280 const FloatRect contentBounds(0, 0, m_contentsRect.width(), m_contentsRect.height());
2282 FloatPoint clippingOrigin(m_contentsClippingRect.rect().location());
2283 FloatRect clippingBounds(FloatPoint(), m_contentsClippingRect.rect().size());
2285 bool gainedOrLostClippingLayer = false;
2286 if (m_contentsClippingRect.isRounded() || !m_contentsClippingRect.rect().contains(m_contentsRect)) {
2287 if (!m_contentsClippingLayer) {
2288 m_contentsClippingLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
2289 m_contentsClippingLayer->setAnchorPoint(FloatPoint());
2291 m_contentsClippingLayer->setName(String::format("Contents Clipping Layer %llu", m_contentsClippingLayer->layerID()));
2293 gainedOrLostClippingLayer = true;
2296 m_contentsClippingLayer->setPosition(clippingOrigin);
2297 m_contentsClippingLayer->setBounds(clippingBounds);
2299 updateClippingStrategy(*m_contentsClippingLayer, m_contentsShapeMaskLayer, m_contentsClippingRect);
2301 if (gainedOrLostClippingLayer) {
2302 m_contentsLayer->removeFromSuperlayer();
2303 m_contentsClippingLayer->appendSublayer(*m_contentsLayer);
2306 contentOrigin = FloatPoint(m_contentsRect.location() - m_contentsClippingRect.rect().location());
2308 if (m_contentsClippingLayer) {
2309 m_contentsLayer->removeFromSuperlayer();
2311 m_contentsClippingLayer->removeFromSuperlayer();
2312 m_contentsClippingLayer->setOwner(nullptr);
2313 m_contentsClippingLayer->setMask(nullptr);
2314 m_contentsClippingLayer = nullptr;
2315 gainedOrLostClippingLayer = true;
2318 if (m_contentsShapeMaskLayer) {
2319 m_contentsShapeMaskLayer->setOwner(nullptr);
2320 m_contentsShapeMaskLayer = nullptr;
2323 contentOrigin = m_contentsRect.location();
2326 if (gainedOrLostClippingLayer)
2327 noteSublayersChanged(DontScheduleFlush);
2329 m_contentsLayer->setPosition(contentOrigin);
2330 m_contentsLayer->setBounds(contentBounds);
2332 if (m_contentsLayerClones) {
2333 for (auto& layer : m_contentsLayerClones->values()) {
2334 layer->setPosition(contentOrigin);
2335 layer->setBounds(contentBounds);
2339 if (m_contentsClippingLayerClones) {
2340 if (!m_contentsShapeMaskLayerClones && m_contentsShapeMaskLayer)
2341 m_contentsShapeMaskLayerClones = std::make_unique<LayerMap>();
2343 for (auto& clone : *m_contentsClippingLayerClones) {
2344 CloneID cloneID = clone.key;
2345 RefPtr<PlatformCALayer> shapeMaskLayerClone;
2346 if (m_contentsShapeMaskLayerClones)
2347 shapeMaskLayerClone = m_contentsShapeMaskLayerClones->get(cloneID);
2349 bool hadShapeMask = shapeMaskLayerClone;
2350 updateClippingStrategy(*clone.value, shapeMaskLayerClone, m_contentsClippingRect);
2352 if (!shapeMaskLayerClone && m_contentsShapeMaskLayerClones)
2353 m_contentsShapeMaskLayerClones->remove(cloneID);
2354 else if (shapeMaskLayerClone && !hadShapeMask)
2355 m_contentsShapeMaskLayerClones->add(cloneID, shapeMaskLayerClone);
2360 void GraphicsLayerCA::updateMasksToBoundsRect()
2362 updateClippingStrategy(*m_layer, m_shapeMaskLayer, m_masksToBoundsRect);
2364 if (m_layerClones) {
2365 for (auto& clone : *m_layerClones) {
2366 CloneID cloneID = clone.key;
2367 RefPtr<PlatformCALayer> shapeMaskLayerClone;
2368 if (m_shapeMaskLayerClones)
2369 shapeMaskLayerClone = m_shapeMaskLayerClones->get(cloneID);
2371 bool hadShapeMask = shapeMaskLayerClone;
2372 updateClippingStrategy(*clone.value, shapeMaskLayerClone, m_masksToBoundsRect);
2374 if (!shapeMaskLayerClone && m_shapeMaskLayerClones)
2375 m_shapeMaskLayerClones->remove(cloneID);
2376 else if (shapeMaskLayerClone && !hadShapeMask)
2377 m_shapeMaskLayerClones->add(cloneID, shapeMaskLayerClone);
2382 void GraphicsLayerCA::updateMaskLayer()
2384 PlatformCALayer* maskCALayer = m_maskLayer ? downcast<GraphicsLayerCA>(*m_maskLayer).primaryLayer() : nullptr;
2385 m_layer->setMask(maskCALayer);
2387 LayerMap* maskLayerCloneMap = m_maskLayer ? downcast<GraphicsLayerCA>(*m_maskLayer).primaryLayerClones() : nullptr;
2389 if (LayerMap* layerCloneMap = m_layerClones.get()) {
2390 for (auto& clone : *layerCloneMap) {
2391 PlatformCALayer* maskClone = maskLayerCloneMap ? maskLayerCloneMap->get(clone.key) : nullptr;
2392 clone.value->setMask(maskClone);
2397 void GraphicsLayerCA::updateReplicatedLayers()
2399 // Clone the descendants of the replicated layer, and parent under us.
2400 ReplicaState replicaState(ReplicaState::ReplicaBranch);
2402 RefPtr<PlatformCALayer>replicaRoot = replicatedLayerRoot(replicaState);
2406 if (m_structuralLayer)
2407 m_structuralLayer->insertSublayer(*replicaRoot, 0);
2409 m_layer->insertSublayer(*replicaRoot, 0);
2412 // For now, this assumes that layers only ever have one replica, so replicaIndices contains only 0 and 1.
2413 GraphicsLayerCA::CloneID GraphicsLayerCA::ReplicaState::cloneID() const
2415 size_t depth = m_replicaBranches.size();
2417 const size_t bitsPerUChar = sizeof(UChar) * 8;
2418 size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar;
2420 Vector<UChar> result(vectorSize);
2423 // Create a string from the bit sequence which we can use to identify the clone.
2424 // Note that the string may contain embedded nulls, but that's OK.
2425 for (size_t i = 0; i < depth; ++i) {
2426 UChar& currChar = result[i / bitsPerUChar];
2427 currChar = (currChar << 1) | m_replicaBranches[i];
2430 return String::adopt(result);
2433 PassRefPtr<PlatformCALayer> GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState)
2435 // Limit replica nesting, to avoid 2^N explosion of replica layers.
2436 if (!m_replicatedLayer || replicaState.replicaDepth() == ReplicaState::maxReplicaDepth)
2439 GraphicsLayerCA& replicatedLayer = downcast<GraphicsLayerCA>(*m_replicatedLayer);
2441 RefPtr<PlatformCALayer> clonedLayerRoot = replicatedLayer.fetchCloneLayers(this, replicaState, RootCloneLevel);
2442 FloatPoint cloneRootPosition = replicatedLayer.positionForCloneRootLayer();
2444 // Replica root has no offset or transform
2445 clonedLayerRoot->setPosition(cloneRootPosition);
2446 clonedLayerRoot->setTransform(TransformationMatrix());
2448 return clonedLayerRoot;
2451 void GraphicsLayerCA::updateAnimations()
2453 if (m_animationsToProcess.size()) {
2454 AnimationsToProcessMap::const_iterator end = m_animationsToProcess.end();
2455 for (AnimationsToProcessMap::const_iterator it = m_animationsToProcess.begin(); it != end; ++it) {
2456 const String& currAnimationName = it->key;
2457 AnimationsMap::iterator animationIt = m_runningAnimations.find(currAnimationName);
2458 if (animationIt == m_runningAnimations.end())
2461 const AnimationProcessingAction& processingInfo = it->value;
2462 const Vector<LayerPropertyAnimation>& animations = animationIt->value;
2463 for (size_t i = 0; i < animations.size(); ++i) {
2464 const LayerPropertyAnimation& currAnimation = animations[i];
2465 switch (processingInfo.action) {
2467 removeCAAnimationFromLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, currAnimation.m_subIndex);
2470 pauseCAAnimationOnLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, currAnimation.m_subIndex, processingInfo.timeOffset);
2475 if (processingInfo.action == Remove)
2476 m_runningAnimations.remove(currAnimationName);
2479 m_animationsToProcess.clear();
2482 size_t numAnimations;
2483 if ((numAnimations = m_uncomittedAnimations.size())) {
2484 for (size_t i = 0; i < numAnimations; ++i) {
2485 const LayerPropertyAnimation& pendingAnimation = m_uncomittedAnimations[i];
2486 setAnimationOnLayer(*pendingAnimation.m_animation, pendingAnimation.m_property, pendingAnimation.m_name, pendingAnimation.m_index, pendingAnimation.m_subIndex, pendingAnimation.m_timeOffset);
2488 AnimationsMap::iterator it = m_runningAnimations.find(pendingAnimation.m_name);
2489 if (it == m_runningAnimations.end()) {
2490 Vector<LayerPropertyAnimation> animations;
2491 animations.append(pendingAnimation);
2492 m_runningAnimations.add(pendingAnimation.m_name, animations);
2494 Vector<LayerPropertyAnimation>& animations = it->value;
2495 animations.append(pendingAnimation);
2498 m_uncomittedAnimations.clear();
2502 bool GraphicsLayerCA::isRunningTransformAnimation() const
2504 AnimationsMap::const_iterator end = m_runningAnimations.end();
2505 for (AnimationsMap::const_iterator it = m_runningAnimations.begin(); it != end; ++it) {
2506 const Vector<LayerPropertyAnimation>& propertyAnimations = it->value;
2507 size_t numAnimations = propertyAnimations.size();
2508 for (size_t i = 0; i < numAnimations; ++i) {
2509 const LayerPropertyAnimation& currAnimation = propertyAnimations[i];
2510 if (currAnimation.m_property == AnimatedPropertyTransform)
2517 void GraphicsLayerCA::setAnimationOnLayer(PlatformCAAnimation& caAnim, AnimatedPropertyID property, const String& animationName, int index, int subIndex, double timeOffset)
2519 PlatformCALayer* layer = animatedLayer(property);
2522 caAnim.setBeginTime(CACurrentMediaTime() - timeOffset);
2524 String animationID = animationIdentifier(animationName, property, index, subIndex);
2526 layer->removeAnimationForKey(animationID);
2527 layer->addAnimationForKey(animationID, caAnim);
2529 if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
2530 for (auto& clone : *layerCloneMap) {
2531 // Skip immediate replicas, since they move with the original.
2532 if (m_replicaLayer && isReplicatedRootClone(clone.key))
2535 clone.value->removeAnimationForKey(animationID);
2536 clone.value->addAnimationForKey(animationID, caAnim);
2541 // Workaround for <rdar://problem/7311367>
2542 static void bug7311367Workaround(PlatformCALayer* transformLayer, const TransformationMatrix& transform)
2544 if (!transformLayer)
2547 TransformationMatrix caTransform = transform;
2548 caTransform.setM41(caTransform.m41() + 1);
2549 transformLayer->setTransform(caTransform);
2551 caTransform.setM41(caTransform.m41() - 1);
2552 transformLayer->setTransform(caTransform);
2555 bool GraphicsLayerCA::removeCAAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index, int subIndex)
2557 PlatformCALayer* layer = animatedLayer(property);
2559 String animationID = animationIdentifier(animationName, property, index, subIndex);
2561 if (!layer->animationForKey(animationID))
2564 layer->removeAnimationForKey(animationID);
2565 bug7311367Workaround(m_structuralLayer.get(), m_transform);
2567 if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
2568 for (auto& clone : *layerCloneMap) {
2569 // Skip immediate replicas, since they move with the original.
2570 if (m_replicaLayer && isReplicatedRootClone(clone.key))
2573 clone.value->removeAnimationForKey(animationID);
2579 void GraphicsLayerCA::pauseCAAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, int subIndex, double timeOffset)
2581 PlatformCALayer* layer = animatedLayer(property);
2583 String animationID = animationIdentifier(animationName, property, index, subIndex);
2585 RefPtr<PlatformCAAnimation> curAnim = layer->animationForKey(animationID);
2589 // Animations on the layer are immutable, so we have to clone and modify.
2590 RefPtr<PlatformCAAnimation> newAnim = curAnim->copy();
2592 newAnim->setSpeed(0);
2593 newAnim->setTimeOffset(timeOffset);
2595 layer->addAnimationForKey(animationID, *newAnim); // This will replace the running animation.
2597 // Pause the animations on the clones too.
2598 if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
2599 for (auto& clone : *layerCloneMap) {
2600 // Skip immediate replicas, since they move with the original.
2601 if (m_replicaLayer && isReplicatedRootClone(clone.key))
2603 clone.value->addAnimationForKey(animationID, *newAnim);
2608 void GraphicsLayerCA::repaintLayerDirtyRects()
2610 if (m_needsFullRepaint) {
2611 ASSERT(!m_dirtyRects.size());
2612 m_layer->setNeedsDisplay();
2613 m_needsFullRepaint = false;
2617 if (!m_dirtyRects.size())
2620 for (size_t i = 0; i < m_dirtyRects.size(); ++i)
2621 m_layer->setNeedsDisplayInRect(m_dirtyRects[i]);
2623 m_dirtyRects.clear();
2626 void GraphicsLayerCA::updateContentsNeedsDisplay()
2628 if (m_contentsLayer)
2629 m_contentsLayer->setNeedsDisplay();
2632 bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset)
2634 ASSERT(valueList.property() != AnimatedPropertyTransform && (!supportsAcceleratedFilterAnimations() || valueList.property() != AnimatedPropertyWebkitFilter));
2636 bool isKeyframe = valueList.size() > 2;
2639 bool additive = false;
2640 int animationIndex = 0;
2642 RefPtr<PlatformCAAnimation> caAnimation;
2645 caAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
2646 valuesOK = setAnimationKeyframes(valueList, animation, caAnimation.get());
2648 caAnimation = createBasicAnimation(animation, propertyIdToString(valueList.property()), additive);
2649 valuesOK = setAnimationEndpoints(valueList, animation, caAnimation.get());
2655 m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, 0, timeOffset));
2660 bool GraphicsLayerCA::appendToUncommittedAnimations(const KeyframeValueList& valueList, const TransformOperations* operations, const Animation* animation, const String& animationName, const FloatSize& boxSize, int animationIndex, double timeOffset, bool isMatrixAnimation)
2662 TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : operations->operations().at(animationIndex)->type();
2663 bool additive = animationIndex > 0;
2664 bool isKeyframe = valueList.size() > 2;
2666 RefPtr<PlatformCAAnimation> caAnimation;
2667 bool validMatrices = true;
2669 caAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
2670 validMatrices = setTransformAnimationKeyframes(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize);
2672 caAnimation = createBasicAnimation(animation, propertyIdToString(valueList.property()), additive);
2673 validMatrices = setTransformAnimationEndpoints(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize);
2679 m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, 0, timeOffset));
2683 bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const FloatSize& boxSize)
2685 ASSERT(valueList.property() == AnimatedPropertyTransform);
2687 bool hasBigRotation;
2688 int listIndex = validateTransformOperations(valueList, hasBigRotation);
2689 const TransformOperations* operations = (listIndex >= 0) ? &static_cast<const TransformAnimationValue&>(valueList.at(listIndex)).value() : 0;
2691 bool validMatrices = true;
2693 // If function lists don't match we do a matrix animation, otherwise we do a component hardware animation.
2694 bool isMatrixAnimation = listIndex < 0;
2695 int numAnimations = isMatrixAnimation ? 1 : operations->size();
2698 bool reverseAnimationList = false;
2700 bool reverseAnimationList = true;
2702 // Old versions of Core Animation apply animations in reverse order (<rdar://problem/7095638>) so we need to flip the list.
2703 // to be non-additive. For binary compatibility, the current version of Core Animation preserves this behavior for applications linked
2704 // on or before Snow Leopard.
2705 // FIXME: This fix has not been added to QuartzCore on Windows yet (<rdar://problem/9112233>) so we expect the
2706 // reversed animation behavior
2707 static bool executableWasLinkedOnOrBeforeSnowLeopard = wkExecutableWasLinkedOnOrBeforeSnowLeopard();
2708 if (!executableWasLinkedOnOrBeforeSnowLeopard)
2709 reverseAnimationList = false;
2711 #endif // PLATFORM(IOS)
2712 if (reverseAnimationList) {
2713 for (int animationIndex = numAnimations - 1; animationIndex >= 0; --animationIndex) {
2714 if (!appendToUncommittedAnimations(valueList, operations, animation, animationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) {
2715 validMatrices = false;
2720 for (int animationIndex = 0; animationIndex < numAnimations; ++animationIndex) {
2721 if (!appendToUncommittedAnimations(valueList, operations, animation, animationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) {
2722 validMatrices = false;
2728 return validMatrices;
2731 bool GraphicsLayerCA::appendToUncommittedAnimations(const KeyframeValueList& valueList, const FilterOperation* operation, const Animation* animation, const String& animationName, int animationIndex, double timeOffset)
2733 bool isKeyframe = valueList.size() > 2;
2735 FilterOperation::OperationType filterOp = operation->type();
2736 int numAnimatedProperties = PlatformCAFilters::numAnimatedFilterProperties(filterOp);
2738 // Each filter might need to animate multiple properties, each with their own keyPath. The keyPath is always of the form:
2740 // filter.filter_<animationIndex>.<filterPropertyName>
2742 // PlatformCAAnimation tells us how many properties each filter has and we iterate that many times and create an animation
2743 // for each. This internalFilterPropertyIndex gets passed to PlatformCAAnimation so it can properly create the property animation
2745 for (int internalFilterPropertyIndex = 0; internalFilterPropertyIndex < numAnimatedProperties; ++internalFilterPropertyIndex) {
2747 RefPtr<PlatformCAAnimation> caAnimation;
2748 String keyPath = String::format("filters.filter_%d.%s", animationIndex, PlatformCAFilters::animatedFilterPropertyName(filterOp, internalFilterPropertyIndex));
2751 caAnimation = createKeyframeAnimation(animation, keyPath, false);
2752 valuesOK = setFilterAnimationKeyframes(valueList, animation, caAnimation.get(), animationIndex, internalFilterPropertyIndex, filterOp);
2754 caAnimation = createBasicAnimation(animation, keyPath, false);
2755 valuesOK = setFilterAnimationEndpoints(valueList, animation, caAnimation.get(), animationIndex, internalFilterPropertyIndex);
2760 m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, internalFilterPropertyIndex, timeOffset));
2766 bool GraphicsLayerCA::createFilterAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset)
2768 #if ENABLE(FILTERS_LEVEL_2)
2769 ASSERT(valueList.property() == AnimatedPropertyWebkitFilter || valueList.property() == AnimatedPropertyWebkitBackdropFilter);
2771 ASSERT(valueList.property() == AnimatedPropertyWebkitFilter);
2774 int listIndex = validateFilterOperations(valueList);
2778 const FilterOperations& operations = static_cast<const FilterAnimationValue&>(valueList.at(listIndex)).value();
2779 // Make sure the platform layer didn't fallback to using software filter compositing instead.
2780 if (!filtersCanBeComposited(operations))
2783 int numAnimations = operations.size();
2785 // FIXME: We can't currently hardware animate shadows.
2786 for (int i = 0; i < numAnimations; ++i) {
2787 if (operations.at(i)->type() == FilterOperation::DROP_SHADOW)
2791 for (int animationIndex = 0; animationIndex < numAnimations; ++animationIndex) {
2792 if (!appendToUncommittedAnimations(valueList, operations.operations().at(animationIndex).get(), animation, animationName, animationIndex, timeOffset))
2799 PassRefPtr<PlatformCAAnimation> GraphicsLayerCA::createBasicAnimation(const Animation* anim, const String& keyPath, bool additive)
2801 RefPtr<PlatformCAAnimation> basicAnim = createPlatformCAAnimation(PlatformCAAnimation::Basic, keyPath);
2802 setupAnimation(basicAnim.get(), anim, additive);
2806 PassRefPtr<PlatformCAAnimation>GraphicsLayerCA::createKeyframeAnimation(const Animation* anim, const String& keyPath, bool additive)
2808 RefPtr<PlatformCAAnimation> keyframeAnim = createPlatformCAAnimation(PlatformCAAnimation::Keyframe, keyPath);
2809 setupAnimation(keyframeAnim.get(), anim, additive);
2810 return keyframeAnim;
2813 void GraphicsLayerCA::setupAnimation(PlatformCAAnimation* propertyAnim, const Animation* anim, bool additive)
2815 double duration = anim->duration();
2817 duration = cAnimationAlmostZeroDuration;
2819 float repeatCount = anim->iterationCount();
2820 if (repeatCount == Animation::IterationCountInfinite)
2821 repeatCount = std::numeric_limits<float>::max();
2822 else if (anim->direction() == Animation::AnimationDirectionAlternate || anim->direction() == Animation::AnimationDirectionAlternateReverse)
2825 PlatformCAAnimation::FillModeType fillMode = PlatformCAAnimation::NoFillMode;
2826 switch (anim->fillMode()) {
2827 case AnimationFillModeNone:
2828 fillMode = PlatformCAAnimation::Forwards; // Use "forwards" rather than "removed" because the style system will remove the animation when it is finished. This avoids a flash.
2830 case AnimationFillModeBackwards:
2831 fillMode = PlatformCAAnimation::Both; // Use "both" rather than "backwards" because the style system will remove the animation when it is finished. This avoids a flash.
2833 case AnimationFillModeForwards:
2834 fillMode = PlatformCAAnimation::Forwards;
2836 case AnimationFillModeBoth:
2837 fillMode = PlatformCAAnimation::Both;
2841 propertyAnim->setDuration(duration);
2842 propertyAnim->setRepeatCount(repeatCount);
2843 propertyAnim->setAutoreverses(anim->direction() == Animation::AnimationDirectionAlternate || anim->direction() == Animation::AnimationDirectionAlternateReverse);
2844 propertyAnim->setRemovedOnCompletion(false);
2845 propertyAnim->setAdditive(additive);
2846 propertyAnim->setFillMode(fillMode);
2849 const TimingFunction* GraphicsLayerCA::timingFunctionForAnimationValue(const AnimationValue& animValue, const Animation& anim)
2851 if (animValue.timingFunction())
2852 return animValue.timingFunction();
2853 if (anim.isTimingFunctionSet())
2854 return anim.timingFunction().get();
2856 return CubicBezierTimingFunction::defaultTimingFunction();
2859 bool GraphicsLayerCA::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* basicAnim)
2861 bool forwards = animation->directionIsForwards();
2863 unsigned fromIndex = !forwards;
2864 unsigned toIndex = forwards;
2866 switch (valueList.property()) {
2867 case AnimatedPropertyOpacity: {
2868 basicAnim->setFromValue(static_cast<const FloatAnimationValue&>(valueList.at(fromIndex)).value());
2869 basicAnim->setToValue(static_cast<const FloatAnimationValue&>(valueList.at(toIndex)).value());
2873 ASSERT_NOT_REACHED(); // we don't animate color yet
2877 // This codepath is used for 2-keyframe animations, so we still need to look in the start
2878 // for a timing function. Even in the reversing animation case, the first keyframe provides the timing function.
2879 const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), *animation);
2881 basicAnim->setTimingFunction(timingFunction, !forwards);
2886 bool GraphicsLayerCA::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* keyframeAnim)
2888 Vector<float> keyTimes;
2889 Vector<float> values;
2890 Vector<const TimingFunction*> timingFunctions;
2892 bool forwards = animation->directionIsForwards();
2894 for (unsigned i = 0; i < valueList.size(); ++i) {
2895 unsigned index = forwards ? i : (valueList.size() - i - 1);
2896 const AnimationValue& curValue = valueList.at(index);
2897 keyTimes.append(forwards ? curValue.keyTime() : (1 - curValue.keyTime()));
2899 switch (valueList.property()) {
2900 case AnimatedPropertyOpacity: {
2901 const FloatAnimationValue& floatValue = static_cast<const FloatAnimationValue&>(curValue);
2902 values.append(floatValue.value());
2906 ASSERT_NOT_REACHED(); // we don't animate color yet
2910 if (i < (valueList.size() - 1))
2911 timingFunctions.append(timingFunctionForAnimationValue(forwards ? curValue : valueList.at(index - 1), *animation));
2914 keyframeAnim->setKeyTimes(keyTimes);
2915 keyframeAnim->setValues(values);
2916 keyframeAnim->setTimingFunctions(timingFunctions, !forwards);
2921 bool GraphicsLayerCA::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const FloatSize& boxSize)
2923 ASSERT(valueList.size() == 2);
2925 bool forwards = animation->directionIsForwards();
2927 unsigned fromIndex = !forwards;
2928 unsigned toIndex = forwards;
2930 const TransformAnimationValue& startValue = static_cast<const TransformAnimationValue&>(valueList.at(fromIndex));
2931 const TransformAnimationValue& endValue = static_cast<const TransformAnimationValue&>(valueList.at(toIndex));
2933 if (isMatrixAnimation) {
2934 TransformationMatrix fromTransform, toTransform;
2935 startValue.value().apply(boxSize, fromTransform);
2936 endValue.value().apply(boxSize, toTransform);
2938 // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
2939 if (!fromTransform.isInvertible() || !toTransform.isInvertible())
2942 basicAnim->setFromValue(fromTransform);
2943 basicAnim->setToValue(toTransform);
2945 if (isTransformTypeNumber(transformOpType)) {
2947 getTransformFunctionValue(startValue.value().at(functionIndex), transformOpType, boxSize, fromValue);
2948 basicAnim->setFromValue(fromValue);
2951 getTransformFunctionValue(endValue.value().at(functionIndex), transformOpType, boxSize, toValue);
2952 basicAnim->setToValue(toValue);
2953 } else if (isTransformTypeFloatPoint3D(transformOpType)) {
2954 FloatPoint3D fromValue;
2955 getTransformFunctionValue(startValue.value().at(functionIndex), transformOpType, boxSize, fromValue);
2956 basicAnim->setFromValue(fromValue);
2958 FloatPoint3D toValue;
2959 getTransformFunctionValue(endValue.value().at(functionIndex), transformOpType, boxSize, toValue);
2960 basicAnim->setToValue(toValue);
2962 TransformationMatrix fromValue;
2963 getTransformFunctionValue(startValue.value().at(functionIndex), transformOpType, boxSize, fromValue);
2964 basicAnim->setFromValue(fromValue);
2966 TransformationMatrix toValue;
2967 getTransformFunctionValue(endValue.value().at(functionIndex), transformOpType, boxSize, toValue);
2968 basicAnim->setToValue(toValue);
2972 // This codepath is used for 2-keyframe animations, so we still need to look in the start
2973 // for a timing function. Even in the reversing animation case, the first keyframe provides the timing function.
2974 const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), *animation);
2975 basicAnim->setTimingFunction(timingFunction, !forwards);
2977 PlatformCAAnimation::ValueFunctionType valueFunction = getValueFunctionNameForTransformOperation(transformOpType);
2978 if (valueFunction != PlatformCAAnimation::NoValueFunction)
2979 basicAnim->setValueFunction(valueFunction);
2984 bool GraphicsLayerCA::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const FloatSize& boxSize)
2986 Vector<float> keyTimes;
2987 Vector<float> floatValues;
2988 Vector<FloatPoint3D> floatPoint3DValues;
2989 Vector<TransformationMatrix> transformationMatrixValues;
2990 Vector<const TimingFunction*> timingFunctions;
2992 bool forwards = animation->directionIsForwards();
2994 for (unsigned i = 0; i < valueList.size(); ++i) {
2995 unsigned index = forwards ? i : (valueList.size() - i - 1);
2996 const TransformAnimationValue& curValue = static_cast<const TransformAnimationValue&>(valueList.at(index));
2997 keyTimes.append(forwards ? curValue.keyTime() : (1 - curValue.keyTime()));
2999 TransformationMatrix transform;
3001 if (isMatrixAnimation) {
3002 curValue.value().apply(boxSize, transform);
3004 // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
3005 if (!transform.isInvertible())
3008 transformationMatrixValues.append(transform);
3010 const TransformOperation* transformOp = curValue.value().at(functionIndex);
3011 if (isTransformTypeNumber(transformOpType)) {
3013 getTransformFunctionValue(transformOp, transformOpType, boxSize, value);
3014 floatValues.append(value);
3015 } else if (isTransformTypeFloatPoint3D(transformOpType)) {
3017 getTransformFunctionValue(transformOp, transformOpType, boxSize, value);
3018 floatPoint3DValues.append(value);
3020 TransformationMatrix value;
3021 getTransformFunctionValue(transformOp, transformOpType, boxSize, value);
3022 transformationMatrixValues.append(value);
3025 curValue.value().apply(boxSize, transform);
3028 if (i < (valueList.size() - 1))
3029 timingFunctions.append(timingFunctionForAnimationValue(forwards ? curValue : valueList.at(index - 1), *animation));
3032 keyframeAnim->setKeyTimes(keyTimes);
3034 if (isTransformTypeNumber(transformOpType))
3035 keyframeAnim->setValues(floatValues);
3036 else if (isTransformTypeFloatPoint3D(transformOpType))
3037 keyframeAnim->setValues(floatPoint3DValues);
3039 keyframeAnim->setValues(transformationMatrixValues);
3041 keyframeAnim->setTimingFunctions(timingFunctions, !forwards);
3043 PlatformCAAnimation::ValueFunctionType valueFunction = getValueFunctionNameForTransformOperation(transformOpType);
3044 if (valueFunction != PlatformCAAnimation::NoValueFunction)
3045 keyframeAnim->setValueFunction(valueFunction);
3050 bool GraphicsLayerCA::setFilterAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* basicAnim, int functionIndex, int internalFilterPropertyIndex)
3052 ASSERT(valueList.size() == 2);
3054 bool forwards = animation->directionIsForwards();
3056 unsigned fromIndex = !forwards;
3057 unsigned toIndex = forwards;
3059 const FilterAnimationValue& fromValue = static_cast<const FilterAnimationValue&>(valueList.at(fromIndex));
3060 const FilterAnimationValue& toValue = static_cast<const FilterAnimationValue&>(valueList.at(toIndex));
3062 const FilterOperation* fromOperation = fromValue.value().at(functionIndex);
3063 const FilterOperation* toOperation = toValue.value().at(functionIndex);
3065 RefPtr<DefaultFilterOperation> defaultFromOperation;
3066 RefPtr<DefaultFilterOperation> defaultToOperation;
3068 ASSERT(fromOperation || toOperation);
3070 if (!fromOperation) {
3071 defaultFromOperation = DefaultFilterOperation::create(toOperation->type());
3072 fromOperation = defaultFromOperation.get();
3076 defaultToOperation = DefaultFilterOperation::create(fromOperation->type());
3077 toOperation = defaultToOperation.get();
3080 basicAnim->setFromValue(fromOperation, internalFilterPropertyIndex);
3081 basicAnim->setToValue(toOperation, internalFilterPropertyIndex);
3083 // This codepath is used for 2-keyframe animations, so we still need to look in the start
3084 // for a timing function. Even in the reversing animation case, the first keyframe provides the timing function.
3085 basicAnim->setTimingFunction(timingFunctionForAnimationValue(valueList.at(0), *animation), !forwards);
3090 bool GraphicsLayerCA::setFilterAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* keyframeAnim, int functionIndex, int internalFilterPropertyIndex, FilterOperation::OperationType filterOp)
3092 Vector<float> keyTimes;
3093 Vector<RefPtr<FilterOperation>> values;
3094 Vector<const TimingFunction*> timingFunctions;
3095 RefPtr<DefaultFilterOperation> defaultOperation;
3097 bool forwards = animation->directionIsForwards();
3099 for (unsigned i = 0; i < valueList.size(); ++i) {
3100 unsigned index = forwards ? i : (valueList.size() - i - 1);
3101 const FilterAnimationValue& curValue = static_cast<const FilterAnimationValue&>(valueList.at(index));
3102 keyTimes.append(forwards ? curValue.keyTime() : (1 - curValue.keyTime()));
3104 if (curValue.value().operations().size() > static_cast<size_t>(functionIndex))
3105 values.append(curValue.value().operations()[functionIndex]);
3107 if (!defaultOperation)
3108 defaultOperation = DefaultFilterOperation::create(filterOp);
3109 values.append(defaultOperation);
3112 if (i < (valueList.size() - 1))
3113 timingFunctions.append(timingFunctionForAnimationValue(forwards ? curValue : valueList.at(index - 1), *animation));
3116 keyframeAnim->setKeyTimes(keyTimes);
3117 keyframeAnim->setValues(values, internalFilterPropertyIndex);
3118 keyframeAnim->setTimingFunctions(timingFunctions, !forwards);
3123 void GraphicsLayerCA::suspendAnimations(double time)
3125 double t = PlatformCALayer::currentTimeToMediaTime(time ? time : monotonicallyIncreasingTime());
3126 primaryLayer()->setSpeed(0);
3127 primaryLayer()->setTimeOffset(t);
3129 // Suspend the animations on the clones too.
3130 if (LayerMap* layerCloneMap = primaryLayerClones()) {
3131 for (auto& layer : layerCloneMap->values()) {
3133 layer->setTimeOffset(t);
3138 void GraphicsLayerCA::resumeAnimations()
3140 primaryLayer()->setSpeed(1);
3141 primaryLayer()->setTimeOffset(0);
3143 // Resume the animations on the clones too.
3144 if (LayerMap* layerCloneMap = primaryLayerClones()) {
3145 for (auto& layer : layerCloneMap->values()) {
3147 layer->setTimeOffset(0);
3152 PlatformCALayer* GraphicsLayerCA::hostLayerForSublayers() const
3154 return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get();
3157 PlatformCALayer* GraphicsLayerCA::layerForSuperlayer() const
3159 return m_structuralLayer ? m_structuralLayer.get() : m_layer.get();
3162 PlatformCALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const
3165 case AnimatedPropertyBackgroundColor:
3166 return m_contentsLayer.get();
3167 #if ENABLE(FILTERS_LEVEL_2)
3168 case AnimatedPropertyWebkitBackdropFilter:
3169 // FIXME: Should be just m_backdropLayer.get(). Also, add an ASSERT(m_backdropLayer) here when https://bugs.webkit.org/show_bug.cgi?id=145322 is fixed.
3170 return m_backdropLayer ? m_backdropLayer.get() : primaryLayer();
3173 return primaryLayer();
3177 GraphicsLayerCA::LayerMap* GraphicsLayerCA::animatedLayerClones(AnimatedPropertyID property) const
3179 return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones();
3182 void GraphicsLayerCA::updateContentsScale(float pageScaleFactor)
3184 float contentsScale = pageScaleFactor * deviceScaleFactor();
3186 if (isPageTiledBackingLayer() && tiledBacking()) {
3187 float zoomedOutScale = m_client.zoomedOutPageScaleFactor() * deviceScaleFactor();
3188 tiledBacking()->setZoomedOutContentsScale(zoomedOutScale);
3191 if (contentsScale == m_layer->contentsScale())
3194 m_layer->setContentsScale(contentsScale);
3196 if (m_contentsLayer && m_contentsLayerPurpose == ContentsLayerForMedia)
3197 m_contentsLayer->setContentsScale(contentsScale);
3199 if (tiledBacking()) {
3200 // Scale change may swap in a different set of tiles changing the custom child layers.
3201 if (isPageTiledBackingLayer())
3202 m_uncommittedChanges |= ChildrenChanged;
3203 // Tiled backing repaints automatically on scale change.
3208 m_layer->setNeedsDisplay();
3211 void GraphicsLayerCA::updateCustomAppearance()
3213 m_layer->updateCustomAppearance(m_customAppearance);
3216 void GraphicsLayerCA::setShowDebugBorder(bool showBorder)
3218 if (showBorder == m_showDebugBorder)
3221 GraphicsLayer::setShowDebugBorder(showBorder);
3222 noteLayerPropertyChanged(DebugIndicatorsChanged);
3225 void GraphicsLayerCA::setShowRepaintCounter(bool showCounter)
3227 if (showCounter == m_showRepaintCounter)
3230 GraphicsLayer::setShowRepaintCounter(showCounter);
3231 noteLayerPropertyChanged(DebugIndicatorsChanged);
3234 void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
3236 if (color.isValid())
3237 m_layer->setBackgroundColor(color);
3239 m_layer->setBackgroundColor(Color::transparent);
3242 void GraphicsLayerCA::getDebugBorderInfo(Color& color, float& width) const
3244 if (isPageTiledBackingLayer()) {
3245 color = Color(0, 0, 128, 128); // tile cache layer: dark blue
3250 GraphicsLayer::getDebugBorderInfo(color, width);
3253 static void dumpInnerLayer(TextStream& textStream, String label, PlatformCALayer* layer, int indent, LayerTreeAsTextBehavior behavior)
3258 writeIndent(textStream, indent + 1);
3259 textStream << "(" << label << " ";
3260 if (behavior & LayerTreeAsTextDebug)
3261 textStream << "id=" << layer->layerID() << " ";
3262 textStream << layer->position().x() << ", " << layer->position().y()
3263 << " " << layer->bounds().width() << " x " << layer->bounds().height() << ")\n";
3266 void GraphicsLayerCA::dumpAdditionalProperties(TextStream& textStream, int indent, LayerTreeAsTextBehavior behavior) const
3268 if (behavior & LayerTreeAsTextIncludeVisibleRects) {
3269 writeIndent(textStream, indent + 1);
3270 textStream << "(visible rect " << m_visibleRect.x() << ", " << m_visibleRect.y() << " " << m_visibleRect.width() << " x " << m_visibleRect.height() << ")\n";
3272 writeIndent(textStream, indent + 1);
3273 textStream << "(coverage rect " << m_coverageRect.x() << ", " << m_coverageRect.y() << " " << m_coverageRect.width() << " x " << m_coverageRect.height() << ")\n";
3275 writeIndent(textStream, indent + 1);
3276 textStream << "(intersects coverage rect " << m_intersectsCoverageRect << ")\n";
3278 writeIndent(textStream, indent + 1);
3279 textStream << "(contentsScale " << m_layer->contentsScale() << ")\n";
3282 if (tiledBacking() && (behavior & LayerTreeAsTextIncludeTileCaches)) {
3283 if (behavior & LayerTreeAsTextDebug) {
3284 writeIndent(textStream, indent + 1);
3285 textStream << "(tiled backing " << tiledBacking() << ")\n";
3288 IntRect tileCoverageRect = tiledBacking()->tileCoverageRect();
3289 writeIndent(textStream, indent + 1);
3290 textStream << "(tile cache coverage " << tileCoverageRect.x() << ", " << tileCoverageRect.y() << " " << tileCoverageRect.width() << " x " << tileCoverageRect.height() << ")\n";
3292 IntSize tileSize = tiledBacking()->tileSize();
3293 writeIndent(textStream, indent + 1);
3294 textStream << "(tile size " << tileSize.width() << " x " << tileSize.height() << ")\n";
3296 IntRect gridExtent = tiledBacking()->tileGridExtent();
3297 writeIndent(textStream, indent + 1);
3298 textStream << "(top left tile " << gridExtent.x() << ", " << gridExtent.y() << " tiles grid " << gridExtent.width() << " x " << gridExtent.height() << ")\n";
3301 if (behavior & LayerTreeAsTextIncludeContentLayers) {
3302 dumpInnerLayer(textStream, "structural layer", m_structuralLayer.get(), indent, behavior);
3303 dumpInnerLayer(textStream, "contents clipping layer", m_contentsClippingLayer.get(), indent, behavior);
3304 dumpInnerLayer(textStream, "shape mask layer", m_shapeMaskLayer.get(), indent, behavior);