GraphicsLayerCA.cpp [plain text]
#include "config.h"
#include "GraphicsLayerCA.h"
#include "Animation.h"
#include "FloatConversion.h"
#include "FloatRect.h"
#include "GraphicsLayerFactory.h"
#include "Image.h"
#include "PlatformCAFilters.h"
#include "PlatformCALayer.h"
#include "RotateTransformOperation.h"
#include "ScaleTransformOperation.h"
#include "TextStream.h"
#include "TiledBacking.h"
#include "TransformState.h"
#include "TranslateTransformOperation.h"
#include <QuartzCore/CATransform3D.h>
#include <limits.h>
#include <wtf/CurrentTime.h>
#include <wtf/TemporaryChange.h>
#include <wtf/text/WTFString.h>
#if PLATFORM(IOS)
#include "SystemMemory.h"
#include "WebCoreThread.h"
#endif
#if PLATFORM(COCOA)
#include "PlatformCAAnimationMac.h"
#include "PlatformCALayerMac.h"
#include "WebCoreSystemInterface.h"
#endif
#if PLATFORM(WIN)
#include "PlatformCAAnimationWin.h"
#include "PlatformCALayerWin.h"
#endif
namespace WebCore {
#if PLATFORM(IOS)
static const int cMaxPixelDimension = 1280;
static const int cMaxPixelDimensionLowMemory = 1024;
static const int cMemoryLevelToUseSmallerPixelDimension = 35;
#else
static const int cMaxPixelDimension = 2000;
#endif
static const int cMaxLayerTreeDepth = 250;
static const float cAnimationAlmostZeroDuration = 1e-3f;
static inline bool isIntegral(float value)
{
return static_cast<int>(value) == value;
}
static bool isTransformTypeTransformationMatrix(TransformOperation::OperationType transformType)
{
switch (transformType) {
case TransformOperation::SKEW_X:
case TransformOperation::SKEW_Y:
case TransformOperation::SKEW:
case TransformOperation::MATRIX:
case TransformOperation::ROTATE_3D:
case TransformOperation::MATRIX_3D:
case TransformOperation::PERSPECTIVE:
case TransformOperation::IDENTITY:
case TransformOperation::NONE:
return true;
default:
return false;
}
}
static bool isTransformTypeFloatPoint3D(TransformOperation::OperationType transformType)
{
switch (transformType) {
case TransformOperation::SCALE:
case TransformOperation::SCALE_3D:
case TransformOperation::TRANSLATE:
case TransformOperation::TRANSLATE_3D:
return true;
default:
return false;
}
}
static bool isTransformTypeNumber(TransformOperation::OperationType transformType)
{
return !isTransformTypeTransformationMatrix(transformType) && !isTransformTypeFloatPoint3D(transformType);
}
static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const FloatSize& size, float& value)
{
switch (transformType) {
case TransformOperation::ROTATE:
case TransformOperation::ROTATE_X:
case TransformOperation::ROTATE_Y:
value = transformOp ? narrowPrecisionToFloat(deg2rad(toRotateTransformOperation(transformOp)->angle())) : 0;
break;
case TransformOperation::SCALE_X:
value = transformOp ? narrowPrecisionToFloat(toScaleTransformOperation(transformOp)->x()) : 1;
break;
case TransformOperation::SCALE_Y:
value = transformOp ? narrowPrecisionToFloat(toScaleTransformOperation(transformOp)->y()) : 1;
break;
case TransformOperation::SCALE_Z:
value = transformOp ? narrowPrecisionToFloat(toScaleTransformOperation(transformOp)->z()) : 1;
break;
case TransformOperation::TRANSLATE_X:
value = transformOp ? narrowPrecisionToFloat(toTranslateTransformOperation(transformOp)->x(size)) : 0;
break;
case TransformOperation::TRANSLATE_Y:
value = transformOp ? narrowPrecisionToFloat(toTranslateTransformOperation(transformOp)->y(size)) : 0;
break;
case TransformOperation::TRANSLATE_Z:
value = transformOp ? narrowPrecisionToFloat(toTranslateTransformOperation(transformOp)->z(size)) : 0;
break;
default:
break;
}
}
static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const FloatSize& size, FloatPoint3D& value)
{
switch (transformType) {
case TransformOperation::SCALE:
case TransformOperation::SCALE_3D: {
const ScaleTransformOperation* scaleTransformOp = toScaleTransformOperation(transformOp);
value.setX(scaleTransformOp ? narrowPrecisionToFloat(scaleTransformOp->x()) : 1);
value.setY(scaleTransformOp ? narrowPrecisionToFloat(scaleTransformOp->y()) : 1);
value.setZ(scaleTransformOp ? narrowPrecisionToFloat(scaleTransformOp->z()) : 1);
break;
}
case TransformOperation::TRANSLATE:
case TransformOperation::TRANSLATE_3D: {
const TranslateTransformOperation* translateTransformOp = toTranslateTransformOperation(transformOp);
value.setX(translateTransformOp ? narrowPrecisionToFloat(translateTransformOp->x(size)) : 0);
value.setY(translateTransformOp ? narrowPrecisionToFloat(translateTransformOp->y(size)) : 0);
value.setZ(translateTransformOp ? narrowPrecisionToFloat(translateTransformOp->z(size)) : 0);
break;
}
default:
break;
}
}
static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const FloatSize& size, TransformationMatrix& value)
{
switch (transformType) {
case TransformOperation::SKEW_X:
case TransformOperation::SKEW_Y:
case TransformOperation::SKEW:
case TransformOperation::MATRIX:
case TransformOperation::ROTATE_3D:
case TransformOperation::MATRIX_3D:
case TransformOperation::PERSPECTIVE:
case TransformOperation::IDENTITY:
case TransformOperation::NONE:
if (transformOp)
transformOp->apply(value, size);
else
value.makeIdentity();
break;
default:
break;
}
}
static PlatformCAAnimation::ValueFunctionType getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType)
{
switch (transformType) {
case TransformOperation::ROTATE_X:
return PlatformCAAnimation::RotateX;
case TransformOperation::ROTATE_Y:
return PlatformCAAnimation::RotateY;
case TransformOperation::ROTATE:
return PlatformCAAnimation::RotateZ;
case TransformOperation::SCALE_X:
return PlatformCAAnimation::ScaleX;
case TransformOperation::SCALE_Y:
return PlatformCAAnimation::ScaleY;
case TransformOperation::SCALE_Z:
return PlatformCAAnimation::ScaleZ;
case TransformOperation::TRANSLATE_X:
return PlatformCAAnimation::TranslateX;
case TransformOperation::TRANSLATE_Y:
return PlatformCAAnimation::TranslateY;
case TransformOperation::TRANSLATE_Z:
return PlatformCAAnimation::TranslateZ;
case TransformOperation::SCALE:
case TransformOperation::SCALE_3D:
return PlatformCAAnimation::Scale;
case TransformOperation::TRANSLATE:
case TransformOperation::TRANSLATE_3D:
return PlatformCAAnimation::Translate;
default:
return PlatformCAAnimation::NoValueFunction;
}
}
static String propertyIdToString(AnimatedPropertyID property)
{
switch (property) {
case AnimatedPropertyWebkitTransform:
return "transform";
case AnimatedPropertyOpacity:
return "opacity";
case AnimatedPropertyBackgroundColor:
return "backgroundColor";
case AnimatedPropertyWebkitFilter:
#if ENABLE(CSS_FILTERS)
return "filters";
#else
ASSERT_NOT_REACHED();
#endif
case AnimatedPropertyInvalid:
ASSERT_NOT_REACHED();
}
ASSERT_NOT_REACHED();
return "";
}
static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index, int subIndex)
{
return animationName + '_' + String::number(property) + '_' + String::number(index) + '_' + String::number(subIndex);
}
static bool animationHasStepsTimingFunction(const KeyframeValueList& valueList, const Animation* anim)
{
if (anim->timingFunction()->isStepsTimingFunction())
return true;
for (unsigned i = 0; i < valueList.size(); ++i) {
if (const TimingFunction* timingFunction = valueList.at(i).timingFunction()) {
if (timingFunction->isStepsTimingFunction())
return true;
}
}
return false;
}
#if ENABLE(CSS_FILTERS) || !ASSERT_DISABLED
static inline bool supportsAcceleratedFilterAnimations()
{
#if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
return true;
#else
return false;
#endif
}
#endif
std::unique_ptr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, GraphicsLayerClient& client)
{
std::unique_ptr<GraphicsLayer> graphicsLayer;
if (!factory)
graphicsLayer = std::make_unique<GraphicsLayerCA>(client);
else
graphicsLayer = factory->createGraphicsLayer(client);
graphicsLayer->initialize();
return graphicsLayer;
}
#if ENABLE(CSS_FILTERS)
bool GraphicsLayerCA::filtersCanBeComposited(const FilterOperations& filters)
{
#if PLATFORM(COCOA)
return PlatformCALayerMac::filtersCanBeComposited(filters);
#elif PLATFORM(WIN)
return PlatformCALayerWin::filtersCanBeComposited(filters);
#endif
}
#endif
PassRefPtr<PlatformCALayer> GraphicsLayerCA::createPlatformCALayer(PlatformCALayer::LayerType layerType, PlatformCALayerClient* owner)
{
#if PLATFORM(COCOA)
return PlatformCALayerMac::create(layerType, owner);
#elif PLATFORM(WIN)
return PlatformCALayerWin::create(layerType, owner);
#endif
}
PassRefPtr<PlatformCALayer> GraphicsLayerCA::createPlatformCALayer(PlatformLayer* platformLayer, PlatformCALayerClient* owner)
{
#if PLATFORM(COCOA)
return PlatformCALayerMac::create(platformLayer, owner);
#elif PLATFORM(WIN)
return PlatformCALayerWin::create(platformLayer, owner);
#endif
}
PassRefPtr<PlatformCAAnimation> GraphicsLayerCA::createPlatformCAAnimation(PlatformCAAnimation::AnimationType type, const String& keyPath)
{
#if PLATFORM(COCOA)
return PlatformCAAnimationMac::create(type, keyPath);
#elif PLATFORM(WIN)
return PlatformCAAnimationWin::create(type, keyPath);
#endif
}
GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient& client)
: GraphicsLayer(client)
, m_contentsLayerPurpose(NoContentsLayer)
, m_isPageTiledBackingLayer(false)
, m_uncommittedChanges(0)
, m_isCommittingChanges(false)
{
}
void GraphicsLayerCA::initialize()
{
PlatformCALayer::LayerType layerType = PlatformCALayer::LayerTypeWebLayer;
if (client().shouldUseTiledBacking(this)) {
layerType = PlatformCALayer::LayerTypePageTiledBackingLayer;
m_isPageTiledBackingLayer = true;
}
m_layer = createPlatformCALayer(layerType, this);
noteLayerPropertyChanged(ContentsScaleChanged);
}
GraphicsLayerCA::~GraphicsLayerCA()
{
willBeDestroyed();
}
void GraphicsLayerCA::willBeDestroyed()
{
if (m_layer)
m_layer->setOwner(nullptr);
if (m_contentsLayer)
m_contentsLayer->setOwner(nullptr);
if (m_contentsClippingLayer)
m_contentsClippingLayer->setOwner(nullptr);
if (m_structuralLayer)
m_structuralLayer->setOwner(nullptr);
removeCloneLayers();
GraphicsLayer::willBeDestroyed();
}
void GraphicsLayerCA::setName(const String& name)
{
String caLayerDescription;
if (!m_layer->isPlatformCALayerRemote())
caLayerDescription = String::format("CALayer(%p) ", m_layer->platformLayer());
String longName = caLayerDescription + String::format("GraphicsLayer(%p) ", this) + name;
GraphicsLayer::setName(longName);
noteLayerPropertyChanged(NameChanged);
}
GraphicsLayer::PlatformLayerID GraphicsLayerCA::primaryLayerID() const
{
return primaryLayer()->layerID();
}
PlatformLayer* GraphicsLayerCA::platformLayer() const
{
return primaryLayer()->platformLayer();
}
bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children)
{
bool childrenChanged = GraphicsLayer::setChildren(children);
if (childrenChanged)
noteSublayersChanged();
return childrenChanged;
}
void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
{
GraphicsLayer::addChild(childLayer);
noteSublayersChanged();
}
void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
{
GraphicsLayer::addChildAtIndex(childLayer, index);
noteSublayersChanged();
}
void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
{
GraphicsLayer::addChildBelow(childLayer, sibling);
noteSublayersChanged();
}
void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
{
GraphicsLayer::addChildAbove(childLayer, sibling);
noteSublayersChanged();
}
bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
{
if (GraphicsLayer::replaceChild(oldChild, newChild)) {
noteSublayersChanged();
return true;
}
return false;
}
void GraphicsLayerCA::removeFromParent()
{
if (m_parent)
toGraphicsLayerCA(m_parent)->noteSublayersChanged();
GraphicsLayer::removeFromParent();
}
void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer)
{
if (layer == m_maskLayer)
return;
GraphicsLayer::setMaskLayer(layer);
noteLayerPropertyChanged(MaskLayerChanged);
propagateLayerChangeToReplicas();
if (m_replicatedLayer)
toGraphicsLayerCA(m_replicatedLayer)->propagateLayerChangeToReplicas();
}
void GraphicsLayerCA::setReplicatedLayer(GraphicsLayer* layer)
{
if (layer == m_replicatedLayer)
return;
GraphicsLayer::setReplicatedLayer(layer);
noteLayerPropertyChanged(ReplicatedLayerChanged);
}
void GraphicsLayerCA::setReplicatedByLayer(GraphicsLayer* layer)
{
if (layer == m_replicaLayer)
return;
GraphicsLayer::setReplicatedByLayer(layer);
noteSublayersChanged();
noteLayerPropertyChanged(ReplicatedLayerChanged);
}
void GraphicsLayerCA::setPosition(const FloatPoint& point)
{
if (point == m_position)
return;
GraphicsLayer::setPosition(point);
noteLayerPropertyChanged(GeometryChanged);
}
void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
{
if (point == m_anchorPoint)
return;
GraphicsLayer::setAnchorPoint(point);
noteLayerPropertyChanged(GeometryChanged);
}
void GraphicsLayerCA::setSize(const FloatSize& size)
{
if (size == m_size)
return;
GraphicsLayer::setSize(size);
noteLayerPropertyChanged(GeometryChanged);
}
void GraphicsLayerCA::setBoundsOrigin(const FloatPoint& origin)
{
if (origin == m_boundsOrigin)
return;
GraphicsLayer::setBoundsOrigin(origin);
noteLayerPropertyChanged(GeometryChanged);
}
void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
{
if (t == m_transform)
return;
GraphicsLayer::setTransform(t);
noteLayerPropertyChanged(TransformChanged);
}
void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
{
if (t == m_childrenTransform)
return;
GraphicsLayer::setChildrenTransform(t);
noteLayerPropertyChanged(ChildrenTransformChanged);
}
void GraphicsLayerCA::moveOrCopyLayerAnimation(MoveOrCopy operation, const String& animationIdentifier, PlatformCALayer *fromLayer, PlatformCALayer *toLayer)
{
RefPtr<PlatformCAAnimation> anim = fromLayer->animationForKey(animationIdentifier);
if (!anim)
return;
switch (operation) {
case Move:
fromLayer->removeAnimationForKey(animationIdentifier);
toLayer->addAnimationForKey(animationIdentifier, anim.get());
break;
case Copy:
toLayer->addAnimationForKey(animationIdentifier, anim.get());
break;
}
}
void GraphicsLayerCA::moveOrCopyAnimations(MoveOrCopy operation, PlatformCALayer *fromLayer, PlatformCALayer *toLayer)
{
AnimationsMap::const_iterator end = m_runningAnimations.end();
for (AnimationsMap::const_iterator it = m_runningAnimations.begin(); it != end; ++it) {
const Vector<LayerPropertyAnimation>& propertyAnimations = it->value;
size_t numAnimations = propertyAnimations.size();
for (size_t i = 0; i < numAnimations; ++i) {
const LayerPropertyAnimation& currAnimation = propertyAnimations[i];
if (currAnimation.m_property == AnimatedPropertyWebkitTransform || currAnimation.m_property == AnimatedPropertyOpacity
|| currAnimation.m_property == AnimatedPropertyBackgroundColor
#if ENABLE(CSS_FILTERS)
|| currAnimation.m_property == AnimatedPropertyWebkitFilter
#endif
)
moveOrCopyLayerAnimation(operation, animationIdentifier(currAnimation.m_name, currAnimation.m_property, currAnimation.m_index, currAnimation.m_subIndex), fromLayer, toLayer);
}
}
}
void GraphicsLayerCA::setPreserves3D(bool preserves3D)
{
if (preserves3D == m_preserves3D)
return;
GraphicsLayer::setPreserves3D(preserves3D);
noteLayerPropertyChanged(Preserves3DChanged);
}
void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
{
if (masksToBounds == m_masksToBounds)
return;
GraphicsLayer::setMasksToBounds(masksToBounds);
noteLayerPropertyChanged(MasksToBoundsChanged | DebugIndicatorsChanged);
}
void GraphicsLayerCA::setDrawsContent(bool drawsContent)
{
if (drawsContent == m_drawsContent)
return;
GraphicsLayer::setDrawsContent(drawsContent);
noteLayerPropertyChanged(DrawsContentChanged | DebugIndicatorsChanged);
}
void GraphicsLayerCA::setContentsVisible(bool contentsVisible)
{
if (contentsVisible == m_contentsVisible)
return;
GraphicsLayer::setContentsVisible(contentsVisible);
noteLayerPropertyChanged(ContentsVisibilityChanged);
if (m_contentsLayer)
noteSublayersChanged();
}
void GraphicsLayerCA::setAcceleratesDrawing(bool acceleratesDrawing)
{
if (acceleratesDrawing == m_acceleratesDrawing)
return;
GraphicsLayer::setAcceleratesDrawing(acceleratesDrawing);
noteLayerPropertyChanged(AcceleratesDrawingChanged);
}
void GraphicsLayerCA::setBackgroundColor(const Color& color)
{
if (m_backgroundColor == color)
return;
GraphicsLayer::setBackgroundColor(color);
noteLayerPropertyChanged(BackgroundColorChanged);
}
void GraphicsLayerCA::setContentsOpaque(bool opaque)
{
if (m_contentsOpaque == opaque)
return;
GraphicsLayer::setContentsOpaque(opaque);
noteLayerPropertyChanged(ContentsOpaqueChanged);
}
void GraphicsLayerCA::setBackfaceVisibility(bool visible)
{
if (m_backfaceVisibility == visible)
return;
GraphicsLayer::setBackfaceVisibility(visible);
noteLayerPropertyChanged(BackfaceVisibilityChanged);
}
void GraphicsLayerCA::setOpacity(float opacity)
{
float clampedOpacity = std::max(0.0f, std::min(opacity, 1.0f));
if (clampedOpacity == m_opacity)
return;
GraphicsLayer::setOpacity(clampedOpacity);
noteLayerPropertyChanged(OpacityChanged);
}
#if ENABLE(CSS_FILTERS)
bool GraphicsLayerCA::setFilters(const FilterOperations& filterOperations)
{
bool canCompositeFilters = filtersCanBeComposited(filterOperations);
if (m_filters == filterOperations)
return canCompositeFilters;
ASSERT(!filterOperations.size() || !preserves3D());
if (canCompositeFilters) {
GraphicsLayer::setFilters(filterOperations);
noteLayerPropertyChanged(FiltersChanged);
} else if (filters().size()) {
clearFilters();
noteLayerPropertyChanged(FiltersChanged);
}
return canCompositeFilters;
}
#endif
#if ENABLE(CSS_COMPOSITING)
void GraphicsLayerCA::setBlendMode(BlendMode blendMode)
{
if (GraphicsLayer::blendMode() == blendMode)
return;
GraphicsLayer::setBlendMode(blendMode);
noteLayerPropertyChanged(BlendModeChanged);
}
#endif
void GraphicsLayerCA::setNeedsDisplay()
{
setNeedsDisplayInRect(FloatRect::infiniteRect());
}
void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& r, ShouldClipToLayer shouldClip)
{
if (!drawsContent())
return;
FloatRect rect(r);
if (shouldClip == ClipToLayer) {
FloatRect layerBounds(FloatPoint(), m_size);
rect.intersect(layerBounds);
}
if (rect.isEmpty())
return;
const size_t maxDirtyRects = 32;
for (size_t i = 0; i < m_dirtyRects.size(); ++i) {
if (m_dirtyRects[i].contains(rect))
return;
}
if (m_dirtyRects.size() < maxDirtyRects)
m_dirtyRects.append(rect);
else
m_dirtyRects[0].unite(rect);
noteLayerPropertyChanged(DirtyRectsChanged);
addRepaintRect(rect);
}
void GraphicsLayerCA::setContentsNeedsDisplay()
{
noteLayerPropertyChanged(ContentsNeedsDisplay);
}
void GraphicsLayerCA::setContentsRect(const FloatRect& rect)
{
if (rect == m_contentsRect)
return;
GraphicsLayer::setContentsRect(rect);
noteLayerPropertyChanged(ContentsRectsChanged);
}
void GraphicsLayerCA::setContentsClippingRect(const FloatRect& rect)
{
if (rect == m_contentsClippingRect)
return;
GraphicsLayer::setContentsClippingRect(rect);
noteLayerPropertyChanged(ContentsRectsChanged);
}
bool GraphicsLayerCA::shouldRepaintOnSizeChange() const
{
return drawsContent() && !tiledBacking();
}
bool GraphicsLayerCA::animationCanBeAccelerated(const KeyframeValueList& valueList, const Animation* anim) const
{
if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
return false;
if (animationHasStepsTimingFunction(valueList, anim))
return false;
return true;
}
bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const FloatSize& boxSize, const Animation* anim, const String& animationName, double timeOffset)
{
ASSERT(!animationName.isEmpty());
if (!animationCanBeAccelerated(valueList, anim))
return false;
bool createdAnimations = false;
if (valueList.property() == AnimatedPropertyWebkitTransform)
createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize);
#if ENABLE(CSS_FILTERS)
else if (valueList.property() == AnimatedPropertyWebkitFilter) {
if (supportsAcceleratedFilterAnimations())
createdAnimations = createFilterAnimationsFromKeyframes(valueList, anim, animationName, timeOffset);
}
#endif
else
createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset);
if (createdAnimations)
noteLayerPropertyChanged(AnimationChanged);
return createdAnimations;
}
void GraphicsLayerCA::pauseAnimation(const String& animationName, double timeOffset)
{
if (!animationIsRunning(animationName))
return;
AnimationsToProcessMap::iterator it = m_animationsToProcess.find(animationName);
if (it != m_animationsToProcess.end()) {
AnimationProcessingAction& processingInfo = it->value;
if (processingInfo.action != Remove)
processingInfo.action = Pause;
} else
m_animationsToProcess.add(animationName, AnimationProcessingAction(Pause, timeOffset));
noteLayerPropertyChanged(AnimationChanged);
}
void GraphicsLayerCA::removeAnimation(const String& animationName)
{
if (!animationIsRunning(animationName))
return;
m_animationsToProcess.add(animationName, AnimationProcessingAction(Remove));
noteLayerPropertyChanged(AnimationChanged);
}
void GraphicsLayerCA::platformCALayerAnimationStarted(CFTimeInterval startTime)
{
client().notifyAnimationStarted(this, startTime);
}
void GraphicsLayerCA::setContentsToSolidColor(const Color& color)
{
if (color == m_contentsSolidColor)
return;
m_contentsSolidColor = color;
bool contentsLayerChanged = false;
if (m_contentsSolidColor.isValid() && m_contentsSolidColor.alpha()) {
if (!m_contentsLayer || m_contentsLayerPurpose != ContentsLayerForBackgroundColor) {
m_contentsLayerPurpose = ContentsLayerForBackgroundColor;
m_contentsLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
#ifndef NDEBUG
m_contentsLayer->setName("Background Color Layer");
#endif
contentsLayerChanged = true;
}
} else {
contentsLayerChanged = m_contentsLayer;
m_contentsLayerPurpose = NoContentsLayer;
m_contentsLayer = 0;
}
if (contentsLayerChanged)
noteSublayersChanged();
noteLayerPropertyChanged(ContentsColorLayerChanged);
}
void GraphicsLayerCA::setContentsToImage(Image* image)
{
if (image) {
CGImageRef newImage = image->nativeImageForCurrentFrame();
if (!newImage)
return;
if (m_uncorrectedContentsImage && m_uncorrectedContentsImage.get() == newImage)
return;
m_uncorrectedContentsImage = newImage;
m_pendingContentsImage = newImage;
#if !PLATFORM(WIN) && !PLATFORM(IOS)
CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get());
static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
if (colorSpace && CFEqual(colorSpace, deviceRGB)) {
static CGColorSpaceRef genericRGB = CGDisplayCopyColorSpace(kCGDirectMainDisplay);
m_pendingContentsImage = adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB));
}
#endif
m_contentsLayerPurpose = ContentsLayerForImage;
if (!m_contentsLayer)
noteSublayersChanged();
} else {
m_uncorrectedContentsImage = 0;
m_pendingContentsImage = 0;
m_contentsLayerPurpose = NoContentsLayer;
if (m_contentsLayer)
noteSublayersChanged();
}
noteLayerPropertyChanged(ContentsImageChanged);
}
void GraphicsLayerCA::setContentsToMedia(PlatformLayer* mediaLayer)
{
if (m_contentsLayer && mediaLayer == m_contentsLayer->platformLayer())
return;
PlatformCALayer* platformCALayer = PlatformCALayer::platformCALayer(mediaLayer);
m_contentsLayer = mediaLayer ? (platformCALayer ? platformCALayer : createPlatformCALayer(mediaLayer, this)) : 0;
m_contentsLayerPurpose = mediaLayer ? ContentsLayerForMedia : NoContentsLayer;
noteSublayersChanged();
noteLayerPropertyChanged(ContentsMediaLayerChanged);
}
#if PLATFORM(IOS)
PlatformLayer* GraphicsLayerCA::contentsLayerForMedia() const
{
return m_contentsLayerPurpose == ContentsLayerForMedia ? m_contentsLayer->platformLayer() : nullptr;
}
#endif
void GraphicsLayerCA::setContentsToCanvas(PlatformLayer* canvasLayer)
{
if (m_contentsLayer && canvasLayer == m_contentsLayer->platformLayer())
return;
m_contentsLayer = canvasLayer ? createPlatformCALayer(canvasLayer, this) : 0;
m_contentsLayerPurpose = canvasLayer ? ContentsLayerForCanvas : NoContentsLayer;
noteSublayersChanged();
noteLayerPropertyChanged(ContentsCanvasLayerChanged);
}
void GraphicsLayerCA::layerDidDisplay(PlatformCALayer* layer)
{
LayerMap* layerCloneMap;
if (layer == m_layer)
layerCloneMap = m_layerClones.get();
else if (layer == m_contentsLayer)
layerCloneMap = m_contentsLayerClones.get();
else
return;
if (layerCloneMap) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
PlatformCALayer* currClone = it->value.get();
if (!currClone)
continue;
currClone->copyContentsFromLayer(layer);
}
}
}
FloatPoint GraphicsLayerCA::computePositionRelativeToBase(float& pageScale) const
{
pageScale = 1;
FloatPoint offset;
for (const GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) {
if (currLayer->appliesPageScale()) {
pageScale = currLayer->pageScaleFactor();
return offset;
}
offset += currLayer->position();
}
return FloatPoint();
}
void GraphicsLayerCA::flushCompositingState(const FloatRect& clipRect)
{
TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
recursiveCommitChanges(CommitState(), state);
}
void GraphicsLayerCA::flushCompositingStateForThisLayerOnly()
{
float pageScaleFactor;
bool hadChanges = m_uncommittedChanges;
CommitState commitState;
FloatPoint offset = computePositionRelativeToBase(pageScaleFactor);
commitLayerChangesBeforeSublayers(commitState, pageScaleFactor, offset, m_visibleRect);
commitLayerChangesAfterSublayers(commitState);
if (hadChanges)
client().didCommitChangesForLayer(this);
}
bool GraphicsLayerCA::recursiveVisibleRectChangeRequiresFlush(const TransformState& state) const
{
TransformState localState = state;
FloatRect newVisibleRect = computeVisibleRect(localState, 0);
if (m_layer->layerType() == PlatformCALayer::LayerTypeTiledBackingLayer)
newVisibleRect = adjustTiledLayerVisibleRect(tiledBacking(), m_visibleRect, newVisibleRect, m_sizeAtLastVisibleRectUpdate, m_size);
if (newVisibleRect != m_visibleRect) {
if (TiledBacking* tiledBacking = this->tiledBacking()) {
if (tiledBacking->tilesWouldChangeForVisibleRect(newVisibleRect))
return true;
}
}
if (m_maskLayer) {
GraphicsLayerCA* maskLayerCA = toGraphicsLayerCA(m_maskLayer);
if (maskLayerCA->recursiveVisibleRectChangeRequiresFlush(localState))
return true;
}
const Vector<GraphicsLayer*>& childLayers = children();
size_t numChildren = childLayers.size();
for (size_t i = 0; i < numChildren; ++i) {
GraphicsLayerCA* curChild = toGraphicsLayerCA(childLayers[i]);
if (curChild->recursiveVisibleRectChangeRequiresFlush(localState))
return true;
}
if (m_replicaLayer)
if (toGraphicsLayerCA(m_replicaLayer)->recursiveVisibleRectChangeRequiresFlush(localState))
return true;
return false;
}
bool GraphicsLayerCA::visibleRectChangeRequiresFlush(const FloatRect& clipRect) const
{
TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
return recursiveVisibleRectChangeRequiresFlush(state);
}
TiledBacking* GraphicsLayerCA::tiledBacking() const
{
return m_layer->tiledBacking();
}
TransformationMatrix GraphicsLayerCA::layerTransform(const FloatPoint& position, const TransformationMatrix* customTransform) const
{
TransformationMatrix transform;
transform.translate(position.x(), position.y());
TransformationMatrix currentTransform = customTransform ? *customTransform : m_transform;
if (!currentTransform.isIdentity()) {
FloatPoint3D absoluteAnchorPoint(anchorPoint());
absoluteAnchorPoint.scale(size().width(), size().height(), 1);
transform.translate3d(absoluteAnchorPoint.x(), absoluteAnchorPoint.y(), absoluteAnchorPoint.z());
transform.multiply(currentTransform);
transform.translate3d(-absoluteAnchorPoint.x(), -absoluteAnchorPoint.y(), -absoluteAnchorPoint.z());
}
if (GraphicsLayer* parentLayer = parent()) {
if (!parentLayer->childrenTransform().isIdentity()) {
FloatPoint3D parentAnchorPoint(parentLayer->anchorPoint());
parentAnchorPoint.scale(parentLayer->size().width(), parentLayer->size().height(), 1);
transform.translateRight3d(-parentAnchorPoint.x(), -parentAnchorPoint.y(), -parentAnchorPoint.z());
transform = parentLayer->childrenTransform() * transform;
transform.translateRight3d(parentAnchorPoint.x(), parentAnchorPoint.y(), parentAnchorPoint.z());
}
}
return transform;
}
FloatRect GraphicsLayerCA::computeVisibleRect(TransformState& state, ComputeVisibleRectFlags flags) const
{
bool preserve3D = preserves3D() || (parent() ? parent()->preserves3D() : false);
TransformState::TransformAccumulation accumulation = preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform;
FloatPoint position = m_position;
client().customPositionForVisibleRectComputation(this, position);
TransformationMatrix layerTransform;
TransformationMatrix currentTransform;
if ((flags & RespectAnimatingTransforms) && client().getCurrentTransform(this, currentTransform))
layerTransform = this->layerTransform(position, ¤tTransform);
else
layerTransform = this->layerTransform(position);
bool applyWasClamped;
state.applyTransform(layerTransform, accumulation, &applyWasClamped);
bool mapWasClamped;
FloatRect clipRectForChildren = state.mappedQuad(&mapWasClamped).boundingBox();
FloatPoint boundsOrigin = m_boundsOrigin;
#if PLATFORM(IOS)
if (m_layer->isPlatformCALayerMac())
boundsOrigin = m_layer->bounds().location();
#endif
clipRectForChildren.move(boundsOrigin.x(), boundsOrigin.y());
FloatRect clipRectForSelf(boundsOrigin, m_size);
if (!applyWasClamped && !mapWasClamped)
clipRectForSelf.intersect(clipRectForChildren);
if (masksToBounds()) {
ASSERT(accumulation == TransformState::FlattenTransform);
state.setQuad(clipRectForSelf);
}
return clipRectForSelf;
}
void GraphicsLayerCA::recursiveCommitChanges(const CommitState& commitState, const TransformState& state, float pageScaleFactor, const FloatPoint& positionRelativeToBase, bool affectedByPageScale)
{
TransformState localState = state;
CommitState childCommitState = commitState;
bool affectedByTransformAnimation = commitState.ancestorHasTransformAnimation;
FloatRect visibleRect = computeVisibleRect(localState);
FloatRect oldVisibleRect = m_visibleRect;
if (visibleRect != m_visibleRect) {
m_uncommittedChanges |= VisibleRectChanged;
m_visibleRect = visibleRect;
if (GraphicsLayerCA* maskLayer = toGraphicsLayerCA(m_maskLayer)) {
maskLayer->m_uncommittedChanges |= VisibleRectChanged;
maskLayer->m_visibleRect = visibleRect;
}
}
#ifdef VISIBLE_TILE_WASH
if ((!m_transform.isIdentity() || m_usingTiledBacking) && !m_visibleTileWashLayer) {
static Color washFillColor(255, 0, 0, 50);
static Color washBorderColor(255, 0, 0, 100);
m_visibleTileWashLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
String name = String::format("Visible Tile Wash Layer %p", m_visibleTileWashLayer->platformLayer());
m_visibleTileWashLayer->setName(name);
m_visibleTileWashLayer->setAnchorPoint(FloatPoint3D(0, 0, 0));
m_visibleTileWashLayer->setBorderColor(washBorderColor);
m_visibleTileWashLayer->setBorderWidth(8);
m_visibleTileWashLayer->setBackgroundColor(washFillColor);
noteSublayersChanged(DontScheduleFlush);
}
if (m_visibleTileWashLayer) {
m_visibleTileWashLayer->setPosition(m_visibleRect.location());
m_visibleTileWashLayer->setBounds(FloatRect(FloatPoint(), m_visibleRect.size()));
}
#endif
bool hadChanges = m_uncommittedChanges;
if (appliesPageScale()) {
pageScaleFactor = this->pageScaleFactor();
affectedByPageScale = true;
}
FloatPoint baseRelativePosition = positionRelativeToBase;
if (affectedByPageScale)
baseRelativePosition += m_position;
commitLayerChangesBeforeSublayers(childCommitState, pageScaleFactor, baseRelativePosition, oldVisibleRect);
if (isRunningTransformAnimation()) {
childCommitState.ancestorHasTransformAnimation = true;
affectedByTransformAnimation = true;
}
if (GraphicsLayerCA* maskLayer = toGraphicsLayerCA(m_maskLayer))
maskLayer->commitLayerChangesBeforeSublayers(childCommitState, pageScaleFactor, baseRelativePosition, oldVisibleRect);
const Vector<GraphicsLayer*>& childLayers = children();
size_t numChildren = childLayers.size();
for (size_t i = 0; i < numChildren; ++i) {
GraphicsLayerCA* curChild = toGraphicsLayerCA(childLayers[i]);
curChild->recursiveCommitChanges(childCommitState, localState, pageScaleFactor, baseRelativePosition, affectedByPageScale);
}
if (GraphicsLayerCA* replicaLayer = toGraphicsLayerCA(m_replicaLayer))
replicaLayer->recursiveCommitChanges(childCommitState, localState, pageScaleFactor, baseRelativePosition, affectedByPageScale);
if (GraphicsLayerCA* maskLayer = toGraphicsLayerCA(m_maskLayer))
maskLayer->commitLayerChangesAfterSublayers(childCommitState);
commitLayerChangesAfterSublayers(childCommitState);
if (affectedByTransformAnimation && m_layer->layerType() == PlatformCALayer::LayerTypeTiledBackingLayer)
client().notifyFlushBeforeDisplayRefresh(this);
if (hadChanges)
client().didCommitChangesForLayer(this);
}
bool GraphicsLayerCA::platformCALayerShowRepaintCounter(PlatformCALayer* platformLayer) const
{
if (m_isPageTiledBackingLayer && platformLayer)
return false;
return isShowingRepaintCounter();
}
void GraphicsLayerCA::platformCALayerPaintContents(PlatformCALayer*, GraphicsContext& context, const FloatRect& clip)
{
paintGraphicsLayerContents(context, clip);
}
void GraphicsLayerCA::platformCALayerSetNeedsToRevalidateTiles()
{
noteLayerPropertyChanged(TilingAreaChanged, m_isCommittingChanges ? DontScheduleFlush : ScheduleFlush);
}
float GraphicsLayerCA::platformCALayerDeviceScaleFactor() const
{
return deviceScaleFactor();
}
float GraphicsLayerCA::platformCALayerContentsScaleMultiplierForNewTiles(PlatformCALayer*) const
{
return client().contentsScaleMultiplierForNewTiles(this);
}
bool GraphicsLayerCA::platformCALayerShouldAggressivelyRetainTiles(PlatformCALayer*) const
{
return client().shouldAggressivelyRetainTiles(this);
}
bool GraphicsLayerCA::platformCALayerShouldTemporarilyRetainTileCohorts(PlatformCALayer*) const
{
return client().shouldTemporarilyRetainTileCohorts(this);
}
void GraphicsLayerCA::commitLayerChangesBeforeSublayers(CommitState& commitState, float pageScaleFactor, const FloatPoint& positionRelativeToBase, const FloatRect& oldVisibleRect)
{
TemporaryChange<bool> committingChangesChange(m_isCommittingChanges, true);
++commitState.treeDepth;
if (m_structuralLayer)
++commitState.treeDepth;
if (!m_uncommittedChanges) {
if (commitState.treeDepth > cMaxLayerTreeDepth)
m_uncommittedChanges |= ChildrenChanged;
}
bool needTiledLayer = requiresTiledLayer(pageScaleFactor);
if (needTiledLayer != m_usingTiledBacking)
swapFromOrToTiledLayer(needTiledLayer);
if (m_uncommittedChanges & (Preserves3DChanged | ReplicatedLayerChanged))
updateStructuralLayer();
if (m_uncommittedChanges & GeometryChanged)
updateGeometry(pageScaleFactor, positionRelativeToBase);
if (m_uncommittedChanges & DrawsContentChanged)
updateLayerDrawsContent();
if (m_uncommittedChanges & NameChanged)
updateLayerNames();
if (m_uncommittedChanges & ContentsImageChanged) updateContentsImage();
if (m_uncommittedChanges & ContentsMediaLayerChanged) updateContentsMediaLayer();
if (m_uncommittedChanges & ContentsCanvasLayerChanged) updateContentsCanvasLayer();
if (m_uncommittedChanges & ContentsColorLayerChanged) updateContentsColorLayer();
if (m_uncommittedChanges & BackgroundColorChanged)
updateBackgroundColor();
if (m_uncommittedChanges & TransformChanged)
updateTransform();
if (m_uncommittedChanges & ChildrenTransformChanged)
updateChildrenTransform();
if (m_uncommittedChanges & MasksToBoundsChanged)
updateMasksToBounds();
if (m_uncommittedChanges & ContentsVisibilityChanged)
updateContentsVisibility();
if (m_uncommittedChanges & ContentsOpaqueChanged)
updateContentsOpaque(pageScaleFactor);
if (m_uncommittedChanges & BackfaceVisibilityChanged)
updateBackfaceVisibility();
if (m_uncommittedChanges & OpacityChanged)
updateOpacityOnLayer();
#if ENABLE(CSS_FILTERS)
if (m_uncommittedChanges & FiltersChanged)
updateFilters();
#endif
#if ENABLE(CSS_COMPOSITING)
if (m_uncommittedChanges & BlendModeChanged)
updateBlendMode();
#endif
if (m_uncommittedChanges & AnimationChanged)
updateAnimations();
if (m_uncommittedChanges & ContentsScaleChanged)
updateContentsScale(pageScaleFactor);
if (m_uncommittedChanges & VisibleRectChanged)
updateVisibleRect(oldVisibleRect);
if (m_uncommittedChanges & TilingAreaChanged) updateTiles();
if (m_uncommittedChanges & DirtyRectsChanged)
repaintLayerDirtyRects();
if (m_uncommittedChanges & ContentsRectsChanged) updateContentsRects();
if (m_uncommittedChanges & MaskLayerChanged) {
updateMaskLayer();
m_uncommittedChanges &= ~MaskLayerChanged;
}
if (m_uncommittedChanges & ContentsNeedsDisplay)
updateContentsNeedsDisplay();
if (m_uncommittedChanges & AcceleratesDrawingChanged)
updateAcceleratesDrawing();
if (m_uncommittedChanges & DebugIndicatorsChanged)
updateDebugBorder();
if (m_uncommittedChanges & CustomAppearanceChanged)
updateCustomAppearance();
if (m_uncommittedChanges & CustomBehaviorChanged)
updateCustomBehavior();
if (m_uncommittedChanges & ChildrenChanged) {
updateSublayerList();
m_uncommittedChanges &= ~ChildrenChanged;
}
if (commitState.treeDepth > cMaxLayerTreeDepth)
m_uncommittedChanges |= ChildrenChanged;
}
void GraphicsLayerCA::commitLayerChangesAfterSublayers(CommitState& commitState)
{
if (!m_uncommittedChanges)
return;
TemporaryChange<bool> committingChangesChange(m_isCommittingChanges, true);
if (m_uncommittedChanges & MaskLayerChanged)
updateMaskLayer();
if (m_uncommittedChanges & ChildrenChanged)
updateSublayerList(commitState.treeDepth > cMaxLayerTreeDepth);
if (m_uncommittedChanges & ReplicatedLayerChanged)
updateReplicatedLayers();
m_uncommittedChanges = NoChange;
}
void GraphicsLayerCA::updateLayerNames()
{
switch (structuralLayerPurpose()) {
case StructuralLayerForPreserves3D:
m_structuralLayer->setName("Transform layer " + name());
break;
case StructuralLayerForReplicaFlattening:
m_structuralLayer->setName("Replica flattening layer " + name());
break;
case NoStructuralLayer:
break;
}
m_layer->setName(name());
}
void GraphicsLayerCA::updateSublayerList(bool maxLayerDepthReached)
{
if (maxLayerDepthReached) {
m_layer->setSublayers(PlatformCALayerList());
return;
}
const PlatformCALayerList* customSublayers = m_layer->customSublayers();
PlatformCALayerList structuralLayerChildren;
PlatformCALayerList primaryLayerChildren;
PlatformCALayerList& childListForSublayers = m_structuralLayer ? structuralLayerChildren : primaryLayerChildren;
if (customSublayers)
primaryLayerChildren.appendVector(*customSublayers);
if (m_structuralLayer) {
if (m_replicaLayer)
structuralLayerChildren.append(toGraphicsLayerCA(m_replicaLayer)->primaryLayer());
structuralLayerChildren.append(m_layer);
}
if (m_contentsLayer && m_contentsVisible) {
primaryLayerChildren.append(m_contentsClippingLayer ? m_contentsClippingLayer : m_contentsLayer);
}
const Vector<GraphicsLayer*>& childLayers = children();
size_t numChildren = childLayers.size();
for (size_t i = 0; i < numChildren; ++i) {
GraphicsLayerCA* curChild = toGraphicsLayerCA(childLayers[i]);
PlatformCALayer* childLayer = curChild->layerForSuperlayer();
childListForSublayers.append(childLayer);
}
#ifdef VISIBLE_TILE_WASH
if (m_visibleTileWashLayer)
childListForSublayers.append(m_visibleTileWashLayer);
#endif
if (m_structuralLayer)
m_structuralLayer->setSublayers(structuralLayerChildren);
m_layer->setSublayers(primaryLayerChildren);
}
void GraphicsLayerCA::updateGeometry(float pageScaleFactor, const FloatPoint& positionRelativeToBase)
{
FloatPoint scaledPosition = m_position;
FloatPoint3D scaledAnchorPoint = m_anchorPoint;
FloatSize scaledSize = m_size;
FloatSize pixelAlignmentOffset;
if (m_client.needsPixelAligment() && !isIntegral(pageScaleFactor) && m_drawsContent && !m_masksToBounds)
computePixelAlignment(pageScaleFactor, positionRelativeToBase, scaledPosition, scaledAnchorPoint, pixelAlignmentOffset);
FloatPoint adjustedPosition(scaledPosition.x() + scaledAnchorPoint.x() * scaledSize.width(), scaledPosition.y() + scaledAnchorPoint.y() * scaledSize.height());
if (m_structuralLayer) {
FloatPoint layerPosition(m_position.x() + m_anchorPoint.x() * m_size.width(), m_position.y() + m_anchorPoint.y() * m_size.height());
FloatRect layerBounds(m_boundsOrigin, m_size);
m_structuralLayer->setPosition(layerPosition);
m_structuralLayer->setBounds(layerBounds);
m_structuralLayer->setAnchorPoint(m_anchorPoint);
if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
PlatformCALayer* clone = it->value.get();
FloatPoint clonePosition = layerPosition;
if (m_replicaLayer && isReplicatedRootClone(it->key)) {
clonePosition = positionForCloneRootLayer();
}
clone->setPosition(clonePosition);
clone->setBounds(layerBounds);
clone->setAnchorPoint(m_anchorPoint);
}
}
scaledAnchorPoint = FloatPoint(0.5f, 0.5f);
adjustedPosition = FloatPoint(scaledAnchorPoint.x() * scaledSize.width() - pixelAlignmentOffset.width(), scaledAnchorPoint.y() * scaledSize.height() - pixelAlignmentOffset.height());
}
m_pixelAlignmentOffset = pixelAlignmentOffset;
m_layer->setPosition(adjustedPosition);
FloatRect adjustedBounds = FloatRect(FloatPoint(m_boundsOrigin - pixelAlignmentOffset), m_size);
m_layer->setBounds(adjustedBounds);
m_layer->setAnchorPoint(scaledAnchorPoint);
if (LayerMap* layerCloneMap = m_layerClones.get()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
PlatformCALayer* clone = it->value.get();
FloatPoint clonePosition = adjustedPosition;
if (!m_structuralLayer && m_replicaLayer && isReplicatedRootClone(it->key)) {
clonePosition = positionForCloneRootLayer();
}
clone->setPosition(clonePosition);
clone->setBounds(adjustedBounds);
clone->setAnchorPoint(scaledAnchorPoint);
}
}
}
void GraphicsLayerCA::updateTransform()
{
primaryLayer()->setTransform(m_transform);
if (LayerMap* layerCloneMap = primaryLayerClones()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
PlatformCALayer* currLayer = it->value.get();
if (m_replicaLayer && isReplicatedRootClone(it->key)) {
currLayer->setTransform(TransformationMatrix());
} else
currLayer->setTransform(m_transform);
}
}
}
void GraphicsLayerCA::updateChildrenTransform()
{
primaryLayer()->setSublayerTransform(m_childrenTransform);
if (LayerMap* layerCloneMap = primaryLayerClones()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
it->value->setSublayerTransform(m_childrenTransform);
}
}
void GraphicsLayerCA::updateMasksToBounds()
{
m_layer->setMasksToBounds(m_masksToBounds);
if (LayerMap* layerCloneMap = m_layerClones.get()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
it->value->setMasksToBounds(m_masksToBounds);
}
}
void GraphicsLayerCA::updateContentsVisibility()
{
if (m_contentsVisible) {
if (m_drawsContent)
m_layer->setNeedsDisplay();
} else {
m_layer->setContents(0);
if (LayerMap* layerCloneMap = m_layerClones.get()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
it->value->setContents(0);
}
}
}
void GraphicsLayerCA::updateContentsOpaque(float pageScaleFactor)
{
bool contentsOpaque = m_contentsOpaque;
if (contentsOpaque) {
float contentsScale = pageScaleFactor * deviceScaleFactor();
if (!isIntegral(contentsScale) && !m_client.paintsOpaquelyAtNonIntegralScales(this))
contentsOpaque = false;
}
m_layer->setOpaque(contentsOpaque);
if (LayerMap* layerCloneMap = m_layerClones.get()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
it->value->setOpaque(contentsOpaque);
}
}
void GraphicsLayerCA::updateBackfaceVisibility()
{
if (m_structuralLayer && structuralLayerPurpose() == StructuralLayerForReplicaFlattening) {
m_structuralLayer->setDoubleSided(m_backfaceVisibility);
if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
it->value->setDoubleSided(m_backfaceVisibility);
}
}
m_layer->setDoubleSided(m_backfaceVisibility);
if (LayerMap* layerCloneMap = m_layerClones.get()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
it->value->setDoubleSided(m_backfaceVisibility);
}
}
#if ENABLE(CSS_FILTERS)
void GraphicsLayerCA::updateFilters()
{
m_layer->setFilters(m_filters);
if (LayerMap* layerCloneMap = m_layerClones.get()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
if (m_replicaLayer && isReplicatedRootClone(it->key))
continue;
it->value->setFilters(m_filters);
}
}
}
#endif
#if ENABLE(CSS_COMPOSITING)
void GraphicsLayerCA::updateBlendMode()
{
primaryLayer()->setBlendMode(m_blendMode);
if (LayerMap* layerCloneMap = primaryLayerClones()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
if (m_replicaLayer && isReplicatedRootClone(it->key))
continue;
it->value->setBlendMode(m_blendMode);
}
}
}
#endif
void GraphicsLayerCA::updateStructuralLayer()
{
ensureStructuralLayer(structuralLayerPurpose());
}
void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose)
{
const LayerChangeFlags structuralLayerChangeFlags = NameChanged
| GeometryChanged
| TransformChanged
| ChildrenTransformChanged
| ChildrenChanged
| BackfaceVisibilityChanged
#if ENABLE(CSS_FILTERS)
| FiltersChanged
#endif
| OpacityChanged;
if (purpose == NoStructuralLayer) {
if (m_structuralLayer) {
m_layer->removeFromSuperlayer();
ASSERT(m_structuralLayer->superlayer());
m_structuralLayer->superlayer()->replaceSublayer(m_structuralLayer.get(), m_layer.get());
moveOrCopyAnimations(Move, m_structuralLayer.get(), m_layer.get());
m_structuralLayer = 0;
m_uncommittedChanges |= structuralLayerChangeFlags;
}
return;
}
#if PLATFORM(IOS)
RefPtr<PlatformCALayer> oldPrimaryLayer = m_structuralLayer ? m_structuralLayer.get() : m_layer.get();
#endif
bool structuralLayerChanged = false;
if (purpose == StructuralLayerForPreserves3D) {
if (m_structuralLayer && m_structuralLayer->layerType() != PlatformCALayer::LayerTypeTransformLayer)
m_structuralLayer = 0;
if (!m_structuralLayer) {
m_structuralLayer = createPlatformCALayer(PlatformCALayer::LayerTypeTransformLayer, this);
structuralLayerChanged = true;
}
} else {
if (m_structuralLayer && m_structuralLayer->layerType() != PlatformCALayer::LayerTypeLayer)
m_structuralLayer = 0;
if (!m_structuralLayer) {
m_structuralLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
structuralLayerChanged = true;
}
}
if (!structuralLayerChanged)
return;
m_uncommittedChanges |= structuralLayerChangeFlags;
toGraphicsLayerCA(parent())->noteSublayersChanged(DontScheduleFlush);
FloatPoint point(m_size.width() / 2.0f, m_size.height() / 2.0f);
FloatPoint3D anchorPoint(0.5f, 0.5f, 0);
m_layer->setPosition(point);
m_layer->setAnchorPoint(anchorPoint);
m_layer->setTransform(TransformationMatrix());
m_layer->setOpacity(1);
if (m_layerClones) {
LayerMap::const_iterator end = m_layerClones->end();
for (LayerMap::const_iterator it = m_layerClones->begin(); it != end; ++it) {
PlatformCALayer* currLayer = it->value.get();
currLayer->setPosition(point);
currLayer->setAnchorPoint(anchorPoint);
currLayer->setTransform(TransformationMatrix());
currLayer->setOpacity(1);
}
}
moveOrCopyAnimations(Move, m_layer.get(), m_structuralLayer.get());
}
GraphicsLayerCA::StructuralLayerPurpose GraphicsLayerCA::structuralLayerPurpose() const
{
if (preserves3D())
return StructuralLayerForPreserves3D;
if (isReplicated())
return StructuralLayerForReplicaFlattening;
return NoStructuralLayer;
}
void GraphicsLayerCA::updateLayerDrawsContent()
{
if (m_drawsContent)
m_layer->setNeedsDisplay();
else {
m_layer->setContents(0);
if (m_layerClones) {
LayerMap::const_iterator end = m_layerClones->end();
for (LayerMap::const_iterator it = m_layerClones->begin(); it != end; ++it)
it->value->setContents(0);
}
}
}
void GraphicsLayerCA::updateAcceleratesDrawing()
{
m_layer->setAcceleratesDrawing(m_acceleratesDrawing);
}
void GraphicsLayerCA::updateDebugBorder()
{
if (isShowingDebugBorder())
updateDebugIndicators();
else
m_layer->setBorderWidth(0);
}
FloatRect GraphicsLayerCA::adjustTiledLayerVisibleRect(TiledBacking* tiledBacking, const FloatRect& oldVisibleRect, const FloatRect& newVisibleRect, const FloatSize& oldSize, const FloatSize& newSize)
{
if (oldVisibleRect.isEmpty() || newSize != oldSize || !newVisibleRect.intersects(oldVisibleRect))
return newVisibleRect;
const float paddingMultiplier = 2;
float leftEdgeDelta = paddingMultiplier * (newVisibleRect.x() - oldVisibleRect.x());
float rightEdgeDelta = paddingMultiplier * (newVisibleRect.maxX() - oldVisibleRect.maxX());
float topEdgeDelta = paddingMultiplier * (newVisibleRect.y() - oldVisibleRect.y());
float bottomEdgeDelta = paddingMultiplier * (newVisibleRect.maxY() - oldVisibleRect.maxY());
FloatRect existingTileBackingRect = tiledBacking->visibleRect();
FloatRect expandedRect = newVisibleRect;
if (leftEdgeDelta < 0) {
float newLeft = expandedRect.x() + leftEdgeDelta;
if (newLeft < existingTileBackingRect.x())
expandedRect.shiftXEdgeTo(newLeft);
else
expandedRect.shiftXEdgeTo(existingTileBackingRect.x());
}
if (rightEdgeDelta > 0) {
float newRight = expandedRect.maxX() + rightEdgeDelta;
if (newRight > existingTileBackingRect.maxX())
expandedRect.setWidth(newRight - expandedRect.x());
else
expandedRect.setWidth(existingTileBackingRect.maxX() - expandedRect.x());
}
if (topEdgeDelta < 0) {
float newTop = expandedRect.y() + topEdgeDelta;
if (newTop < existingTileBackingRect.y())
expandedRect.shiftYEdgeTo(newTop);
else
expandedRect.shiftYEdgeTo(existingTileBackingRect.y());
}
if (bottomEdgeDelta > 0) {
float newBottom = expandedRect.maxY() + bottomEdgeDelta;
if (newBottom > existingTileBackingRect.maxY())
expandedRect.setHeight(newBottom - expandedRect.y());
else
expandedRect.setHeight(existingTileBackingRect.maxY() - expandedRect.y());
}
expandedRect.intersect(tiledBacking->boundsWithoutMargin());
return expandedRect;
}
void GraphicsLayerCA::updateVisibleRect(const FloatRect& oldVisibleRect)
{
if (!m_layer->usesTiledBackingLayer())
return;
FloatRect tileArea = m_visibleRect;
if (m_layer->layerType() == PlatformCALayer::LayerTypeTiledBackingLayer)
tileArea = adjustTiledLayerVisibleRect(tiledBacking(), oldVisibleRect, tileArea, m_sizeAtLastVisibleRectUpdate, m_size);
tiledBacking()->setVisibleRect(tileArea);
m_sizeAtLastVisibleRectUpdate = m_size;
}
void GraphicsLayerCA::updateTiles()
{
if (!m_layer->usesTiledBackingLayer())
return;
tiledBacking()->revalidateTiles();
}
void GraphicsLayerCA::updateBackgroundColor()
{
m_layer->setBackgroundColor(m_backgroundColor);
}
void GraphicsLayerCA::updateContentsImage()
{
if (m_pendingContentsImage) {
if (!m_contentsLayer.get()) {
m_contentsLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
#ifndef NDEBUG
m_contentsLayer->setName("Image Layer");
#endif
setupContentsLayer(m_contentsLayer.get());
}
m_contentsLayer->setMinificationFilter(PlatformCALayer::Trilinear);
m_contentsLayer->setContents(m_pendingContentsImage.get());
m_pendingContentsImage = 0;
if (m_contentsLayerClones) {
LayerMap::const_iterator end = m_contentsLayerClones->end();
for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it)
it->value->setContents(m_contentsLayer->contents());
}
updateContentsRects();
} else {
m_contentsLayer = 0;
}
}
void GraphicsLayerCA::updateContentsMediaLayer()
{
if (!m_contentsLayer || m_contentsLayerPurpose != ContentsLayerForMedia)
return;
setupContentsLayer(m_contentsLayer.get());
updateContentsRects();
}
void GraphicsLayerCA::updateContentsCanvasLayer()
{
if (!m_contentsLayer || m_contentsLayerPurpose != ContentsLayerForCanvas)
return;
setupContentsLayer(m_contentsLayer.get());
m_contentsLayer->setNeedsDisplay();
updateContentsRects();
}
void GraphicsLayerCA::updateContentsColorLayer()
{
if (!m_contentsLayer || m_contentsLayerPurpose != ContentsLayerForBackgroundColor)
return;
setupContentsLayer(m_contentsLayer.get());
updateContentsRects();
ASSERT(m_contentsSolidColor.isValid());
m_contentsLayer->setBackgroundColor(m_contentsSolidColor);
if (m_contentsLayerClones) {
LayerMap::const_iterator end = m_contentsLayerClones->end();
for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it)
it->value->setBackgroundColor(m_contentsSolidColor);
}
}
void GraphicsLayerCA::updateContentsRects()
{
if (!m_contentsLayer)
return;
FloatPoint contentOrigin;
FloatRect contentBounds(0, 0, m_contentsRect.width(), m_contentsRect.height());
FloatPoint clippingOrigin;
FloatRect clippingBounds;
bool gainedOrLostClippingLayer = false;
if (!m_contentsClippingRect.contains(m_contentsRect)) {
if (!m_contentsClippingLayer) {
m_contentsClippingLayer = createPlatformCALayer(PlatformCALayer::LayerTypeLayer, this);
m_contentsClippingLayer->setMasksToBounds(true);
m_contentsClippingLayer->setAnchorPoint(FloatPoint());
#ifndef NDEBUG
m_contentsClippingLayer->setName("Contents Clipping");
#endif
m_contentsLayer->removeFromSuperlayer();
m_contentsClippingLayer->appendSublayer(m_contentsLayer.get());
gainedOrLostClippingLayer = true;
}
clippingOrigin = m_contentsClippingRect.location();
clippingBounds.setSize(m_contentsClippingRect.size());
contentOrigin = FloatPoint(m_contentsRect.location() - m_contentsClippingRect.location());
m_contentsClippingLayer->setPosition(clippingOrigin);
m_contentsClippingLayer->setBounds(clippingBounds);
m_contentsLayer->setPosition(contentOrigin);
m_contentsLayer->setBounds(contentBounds);
} else {
if (m_contentsClippingLayer) {
m_contentsLayer->removeFromSuperlayer();
m_contentsClippingLayer->removeFromSuperlayer();
m_contentsClippingLayer->setOwner(0);
m_contentsClippingLayer = nullptr;
gainedOrLostClippingLayer = true;
}
contentOrigin = m_contentsRect.location();
}
if (gainedOrLostClippingLayer)
noteSublayersChanged(DontScheduleFlush);
m_contentsLayer->setPosition(contentOrigin);
m_contentsLayer->setBounds(contentBounds);
if (m_contentsLayerClones) {
LayerMap::const_iterator end = m_contentsLayerClones->end();
for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) {
it->value->setPosition(contentOrigin);
it->value->setBounds(contentBounds);
}
}
if (m_contentsClippingLayerClones) {
LayerMap::const_iterator end = m_contentsClippingLayerClones->end();
for (LayerMap::const_iterator it = m_contentsClippingLayerClones->begin(); it != end; ++it) {
it->value->setPosition(clippingOrigin);
it->value->setBounds(clippingBounds);
}
}
}
void GraphicsLayerCA::updateMaskLayer()
{
PlatformCALayer* maskCALayer = m_maskLayer ? toGraphicsLayerCA(m_maskLayer)->primaryLayer() : 0;
m_layer->setMask(maskCALayer);
LayerMap* maskLayerCloneMap = m_maskLayer ? toGraphicsLayerCA(m_maskLayer)->primaryLayerClones() : 0;
if (LayerMap* layerCloneMap = m_layerClones.get()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
PlatformCALayer* maskClone = maskLayerCloneMap ? maskLayerCloneMap->get(it->key) : 0;
it->value->setMask(maskClone);
}
}
}
void GraphicsLayerCA::updateReplicatedLayers()
{
ReplicaState replicaState(ReplicaState::ReplicaBranch);
RefPtr<PlatformCALayer>replicaRoot = replicatedLayerRoot(replicaState);
if (!replicaRoot)
return;
if (m_structuralLayer)
m_structuralLayer->insertSublayer(replicaRoot.get(), 0);
else
m_layer->insertSublayer(replicaRoot.get(), 0);
}
GraphicsLayerCA::CloneID GraphicsLayerCA::ReplicaState::cloneID() const
{
size_t depth = m_replicaBranches.size();
const size_t bitsPerUChar = sizeof(UChar) * 8;
size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar;
Vector<UChar> result(vectorSize);
result.fill(0);
for (size_t i = 0; i < depth; ++i) {
UChar& currChar = result[i / bitsPerUChar];
currChar = (currChar << 1) | m_replicaBranches[i];
}
return String::adopt(result);
}
PassRefPtr<PlatformCALayer> GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState)
{
if (!m_replicatedLayer || replicaState.replicaDepth() == ReplicaState::maxReplicaDepth)
return 0;
GraphicsLayerCA* replicatedLayer = toGraphicsLayerCA(m_replicatedLayer);
RefPtr<PlatformCALayer> clonedLayerRoot = replicatedLayer->fetchCloneLayers(this, replicaState, RootCloneLevel);
FloatPoint cloneRootPosition = replicatedLayer->positionForCloneRootLayer();
clonedLayerRoot->setPosition(cloneRootPosition);
clonedLayerRoot->setTransform(TransformationMatrix());
return clonedLayerRoot;
}
void GraphicsLayerCA::updateAnimations()
{
if (m_animationsToProcess.size()) {
AnimationsToProcessMap::const_iterator end = m_animationsToProcess.end();
for (AnimationsToProcessMap::const_iterator it = m_animationsToProcess.begin(); it != end; ++it) {
const String& currAnimationName = it->key;
AnimationsMap::iterator animationIt = m_runningAnimations.find(currAnimationName);
if (animationIt == m_runningAnimations.end())
continue;
const AnimationProcessingAction& processingInfo = it->value;
const Vector<LayerPropertyAnimation>& animations = animationIt->value;
for (size_t i = 0; i < animations.size(); ++i) {
const LayerPropertyAnimation& currAnimation = animations[i];
switch (processingInfo.action) {
case Remove:
removeCAAnimationFromLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, currAnimation.m_subIndex);
break;
case Pause:
pauseCAAnimationOnLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, currAnimation.m_subIndex, processingInfo.timeOffset);
break;
}
}
if (processingInfo.action == Remove)
m_runningAnimations.remove(currAnimationName);
}
m_animationsToProcess.clear();
}
size_t numAnimations;
if ((numAnimations = m_uncomittedAnimations.size())) {
for (size_t i = 0; i < numAnimations; ++i) {
const LayerPropertyAnimation& pendingAnimation = m_uncomittedAnimations[i];
setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_name, pendingAnimation.m_index, pendingAnimation.m_subIndex, pendingAnimation.m_timeOffset);
AnimationsMap::iterator it = m_runningAnimations.find(pendingAnimation.m_name);
if (it == m_runningAnimations.end()) {
Vector<LayerPropertyAnimation> animations;
animations.append(pendingAnimation);
m_runningAnimations.add(pendingAnimation.m_name, animations);
} else {
Vector<LayerPropertyAnimation>& animations = it->value;
animations.append(pendingAnimation);
}
}
m_uncomittedAnimations.clear();
}
}
bool GraphicsLayerCA::isRunningTransformAnimation() const
{
AnimationsMap::const_iterator end = m_runningAnimations.end();
for (AnimationsMap::const_iterator it = m_runningAnimations.begin(); it != end; ++it) {
const Vector<LayerPropertyAnimation>& propertyAnimations = it->value;
size_t numAnimations = propertyAnimations.size();
for (size_t i = 0; i < numAnimations; ++i) {
const LayerPropertyAnimation& currAnimation = propertyAnimations[i];
if (currAnimation.m_property == AnimatedPropertyWebkitTransform)
return true;
}
}
return false;
}
void GraphicsLayerCA::setAnimationOnLayer(PlatformCAAnimation* caAnim, AnimatedPropertyID property, const String& animationName, int index, int subIndex, double timeOffset)
{
PlatformCALayer* layer = animatedLayer(property);
if (timeOffset)
caAnim->setBeginTime(CACurrentMediaTime() - timeOffset);
String animationID = animationIdentifier(animationName, property, index, subIndex);
layer->removeAnimationForKey(animationID);
layer->addAnimationForKey(animationID, caAnim);
if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
if (m_replicaLayer && isReplicatedRootClone(it->key))
continue;
it->value->removeAnimationForKey(animationID);
it->value->addAnimationForKey(animationID, caAnim);
}
}
}
static void bug7311367Workaround(PlatformCALayer* transformLayer, const TransformationMatrix& transform)
{
if (!transformLayer)
return;
TransformationMatrix caTransform = transform;
caTransform.setM41(caTransform.m41() + 1);
transformLayer->setTransform(caTransform);
caTransform.setM41(caTransform.m41() - 1);
transformLayer->setTransform(caTransform);
}
bool GraphicsLayerCA::removeCAAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index, int subIndex)
{
PlatformCALayer* layer = animatedLayer(property);
String animationID = animationIdentifier(animationName, property, index, subIndex);
if (!layer->animationForKey(animationID))
return false;
layer->removeAnimationForKey(animationID);
bug7311367Workaround(m_structuralLayer.get(), m_transform);
if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
if (m_replicaLayer && isReplicatedRootClone(it->key))
continue;
it->value->removeAnimationForKey(animationID);
}
}
return true;
}
void GraphicsLayerCA::pauseCAAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, int subIndex, double timeOffset)
{
PlatformCALayer* layer = animatedLayer(property);
String animationID = animationIdentifier(animationName, property, index, subIndex);
RefPtr<PlatformCAAnimation> curAnim = layer->animationForKey(animationID);
if (!curAnim)
return;
RefPtr<PlatformCAAnimation> newAnim = curAnim->copy();
newAnim->setSpeed(0);
newAnim->setTimeOffset(timeOffset);
layer->addAnimationForKey(animationID, newAnim.get());
if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
if (m_replicaLayer && isReplicatedRootClone(it->key))
continue;
it->value->addAnimationForKey(animationID, newAnim.get());
}
}
}
void GraphicsLayerCA::repaintLayerDirtyRects()
{
if (!m_dirtyRects.size())
return;
for (size_t i = 0; i < m_dirtyRects.size(); ++i)
m_layer->setNeedsDisplay(&(m_dirtyRects[i]));
m_dirtyRects.clear();
}
void GraphicsLayerCA::updateContentsNeedsDisplay()
{
if (m_contentsLayer)
m_contentsLayer->setNeedsDisplay();
}
bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset)
{
ASSERT(valueList.property() != AnimatedPropertyWebkitTransform && (!supportsAcceleratedFilterAnimations() || valueList.property() != AnimatedPropertyWebkitFilter));
bool isKeyframe = valueList.size() > 2;
bool valuesOK;
bool additive = false;
int animationIndex = 0;
RefPtr<PlatformCAAnimation> caAnimation;
if (isKeyframe) {
caAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
valuesOK = setAnimationKeyframes(valueList, animation, caAnimation.get());
} else {
caAnimation = createBasicAnimation(animation, propertyIdToString(valueList.property()), additive);
valuesOK = setAnimationEndpoints(valueList, animation, caAnimation.get());
}
if (!valuesOK)
return false;
m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, 0, timeOffset));
return true;
}
bool GraphicsLayerCA::appendToUncommittedAnimations(const KeyframeValueList& valueList, const TransformOperations* operations, const Animation* animation, const String& animationName, const FloatSize& boxSize, int animationIndex, double timeOffset, bool isMatrixAnimation)
{
TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : operations->operations().at(animationIndex)->type();
bool additive = animationIndex > 0;
bool isKeyframe = valueList.size() > 2;
RefPtr<PlatformCAAnimation> caAnimation;
bool validMatrices = true;
if (isKeyframe) {
caAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
validMatrices = setTransformAnimationKeyframes(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize);
} else {
caAnimation = createBasicAnimation(animation, propertyIdToString(valueList.property()), additive);
validMatrices = setTransformAnimationEndpoints(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize);
}
if (!validMatrices)
return false;
m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, 0, timeOffset));
return true;
}
bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const FloatSize& boxSize)
{
ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
bool hasBigRotation;
int listIndex = validateTransformOperations(valueList, hasBigRotation);
const TransformOperations* operations = (listIndex >= 0) ? &static_cast<const TransformAnimationValue&>(valueList.at(listIndex)).value() : 0;
bool validMatrices = true;
bool isMatrixAnimation = listIndex < 0;
int numAnimations = isMatrixAnimation ? 1 : operations->size();
#if PLATFORM(IOS)
bool reverseAnimationList = false;
#else
bool reverseAnimationList = true;
#if !PLATFORM(WIN)
static bool executableWasLinkedOnOrBeforeSnowLeopard = wkExecutableWasLinkedOnOrBeforeSnowLeopard();
if (!executableWasLinkedOnOrBeforeSnowLeopard)
reverseAnimationList = false;
#endif
#endif // PLATFORM(IOS)
if (reverseAnimationList) {
for (int animationIndex = numAnimations - 1; animationIndex >= 0; --animationIndex) {
if (!appendToUncommittedAnimations(valueList, operations, animation, animationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) {
validMatrices = false;
break;
}
}
} else {
for (int animationIndex = 0; animationIndex < numAnimations; ++animationIndex) {
if (!appendToUncommittedAnimations(valueList, operations, animation, animationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) {
validMatrices = false;
break;
}
}
}
return validMatrices;
}
#if ENABLE(CSS_FILTERS)
bool GraphicsLayerCA::appendToUncommittedAnimations(const KeyframeValueList& valueList, const FilterOperation* operation, const Animation* animation, const String& animationName, int animationIndex, double timeOffset)
{
bool isKeyframe = valueList.size() > 2;
FilterOperation::OperationType filterOp = operation->type();
int numAnimatedProperties = PlatformCAFilters::numAnimatedFilterProperties(filterOp);
for (int internalFilterPropertyIndex = 0; internalFilterPropertyIndex < numAnimatedProperties; ++internalFilterPropertyIndex) {
bool valuesOK;
RefPtr<PlatformCAAnimation> caAnimation;
String keyPath = String::format("filters.filter_%d.%s", animationIndex, PlatformCAFilters::animatedFilterPropertyName(filterOp, internalFilterPropertyIndex));
if (isKeyframe) {
caAnimation = createKeyframeAnimation(animation, keyPath, false);
valuesOK = setFilterAnimationKeyframes(valueList, animation, caAnimation.get(), animationIndex, internalFilterPropertyIndex, filterOp);
} else {
caAnimation = createBasicAnimation(animation, keyPath, false);
valuesOK = setFilterAnimationEndpoints(valueList, animation, caAnimation.get(), animationIndex, internalFilterPropertyIndex);
}
ASSERT(valuesOK);
m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, internalFilterPropertyIndex, timeOffset));
}
return true;
}
bool GraphicsLayerCA::createFilterAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset)
{
ASSERT(valueList.property() == AnimatedPropertyWebkitFilter);
int listIndex = validateFilterOperations(valueList);
if (listIndex < 0)
return false;
const FilterOperations& operations = static_cast<const FilterAnimationValue&>(valueList.at(listIndex)).value();
if (!filtersCanBeComposited(operations))
return false;
int numAnimations = operations.size();
for (int i = 0; i < numAnimations; ++i) {
if (operations.at(i)->type() == FilterOperation::DROP_SHADOW)
return false;
}
for (int animationIndex = 0; animationIndex < numAnimations; ++animationIndex) {
if (!appendToUncommittedAnimations(valueList, operations.operations().at(animationIndex).get(), animation, animationName, animationIndex, timeOffset))
return false;
}
return true;
}
#endif
PassRefPtr<PlatformCAAnimation> GraphicsLayerCA::createBasicAnimation(const Animation* anim, const String& keyPath, bool additive)
{
RefPtr<PlatformCAAnimation> basicAnim = createPlatformCAAnimation(PlatformCAAnimation::Basic, keyPath);
setupAnimation(basicAnim.get(), anim, additive);
return basicAnim;
}
PassRefPtr<PlatformCAAnimation>GraphicsLayerCA::createKeyframeAnimation(const Animation* anim, const String& keyPath, bool additive)
{
RefPtr<PlatformCAAnimation> keyframeAnim = createPlatformCAAnimation(PlatformCAAnimation::Keyframe, keyPath);
setupAnimation(keyframeAnim.get(), anim, additive);
return keyframeAnim;
}
void GraphicsLayerCA::setupAnimation(PlatformCAAnimation* propertyAnim, const Animation* anim, bool additive)
{
double duration = anim->duration();
if (duration <= 0)
duration = cAnimationAlmostZeroDuration;
float repeatCount = anim->iterationCount();
if (repeatCount == Animation::IterationCountInfinite)
repeatCount = std::numeric_limits<float>::max();
else if (anim->direction() == Animation::AnimationDirectionAlternate || anim->direction() == Animation::AnimationDirectionAlternateReverse)
repeatCount /= 2;
PlatformCAAnimation::FillModeType fillMode = PlatformCAAnimation::NoFillMode;
switch (anim->fillMode()) {
case AnimationFillModeNone:
fillMode = PlatformCAAnimation::Forwards; break;
case AnimationFillModeBackwards:
fillMode = PlatformCAAnimation::Both; break;
case AnimationFillModeForwards:
fillMode = PlatformCAAnimation::Forwards;
break;
case AnimationFillModeBoth:
fillMode = PlatformCAAnimation::Both;
break;
}
propertyAnim->setDuration(duration);
propertyAnim->setRepeatCount(repeatCount);
propertyAnim->setAutoreverses(anim->direction() == Animation::AnimationDirectionAlternate || anim->direction() == Animation::AnimationDirectionAlternateReverse);
propertyAnim->setRemovedOnCompletion(false);
propertyAnim->setAdditive(additive);
propertyAnim->setFillMode(fillMode);
}
const TimingFunction* GraphicsLayerCA::timingFunctionForAnimationValue(const AnimationValue& animValue, const Animation& anim)
{
if (animValue.timingFunction())
return animValue.timingFunction();
if (anim.isTimingFunctionSet())
return anim.timingFunction().get();
return CubicBezierTimingFunction::defaultTimingFunction();
}
bool GraphicsLayerCA::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* basicAnim)
{
bool forwards = animation->directionIsForwards();
unsigned fromIndex = !forwards;
unsigned toIndex = forwards;
switch (valueList.property()) {
case AnimatedPropertyOpacity: {
basicAnim->setFromValue(static_cast<const FloatAnimationValue&>(valueList.at(fromIndex)).value());
basicAnim->setToValue(static_cast<const FloatAnimationValue&>(valueList.at(toIndex)).value());
break;
}
default:
ASSERT_NOT_REACHED(); break;
}
const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), *animation);
if (timingFunction)
basicAnim->setTimingFunction(timingFunction, !forwards);
return true;
}
bool GraphicsLayerCA::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* keyframeAnim)
{
Vector<float> keyTimes;
Vector<float> values;
Vector<const TimingFunction*> timingFunctions;
bool forwards = animation->directionIsForwards();
for (unsigned i = 0; i < valueList.size(); ++i) {
unsigned index = forwards ? i : (valueList.size() - i - 1);
const AnimationValue& curValue = valueList.at(index);
keyTimes.append(forwards ? curValue.keyTime() : (1 - curValue.keyTime()));
switch (valueList.property()) {
case AnimatedPropertyOpacity: {
const FloatAnimationValue& floatValue = static_cast<const FloatAnimationValue&>(curValue);
values.append(floatValue.value());
break;
}
default:
ASSERT_NOT_REACHED(); break;
}
if (i < (valueList.size() - 1))
timingFunctions.append(timingFunctionForAnimationValue(forwards ? curValue : valueList.at(index - 1), *animation));
}
keyframeAnim->setKeyTimes(keyTimes);
keyframeAnim->setValues(values);
keyframeAnim->setTimingFunctions(timingFunctions, !forwards);
return true;
}
bool GraphicsLayerCA::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const FloatSize& boxSize)
{
ASSERT(valueList.size() == 2);
bool forwards = animation->directionIsForwards();
unsigned fromIndex = !forwards;
unsigned toIndex = forwards;
const TransformAnimationValue& startValue = static_cast<const TransformAnimationValue&>(valueList.at(fromIndex));
const TransformAnimationValue& endValue = static_cast<const TransformAnimationValue&>(valueList.at(toIndex));
if (isMatrixAnimation) {
TransformationMatrix fromTransform, toTransform;
startValue.value().apply(boxSize, fromTransform);
endValue.value().apply(boxSize, toTransform);
if (!fromTransform.isInvertible() || !toTransform.isInvertible())
return false;
basicAnim->setFromValue(fromTransform);
basicAnim->setToValue(toTransform);
} else {
if (isTransformTypeNumber(transformOpType)) {
float fromValue;
getTransformFunctionValue(startValue.value().at(functionIndex), transformOpType, boxSize, fromValue);
basicAnim->setFromValue(fromValue);
float toValue;
getTransformFunctionValue(endValue.value().at(functionIndex), transformOpType, boxSize, toValue);
basicAnim->setToValue(toValue);
} else if (isTransformTypeFloatPoint3D(transformOpType)) {
FloatPoint3D fromValue;
getTransformFunctionValue(startValue.value().at(functionIndex), transformOpType, boxSize, fromValue);
basicAnim->setFromValue(fromValue);
FloatPoint3D toValue;
getTransformFunctionValue(endValue.value().at(functionIndex), transformOpType, boxSize, toValue);
basicAnim->setToValue(toValue);
} else {
TransformationMatrix fromValue;
getTransformFunctionValue(startValue.value().at(functionIndex), transformOpType, boxSize, fromValue);
basicAnim->setFromValue(fromValue);
TransformationMatrix toValue;
getTransformFunctionValue(endValue.value().at(functionIndex), transformOpType, boxSize, toValue);
basicAnim->setToValue(toValue);
}
}
const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), *animation);
basicAnim->setTimingFunction(timingFunction, !forwards);
PlatformCAAnimation::ValueFunctionType valueFunction = getValueFunctionNameForTransformOperation(transformOpType);
if (valueFunction != PlatformCAAnimation::NoValueFunction)
basicAnim->setValueFunction(valueFunction);
return true;
}
bool GraphicsLayerCA::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const FloatSize& boxSize)
{
Vector<float> keyTimes;
Vector<float> floatValues;
Vector<FloatPoint3D> floatPoint3DValues;
Vector<TransformationMatrix> transformationMatrixValues;
Vector<const TimingFunction*> timingFunctions;
bool forwards = animation->directionIsForwards();
for (unsigned i = 0; i < valueList.size(); ++i) {
unsigned index = forwards ? i : (valueList.size() - i - 1);
const TransformAnimationValue& curValue = static_cast<const TransformAnimationValue&>(valueList.at(index));
keyTimes.append(forwards ? curValue.keyTime() : (1 - curValue.keyTime()));
TransformationMatrix transform;
if (isMatrixAnimation) {
curValue.value().apply(boxSize, transform);
if (!transform.isInvertible())
return false;
transformationMatrixValues.append(transform);
} else {
const TransformOperation* transformOp = curValue.value().at(functionIndex);
if (isTransformTypeNumber(transformOpType)) {
float value;
getTransformFunctionValue(transformOp, transformOpType, boxSize, value);
floatValues.append(value);
} else if (isTransformTypeFloatPoint3D(transformOpType)) {
FloatPoint3D value;
getTransformFunctionValue(transformOp, transformOpType, boxSize, value);
floatPoint3DValues.append(value);
} else {
TransformationMatrix value;
getTransformFunctionValue(transformOp, transformOpType, boxSize, value);
transformationMatrixValues.append(value);
}
curValue.value().apply(boxSize, transform);
}
if (i < (valueList.size() - 1))
timingFunctions.append(timingFunctionForAnimationValue(forwards ? curValue : valueList.at(index - 1), *animation));
}
keyframeAnim->setKeyTimes(keyTimes);
if (isTransformTypeNumber(transformOpType))
keyframeAnim->setValues(floatValues);
else if (isTransformTypeFloatPoint3D(transformOpType))
keyframeAnim->setValues(floatPoint3DValues);
else
keyframeAnim->setValues(transformationMatrixValues);
keyframeAnim->setTimingFunctions(timingFunctions, !forwards);
PlatformCAAnimation::ValueFunctionType valueFunction = getValueFunctionNameForTransformOperation(transformOpType);
if (valueFunction != PlatformCAAnimation::NoValueFunction)
keyframeAnim->setValueFunction(valueFunction);
return true;
}
#if ENABLE(CSS_FILTERS)
bool GraphicsLayerCA::setFilterAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* basicAnim, int functionIndex, int internalFilterPropertyIndex)
{
ASSERT(valueList.size() == 2);
bool forwards = animation->directionIsForwards();
unsigned fromIndex = !forwards;
unsigned toIndex = forwards;
const FilterAnimationValue& fromValue = static_cast<const FilterAnimationValue&>(valueList.at(fromIndex));
const FilterAnimationValue& toValue = static_cast<const FilterAnimationValue&>(valueList.at(toIndex));
const FilterOperation* fromOperation = fromValue.value().at(functionIndex);
const FilterOperation* toOperation = toValue.value().at(functionIndex);
RefPtr<DefaultFilterOperation> defaultFromOperation;
RefPtr<DefaultFilterOperation> defaultToOperation;
ASSERT(fromOperation || toOperation);
if (!fromOperation) {
defaultFromOperation = DefaultFilterOperation::create(toOperation->type());
fromOperation = defaultFromOperation.get();
}
if (!toOperation) {
defaultToOperation = DefaultFilterOperation::create(fromOperation->type());
toOperation = defaultToOperation.get();
}
basicAnim->setFromValue(fromOperation, internalFilterPropertyIndex);
basicAnim->setToValue(toOperation, internalFilterPropertyIndex);
basicAnim->setTimingFunction(timingFunctionForAnimationValue(valueList.at(0), *animation), !forwards);
return true;
}
bool GraphicsLayerCA::setFilterAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* keyframeAnim, int functionIndex, int internalFilterPropertyIndex, FilterOperation::OperationType filterOp)
{
Vector<float> keyTimes;
Vector<RefPtr<FilterOperation>> values;
Vector<const TimingFunction*> timingFunctions;
RefPtr<DefaultFilterOperation> defaultOperation;
bool forwards = animation->directionIsForwards();
for (unsigned i = 0; i < valueList.size(); ++i) {
unsigned index = forwards ? i : (valueList.size() - i - 1);
const FilterAnimationValue& curValue = static_cast<const FilterAnimationValue&>(valueList.at(index));
keyTimes.append(forwards ? curValue.keyTime() : (1 - curValue.keyTime()));
if (curValue.value().operations().size() > static_cast<size_t>(functionIndex))
values.append(curValue.value().operations()[functionIndex]);
else {
if (!defaultOperation)
defaultOperation = DefaultFilterOperation::create(filterOp);
values.append(defaultOperation);
}
if (i < (valueList.size() - 1))
timingFunctions.append(timingFunctionForAnimationValue(forwards ? curValue : valueList.at(index - 1), *animation));
}
keyframeAnim->setKeyTimes(keyTimes);
keyframeAnim->setValues(values, internalFilterPropertyIndex);
keyframeAnim->setTimingFunctions(timingFunctions, !forwards);
return true;
}
#endif
void GraphicsLayerCA::suspendAnimations(double time)
{
double t = PlatformCALayer::currentTimeToMediaTime(time ? time : monotonicallyIncreasingTime());
primaryLayer()->setSpeed(0);
primaryLayer()->setTimeOffset(t);
if (LayerMap* layerCloneMap = primaryLayerClones()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
it->value->setSpeed(0);
it->value->setTimeOffset(t);
}
}
}
void GraphicsLayerCA::resumeAnimations()
{
primaryLayer()->setSpeed(1);
primaryLayer()->setTimeOffset(0);
if (LayerMap* layerCloneMap = primaryLayerClones()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
it->value->setSpeed(1);
it->value->setTimeOffset(0);
}
}
}
PlatformCALayer* GraphicsLayerCA::hostLayerForSublayers() const
{
return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get();
}
PlatformCALayer* GraphicsLayerCA::layerForSuperlayer() const
{
return m_structuralLayer ? m_structuralLayer.get() : m_layer.get();
}
PlatformCALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const
{
return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
}
GraphicsLayerCA::LayerMap* GraphicsLayerCA::animatedLayerClones(AnimatedPropertyID property) const
{
return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones();
}
void GraphicsLayerCA::updateContentsScale(float pageScaleFactor)
{
float contentsScale = pageScaleFactor * deviceScaleFactor();
if (m_isPageTiledBackingLayer && tiledBacking()) {
float zoomedOutScale = m_client.zoomedOutPageScaleFactor() * deviceScaleFactor();
tiledBacking()->setZoomedOutContentsScale(zoomedOutScale);
}
if (contentsScale == m_layer->contentsScale())
return;
m_layer->setContentsScale(contentsScale);
if (tiledBacking()) {
if (m_isPageTiledBackingLayer)
m_uncommittedChanges |= ChildrenChanged;
return;
}
if (drawsContent())
m_layer->setNeedsDisplay();
}
void GraphicsLayerCA::updateCustomAppearance()
{
m_layer->updateCustomAppearance(m_customAppearance);
}
void GraphicsLayerCA::updateCustomBehavior()
{
m_layer->updateCustomBehavior(m_customBehavior);
}
void GraphicsLayerCA::setShowDebugBorder(bool showBorder)
{
if (showBorder == m_showDebugBorder)
return;
GraphicsLayer::setShowDebugBorder(showBorder);
noteLayerPropertyChanged(DebugIndicatorsChanged);
}
void GraphicsLayerCA::setShowRepaintCounter(bool showCounter)
{
if (showCounter == m_showRepaintCounter)
return;
GraphicsLayer::setShowRepaintCounter(showCounter);
noteLayerPropertyChanged(DebugIndicatorsChanged);
}
void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
{
if (color.isValid())
m_layer->setBackgroundColor(color);
else
m_layer->setBackgroundColor(Color::transparent);
}
void GraphicsLayerCA::getDebugBorderInfo(Color& color, float& width) const
{
if (m_isPageTiledBackingLayer) {
color = Color(0, 0, 128, 128); width = 0.5;
return;
}
GraphicsLayer::getDebugBorderInfo(color, width);
}
void GraphicsLayerCA::dumpAdditionalProperties(TextStream& textStream, int indent, LayerTreeAsTextBehavior behavior) const
{
if (behavior & LayerTreeAsTextIncludeVisibleRects) {
writeIndent(textStream, indent + 1);
textStream << "(visible rect " << m_visibleRect.x() << ", " << m_visibleRect.y() << " " << m_visibleRect.width() << " x " << m_visibleRect.height() << ")\n";
writeIndent(textStream, indent + 1);
textStream << "(contentsScale " << m_layer->contentsScale() << ")\n";
}
if (tiledBacking() && (behavior & LayerTreeAsTextIncludeTileCaches)) {
if (behavior & LayerTreeAsTextDebug) {
writeIndent(textStream, indent + 1);
textStream << "(tiled backing " << tiledBacking() << ")\n";
}
IntRect tileCoverageRect = tiledBacking()->tileCoverageRect();
writeIndent(textStream, indent + 1);
textStream << "(tile cache coverage " << tileCoverageRect.x() << ", " << tileCoverageRect.y() << " " << tileCoverageRect.width() << " x " << tileCoverageRect.height() << ")\n";
IntSize tileSize = tiledBacking()->tileSize();
writeIndent(textStream, indent + 1);
textStream << "(tile size " << tileSize.width() << " x " << tileSize.height() << ")\n";
IntRect gridExtent = tiledBacking()->tileGridExtent();
writeIndent(textStream, indent + 1);
textStream << "(top left tile " << gridExtent.x() << ", " << gridExtent.y() << " tiles grid " << gridExtent.width() << " x " << gridExtent.height() << ")\n";
}
if (behavior & LayerTreeAsTextIncludeContentLayers) {
if (m_contentsClippingLayer) {
writeIndent(textStream, indent + 1);
textStream << "(contents clipping layer " << m_contentsClippingLayer->position().x() << ", " << m_contentsClippingLayer->position().y()
<< " " << m_contentsClippingLayer->bounds().width() << " x " << m_contentsClippingLayer->bounds().height() << ")\n";
}
if (m_contentsLayer) {
writeIndent(textStream, indent + 1);
textStream << "(contents layer " << m_contentsLayer->position().x() << ", " << m_contentsLayer->position().y()
<< " " << m_contentsLayer->bounds().width() << " x " << m_contentsLayer->bounds().height() << ")\n";
}
}
}
void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth)
{
if (color.isValid()) {
m_layer->setBorderColor(color);
m_layer->setBorderWidth(borderWidth);
} else {
m_layer->setBorderColor(Color::transparent);
m_layer->setBorderWidth(0);
}
}
void GraphicsLayerCA::setCustomAppearance(CustomAppearance customAppearance)
{
if (customAppearance == m_customAppearance)
return;
GraphicsLayer::setCustomAppearance(customAppearance);
noteLayerPropertyChanged(CustomAppearanceChanged);
}
void GraphicsLayerCA::setCustomBehavior(CustomBehavior customBehavior)
{
if (customBehavior == m_customBehavior)
return;
GraphicsLayer::setCustomBehavior(customBehavior);
noteLayerPropertyChanged(CustomBehaviorChanged);
}
bool GraphicsLayerCA::requiresTiledLayer(float pageScaleFactor) const
{
if (!m_drawsContent || m_isPageTiledBackingLayer)
return false;
#if PLATFORM(IOS)
int maxPixelDimension = systemMemoryLevel() < cMemoryLevelToUseSmallerPixelDimension ? cMaxPixelDimensionLowMemory : cMaxPixelDimension;
return m_size.width() * pageScaleFactor > maxPixelDimension || m_size.height() * pageScaleFactor > maxPixelDimension;
#else
return m_size.width() * pageScaleFactor > cMaxPixelDimension || m_size.height() * pageScaleFactor > cMaxPixelDimension;
#endif
}
void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
{
ASSERT(m_layer->layerType() != PlatformCALayer::LayerTypePageTiledBackingLayer);
ASSERT(useTiledLayer != m_usingTiledBacking);
RefPtr<PlatformCALayer> oldLayer = m_layer;
PlatformCALayer::LayerType layerType = useTiledLayer ? PlatformCALayer::LayerTypeTiledBackingLayer : PlatformCALayer::LayerTypeWebLayer;
m_layer = createPlatformCALayer(layerType, this);
m_usingTiledBacking = useTiledLayer;
m_layer->adoptSublayers(oldLayer.get());
#ifdef VISIBLE_TILE_WASH
if (m_visibleTileWashLayer)
m_layer->appendSublayer(m_visibleTileWashLayer.get());
#endif
if (isMaskLayer()) {
if (GraphicsLayer* parentLayer = parent())
toGraphicsLayerCA(parentLayer)->noteLayerPropertyChanged(MaskLayerChanged);
} else if (oldLayer->superlayer()) {
oldLayer->superlayer()->replaceSublayer(oldLayer.get(), m_layer.get());
}
m_uncommittedChanges |= ChildrenChanged
| GeometryChanged
| TransformChanged
| ChildrenTransformChanged
| MasksToBoundsChanged
| ContentsOpaqueChanged
| BackfaceVisibilityChanged
| BackgroundColorChanged
| ContentsScaleChanged
| AcceleratesDrawingChanged
| FiltersChanged
| MaskLayerChanged
| OpacityChanged
| DebugIndicatorsChanged;
if (m_usingTiledBacking)
m_uncommittedChanges |= VisibleRectChanged;
#ifndef NDEBUG
String name = String::format("%sCALayer(%p) GraphicsLayer(%p) ", (m_layer->layerType() == PlatformCALayer::LayerTypeWebTiledLayer) ? "Tiled " : "", m_layer->platformLayer(), this) + m_name;
m_layer->setName(name);
#endif
moveOrCopyAnimations(Move, oldLayer.get(), m_layer.get());
setNeedsDisplay();
client().tiledBackingUsageChanged(this, m_usingTiledBacking);
}
GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCA::defaultContentsOrientation() const
{
return CompositingCoordinatesTopDown;
}
void GraphicsLayerCA::setupContentsLayer(PlatformCALayer* contentsLayer)
{
#if !PLATFORM(IOS)
contentsLayer->setMasksToBounds(true);
#endif
if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) {
TransformationMatrix flipper(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
contentsLayer->setTransform(flipper);
contentsLayer->setAnchorPoint(FloatPoint3D(0, 1, 0));
} else
contentsLayer->setAnchorPoint(FloatPoint3D());
if (isShowingDebugBorder()) {
contentsLayer->setBorderColor(Color(0, 0, 128, 180));
contentsLayer->setBorderWidth(4);
}
}
PassRefPtr<PlatformCALayer> GraphicsLayerCA::findOrMakeClone(CloneID cloneID, PlatformCALayer *sourceLayer, LayerMap* clones, CloneLevel cloneLevel)
{
if (!sourceLayer)
return 0;
RefPtr<PlatformCALayer> resultLayer;
RefPtr<PlatformCALayer> dummy;
LayerMap::AddResult addResult = clones->add(cloneID, dummy);
if (!addResult.isNewEntry) {
resultLayer = addResult.iterator->value.get();
} else {
resultLayer = cloneLayer(sourceLayer, cloneLevel);
#ifndef NDEBUG
resultLayer->setName(String::format("Clone %d of layer %llu", cloneID[0U], sourceLayer->layerID()));
#endif
addResult.iterator->value = resultLayer;
}
return resultLayer;
}
void GraphicsLayerCA::ensureCloneLayers(CloneID cloneID, RefPtr<PlatformCALayer>& primaryLayer, RefPtr<PlatformCALayer>& structuralLayer,
RefPtr<PlatformCALayer>& contentsLayer, RefPtr<PlatformCALayer>& contentsClippingLayer, CloneLevel cloneLevel)
{
structuralLayer = 0;
contentsLayer = 0;
if (!m_layerClones)
m_layerClones = adoptPtr(new LayerMap);
if (!m_structuralLayerClones && m_structuralLayer)
m_structuralLayerClones = adoptPtr(new LayerMap);
if (!m_contentsLayerClones && m_contentsLayer)
m_contentsLayerClones = adoptPtr(new LayerMap);
if (!m_contentsClippingLayerClones && m_contentsClippingLayer)
m_contentsClippingLayerClones = adoptPtr(new LayerMap);
primaryLayer = findOrMakeClone(cloneID, m_layer.get(), m_layerClones.get(), cloneLevel);
structuralLayer = findOrMakeClone(cloneID, m_structuralLayer.get(), m_structuralLayerClones.get(), cloneLevel);
contentsLayer = findOrMakeClone(cloneID, m_contentsLayer.get(), m_contentsLayerClones.get(), cloneLevel);
contentsClippingLayer = findOrMakeClone(cloneID, m_contentsClippingLayer.get(), m_contentsClippingLayerClones.get(), cloneLevel);
}
void GraphicsLayerCA::removeCloneLayers()
{
m_layerClones = nullptr;
m_structuralLayerClones = nullptr;
m_contentsLayerClones = nullptr;
m_contentsClippingLayerClones = nullptr;
}
FloatPoint GraphicsLayerCA::positionForCloneRootLayer() const
{
if (!m_replicaLayer)
return FloatPoint();
FloatPoint replicaPosition = m_replicaLayer->replicatedLayerPosition();
return FloatPoint(replicaPosition.x() + m_anchorPoint.x() * m_size.width(),
replicaPosition.y() + m_anchorPoint.y() * m_size.height());
}
void GraphicsLayerCA::propagateLayerChangeToReplicas()
{
for (GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) {
GraphicsLayerCA* currLayerCA = toGraphicsLayerCA(currLayer);
if (!currLayerCA->hasCloneLayers())
break;
if (currLayerCA->replicaLayer())
toGraphicsLayerCA(currLayerCA->replicaLayer())->noteLayerPropertyChanged(ReplicatedLayerChanged);
}
}
PassRefPtr<PlatformCALayer> GraphicsLayerCA::fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState& replicaState, CloneLevel cloneLevel)
{
RefPtr<PlatformCALayer> primaryLayer;
RefPtr<PlatformCALayer> structuralLayer;
RefPtr<PlatformCALayer> contentsLayer;
RefPtr<PlatformCALayer> contentsClippingLayer;
ensureCloneLayers(replicaState.cloneID(), primaryLayer, structuralLayer, contentsLayer, contentsClippingLayer, cloneLevel);
if (m_maskLayer) {
RefPtr<PlatformCALayer> maskClone = toGraphicsLayerCA(m_maskLayer)->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
primaryLayer->setMask(maskClone.get());
}
if (m_replicatedLayer) {
RefPtr<PlatformCALayer> replicaRoot = replicatedLayerRoot(replicaState);
if (!replicaRoot)
return 0;
if (structuralLayer) {
structuralLayer->insertSublayer(replicaRoot.get(), 0);
return structuralLayer;
}
primaryLayer->insertSublayer(replicaRoot.get(), 0);
return primaryLayer;
}
const Vector<GraphicsLayer*>& childLayers = children();
Vector<RefPtr<PlatformCALayer>> clonalSublayers;
RefPtr<PlatformCALayer> replicaLayer;
if (m_replicaLayer && m_replicaLayer != replicaRoot) {
replicaState.setBranchType(ReplicaState::ReplicaBranch);
replicaLayer = toGraphicsLayerCA(m_replicaLayer)->fetchCloneLayers(replicaRoot, replicaState, RootCloneLevel);
replicaState.setBranchType(ReplicaState::ChildBranch);
}
if (contentsClippingLayer) {
ASSERT(contentsLayer);
contentsClippingLayer->appendSublayer(contentsLayer.get());
}
if (replicaLayer || structuralLayer || contentsLayer || contentsClippingLayer || childLayers.size() > 0) {
if (structuralLayer) {
if (replicaLayer)
clonalSublayers.append(replicaLayer);
clonalSublayers.append(primaryLayer);
} else if (contentsClippingLayer) {
clonalSublayers.append(contentsClippingLayer);
} else if (contentsLayer) {
clonalSublayers.append(contentsLayer);
}
replicaState.push(ReplicaState::ChildBranch);
size_t numChildren = childLayers.size();
for (size_t i = 0; i < numChildren; ++i) {
GraphicsLayerCA* curChild = toGraphicsLayerCA(childLayers[i]);
RefPtr<PlatformCALayer> childLayer = curChild->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
if (childLayer)
clonalSublayers.append(childLayer);
}
replicaState.pop();
for (size_t i = 0; i < clonalSublayers.size(); ++i)
clonalSublayers[i]->removeFromSuperlayer();
}
RefPtr<PlatformCALayer> result;
if (structuralLayer) {
structuralLayer->setSublayers(clonalSublayers);
if (contentsClippingLayer || contentsLayer) {
primaryLayer->removeAllSublayers();
primaryLayer->appendSublayer(contentsClippingLayer ? contentsClippingLayer.get() : contentsLayer.get());
}
result = structuralLayer;
} else {
primaryLayer->setSublayers(clonalSublayers);
result = primaryLayer;
}
return result;
}
PassRefPtr<PlatformCALayer> GraphicsLayerCA::cloneLayer(PlatformCALayer *layer, CloneLevel cloneLevel)
{
RefPtr<PlatformCALayer> newLayer = layer->clone(this);
if (cloneLevel == IntermediateCloneLevel) {
newLayer->setOpacity(layer->opacity());
moveOrCopyAnimations(Copy, layer, newLayer.get());
}
if (isShowingDebugBorder()) {
newLayer->setBorderColor(Color(255, 122, 251));
newLayer->setBorderWidth(2);
}
return newLayer;
}
void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity)
{
LayerMap* layerCloneMap = 0;
if (preserves3D()) {
m_layer->setOpacity(accumulatedOpacity);
layerCloneMap = m_layerClones.get();
} else {
primaryLayer()->setOpacity(accumulatedOpacity);
layerCloneMap = primaryLayerClones();
}
if (layerCloneMap) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
if (m_replicaLayer && isReplicatedRootClone(it->key))
continue;
it->value->setOpacity(m_opacity);
}
}
}
void GraphicsLayerCA::updateOpacityOnLayer()
{
primaryLayer()->setOpacity(m_opacity);
if (LayerMap* layerCloneMap = primaryLayerClones()) {
LayerMap::const_iterator end = layerCloneMap->end();
for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
if (m_replicaLayer && isReplicatedRootClone(it->key))
continue;
it->value->setOpacity(m_opacity);
}
}
}
void GraphicsLayerCA::deviceOrPageScaleFactorChanged()
{
noteChangesForScaleSensitiveProperties();
}
void GraphicsLayerCA::noteChangesForScaleSensitiveProperties()
{
noteLayerPropertyChanged(GeometryChanged | ContentsScaleChanged | ContentsOpaqueChanged);
}
void GraphicsLayerCA::computePixelAlignment(float pageScale, const FloatPoint& positionRelativeToBase,
FloatPoint& position, FloatPoint3D& anchorPoint, FloatSize& alignmentOffset) const
{
FloatRect baseRelativeBounds(positionRelativeToBase, m_size);
FloatRect scaledBounds = baseRelativeBounds;
float contentsScale = pageScale * deviceScaleFactor();
scaledBounds.scale(contentsScale);
FloatRect alignedBounds = enclosingRectForPainting(LayoutRect(scaledBounds), deviceScaleFactor());
alignedBounds.scale(1 / contentsScale);
alignmentOffset = baseRelativeBounds.location() - alignedBounds.location();
position = m_position - alignmentOffset;
float anchorPointX = m_anchorPoint.x();
float anchorPointY = m_anchorPoint.y();
if (alignedBounds.width())
anchorPointX = (baseRelativeBounds.width() * anchorPointX + alignmentOffset.width()) / alignedBounds.width();
if (alignedBounds.height())
anchorPointY = (baseRelativeBounds.height() * anchorPointY + alignmentOffset.height()) / alignedBounds.height();
anchorPoint = FloatPoint3D(anchorPointX, anchorPointY, m_anchorPoint.z() * contentsScale);
}
void GraphicsLayerCA::noteSublayersChanged(ScheduleFlushOrNot scheduleFlush)
{
noteLayerPropertyChanged(ChildrenChanged, scheduleFlush);
propagateLayerChangeToReplicas();
}
bool GraphicsLayerCA::canThrottleLayerFlush() const
{
return !(m_uncommittedChanges & TilesAdded);
}
void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags, ScheduleFlushOrNot scheduleFlush)
{
bool hadUncommittedChanges = !!m_uncommittedChanges;
bool oldCanThrottleLayerFlush = canThrottleLayerFlush();
m_uncommittedChanges |= flags;
if (scheduleFlush == ScheduleFlush) {
bool needsFlush = !hadUncommittedChanges || oldCanThrottleLayerFlush != canThrottleLayerFlush();
if (needsFlush)
client().notifyFlushRequired(this);
}
}
double GraphicsLayerCA::backingStoreMemoryEstimate() const
{
if (!drawsContent())
return 0;
if (TiledBacking* tiledBacking = this->tiledBacking())
return tiledBacking->retainedTileBackingStoreMemory();
return 4.0 * size().width() * m_layer->contentsScale() * size().height() * m_layer->contentsScale();
}
}