| Index: third_party/WebKit/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
|
| ===================================================================
|
| --- third_party/WebKit/WebCore/platform/graphics/mac/GraphicsLayerCA.mm (revision 9383)
|
| +++ third_party/WebKit/WebCore/platform/graphics/mac/GraphicsLayerCA.mm (working copy)
|
| @@ -1,1472 +1,1477 @@
|
| -/*
|
| - * Copyright (C) 2009 Apple Inc. All rights reserved.
|
| - *
|
| - * Redistribution and use in source and binary forms, with or without
|
| - * modification, are permitted provided that the following conditions
|
| - * are met:
|
| - * 1. Redistributions of source code must retain the above copyright
|
| - * notice, this list of conditions and the following disclaimer.
|
| - * 2. Redistributions in binary form must reproduce the above copyright
|
| - * notice, this list of conditions and the following disclaimer in the
|
| - * documentation and/or other materials provided with the distribution.
|
| - *
|
| - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
| - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
| - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
| - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
| - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
| - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
| - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| - */
|
| -
|
| -#import "config.h"
|
| -
|
| -#if USE(ACCELERATED_COMPOSITING)
|
| -
|
| -#import "GraphicsLayerCA.h"
|
| -
|
| -// Temporary
|
| -#import <QuartzCore/CAAnimationPrivate.h>
|
| -#import <QuartzCore/CAValueFunction.h>
|
| -
|
| -#import "Animation.h"
|
| -#import "BlockExceptions.h"
|
| -#import "CString.h"
|
| -#import "FloatRect.h"
|
| -#import "Image.h"
|
| -#import "PlatformString.h"
|
| -#import <QuartzCore/QuartzCore.h>
|
| -#import "RotateTransformOperation.h"
|
| -#import "ScaleTransformOperation.h"
|
| -#import "SystemTime.h"
|
| -#import "TranslateTransformOperation.h"
|
| -#import "WebLayer.h"
|
| -#import "WebTiledLayer.h"
|
| -#import <wtf/CurrentTime.h>
|
| -
|
| -using namespace std;
|
| -
|
| -namespace WebCore {
|
| -
|
| -// The threshold width or height above which a tiled layer will be used. This should be
|
| -// large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL
|
| -// texture size limit on all supported hardware.
|
| -static const int cMaxPixelDimension = 2000;
|
| -
|
| -// The width and height of a single tile in a tiled layer. Should be large enough to
|
| -// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
|
| -// to keep the overall tile cost low.
|
| -static const int cTiledLayerTileSize = 512;
|
| -
|
| -// If we send a duration of 0 to CA, then it will use the default duration
|
| -// of 250ms. So send a very small value instead.
|
| -static const float cAnimationAlmostZeroDuration = 1e-3f;
|
| -
|
| -// CACurrentMediaTime() is a time since boot. These methods convert between that and
|
| -// WebCore time, which is system time (UTC).
|
| -static CFTimeInterval currentTimeToMediaTime(double t)
|
| -{
|
| - return CACurrentMediaTime() + t - WTF::currentTime();
|
| -}
|
| -
|
| -static double mediaTimeToCurrentTime(CFTimeInterval t)
|
| -{
|
| - return WTF::currentTime() + t - CACurrentMediaTime();
|
| -}
|
| -
|
| -} // namespace WebCore
|
| -
|
| -static NSString* const WebAnimationCSSPropertyKey = @"GraphicsLayerCA_property";
|
| -
|
| -@interface WebAnimationDelegate : NSObject {
|
| - WebCore::GraphicsLayerCA* m_graphicsLayer;
|
| -}
|
| -
|
| -- (void)animationDidStart:(CAAnimation *)anim;
|
| -- (WebCore::GraphicsLayerCA*)graphicsLayer;
|
| -- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer;
|
| -
|
| -@end
|
| -
|
| -@implementation WebAnimationDelegate
|
| -
|
| -- (void)animationDidStart:(CAAnimation *)animation
|
| -{
|
| - if (!m_graphicsLayer)
|
| - return;
|
| -
|
| - double startTime = WebCore::mediaTimeToCurrentTime([animation beginTime]);
|
| - m_graphicsLayer->client()->notifyAnimationStarted(m_graphicsLayer, startTime);
|
| -}
|
| -
|
| -- (WebCore::GraphicsLayerCA*)graphicsLayer
|
| -{
|
| - return m_graphicsLayer;
|
| -}
|
| -
|
| -- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer
|
| -{
|
| - m_graphicsLayer = graphicsLayer;
|
| -}
|
| -
|
| -@end
|
| -
|
| -namespace WebCore {
|
| -
|
| -inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t)
|
| -{
|
| - toT3D = CATransform3DMakeAffineTransform(t);
|
| -}
|
| -
|
| -static NSValue* getTransformFunctionValue(const GraphicsLayer::TransformValue& transformValue, size_t index, const IntSize& size, TransformOperation::OperationType transformType)
|
| -{
|
| - TransformOperation* op = (index >= transformValue.value()->operations().size()) ? 0 : transformValue.value()->operations()[index].get();
|
| -
|
| - switch (transformType) {
|
| - case TransformOperation::ROTATE:
|
| - return [NSNumber numberWithDouble:op ? (float) (static_cast<RotateTransformOperation*>(op)->angle() * M_PI / 180) : 0];
|
| -
|
| - case TransformOperation::SCALE_X:
|
| - return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->x() : 0];
|
| - case TransformOperation::SCALE_Y:
|
| - return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->y() : 0];
|
| -
|
| - case TransformOperation::TRANSLATE_X:
|
| - return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->x(size) : 0];
|
| - case TransformOperation::TRANSLATE_Y:
|
| - return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->x(size) : 0];
|
| -
|
| - case TransformOperation::SCALE:
|
| - case TransformOperation::TRANSLATE:
|
| - case TransformOperation::SKEW_X:
|
| - case TransformOperation::SKEW_Y:
|
| - case TransformOperation::SKEW:
|
| - case TransformOperation::MATRIX:
|
| - case TransformOperation::IDENTITY:
|
| - case TransformOperation::NONE: {
|
| - TransformationMatrix t;
|
| - if (op)
|
| - op->apply(t, size);
|
| - CATransform3D cat;
|
| - copyTransform(cat, t);
|
| - return [NSValue valueWithCATransform3D:cat];
|
| - }
|
| - }
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -static String getAnimationValueFunction(TransformOperation::OperationType transformType)
|
| -{
|
| - switch (transformType) {
|
| - case TransformOperation::ROTATE:
|
| - return "rotateZ";
|
| - case TransformOperation::SCALE_X:
|
| - return "scaleX";
|
| - case TransformOperation::SCALE_Y:
|
| - return "scaleY";
|
| - case TransformOperation::TRANSLATE_X:
|
| - return "translateX";
|
| - case TransformOperation::TRANSLATE_Y:
|
| - return "translateY";
|
| - default:
|
| - return String();
|
| - }
|
| -}
|
| -
|
| -static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& timingFunction)
|
| -{
|
| - switch (timingFunction.type()) {
|
| - case LinearTimingFunction:
|
| - return [CAMediaTimingFunction functionWithName:@"linear"];
|
| - case CubicBezierTimingFunction:
|
| - return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(timingFunction.x1()) :static_cast<float>(timingFunction.y1())
|
| - :static_cast<float>(timingFunction.x2()) :static_cast<float>(timingFunction.y2())];
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -#ifndef NDEBUG
|
| -static void setLayerBorderColor(PlatformLayer* layer, const Color& color)
|
| -{
|
| - CGColorRef borderColor = cgColor(color);
|
| - [layer setBorderColor:borderColor];
|
| - CGColorRelease(borderColor);
|
| -}
|
| -
|
| -static void clearBorderColor(PlatformLayer* layer)
|
| -{
|
| - [layer setBorderColor:nil];
|
| -}
|
| -#endif
|
| -
|
| -static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color)
|
| -{
|
| - CGColorRef bgColor = cgColor(color);
|
| - [layer setBackgroundColor:bgColor];
|
| - CGColorRelease(bgColor);
|
| -}
|
| -
|
| -static void clearLayerBackgroundColor(PlatformLayer* layer)
|
| -{
|
| - [layer setBackgroundColor:0];
|
| -}
|
| -
|
| -static CALayer* getPresentationLayer(CALayer* layer)
|
| -{
|
| - CALayer* presLayer = [layer presentationLayer];
|
| - if (!presLayer)
|
| - presLayer = layer;
|
| -
|
| - return presLayer;
|
| -}
|
| -
|
| -bool GraphicsLayer::graphicsContextsFlipped()
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -#ifndef NDEBUG
|
| -bool GraphicsLayer::showDebugBorders()
|
| -{
|
| - static int showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"];
|
| - return showDebugBorders;
|
| -}
|
| -
|
| -bool GraphicsLayer::showRepaintCounter()
|
| -{
|
| - static int showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"];
|
| - return showRepaintCounter;
|
| -}
|
| -#endif
|
| -
|
| -static NSDictionary* nullActionsDictionary()
|
| -{
|
| - NSNull* nullValue = [NSNull null];
|
| - NSDictionary* actions = [NSDictionary dictionaryWithObjectsAndKeys:
|
| - nullValue, @"anchorPoint",
|
| - nullValue, @"bounds",
|
| - nullValue, @"contents",
|
| - nullValue, @"contentsRect",
|
| - nullValue, @"opacity",
|
| - nullValue, @"position",
|
| - nullValue, @"shadowColor",
|
| - nullValue, @"sublayerTransform",
|
| - nullValue, @"sublayers",
|
| - nullValue, @"transform",
|
| -#ifndef NDEBUG
|
| - nullValue, @"zPosition",
|
| -#endif
|
| - nil];
|
| - return actions;
|
| -}
|
| -
|
| -GraphicsLayer* GraphicsLayer::createGraphicsLayer(GraphicsLayerClient* client)
|
| -{
|
| - return new GraphicsLayerCA(client);
|
| -}
|
| -
|
| -GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
|
| -: GraphicsLayer(client)
|
| -, m_contentLayerForImageOrVideo(false)
|
| -{
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - m_layer.adoptNS([[WebLayer alloc] init]);
|
| - [m_layer.get() setLayerOwner:this];
|
| -
|
| -#ifndef NDEBUG
|
| - updateDebugIndicators();
|
| -#endif
|
| -
|
| - m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]);
|
| - [m_animationDelegate.get() setLayer:this];
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -GraphicsLayerCA::~GraphicsLayerCA()
|
| -{
|
| - // Remove a inner layer if there is one.
|
| - clearContents();
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - // Clean up the WK layer.
|
| - if (m_layer) {
|
| - WebLayer* layer = m_layer.get();
|
| - [layer setLayerOwner:nil];
|
| - [layer removeFromSuperlayer];
|
| - }
|
| -
|
| - if (m_transformLayer)
|
| - [m_transformLayer.get() removeFromSuperlayer];
|
| -
|
| - // animationDidStart: can fire after this, so we need to clear out the layer on the delegate.
|
| - [m_animationDelegate.get() setLayer:0];
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setName(const String& name)
|
| -{
|
| - String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
|
| - GraphicsLayer::setName(longName);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [m_layer.get() setName:name];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -NativeLayer GraphicsLayerCA::nativeLayer() const
|
| -{
|
| - return m_layer.get();
|
| -}
|
| -
|
| -void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
|
| -{
|
| - GraphicsLayer::addChild(childLayer);
|
| -
|
| - GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
|
| -{
|
| - GraphicsLayer::addChildAtIndex(childLayer, index);
|
| -
|
| - GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() atIndex:index];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
|
| -{
|
| - // FIXME: share code with base class
|
| - ASSERT(childLayer != this);
|
| - childLayer->removeFromParent();
|
| -
|
| - bool found = false;
|
| - for (unsigned i = 0; i < m_children.size(); i++) {
|
| - if (sibling == m_children[i]) {
|
| - m_children.insert(i, childLayer);
|
| - found = true;
|
| - break;
|
| - }
|
| - }
|
| - childLayer->setParent(this);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
|
| - GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
|
| - if (found)
|
| - [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() below:siblingLayerCA->layerForSuperlayer()];
|
| - else {
|
| - m_children.append(childLayer);
|
| - [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
|
| - }
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
|
| -{
|
| - // FIXME: share code with base class
|
| - ASSERT(childLayer != this);
|
| - childLayer->removeFromParent();
|
| -
|
| - unsigned i;
|
| - bool found = false;
|
| - for (i = 0; i < m_children.size(); i++) {
|
| - if (sibling == m_children[i]) {
|
| - m_children.insert(i+1, childLayer);
|
| - found = true;
|
| - break;
|
| - }
|
| - }
|
| - childLayer->setParent(this);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
|
| - GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
|
| - if (found) {
|
| - [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() above:siblingLayerCA->layerForSuperlayer()];
|
| - } else {
|
| - m_children.append(childLayer);
|
| - [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
|
| - }
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
|
| -{
|
| - // FIXME: share code with base class
|
| - ASSERT(!newChild->parent());
|
| -
|
| - bool found = false;
|
| - for (unsigned i = 0; i < m_children.size(); i++) {
|
| - if (oldChild == m_children[i]) {
|
| - m_children[i] = newChild;
|
| - found = true;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (found) {
|
| - oldChild->setParent(0);
|
| -
|
| - newChild->removeFromParent();
|
| - newChild->setParent(this);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - GraphicsLayerCA* oldChildCA = static_cast<GraphicsLayerCA*>(oldChild);
|
| - GraphicsLayerCA* newChildCA = static_cast<GraphicsLayerCA*>(newChild);
|
| - [hostLayerForSublayers() replaceSublayer:oldChildCA->layerForSuperlayer() with:newChildCA->layerForSuperlayer()];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void GraphicsLayerCA::removeFromParent()
|
| -{
|
| - GraphicsLayer::removeFromParent();
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [layerForSuperlayer() removeFromSuperlayer];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setPosition(const FloatPoint& point)
|
| -{
|
| - // Don't short-circuit here, because position and anchor point are inter-dependent.
|
| - GraphicsLayer::setPosition(point);
|
| -
|
| - // Position is offset on the layer by the layer anchor point.
|
| - CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
|
| - m_position.y() + m_anchorPoint.y() * m_size.height());
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [primaryLayer() setPosition:posPoint];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
|
| -{
|
| - // Don't short-circuit here, because position and anchor point are inter-dependent.
|
| - bool zChanged = (point.z() != m_anchorPoint.z());
|
| - GraphicsLayer::setAnchorPoint(point);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - // set the value on the layer to the new transform.
|
| - [primaryLayer() setAnchorPoint:FloatPoint(point.x(), point.y())];
|
| -
|
| - if (zChanged)
|
| - [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
|
| -
|
| - // Position depends on anchor point, so update it now.
|
| - setPosition(m_position);
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setSize(const FloatSize& size)
|
| -{
|
| - GraphicsLayer::setSize(size);
|
| -
|
| - CGRect rect = CGRectMake(0.0f,
|
| - 0.0f,
|
| - m_size.width(),
|
| - m_size.height());
|
| -
|
| - CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - if (m_transformLayer) {
|
| - [m_transformLayer.get() setBounds:rect];
|
| -
|
| - // the anchor of the contents layer is always at 0.5, 0.5, so the position
|
| - // is center-relative
|
| - [m_layer.get() setPosition:centerPoint];
|
| - }
|
| -
|
| - bool needTiledLayer = requiresTiledLayer(m_size);
|
| - if (needTiledLayer != m_usingTiledLayer)
|
| - swapFromOrToTiledLayer(needTiledLayer);
|
| -
|
| - [m_layer.get() setBounds:rect];
|
| -
|
| - // Note that we don't resize m_contentsLayer. It's up the caller to do that.
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - // if we've changed the bounds, we need to recalculate the position
|
| - // of the layer, taking anchor point into account
|
| - setPosition(m_position);
|
| -}
|
| -
|
| -void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
|
| -{
|
| - GraphicsLayer::setTransform(t);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - CATransform3D transform;
|
| - copyTransform(transform, t);
|
| - [primaryLayer() setTransform:transform];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - // Remove any old transition entries for transform.
|
| - removeAllAnimationsForProperty(AnimatedPropertyWebkitTransform);
|
| -
|
| - // Even if we don't have a transition in the list, the layer may still have one.
|
| - // This happens when we are setting the final transform value after an animation or
|
| - // transition has ended. In removeAnimation we toss the entry from the list but don't
|
| - // remove it from the list. That way we aren't in danger of displaying a stale transform
|
| - // in the time between removing the animation and setting the new unanimated value. We
|
| - // can't do this in removeAnimation because we don't know the new transform value there.
|
| - String keyPath = propertyIdToString(AnimatedPropertyWebkitTransform);
|
| - CALayer* layer = animatedLayer(AnimatedPropertyWebkitTransform);
|
| -
|
| - for (int i = 0; ; ++i) {
|
| - String animName = keyPath + "_" + String::number(i);
|
| - if (![layer animationForKey: animName])
|
| - break;
|
| - [layer removeAnimationForKey:animName];
|
| - }
|
| -}
|
| -
|
| -void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
|
| -{
|
| - if (t == m_childrenTransform)
|
| - return;
|
| -
|
| - GraphicsLayer::setChildrenTransform(t);
|
| -
|
| - CATransform3D transform;
|
| - copyTransform(transform, t);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - // Set the value on the layer to the new transform.
|
| - [primaryLayer() setSublayerTransform:transform];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
|
| -{
|
| - String keyPath = GraphicsLayer::propertyIdToString(property);
|
| - for (short index = 0; ; ++index) {
|
| - String animName = keyPath + "_" + String::number(index);
|
| - CAAnimation* anim = [fromLayer animationForKey:animName];
|
| - if (!anim)
|
| - break;
|
| -
|
| - [anim retain];
|
| - [fromLayer removeAnimationForKey:animName];
|
| - [toLayer addAnimation:anim forKey:animName];
|
| - [anim release];
|
| - }
|
| -}
|
| -
|
| -static void moveSublayers(CALayer* fromLayer, CALayer* toLayer)
|
| -{
|
| - NSArray* sublayersCopy = [[fromLayer sublayers] copy]; // Avoid mutation while enumerating, and keep the sublayers alive.
|
| - NSEnumerator* childrenEnumerator = [sublayersCopy objectEnumerator];
|
| -
|
| - CALayer* layer;
|
| - while ((layer = [childrenEnumerator nextObject]) != nil) {
|
| - [layer removeFromSuperlayer];
|
| - [toLayer addSublayer:layer];
|
| - }
|
| - [sublayersCopy release];
|
| -}
|
| -
|
| -void GraphicsLayerCA::setPreserves3D(bool preserves3D)
|
| -{
|
| - GraphicsLayer::setPreserves3D(preserves3D);
|
| -
|
| - CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
|
| - CGPoint centerPoint = CGPointMake(0.5f, 0.5f);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - if (preserves3D && !m_transformLayer) {
|
| - // Create the transform layer.
|
| - m_transformLayer.adoptNS([[CATransformLayer alloc] init]);
|
| -
|
| - // Turn off default animations.
|
| - [m_transformLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
|
| -
|
| -#ifndef NDEBUG
|
| - [m_transformLayer.get() setName:[NSString stringWithFormat:@"Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this]];
|
| -#endif
|
| - // Copy the position from this layer.
|
| - [m_transformLayer.get() setBounds:[m_layer.get() bounds]];
|
| - [m_transformLayer.get() setPosition:[m_layer.get() position]];
|
| - [m_transformLayer.get() setAnchorPoint:[m_layer.get() anchorPoint]];
|
| - [m_transformLayer.get() setAnchorPointZ:[m_layer.get() anchorPointZ]];
|
| - [m_transformLayer.get() setContentsRect:[m_layer.get() contentsRect]];
|
| -#ifndef NDEBUG
|
| - [m_transformLayer.get() setZPosition:[m_layer.get() zPosition]];
|
| -#endif
|
| -
|
| - // The contents layer is positioned at (0,0) relative to the transformLayer.
|
| - [m_layer.get() setPosition:point];
|
| - [m_layer.get() setAnchorPoint:centerPoint];
|
| -#ifndef NDEBUG
|
| - [m_layer.get() setZPosition:0.0f];
|
| -#endif
|
| -
|
| - // Transfer the transform over.
|
| - [m_transformLayer.get() setTransform:[m_layer.get() transform]];
|
| - [m_layer.get() setTransform:CATransform3DIdentity];
|
| -
|
| - // Transfer the opacity from the old layer to the transform layer.
|
| - [m_transformLayer.get() setOpacity:m_opacity];
|
| - [m_layer.get() setOpacity:1];
|
| -
|
| - // Move this layer to be a child of the transform layer.
|
| - [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_transformLayer.get()];
|
| - [m_transformLayer.get() addSublayer:m_layer.get()];
|
| -
|
| - moveAnimation(AnimatedPropertyWebkitTransform, m_layer.get(), m_transformLayer.get());
|
| - moveSublayers(m_layer.get(), m_transformLayer.get());
|
| -
|
| - } else if (!preserves3D && m_transformLayer) {
|
| - // Relace the transformLayer in the parent with this layer.
|
| - [m_layer.get() removeFromSuperlayer];
|
| - [[m_transformLayer.get() superlayer] replaceSublayer:m_transformLayer.get() with:m_layer.get()];
|
| -
|
| - moveAnimation(AnimatedPropertyWebkitTransform, m_transformLayer.get(), m_layer.get());
|
| - moveSublayers(m_transformLayer.get(), m_layer.get());
|
| -
|
| - // Reset the layer position and transform.
|
| - [m_layer.get() setPosition:[m_transformLayer.get() position]];
|
| - [m_layer.get() setAnchorPoint:[m_transformLayer.get() anchorPoint]];
|
| - [m_layer.get() setAnchorPointZ:[m_transformLayer.get() anchorPointZ]];
|
| - [m_layer.get() setContentsRect:[m_transformLayer.get() contentsRect]];
|
| - [m_layer.get() setTransform:[m_transformLayer.get() transform]];
|
| - [m_layer.get() setOpacity:[m_transformLayer.get() opacity]];
|
| -#ifndef NDEBUG
|
| - [m_layer.get() setZPosition:[m_transformLayer.get() zPosition]];
|
| -#endif
|
| -
|
| - // Release the transform layer.
|
| - m_transformLayer = 0;
|
| - }
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
|
| -{
|
| - if (masksToBounds == m_masksToBounds)
|
| - return;
|
| -
|
| - GraphicsLayer::setMasksToBounds(masksToBounds);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [m_layer.get() setMasksToBounds:masksToBounds];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| -#ifndef NDEBUG
|
| - updateDebugIndicators();
|
| -#endif
|
| -}
|
| -
|
| -void GraphicsLayerCA::setDrawsContent(bool drawsContent)
|
| -{
|
| - if (drawsContent != m_drawsContent) {
|
| - GraphicsLayer::setDrawsContent(drawsContent);
|
| -
|
| - bool needTiledLayer = requiresTiledLayer(m_size);
|
| - if (needTiledLayer != m_usingTiledLayer)
|
| - swapFromOrToTiledLayer(needTiledLayer);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - // Clobber any existing content. If necessary, CA will create backing store on the next display.
|
| - [m_layer.get() setContents:nil];
|
| -
|
| -#ifndef NDEBUG
|
| - updateDebugIndicators();
|
| -#endif
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| - }
|
| -}
|
| -
|
| -void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* transition, double beginTime)
|
| -{
|
| - GraphicsLayer::setBackgroundColor(color, transition, beginTime);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - setHasContentsLayer(true);
|
| -
|
| - if (transition && !transition->isEmptyOrZeroDuration()) {
|
| - CALayer* presLayer = [m_contentsLayer.get() presentationLayer];
|
| - // If we don't have a presentationLayer, just use the CALayer
|
| - if (!presLayer)
|
| - presLayer = m_contentsLayer.get();
|
| -
|
| - // Get the current value of the background color from the layer
|
| - CGColorRef fromBackgroundColor = [presLayer backgroundColor];
|
| -
|
| - CGColorRef bgColor = cgColor(color);
|
| - setBasicAnimation(AnimatedPropertyBackgroundColor, "", 0, fromBackgroundColor, bgColor, true, transition, beginTime);
|
| - CGColorRelease(bgColor);
|
| - } else {
|
| - removeAllAnimationsForProperty(AnimatedPropertyBackgroundColor);
|
| - setHasContentsLayer(true);
|
| - setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
|
| - }
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::clearBackgroundColor()
|
| -{
|
| - if (!m_contentLayerForImageOrVideo)
|
| - setHasContentsLayer(false);
|
| - else
|
| - clearLayerBackgroundColor(m_contentsLayer.get());
|
| -}
|
| -
|
| -void GraphicsLayerCA::setContentsOpaque(bool opaque)
|
| -{
|
| - GraphicsLayer::setContentsOpaque(opaque);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [m_layer.get() setOpaque:m_contentsOpaque];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setBackfaceVisibility(bool visible)
|
| -{
|
| - if (m_backfaceVisibility == visible)
|
| - return;
|
| -
|
| - GraphicsLayer::setBackfaceVisibility(visible);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [m_layer.get() setDoubleSided:visible];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -bool GraphicsLayerCA::setOpacity(float opacity, const Animation* transition, double beginTime)
|
| -{
|
| - float clampedOpacity = max(0.0f, min(opacity, 1.0f));
|
| -
|
| - bool opacitiesDiffer = (m_opacity != clampedOpacity);
|
| -
|
| - GraphicsLayer::setOpacity(clampedOpacity, transition, beginTime);
|
| -
|
| - int animIndex = findAnimationEntry(AnimatedPropertyOpacity, 0);
|
| -
|
| - // If we don't have a transition just set the opacity
|
| - if (!transition || transition->isEmptyOrZeroDuration()) {
|
| - // Three cases:
|
| - // 1) no existing animation or transition: just set opacity
|
| - // 2) existing transition: clear it and set opacity
|
| - // 3) existing animation: just return
|
| - //
|
| - if (animIndex < 0 || m_animations[animIndex].isTransition()) {
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [primaryLayer() setOpacity:opacity];
|
| - if (animIndex >= 0) {
|
| - removeAllAnimationsForProperty(AnimatedPropertyOpacity);
|
| - animIndex = -1;
|
| - } else {
|
| - String keyPath = propertyIdToString(AnimatedPropertyOpacity);
|
| -
|
| - // FIXME: using hardcoded '0' here. We should be clearing all animations. For now there is only 1.
|
| - String animName = keyPath + "_0";
|
| - [animatedLayer(AnimatedPropertyOpacity) removeAnimationForKey:animName];
|
| - }
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| - } else {
|
| - // We have an animation, so don't set the opacity directly.
|
| - return false;
|
| - }
|
| - } else {
|
| - // At this point, we know we have a transition. But if it is the same and
|
| - // the opacity value has not changed, don't do anything.
|
| - if (!opacitiesDiffer &&
|
| - ((animIndex == -1) ||
|
| - (m_animations[animIndex].isTransition() && *(m_animations[animIndex].animation()) == *transition))) {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - // If an animation is running, ignore this transition, but still save the value.
|
| - if (animIndex >= 0 && !m_animations[animIndex].isTransition())
|
| - return false;
|
| -
|
| - bool didAnimate = false;
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - NSNumber* fromOpacityValue = nil;
|
| - NSNumber* toOpacityValue = [NSNumber numberWithFloat:opacity];
|
| -
|
| - if (transition && !transition->isEmptyOrZeroDuration()) {
|
| - CALayer* presLayer = getPresentationLayer(primaryLayer());
|
| - float fromOpacity = [presLayer opacity];
|
| - fromOpacityValue = [NSNumber numberWithFloat:fromOpacity];
|
| - setBasicAnimation(AnimatedPropertyOpacity, "", 0, fromOpacityValue, toOpacityValue, true, transition, beginTime);
|
| - didAnimate = true;
|
| - }
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - return didAnimate;
|
| -}
|
| -
|
| -void GraphicsLayerCA::setNeedsDisplay()
|
| -{
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - if (drawsContent())
|
| - [m_layer.get() setNeedsDisplay];
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect)
|
| -{
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - if (drawsContent())
|
| - [m_layer.get() setNeedsDisplayInRect:rect];
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -
|
| -bool GraphicsLayerCA::animateTransform(const TransformValueList& valueList, const IntSize& size, const Animation* anim, double beginTime, bool isTransition)
|
| -{
|
| - if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
|
| - return false;
|
| -
|
| - TransformValueList::FunctionList functionList;
|
| - bool isValid, hasBigRotation;
|
| - valueList.makeFunctionList(functionList, isValid, hasBigRotation);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - // Rules for animation:
|
| - //
|
| - // 1) If functionList is empty or we don't have a big rotation, we do a matrix animation. We could
|
| - // use component animation for lists without a big rotation, but there is no need to, and this
|
| - // is more efficient.
|
| - //
|
| - // 2) Otherwise we do a component hardware animation.
|
| - bool isMatrixAnimation = !isValid || !hasBigRotation;
|
| -
|
| - // Set transform to identity since we are animating components and we need the base
|
| - // to be the identity transform.
|
| - TransformationMatrix t;
|
| - CATransform3D toT3D;
|
| - copyTransform(toT3D, t);
|
| - [primaryLayer() setTransform:toT3D];
|
| -
|
| - bool isKeyframe = valueList.size() > 2;
|
| -
|
| - // Iterate through the transform functions, sending an animation for each one.
|
| - for (int functionIndex = 0; ; ++functionIndex) {
|
| - if (functionIndex >= static_cast<int>(functionList.size()) && !isMatrixAnimation)
|
| - break;
|
| -
|
| - TransformOperation::OperationType opType =
|
| -#if ENABLE(3D_TRANSFORMS)
|
| - isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[functionIndex];
|
| -#else
|
| - isMatrixAnimation ? TransformOperation::MATRIX : functionList[functionIndex];
|
| -#endif
|
| -
|
| - if (isKeyframe) {
|
| - NSMutableArray* timesArray = [[NSMutableArray alloc] init];
|
| - NSMutableArray* valArray = [[NSMutableArray alloc] init];
|
| - NSMutableArray* tfArray = [[NSMutableArray alloc] init];
|
| -
|
| - // Iterate through the keyframes, building arrays for the animation.
|
| - for (Vector<TransformValue>::const_iterator it = valueList.values().begin(); it != valueList.values().end(); ++it) {
|
| - const TransformValue& curValue = (*it);
|
| -
|
| - // fill in the key time and timing function
|
| - [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
|
| -
|
| - const TimingFunction* tf = 0;
|
| - if (curValue.timingFunction())
|
| - tf = curValue.timingFunction();
|
| - else if (anim->isTimingFunctionSet())
|
| - tf = &anim->timingFunction();
|
| -
|
| - CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction(LinearTimingFunction));
|
| - [tfArray addObject:timingFunction];
|
| -
|
| - // fill in the function
|
| - if (isMatrixAnimation) {
|
| - TransformationMatrix t;
|
| - curValue.value()->apply(size, t);
|
| - CATransform3D cat;
|
| - copyTransform(cat, t);
|
| - [valArray addObject:[NSValue valueWithCATransform3D:cat]];
|
| - } else
|
| - [valArray addObject:getTransformFunctionValue(curValue, functionIndex, size, opType)];
|
| - }
|
| -
|
| - // We toss the last tfArray value because it has to one shorter than the others.
|
| - [tfArray removeLastObject];
|
| -
|
| - setKeyframeAnimation(AnimatedPropertyWebkitTransform, getAnimationValueFunction(opType), functionIndex, timesArray, valArray, tfArray, isTransition, anim, beginTime);
|
| -
|
| - [timesArray release];
|
| - [valArray release];
|
| - [tfArray release];
|
| - } else {
|
| - // Is a transition
|
| - id fromValue, toValue;
|
| -
|
| - if (isMatrixAnimation) {
|
| - TransformationMatrix fromt, tot;
|
| - valueList.at(0).value()->apply(size, fromt);
|
| - valueList.at(1).value()->apply(size, tot);
|
| -
|
| - CATransform3D cat;
|
| - copyTransform(cat, fromt);
|
| - fromValue = [NSValue valueWithCATransform3D:cat];
|
| - copyTransform(cat, tot);
|
| - toValue = [NSValue valueWithCATransform3D:cat];
|
| - } else {
|
| - fromValue = getTransformFunctionValue(valueList.at(0), functionIndex, size, opType);
|
| - toValue = getTransformFunctionValue(valueList.at(1), functionIndex, size, opType);
|
| - }
|
| -
|
| - setBasicAnimation(AnimatedPropertyWebkitTransform, getAnimationValueFunction(opType), functionIndex, fromValue, toValue, isTransition, anim, beginTime);
|
| - }
|
| -
|
| - if (isMatrixAnimation)
|
| - break;
|
| - }
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| - return true;
|
| -}
|
| -
|
| -bool GraphicsLayerCA::animateFloat(AnimatedPropertyID property, const FloatValueList& valueList, const Animation* animation, double beginTime)
|
| -{
|
| - if (valueList.size() < 2)
|
| - return false;
|
| -
|
| - // if there is already is an animation for this property and it hasn't changed, ignore it.
|
| - int i = findAnimationEntry(property, 0);
|
| - if (i >= 0 && *m_animations[i].animation() == *animation) {
|
| - m_animations[i].setIsCurrent();
|
| - return false;
|
| - }
|
| -
|
| - if (valueList.size() == 2) {
|
| - float fromVal = valueList.at(0).value();
|
| - float toVal = valueList.at(1).value();
|
| - if (isnan(toVal) && isnan(fromVal))
|
| - return false;
|
| -
|
| - // initialize the property to 0
|
| - [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
|
| - setBasicAnimation(property, "", 0, isnan(fromVal) ? nil : [NSNumber numberWithFloat:fromVal], isnan(toVal) ? nil : [NSNumber numberWithFloat:toVal], false, animation, beginTime);
|
| - return true;
|
| - }
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - NSMutableArray* timesArray = [[NSMutableArray alloc] init];
|
| - NSMutableArray* valArray = [[NSMutableArray alloc] init];
|
| - NSMutableArray* tfArray = [[NSMutableArray alloc] init];
|
| -
|
| - for (unsigned i = 0; i < valueList.values().size(); ++i) {
|
| - const FloatValue& curValue = valueList.values()[i];
|
| - [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
|
| - [valArray addObject:[NSNumber numberWithFloat:curValue.value()]];
|
| -
|
| - const TimingFunction* tf = 0;
|
| - if (curValue.timingFunction())
|
| - tf = curValue.timingFunction();
|
| - else if (animation->isTimingFunctionSet())
|
| - tf = &animation->timingFunction();
|
| -
|
| - CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
|
| - [tfArray addObject:timingFunction];
|
| - }
|
| -
|
| - // We toss the last tfArray value because it has to one shorter than the others.
|
| - [tfArray removeLastObject];
|
| -
|
| - // Initialize the property to 0.
|
| - [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
|
| - // Then set the animation.
|
| - setKeyframeAnimation(property, "", 0, timesArray, valArray, tfArray, false, animation, beginTime);
|
| -
|
| - [timesArray release];
|
| - [valArray release];
|
| - [tfArray release];
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| - return true;
|
| -}
|
| -
|
| -void GraphicsLayerCA::setContentsToImage(Image* image)
|
| -{
|
| - if (image) {
|
| - setHasContentsLayer(true);
|
| -
|
| - // FIXME: is image flipping really a property of the graphics context?
|
| - bool needToFlip = GraphicsLayer::graphicsContextsFlipped();
|
| - CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero;
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - {
|
| - CGImageRef theImage = image->nativeImageForCurrentFrame();
|
| - // FIXME: maybe only do trilinear if the image is being scaled down,
|
| - // but then what if the layer size changes?
|
| -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
|
| - [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear];
|
| -#endif
|
| - if (needToFlip) {
|
| - CATransform3D 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};
|
| - [m_contentsLayer.get() setTransform:flipper];
|
| - }
|
| -
|
| - [m_contentsLayer.get() setAnchorPoint:anchorPoint];
|
| - [m_contentsLayer.get() setContents:(id)theImage];
|
| - }
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| - } else
|
| - setHasContentsLayer(false);
|
| -
|
| - m_contentLayerForImageOrVideo = (image != 0);
|
| -}
|
| -
|
| -void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer)
|
| -{
|
| - setContentsLayer(videoLayer);
|
| - m_contentLayerForImageOrVideo = (videoLayer != 0);
|
| -}
|
| -
|
| -void GraphicsLayerCA::clearContents()
|
| -{
|
| - if (m_contentLayerForImageOrVideo) {
|
| - setHasContentsLayer(false);
|
| - m_contentLayerForImageOrVideo = false;
|
| - }
|
| -}
|
| -
|
| -void GraphicsLayerCA::updateContentsRect()
|
| -{
|
| - if (m_client && m_contentsLayer) {
|
| - IntRect contentRect = m_client->contentsBox(this);
|
| -
|
| - CGPoint point = CGPointMake(contentRect.x(),
|
| - contentRect.y());
|
| - CGRect rect = CGRectMake(0.0f,
|
| - 0.0f,
|
| - contentRect.width(),
|
| - contentRect.height());
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [m_contentsLayer.get() setPosition:point];
|
| - [m_contentsLayer.get() setBounds:rect];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| - }
|
| -}
|
| -
|
| -void GraphicsLayerCA::setBasicAnimation(AnimatedPropertyID property, const String& valueFunction, short index, void* fromVal, void* toVal, bool isTransition, const Animation* transition, double beginTime)
|
| -{
|
| - ASSERT(fromVal || toVal);
|
| -
|
| - WebLayer* layer = animatedLayer(property);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - // add an entry for this animation
|
| - addAnimationEntry(property, index, isTransition, transition);
|
| -
|
| - String keyPath = propertyIdToString(property);
|
| - String animName = keyPath + "_" + String::number(index);
|
| -
|
| - CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:keyPath];
|
| -
|
| - double duration = transition->duration();
|
| - if (duration <= 0)
|
| - duration = cAnimationAlmostZeroDuration;
|
| -
|
| - float repeatCount = transition->iterationCount();
|
| - if (repeatCount < 0)
|
| - repeatCount = FLT_MAX;
|
| - else if (transition->direction()) // If we alternate, the number of cycles is halved
|
| - repeatCount /= 2;
|
| -
|
| - [basicAnim setDuration:duration];
|
| - [basicAnim setRepeatCount:repeatCount];
|
| - [basicAnim setAutoreverses:transition->direction()];
|
| - [basicAnim setRemovedOnCompletion:NO];
|
| -
|
| - // Note that currently transform is the only property which has animations
|
| - // with an index > 0.
|
| - [basicAnim setAdditive:property == AnimatedPropertyWebkitTransform];
|
| - [basicAnim setFillMode:@"extended"];
|
| - [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunction]];
|
| -
|
| - // Set the delegate (and property value).
|
| - int prop = isTransition ? property : AnimatedPropertyInvalid;
|
| - [basicAnim setValue:[NSNumber numberWithInt:prop] forKey:WebAnimationCSSPropertyKey];
|
| - [basicAnim setDelegate:m_animationDelegate.get()];
|
| -
|
| - NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
|
| - [basicAnim setBeginTime:bt];
|
| -
|
| - if (fromVal)
|
| - [basicAnim setFromValue:reinterpret_cast<id>(fromVal)];
|
| - if (toVal)
|
| - [basicAnim setToValue:reinterpret_cast<id>(toVal)];
|
| -
|
| - const TimingFunction* tf = 0;
|
| - if (transition->isTimingFunctionSet())
|
| - tf = &transition->timingFunction();
|
| -
|
| - CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
|
| - [basicAnim setTimingFunction:timingFunction];
|
| -
|
| - // Send over the animation.
|
| - [layer removeAnimationForKey:animName];
|
| - [layer addAnimation:basicAnim forKey:animName];
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setKeyframeAnimation(AnimatedPropertyID property, const String& valueFunction, short index, void* keys, void* values, void* timingFunctions,
|
| - bool isTransition, const Animation* anim, double beginTime)
|
| -{
|
| - PlatformLayer* layer = animatedLayer(property);
|
| -
|
| - // Add an entry for this animation (which may change beginTime).
|
| - addAnimationEntry(property, index, isTransition, anim);
|
| -
|
| - String keyPath = propertyIdToString(property);
|
| - String animName = keyPath + "_" + String::number(index);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:keyPath];
|
| -
|
| - double duration = anim->duration();
|
| - if (duration <= 0)
|
| - duration = cAnimationAlmostZeroDuration;
|
| -
|
| - float repeatCount = anim->iterationCount();
|
| - if (repeatCount < 0)
|
| - repeatCount = FLT_MAX;
|
| - else if (anim->direction())
|
| - repeatCount /= 2;
|
| -
|
| - [keyframeAnim setDuration:duration];
|
| - [keyframeAnim setRepeatCount:repeatCount];
|
| - [keyframeAnim setAutoreverses:anim->direction()];
|
| - [keyframeAnim setRemovedOnCompletion:NO];
|
| -
|
| - // The first animation is non-additive, all the rest are additive.
|
| - // Note that currently transform is the only property which has animations
|
| - // with an index > 0.
|
| - [keyframeAnim setAdditive:(property == AnimatedPropertyWebkitTransform) ? YES : NO];
|
| - [keyframeAnim setFillMode:@"extended"];
|
| - [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunction]];
|
| -
|
| - [keyframeAnim setKeyTimes:reinterpret_cast<id>(keys)];
|
| - [keyframeAnim setValues:reinterpret_cast<id>(values)];
|
| -
|
| - // Set the delegate (and property value).
|
| - int prop = isTransition ? property : AnimatedPropertyInvalid;
|
| - [keyframeAnim setValue:[NSNumber numberWithInt: prop] forKey:WebAnimationCSSPropertyKey];
|
| - [keyframeAnim setDelegate:m_animationDelegate.get()];
|
| -
|
| - NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
|
| - [keyframeAnim setBeginTime:bt];
|
| -
|
| - // Set the timing functions, if any.
|
| - if (timingFunctions != nil)
|
| - [keyframeAnim setTimingFunctions:(id)timingFunctions];
|
| -
|
| - // Send over the animation.
|
| - [layer removeAnimationForKey:animName];
|
| - [layer addAnimation:keyframeAnim forKey:animName];
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::suspendAnimations()
|
| -{
|
| - double t = currentTimeToMediaTime(currentTime());
|
| - [primaryLayer() setSpeed:0];
|
| - [primaryLayer() setTimeOffset:t];
|
| -}
|
| -
|
| -void GraphicsLayerCA::resumeAnimations()
|
| -{
|
| - [primaryLayer() setSpeed:1];
|
| - [primaryLayer() setTimeOffset:0];
|
| -}
|
| -
|
| -void GraphicsLayerCA::removeAnimation(int index, bool reset)
|
| -{
|
| - ASSERT(index >= 0);
|
| -
|
| - AnimatedPropertyID property = m_animations[index].property();
|
| -
|
| - // Set the value of the property and remove the animation.
|
| - String keyPath = propertyIdToString(property);
|
| - String animName = keyPath + "_" + String::number(m_animations[index].index());
|
| - CALayer* layer = animatedLayer(property);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - // If we are not resetting, it means we are pausing. So we need to get the current presentation
|
| - // value into the property before we remove the animation.
|
| - if (!reset) {
|
| - // Put the current value into the property.
|
| - CALayer* presLayer = [layer presentationLayer];
|
| - if (presLayer)
|
| - [layer setValue:[presLayer valueForKeyPath:keyPath] forKeyPath:keyPath];
|
| -
|
| - // Make sure the saved values accurately reflect the value in the layer.
|
| - id val = [layer valueForKeyPath:keyPath];
|
| - switch (property) {
|
| - case AnimatedPropertyWebkitTransform:
|
| - // FIXME: needs comment explaining why the m_transform is not obtained from the layer
|
| - break;
|
| - case AnimatedPropertyBackgroundColor:
|
| - m_backgroundColor = Color(reinterpret_cast<CGColorRef>(val));
|
| - break;
|
| - case AnimatedPropertyOpacity:
|
| - m_opacity = [val floatValue];
|
| - break;
|
| - case AnimatedPropertyInvalid:
|
| - ASSERT_NOT_REACHED();
|
| - break;
|
| - }
|
| - }
|
| -
|
| - // If we have reached the end of an animation, we don't want to actually remove the
|
| - // animation from the CALayer. At some point we will be setting the property to its
|
| - // unanimated value and at that point we will remove the animation. That will avoid
|
| - // any flashing between the time the animation is removed and the property is set.
|
| - if (!reset || m_animations[index].isTransition())
|
| - [layer removeAnimationForKey:animName];
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - // Remove the animation entry.
|
| - m_animations.remove(index);
|
| -}
|
| -
|
| -PlatformLayer* GraphicsLayerCA::hostLayerForSublayers() const
|
| -{
|
| - return m_transformLayer ? m_transformLayer.get() : m_layer.get();
|
| -}
|
| -
|
| -PlatformLayer* GraphicsLayerCA::layerForSuperlayer() const
|
| -{
|
| - if (m_transformLayer)
|
| - return m_transformLayer.get();
|
| -
|
| - return m_layer.get();
|
| -}
|
| -
|
| -PlatformLayer* GraphicsLayerCA::platformLayer() const
|
| -{
|
| - return primaryLayer();
|
| -}
|
| -
|
| -#ifndef NDEBUG
|
| -void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
|
| -{
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - if (color.isValid())
|
| - setLayerBackgroundColor(m_layer.get(), color);
|
| - else
|
| - clearLayerBackgroundColor(m_layer.get());
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth)
|
| -{
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - if (color.isValid()) {
|
| - setLayerBorderColor(m_layer.get(), color);
|
| - [m_layer.get() setBorderWidth:borderWidth];
|
| - } else {
|
| - clearBorderColor(m_layer.get());
|
| - [m_layer.get() setBorderWidth:0];
|
| - }
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setZPosition(float position)
|
| -{
|
| - GraphicsLayer::setZPosition(position);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| - [primaryLayer() setZPosition:position];
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -#endif
|
| -
|
| -bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
|
| -{
|
| - if (!m_drawsContent)
|
| - return false;
|
| -
|
| - // FIXME: catch zero-size height or width here (or earlier)?
|
| - return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension;
|
| -}
|
| -
|
| -void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer)
|
| -{
|
| - if (userTiledLayer == m_usingTiledLayer)
|
| - return;
|
| -
|
| - CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize);
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - RetainPtr<CALayer> oldLayer = m_layer.get();
|
| -
|
| - Class layerClass = userTiledLayer ? [WebTiledLayer self] : [WebLayer self];
|
| - m_layer.adoptNS([[layerClass alloc] init]);
|
| -
|
| - if (userTiledLayer) {
|
| - WebTiledLayer* tiledLayer = (WebTiledLayer*)m_layer.get();
|
| - [tiledLayer setTileSize:tileSize];
|
| - [tiledLayer setLevelsOfDetail:1];
|
| - [tiledLayer setLevelsOfDetailBias:0];
|
| -
|
| - if (GraphicsLayer::graphicsContextsFlipped())
|
| - [tiledLayer setContentsGravity:@"bottomLeft"];
|
| - else
|
| - [tiledLayer setContentsGravity:@"topLeft"];
|
| - }
|
| -
|
| - [m_layer.get() setLayerOwner:this];
|
| - [m_layer.get() setSublayers:[oldLayer.get() sublayers]];
|
| -
|
| - [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()];
|
| -
|
| - [m_layer.get() setBounds:[oldLayer.get() bounds]];
|
| - [m_layer.get() setPosition:[oldLayer.get() position]];
|
| - [m_layer.get() setAnchorPoint:[oldLayer.get() anchorPoint]];
|
| - [m_layer.get() setOpaque:[oldLayer.get() isOpaque]];
|
| - [m_layer.get() setOpacity:[oldLayer.get() opacity]];
|
| - [m_layer.get() setTransform:[oldLayer.get() transform]];
|
| - [m_layer.get() setSublayerTransform:[oldLayer.get() sublayerTransform]];
|
| - [m_layer.get() setDoubleSided:[oldLayer.get() isDoubleSided]];
|
| -#ifndef NDEBUG
|
| - [m_layer.get() setZPosition:[oldLayer.get() zPosition]];
|
| -#endif
|
| -
|
| -#ifndef NDEBUG
|
| - String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name;
|
| - [m_layer.get() setName:name];
|
| -#endif
|
| -
|
| - // move over animations
|
| - moveAnimation(AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get());
|
| - moveAnimation(AnimatedPropertyOpacity, oldLayer.get(), m_layer.get());
|
| - moveAnimation(AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get());
|
| -
|
| - // need to tell new layer to draw itself
|
| - setNeedsDisplay();
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - m_usingTiledLayer = userTiledLayer;
|
| -
|
| -#ifndef NDEBUG
|
| - updateDebugIndicators();
|
| -#endif
|
| -}
|
| -
|
| -void GraphicsLayerCA::setHasContentsLayer(bool hasLayer)
|
| -{
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - if (hasLayer && !m_contentsLayer) {
|
| - // create the inner layer
|
| - WebLayer* contentsLayer = [WebLayer layer];
|
| -#ifndef NDEBUG
|
| - [contentsLayer setName:@"Contents Layer"];
|
| -#endif
|
| - setContentsLayer(contentsLayer);
|
| -
|
| - } else if (!hasLayer && m_contentsLayer)
|
| - setContentsLayer(0);
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer)
|
| -{
|
| - if (contentsLayer == m_contentsLayer)
|
| - return;
|
| -
|
| - BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| -
|
| - if (m_contentsLayer) {
|
| - [m_contentsLayer.get() removeFromSuperlayer];
|
| - m_contentsLayer = 0;
|
| - }
|
| -
|
| - if (contentsLayer) {
|
| - // Turn off implicit animations on the inner layer.
|
| - [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
|
| -
|
| - m_contentsLayer.adoptNS([contentsLayer retain]);
|
| - [m_contentsLayer.get() setAnchorPoint:CGPointZero];
|
| - [m_layer.get() addSublayer:m_contentsLayer.get()];
|
| -
|
| - updateContentsRect();
|
| -
|
| - // Set contents to nil if the layer does not draw its own content.
|
| - if (m_client && !drawsContent())
|
| - [m_layer.get() setContents:nil];
|
| -
|
| -#ifndef NDEBUG
|
| - if (showDebugBorders()) {
|
| - setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180));
|
| - [m_contentsLayer.get() setBorderWidth:1.0f];
|
| - }
|
| -#endif
|
| - }
|
| -#ifndef NDEBUG
|
| - updateDebugIndicators();
|
| -#endif
|
| -
|
| - END_BLOCK_OBJC_EXCEPTIONS
|
| -}
|
| -
|
| -} // namespace WebCore
|
| -
|
| -
|
| -#endif // USE(ACCELERATED_COMPOSITING)
|
| +/*
|
| + * Copyright (C) 2009 Apple Inc. All rights reserved.
|
| + *
|
| + * Redistribution and use in source and binary forms, with or without
|
| + * modification, are permitted provided that the following conditions
|
| + * are met:
|
| + * 1. Redistributions of source code must retain the above copyright
|
| + * notice, this list of conditions and the following disclaimer.
|
| + * 2. Redistributions in binary form must reproduce the above copyright
|
| + * notice, this list of conditions and the following disclaimer in the
|
| + * documentation and/or other materials provided with the distribution.
|
| + *
|
| + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
| + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
| + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
| + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
| + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
| + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
| + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| + */
|
| +
|
| +#import "config.h"
|
| +
|
| +#if USE(ACCELERATED_COMPOSITING)
|
| +
|
| +#import "GraphicsLayerCA.h"
|
| +
|
| +// Temporary
|
| +#import <QuartzCore/CAAnimationPrivate.h>
|
| +#import <QuartzCore/CAValueFunction.h>
|
| +
|
| +#import "Animation.h"
|
| +#import "BlockExceptions.h"
|
| +#import "CString.h"
|
| +#import "FloatRect.h"
|
| +#import "Image.h"
|
| +#import "PlatformString.h"
|
| +#import <QuartzCore/QuartzCore.h>
|
| +#import "RotateTransformOperation.h"
|
| +#import "ScaleTransformOperation.h"
|
| +#import "SystemTime.h"
|
| +#import "TranslateTransformOperation.h"
|
| +#import "WebLayer.h"
|
| +#import "WebTiledLayer.h"
|
| +#import <wtf/CurrentTime.h>
|
| +
|
| +using namespace std;
|
| +
|
| +namespace WebCore {
|
| +
|
| +// The threshold width or height above which a tiled layer will be used. This should be
|
| +// large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL
|
| +// texture size limit on all supported hardware.
|
| +static const int cMaxPixelDimension = 2000;
|
| +
|
| +// The width and height of a single tile in a tiled layer. Should be large enough to
|
| +// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
|
| +// to keep the overall tile cost low.
|
| +static const int cTiledLayerTileSize = 512;
|
| +
|
| +// If we send a duration of 0 to CA, then it will use the default duration
|
| +// of 250ms. So send a very small value instead.
|
| +static const float cAnimationAlmostZeroDuration = 1e-3f;
|
| +
|
| +// CACurrentMediaTime() is a time since boot. These methods convert between that and
|
| +// WebCore time, which is system time (UTC).
|
| +static CFTimeInterval currentTimeToMediaTime(double t)
|
| +{
|
| + return CACurrentMediaTime() + t - WTF::currentTime();
|
| +}
|
| +
|
| +static double mediaTimeToCurrentTime(CFTimeInterval t)
|
| +{
|
| + return WTF::currentTime() + t - CACurrentMediaTime();
|
| +}
|
| +
|
| +} // namespace WebCore
|
| +
|
| +static NSString* const WebAnimationCSSPropertyKey = @"GraphicsLayerCA_property";
|
| +
|
| +@interface WebAnimationDelegate : NSObject {
|
| + WebCore::GraphicsLayerCA* m_graphicsLayer;
|
| +}
|
| +
|
| +- (void)animationDidStart:(CAAnimation *)anim;
|
| +- (WebCore::GraphicsLayerCA*)graphicsLayer;
|
| +- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer;
|
| +
|
| +@end
|
| +
|
| +@implementation WebAnimationDelegate
|
| +
|
| +- (void)animationDidStart:(CAAnimation *)animation
|
| +{
|
| + if (!m_graphicsLayer)
|
| + return;
|
| +
|
| + double startTime = WebCore::mediaTimeToCurrentTime([animation beginTime]);
|
| + m_graphicsLayer->client()->notifyAnimationStarted(m_graphicsLayer, startTime);
|
| +}
|
| +
|
| +- (WebCore::GraphicsLayerCA*)graphicsLayer
|
| +{
|
| + return m_graphicsLayer;
|
| +}
|
| +
|
| +- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer
|
| +{
|
| + m_graphicsLayer = graphicsLayer;
|
| +}
|
| +
|
| +@end
|
| +
|
| +namespace WebCore {
|
| +
|
| +inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t)
|
| +{
|
| + toT3D = CATransform3DMakeAffineTransform(t);
|
| +}
|
| +
|
| +TransformationMatrix CAToTransform3D(const CATransform3D& fromT3D)
|
| +{
|
| + return TransformationMatrix(CATransform3DGetAffineTransform(fromT3D));
|
| +}
|
| +
|
| +static NSValue* getTransformFunctionValue(const GraphicsLayer::TransformValue& transformValue, size_t index, const IntSize& size, TransformOperation::OperationType transformType)
|
| +{
|
| + TransformOperation* op = (index >= transformValue.value()->operations().size()) ? 0 : transformValue.value()->operations()[index].get();
|
| +
|
| + switch (transformType) {
|
| + case TransformOperation::ROTATE:
|
| + return [NSNumber numberWithDouble:op ? (float) (static_cast<RotateTransformOperation*>(op)->angle() * M_PI / 180) : 0];
|
| +
|
| + case TransformOperation::SCALE_X:
|
| + return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->x() : 0];
|
| + case TransformOperation::SCALE_Y:
|
| + return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->y() : 0];
|
| +
|
| + case TransformOperation::TRANSLATE_X:
|
| + return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->x(size) : 0];
|
| + case TransformOperation::TRANSLATE_Y:
|
| + return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->x(size) : 0];
|
| +
|
| + case TransformOperation::SCALE:
|
| + case TransformOperation::TRANSLATE:
|
| + case TransformOperation::SKEW_X:
|
| + case TransformOperation::SKEW_Y:
|
| + case TransformOperation::SKEW:
|
| + case TransformOperation::MATRIX:
|
| + case TransformOperation::IDENTITY:
|
| + case TransformOperation::NONE: {
|
| + TransformationMatrix t;
|
| + if (op)
|
| + op->apply(t, size);
|
| + CATransform3D cat;
|
| + copyTransform(cat, t);
|
| + return [NSValue valueWithCATransform3D:cat];
|
| + }
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static String getAnimationValueFunction(TransformOperation::OperationType transformType)
|
| +{
|
| + switch (transformType) {
|
| + case TransformOperation::ROTATE:
|
| + return "rotateZ";
|
| + case TransformOperation::SCALE_X:
|
| + return "scaleX";
|
| + case TransformOperation::SCALE_Y:
|
| + return "scaleY";
|
| + case TransformOperation::TRANSLATE_X:
|
| + return "translateX";
|
| + case TransformOperation::TRANSLATE_Y:
|
| + return "translateY";
|
| + default:
|
| + return String();
|
| + }
|
| +}
|
| +
|
| +static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& timingFunction)
|
| +{
|
| + switch (timingFunction.type()) {
|
| + case LinearTimingFunction:
|
| + return [CAMediaTimingFunction functionWithName:@"linear"];
|
| + case CubicBezierTimingFunction:
|
| + return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(timingFunction.x1()) :static_cast<float>(timingFunction.y1())
|
| + :static_cast<float>(timingFunction.x2()) :static_cast<float>(timingFunction.y2())];
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +#ifndef NDEBUG
|
| +static void setLayerBorderColor(PlatformLayer* layer, const Color& color)
|
| +{
|
| + CGColorRef borderColor = cgColor(color);
|
| + [layer setBorderColor:borderColor];
|
| + CGColorRelease(borderColor);
|
| +}
|
| +
|
| +static void clearBorderColor(PlatformLayer* layer)
|
| +{
|
| + [layer setBorderColor:nil];
|
| +}
|
| +#endif
|
| +
|
| +static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color)
|
| +{
|
| + CGColorRef bgColor = cgColor(color);
|
| + [layer setBackgroundColor:bgColor];
|
| + CGColorRelease(bgColor);
|
| +}
|
| +
|
| +static void clearLayerBackgroundColor(PlatformLayer* layer)
|
| +{
|
| + [layer setBackgroundColor:0];
|
| +}
|
| +
|
| +static CALayer* getPresentationLayer(CALayer* layer)
|
| +{
|
| + CALayer* presLayer = [layer presentationLayer];
|
| + if (!presLayer)
|
| + presLayer = layer;
|
| +
|
| + return presLayer;
|
| +}
|
| +
|
| +bool GraphicsLayer::graphicsContextsFlipped()
|
| +{
|
| + return true;
|
| +}
|
| +
|
| +#ifndef NDEBUG
|
| +bool GraphicsLayer::showDebugBorders()
|
| +{
|
| + static int showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"];
|
| + return showDebugBorders;
|
| +}
|
| +
|
| +bool GraphicsLayer::showRepaintCounter()
|
| +{
|
| + static int showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"];
|
| + return showRepaintCounter;
|
| +}
|
| +#endif
|
| +
|
| +static NSDictionary* nullActionsDictionary()
|
| +{
|
| + NSNull* nullValue = [NSNull null];
|
| + NSDictionary* actions = [NSDictionary dictionaryWithObjectsAndKeys:
|
| + nullValue, @"anchorPoint",
|
| + nullValue, @"bounds",
|
| + nullValue, @"contents",
|
| + nullValue, @"contentsRect",
|
| + nullValue, @"opacity",
|
| + nullValue, @"position",
|
| + nullValue, @"shadowColor",
|
| + nullValue, @"sublayerTransform",
|
| + nullValue, @"sublayers",
|
| + nullValue, @"transform",
|
| +#ifndef NDEBUG
|
| + nullValue, @"zPosition",
|
| +#endif
|
| + nil];
|
| + return actions;
|
| +}
|
| +
|
| +GraphicsLayer* GraphicsLayer::createGraphicsLayer(GraphicsLayerClient* client)
|
| +{
|
| + return new GraphicsLayerCA(client);
|
| +}
|
| +
|
| +GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
|
| +: GraphicsLayer(client)
|
| +, m_contentLayerForImageOrVideo(false)
|
| +{
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + m_layer.adoptNS([[WebLayer alloc] init]);
|
| + [m_layer.get() setLayerOwner:this];
|
| +
|
| +#ifndef NDEBUG
|
| + updateDebugIndicators();
|
| +#endif
|
| +
|
| + m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]);
|
| + [m_animationDelegate.get() setLayer:this];
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +GraphicsLayerCA::~GraphicsLayerCA()
|
| +{
|
| + // Remove a inner layer if there is one.
|
| + clearContents();
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + // Clean up the WK layer.
|
| + if (m_layer) {
|
| + WebLayer* layer = m_layer.get();
|
| + [layer setLayerOwner:nil];
|
| + [layer removeFromSuperlayer];
|
| + }
|
| +
|
| + if (m_transformLayer)
|
| + [m_transformLayer.get() removeFromSuperlayer];
|
| +
|
| + // animationDidStart: can fire after this, so we need to clear out the layer on the delegate.
|
| + [m_animationDelegate.get() setLayer:0];
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setName(const String& name)
|
| +{
|
| + String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
|
| + GraphicsLayer::setName(longName);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [m_layer.get() setName:name];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +NativeLayer GraphicsLayerCA::nativeLayer() const
|
| +{
|
| + return m_layer.get();
|
| +}
|
| +
|
| +void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
|
| +{
|
| + GraphicsLayer::addChild(childLayer);
|
| +
|
| + GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
|
| +{
|
| + GraphicsLayer::addChildAtIndex(childLayer, index);
|
| +
|
| + GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() atIndex:index];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
|
| +{
|
| + // FIXME: share code with base class
|
| + ASSERT(childLayer != this);
|
| + childLayer->removeFromParent();
|
| +
|
| + bool found = false;
|
| + for (unsigned i = 0; i < m_children.size(); i++) {
|
| + if (sibling == m_children[i]) {
|
| + m_children.insert(i, childLayer);
|
| + found = true;
|
| + break;
|
| + }
|
| + }
|
| + childLayer->setParent(this);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
|
| + GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
|
| + if (found)
|
| + [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() below:siblingLayerCA->layerForSuperlayer()];
|
| + else {
|
| + m_children.append(childLayer);
|
| + [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
|
| + }
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
|
| +{
|
| + // FIXME: share code with base class
|
| + ASSERT(childLayer != this);
|
| + childLayer->removeFromParent();
|
| +
|
| + unsigned i;
|
| + bool found = false;
|
| + for (i = 0; i < m_children.size(); i++) {
|
| + if (sibling == m_children[i]) {
|
| + m_children.insert(i+1, childLayer);
|
| + found = true;
|
| + break;
|
| + }
|
| + }
|
| + childLayer->setParent(this);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
|
| + GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
|
| + if (found) {
|
| + [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() above:siblingLayerCA->layerForSuperlayer()];
|
| + } else {
|
| + m_children.append(childLayer);
|
| + [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
|
| + }
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
|
| +{
|
| + // FIXME: share code with base class
|
| + ASSERT(!newChild->parent());
|
| +
|
| + bool found = false;
|
| + for (unsigned i = 0; i < m_children.size(); i++) {
|
| + if (oldChild == m_children[i]) {
|
| + m_children[i] = newChild;
|
| + found = true;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (found) {
|
| + oldChild->setParent(0);
|
| +
|
| + newChild->removeFromParent();
|
| + newChild->setParent(this);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + GraphicsLayerCA* oldChildCA = static_cast<GraphicsLayerCA*>(oldChild);
|
| + GraphicsLayerCA* newChildCA = static_cast<GraphicsLayerCA*>(newChild);
|
| + [hostLayerForSublayers() replaceSublayer:oldChildCA->layerForSuperlayer() with:newChildCA->layerForSuperlayer()];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +void GraphicsLayerCA::removeFromParent()
|
| +{
|
| + GraphicsLayer::removeFromParent();
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [layerForSuperlayer() removeFromSuperlayer];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setPosition(const FloatPoint& point)
|
| +{
|
| + // Don't short-circuit here, because position and anchor point are inter-dependent.
|
| + GraphicsLayer::setPosition(point);
|
| +
|
| + // Position is offset on the layer by the layer anchor point.
|
| + CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
|
| + m_position.y() + m_anchorPoint.y() * m_size.height());
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [primaryLayer() setPosition:posPoint];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
|
| +{
|
| + // Don't short-circuit here, because position and anchor point are inter-dependent.
|
| + bool zChanged = (point.z() != m_anchorPoint.z());
|
| + GraphicsLayer::setAnchorPoint(point);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + // set the value on the layer to the new transform.
|
| + [primaryLayer() setAnchorPoint:FloatPoint(point.x(), point.y())];
|
| +
|
| + if (zChanged)
|
| + [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
|
| +
|
| + // Position depends on anchor point, so update it now.
|
| + setPosition(m_position);
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setSize(const FloatSize& size)
|
| +{
|
| + GraphicsLayer::setSize(size);
|
| +
|
| + CGRect rect = CGRectMake(0.0f,
|
| + 0.0f,
|
| + m_size.width(),
|
| + m_size.height());
|
| +
|
| + CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + if (m_transformLayer) {
|
| + [m_transformLayer.get() setBounds:rect];
|
| +
|
| + // the anchor of the contents layer is always at 0.5, 0.5, so the position
|
| + // is center-relative
|
| + [m_layer.get() setPosition:centerPoint];
|
| + }
|
| +
|
| + bool needTiledLayer = requiresTiledLayer(m_size);
|
| + if (needTiledLayer != m_usingTiledLayer)
|
| + swapFromOrToTiledLayer(needTiledLayer);
|
| +
|
| + [m_layer.get() setBounds:rect];
|
| +
|
| + // Note that we don't resize m_contentsLayer. It's up the caller to do that.
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + // if we've changed the bounds, we need to recalculate the position
|
| + // of the layer, taking anchor point into account
|
| + setPosition(m_position);
|
| +}
|
| +
|
| +void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
|
| +{
|
| + GraphicsLayer::setTransform(t);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + CATransform3D transform;
|
| + copyTransform(transform, t);
|
| + [primaryLayer() setTransform:transform];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + // Remove any old transition entries for transform.
|
| + removeAllAnimationsForProperty(AnimatedPropertyWebkitTransform);
|
| +
|
| + // Even if we don't have a transition in the list, the layer may still have one.
|
| + // This happens when we are setting the final transform value after an animation or
|
| + // transition has ended. In removeAnimation we toss the entry from the list but don't
|
| + // remove it from the list. That way we aren't in danger of displaying a stale transform
|
| + // in the time between removing the animation and setting the new unanimated value. We
|
| + // can't do this in removeAnimation because we don't know the new transform value there.
|
| + String keyPath = propertyIdToString(AnimatedPropertyWebkitTransform);
|
| + CALayer* layer = animatedLayer(AnimatedPropertyWebkitTransform);
|
| +
|
| + for (int i = 0; ; ++i) {
|
| + String animName = keyPath + "_" + String::number(i);
|
| + if (![layer animationForKey: animName])
|
| + break;
|
| + [layer removeAnimationForKey:animName];
|
| + }
|
| +}
|
| +
|
| +void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
|
| +{
|
| + if (t == m_childrenTransform)
|
| + return;
|
| +
|
| + GraphicsLayer::setChildrenTransform(t);
|
| +
|
| + CATransform3D transform;
|
| + copyTransform(transform, t);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + // Set the value on the layer to the new transform.
|
| + [primaryLayer() setSublayerTransform:transform];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
|
| +{
|
| + String keyPath = GraphicsLayer::propertyIdToString(property);
|
| + for (short index = 0; ; ++index) {
|
| + String animName = keyPath + "_" + String::number(index);
|
| + CAAnimation* anim = [fromLayer animationForKey:animName];
|
| + if (!anim)
|
| + break;
|
| +
|
| + [anim retain];
|
| + [fromLayer removeAnimationForKey:animName];
|
| + [toLayer addAnimation:anim forKey:animName];
|
| + [anim release];
|
| + }
|
| +}
|
| +
|
| +static void moveSublayers(CALayer* fromLayer, CALayer* toLayer)
|
| +{
|
| + NSArray* sublayersCopy = [[fromLayer sublayers] copy]; // Avoid mutation while enumerating, and keep the sublayers alive.
|
| + NSEnumerator* childrenEnumerator = [sublayersCopy objectEnumerator];
|
| +
|
| + CALayer* layer;
|
| + while ((layer = [childrenEnumerator nextObject]) != nil) {
|
| + [layer removeFromSuperlayer];
|
| + [toLayer addSublayer:layer];
|
| + }
|
| + [sublayersCopy release];
|
| +}
|
| +
|
| +void GraphicsLayerCA::setPreserves3D(bool preserves3D)
|
| +{
|
| + GraphicsLayer::setPreserves3D(preserves3D);
|
| +
|
| + CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
|
| + CGPoint centerPoint = CGPointMake(0.5f, 0.5f);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + if (preserves3D && !m_transformLayer) {
|
| + // Create the transform layer.
|
| + m_transformLayer.adoptNS([[CATransformLayer alloc] init]);
|
| +
|
| + // Turn off default animations.
|
| + [m_transformLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
|
| +
|
| +#ifndef NDEBUG
|
| + [m_transformLayer.get() setName:[NSString stringWithFormat:@"Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this]];
|
| +#endif
|
| + // Copy the position from this layer.
|
| + [m_transformLayer.get() setBounds:[m_layer.get() bounds]];
|
| + [m_transformLayer.get() setPosition:[m_layer.get() position]];
|
| + [m_transformLayer.get() setAnchorPoint:[m_layer.get() anchorPoint]];
|
| + [m_transformLayer.get() setAnchorPointZ:[m_layer.get() anchorPointZ]];
|
| + [m_transformLayer.get() setContentsRect:[m_layer.get() contentsRect]];
|
| +#ifndef NDEBUG
|
| + [m_transformLayer.get() setZPosition:[m_layer.get() zPosition]];
|
| +#endif
|
| +
|
| + // The contents layer is positioned at (0,0) relative to the transformLayer.
|
| + [m_layer.get() setPosition:point];
|
| + [m_layer.get() setAnchorPoint:centerPoint];
|
| +#ifndef NDEBUG
|
| + [m_layer.get() setZPosition:0.0f];
|
| +#endif
|
| +
|
| + // Transfer the transform over.
|
| + [m_transformLayer.get() setTransform:[m_layer.get() transform]];
|
| + [m_layer.get() setTransform:CATransform3DIdentity];
|
| +
|
| + // Transfer the opacity from the old layer to the transform layer.
|
| + [m_transformLayer.get() setOpacity:m_opacity];
|
| + [m_layer.get() setOpacity:1];
|
| +
|
| + // Move this layer to be a child of the transform layer.
|
| + [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_transformLayer.get()];
|
| + [m_transformLayer.get() addSublayer:m_layer.get()];
|
| +
|
| + moveAnimation(AnimatedPropertyWebkitTransform, m_layer.get(), m_transformLayer.get());
|
| + moveSublayers(m_layer.get(), m_transformLayer.get());
|
| +
|
| + } else if (!preserves3D && m_transformLayer) {
|
| + // Relace the transformLayer in the parent with this layer.
|
| + [m_layer.get() removeFromSuperlayer];
|
| + [[m_transformLayer.get() superlayer] replaceSublayer:m_transformLayer.get() with:m_layer.get()];
|
| +
|
| + moveAnimation(AnimatedPropertyWebkitTransform, m_transformLayer.get(), m_layer.get());
|
| + moveSublayers(m_transformLayer.get(), m_layer.get());
|
| +
|
| + // Reset the layer position and transform.
|
| + [m_layer.get() setPosition:[m_transformLayer.get() position]];
|
| + [m_layer.get() setAnchorPoint:[m_transformLayer.get() anchorPoint]];
|
| + [m_layer.get() setAnchorPointZ:[m_transformLayer.get() anchorPointZ]];
|
| + [m_layer.get() setContentsRect:[m_transformLayer.get() contentsRect]];
|
| + [m_layer.get() setTransform:[m_transformLayer.get() transform]];
|
| + [m_layer.get() setOpacity:[m_transformLayer.get() opacity]];
|
| +#ifndef NDEBUG
|
| + [m_layer.get() setZPosition:[m_transformLayer.get() zPosition]];
|
| +#endif
|
| +
|
| + // Release the transform layer.
|
| + m_transformLayer = 0;
|
| + }
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
|
| +{
|
| + if (masksToBounds == m_masksToBounds)
|
| + return;
|
| +
|
| + GraphicsLayer::setMasksToBounds(masksToBounds);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [m_layer.get() setMasksToBounds:masksToBounds];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| +#ifndef NDEBUG
|
| + updateDebugIndicators();
|
| +#endif
|
| +}
|
| +
|
| +void GraphicsLayerCA::setDrawsContent(bool drawsContent)
|
| +{
|
| + if (drawsContent != m_drawsContent) {
|
| + GraphicsLayer::setDrawsContent(drawsContent);
|
| +
|
| + bool needTiledLayer = requiresTiledLayer(m_size);
|
| + if (needTiledLayer != m_usingTiledLayer)
|
| + swapFromOrToTiledLayer(needTiledLayer);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + // Clobber any existing content. If necessary, CA will create backing store on the next display.
|
| + [m_layer.get() setContents:nil];
|
| +
|
| +#ifndef NDEBUG
|
| + updateDebugIndicators();
|
| +#endif
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| + }
|
| +}
|
| +
|
| +void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* transition, double beginTime)
|
| +{
|
| + GraphicsLayer::setBackgroundColor(color, transition, beginTime);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + setHasContentsLayer(true);
|
| +
|
| + if (transition && !transition->isEmptyOrZeroDuration()) {
|
| + CALayer* presLayer = [m_contentsLayer.get() presentationLayer];
|
| + // If we don't have a presentationLayer, just use the CALayer
|
| + if (!presLayer)
|
| + presLayer = m_contentsLayer.get();
|
| +
|
| + // Get the current value of the background color from the layer
|
| + CGColorRef fromBackgroundColor = [presLayer backgroundColor];
|
| +
|
| + CGColorRef bgColor = cgColor(color);
|
| + setBasicAnimation(AnimatedPropertyBackgroundColor, "", 0, fromBackgroundColor, bgColor, true, transition, beginTime);
|
| + CGColorRelease(bgColor);
|
| + } else {
|
| + removeAllAnimationsForProperty(AnimatedPropertyBackgroundColor);
|
| + setHasContentsLayer(true);
|
| + setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
|
| + }
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::clearBackgroundColor()
|
| +{
|
| + if (!m_contentLayerForImageOrVideo)
|
| + setHasContentsLayer(false);
|
| + else
|
| + clearLayerBackgroundColor(m_contentsLayer.get());
|
| +}
|
| +
|
| +void GraphicsLayerCA::setContentsOpaque(bool opaque)
|
| +{
|
| + GraphicsLayer::setContentsOpaque(opaque);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [m_layer.get() setOpaque:m_contentsOpaque];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setBackfaceVisibility(bool visible)
|
| +{
|
| + if (m_backfaceVisibility == visible)
|
| + return;
|
| +
|
| + GraphicsLayer::setBackfaceVisibility(visible);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [m_layer.get() setDoubleSided:visible];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +bool GraphicsLayerCA::setOpacity(float opacity, const Animation* transition, double beginTime)
|
| +{
|
| + float clampedOpacity = max(0.0f, min(opacity, 1.0f));
|
| +
|
| + bool opacitiesDiffer = (m_opacity != clampedOpacity);
|
| +
|
| + GraphicsLayer::setOpacity(clampedOpacity, transition, beginTime);
|
| +
|
| + int animIndex = findAnimationEntry(AnimatedPropertyOpacity, 0);
|
| +
|
| + // If we don't have a transition just set the opacity
|
| + if (!transition || transition->isEmptyOrZeroDuration()) {
|
| + // Three cases:
|
| + // 1) no existing animation or transition: just set opacity
|
| + // 2) existing transition: clear it and set opacity
|
| + // 3) existing animation: just return
|
| + //
|
| + if (animIndex < 0 || m_animations[animIndex].isTransition()) {
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [primaryLayer() setOpacity:opacity];
|
| + if (animIndex >= 0) {
|
| + removeAllAnimationsForProperty(AnimatedPropertyOpacity);
|
| + animIndex = -1;
|
| + } else {
|
| + String keyPath = propertyIdToString(AnimatedPropertyOpacity);
|
| +
|
| + // FIXME: using hardcoded '0' here. We should be clearing all animations. For now there is only 1.
|
| + String animName = keyPath + "_0";
|
| + [animatedLayer(AnimatedPropertyOpacity) removeAnimationForKey:animName];
|
| + }
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| + } else {
|
| + // We have an animation, so don't set the opacity directly.
|
| + return false;
|
| + }
|
| + } else {
|
| + // At this point, we know we have a transition. But if it is the same and
|
| + // the opacity value has not changed, don't do anything.
|
| + if (!opacitiesDiffer &&
|
| + ((animIndex == -1) ||
|
| + (m_animations[animIndex].isTransition() && *(m_animations[animIndex].animation()) == *transition))) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + // If an animation is running, ignore this transition, but still save the value.
|
| + if (animIndex >= 0 && !m_animations[animIndex].isTransition())
|
| + return false;
|
| +
|
| + bool didAnimate = false;
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + NSNumber* fromOpacityValue = nil;
|
| + NSNumber* toOpacityValue = [NSNumber numberWithFloat:opacity];
|
| +
|
| + if (transition && !transition->isEmptyOrZeroDuration()) {
|
| + CALayer* presLayer = getPresentationLayer(primaryLayer());
|
| + float fromOpacity = [presLayer opacity];
|
| + fromOpacityValue = [NSNumber numberWithFloat:fromOpacity];
|
| + setBasicAnimation(AnimatedPropertyOpacity, "", 0, fromOpacityValue, toOpacityValue, true, transition, beginTime);
|
| + didAnimate = true;
|
| + }
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + return didAnimate;
|
| +}
|
| +
|
| +void GraphicsLayerCA::setNeedsDisplay()
|
| +{
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + if (drawsContent())
|
| + [m_layer.get() setNeedsDisplay];
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect)
|
| +{
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + if (drawsContent())
|
| + [m_layer.get() setNeedsDisplayInRect:rect];
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +
|
| +bool GraphicsLayerCA::animateTransform(const TransformValueList& valueList, const IntSize& size, const Animation* anim, double beginTime, bool isTransition)
|
| +{
|
| + if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
|
| + return false;
|
| +
|
| + TransformValueList::FunctionList functionList;
|
| + bool isValid, hasBigRotation;
|
| + valueList.makeFunctionList(functionList, isValid, hasBigRotation);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + // Rules for animation:
|
| + //
|
| + // 1) If functionList is empty or we don't have a big rotation, we do a matrix animation. We could
|
| + // use component animation for lists without a big rotation, but there is no need to, and this
|
| + // is more efficient.
|
| + //
|
| + // 2) Otherwise we do a component hardware animation.
|
| + bool isMatrixAnimation = !isValid || !hasBigRotation;
|
| +
|
| + // Set transform to identity since we are animating components and we need the base
|
| + // to be the identity transform.
|
| + TransformationMatrix t;
|
| + CATransform3D toT3D;
|
| + copyTransform(toT3D, t);
|
| + [primaryLayer() setTransform:toT3D];
|
| +
|
| + bool isKeyframe = valueList.size() > 2;
|
| +
|
| + // Iterate through the transform functions, sending an animation for each one.
|
| + for (int functionIndex = 0; ; ++functionIndex) {
|
| + if (functionIndex >= static_cast<int>(functionList.size()) && !isMatrixAnimation)
|
| + break;
|
| +
|
| + TransformOperation::OperationType opType =
|
| +#if ENABLE(3D_TRANSFORMS)
|
| + isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[functionIndex];
|
| +#else
|
| + isMatrixAnimation ? TransformOperation::MATRIX : functionList[functionIndex];
|
| +#endif
|
| +
|
| + if (isKeyframe) {
|
| + NSMutableArray* timesArray = [[NSMutableArray alloc] init];
|
| + NSMutableArray* valArray = [[NSMutableArray alloc] init];
|
| + NSMutableArray* tfArray = [[NSMutableArray alloc] init];
|
| +
|
| + // Iterate through the keyframes, building arrays for the animation.
|
| + for (Vector<TransformValue>::const_iterator it = valueList.values().begin(); it != valueList.values().end(); ++it) {
|
| + const TransformValue& curValue = (*it);
|
| +
|
| + // fill in the key time and timing function
|
| + [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
|
| +
|
| + const TimingFunction* tf = 0;
|
| + if (curValue.timingFunction())
|
| + tf = curValue.timingFunction();
|
| + else if (anim->isTimingFunctionSet())
|
| + tf = &anim->timingFunction();
|
| +
|
| + CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction(LinearTimingFunction));
|
| + [tfArray addObject:timingFunction];
|
| +
|
| + // fill in the function
|
| + if (isMatrixAnimation) {
|
| + TransformationMatrix t;
|
| + curValue.value()->apply(size, t);
|
| + CATransform3D cat;
|
| + copyTransform(cat, t);
|
| + [valArray addObject:[NSValue valueWithCATransform3D:cat]];
|
| + } else
|
| + [valArray addObject:getTransformFunctionValue(curValue, functionIndex, size, opType)];
|
| + }
|
| +
|
| + // We toss the last tfArray value because it has to one shorter than the others.
|
| + [tfArray removeLastObject];
|
| +
|
| + setKeyframeAnimation(AnimatedPropertyWebkitTransform, getAnimationValueFunction(opType), functionIndex, timesArray, valArray, tfArray, isTransition, anim, beginTime);
|
| +
|
| + [timesArray release];
|
| + [valArray release];
|
| + [tfArray release];
|
| + } else {
|
| + // Is a transition
|
| + id fromValue, toValue;
|
| +
|
| + if (isMatrixAnimation) {
|
| + TransformationMatrix fromt, tot;
|
| + valueList.at(0).value()->apply(size, fromt);
|
| + valueList.at(1).value()->apply(size, tot);
|
| +
|
| + CATransform3D cat;
|
| + copyTransform(cat, fromt);
|
| + fromValue = [NSValue valueWithCATransform3D:cat];
|
| + copyTransform(cat, tot);
|
| + toValue = [NSValue valueWithCATransform3D:cat];
|
| + } else {
|
| + fromValue = getTransformFunctionValue(valueList.at(0), functionIndex, size, opType);
|
| + toValue = getTransformFunctionValue(valueList.at(1), functionIndex, size, opType);
|
| + }
|
| +
|
| + setBasicAnimation(AnimatedPropertyWebkitTransform, getAnimationValueFunction(opType), functionIndex, fromValue, toValue, isTransition, anim, beginTime);
|
| + }
|
| +
|
| + if (isMatrixAnimation)
|
| + break;
|
| + }
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| + return true;
|
| +}
|
| +
|
| +bool GraphicsLayerCA::animateFloat(AnimatedPropertyID property, const FloatValueList& valueList, const Animation* animation, double beginTime)
|
| +{
|
| + if (valueList.size() < 2)
|
| + return false;
|
| +
|
| + // if there is already is an animation for this property and it hasn't changed, ignore it.
|
| + int i = findAnimationEntry(property, 0);
|
| + if (i >= 0 && *m_animations[i].animation() == *animation) {
|
| + m_animations[i].setIsCurrent();
|
| + return false;
|
| + }
|
| +
|
| + if (valueList.size() == 2) {
|
| + float fromVal = valueList.at(0).value();
|
| + float toVal = valueList.at(1).value();
|
| + if (isnan(toVal) && isnan(fromVal))
|
| + return false;
|
| +
|
| + // initialize the property to 0
|
| + [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
|
| + setBasicAnimation(property, "", 0, isnan(fromVal) ? nil : [NSNumber numberWithFloat:fromVal], isnan(toVal) ? nil : [NSNumber numberWithFloat:toVal], false, animation, beginTime);
|
| + return true;
|
| + }
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + NSMutableArray* timesArray = [[NSMutableArray alloc] init];
|
| + NSMutableArray* valArray = [[NSMutableArray alloc] init];
|
| + NSMutableArray* tfArray = [[NSMutableArray alloc] init];
|
| +
|
| + for (unsigned i = 0; i < valueList.values().size(); ++i) {
|
| + const FloatValue& curValue = valueList.values()[i];
|
| + [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
|
| + [valArray addObject:[NSNumber numberWithFloat:curValue.value()]];
|
| +
|
| + const TimingFunction* tf = 0;
|
| + if (curValue.timingFunction())
|
| + tf = curValue.timingFunction();
|
| + else if (animation->isTimingFunctionSet())
|
| + tf = &animation->timingFunction();
|
| +
|
| + CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
|
| + [tfArray addObject:timingFunction];
|
| + }
|
| +
|
| + // We toss the last tfArray value because it has to one shorter than the others.
|
| + [tfArray removeLastObject];
|
| +
|
| + // Initialize the property to 0.
|
| + [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
|
| + // Then set the animation.
|
| + setKeyframeAnimation(property, "", 0, timesArray, valArray, tfArray, false, animation, beginTime);
|
| +
|
| + [timesArray release];
|
| + [valArray release];
|
| + [tfArray release];
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| + return true;
|
| +}
|
| +
|
| +void GraphicsLayerCA::setContentsToImage(Image* image)
|
| +{
|
| + if (image) {
|
| + setHasContentsLayer(true);
|
| +
|
| + // FIXME: is image flipping really a property of the graphics context?
|
| + bool needToFlip = GraphicsLayer::graphicsContextsFlipped();
|
| + CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero;
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + {
|
| + CGImageRef theImage = image->nativeImageForCurrentFrame();
|
| + // FIXME: maybe only do trilinear if the image is being scaled down,
|
| + // but then what if the layer size changes?
|
| +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
|
| + [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear];
|
| +#endif
|
| + if (needToFlip) {
|
| + CATransform3D 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};
|
| + [m_contentsLayer.get() setTransform:flipper];
|
| + }
|
| +
|
| + [m_contentsLayer.get() setAnchorPoint:anchorPoint];
|
| + [m_contentsLayer.get() setContents:(id)theImage];
|
| + }
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| + } else
|
| + setHasContentsLayer(false);
|
| +
|
| + m_contentLayerForImageOrVideo = (image != 0);
|
| +}
|
| +
|
| +void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer)
|
| +{
|
| + setContentsLayer(videoLayer);
|
| + m_contentLayerForImageOrVideo = (videoLayer != 0);
|
| +}
|
| +
|
| +void GraphicsLayerCA::clearContents()
|
| +{
|
| + if (m_contentLayerForImageOrVideo) {
|
| + setHasContentsLayer(false);
|
| + m_contentLayerForImageOrVideo = false;
|
| + }
|
| +}
|
| +
|
| +void GraphicsLayerCA::updateContentsRect()
|
| +{
|
| + if (m_client && m_contentsLayer) {
|
| + IntRect contentRect = m_client->contentsBox(this);
|
| +
|
| + CGPoint point = CGPointMake(contentRect.x(),
|
| + contentRect.y());
|
| + CGRect rect = CGRectMake(0.0f,
|
| + 0.0f,
|
| + contentRect.width(),
|
| + contentRect.height());
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [m_contentsLayer.get() setPosition:point];
|
| + [m_contentsLayer.get() setBounds:rect];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| + }
|
| +}
|
| +
|
| +void GraphicsLayerCA::setBasicAnimation(AnimatedPropertyID property, const String& valueFunction, short index, void* fromVal, void* toVal, bool isTransition, const Animation* transition, double beginTime)
|
| +{
|
| + ASSERT(fromVal || toVal);
|
| +
|
| + WebLayer* layer = animatedLayer(property);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + // add an entry for this animation
|
| + addAnimationEntry(property, index, isTransition, transition);
|
| +
|
| + String keyPath = propertyIdToString(property);
|
| + String animName = keyPath + "_" + String::number(index);
|
| +
|
| + CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:keyPath];
|
| +
|
| + double duration = transition->duration();
|
| + if (duration <= 0)
|
| + duration = cAnimationAlmostZeroDuration;
|
| +
|
| + float repeatCount = transition->iterationCount();
|
| + if (repeatCount < 0)
|
| + repeatCount = FLT_MAX;
|
| + else if (transition->direction()) // If we alternate, the number of cycles is halved
|
| + repeatCount /= 2;
|
| +
|
| + [basicAnim setDuration:duration];
|
| + [basicAnim setRepeatCount:repeatCount];
|
| + [basicAnim setAutoreverses:transition->direction()];
|
| + [basicAnim setRemovedOnCompletion:NO];
|
| +
|
| + // Note that currently transform is the only property which has animations
|
| + // with an index > 0.
|
| + [basicAnim setAdditive:property == AnimatedPropertyWebkitTransform];
|
| + [basicAnim setFillMode:@"extended"];
|
| + [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunction]];
|
| +
|
| + // Set the delegate (and property value).
|
| + int prop = isTransition ? property : AnimatedPropertyInvalid;
|
| + [basicAnim setValue:[NSNumber numberWithInt:prop] forKey:WebAnimationCSSPropertyKey];
|
| + [basicAnim setDelegate:m_animationDelegate.get()];
|
| +
|
| + NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
|
| + [basicAnim setBeginTime:bt];
|
| +
|
| + if (fromVal)
|
| + [basicAnim setFromValue:reinterpret_cast<id>(fromVal)];
|
| + if (toVal)
|
| + [basicAnim setToValue:reinterpret_cast<id>(toVal)];
|
| +
|
| + const TimingFunction* tf = 0;
|
| + if (transition->isTimingFunctionSet())
|
| + tf = &transition->timingFunction();
|
| +
|
| + CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
|
| + [basicAnim setTimingFunction:timingFunction];
|
| +
|
| + // Send over the animation.
|
| + [layer removeAnimationForKey:animName];
|
| + [layer addAnimation:basicAnim forKey:animName];
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setKeyframeAnimation(AnimatedPropertyID property, const String& valueFunction, short index, void* keys, void* values, void* timingFunctions,
|
| + bool isTransition, const Animation* anim, double beginTime)
|
| +{
|
| + PlatformLayer* layer = animatedLayer(property);
|
| +
|
| + // Add an entry for this animation (which may change beginTime).
|
| + addAnimationEntry(property, index, isTransition, anim);
|
| +
|
| + String keyPath = propertyIdToString(property);
|
| + String animName = keyPath + "_" + String::number(index);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:keyPath];
|
| +
|
| + double duration = anim->duration();
|
| + if (duration <= 0)
|
| + duration = cAnimationAlmostZeroDuration;
|
| +
|
| + float repeatCount = anim->iterationCount();
|
| + if (repeatCount < 0)
|
| + repeatCount = FLT_MAX;
|
| + else if (anim->direction())
|
| + repeatCount /= 2;
|
| +
|
| + [keyframeAnim setDuration:duration];
|
| + [keyframeAnim setRepeatCount:repeatCount];
|
| + [keyframeAnim setAutoreverses:anim->direction()];
|
| + [keyframeAnim setRemovedOnCompletion:NO];
|
| +
|
| + // The first animation is non-additive, all the rest are additive.
|
| + // Note that currently transform is the only property which has animations
|
| + // with an index > 0.
|
| + [keyframeAnim setAdditive:(property == AnimatedPropertyWebkitTransform) ? YES : NO];
|
| + [keyframeAnim setFillMode:@"extended"];
|
| + [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunction]];
|
| +
|
| + [keyframeAnim setKeyTimes:reinterpret_cast<id>(keys)];
|
| + [keyframeAnim setValues:reinterpret_cast<id>(values)];
|
| +
|
| + // Set the delegate (and property value).
|
| + int prop = isTransition ? property : AnimatedPropertyInvalid;
|
| + [keyframeAnim setValue:[NSNumber numberWithInt: prop] forKey:WebAnimationCSSPropertyKey];
|
| + [keyframeAnim setDelegate:m_animationDelegate.get()];
|
| +
|
| + NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
|
| + [keyframeAnim setBeginTime:bt];
|
| +
|
| + // Set the timing functions, if any.
|
| + if (timingFunctions != nil)
|
| + [keyframeAnim setTimingFunctions:(id)timingFunctions];
|
| +
|
| + // Send over the animation.
|
| + [layer removeAnimationForKey:animName];
|
| + [layer addAnimation:keyframeAnim forKey:animName];
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::suspendAnimations()
|
| +{
|
| + double t = currentTimeToMediaTime(currentTime());
|
| + [primaryLayer() setSpeed:0];
|
| + [primaryLayer() setTimeOffset:t];
|
| +}
|
| +
|
| +void GraphicsLayerCA::resumeAnimations()
|
| +{
|
| + [primaryLayer() setSpeed:1];
|
| + [primaryLayer() setTimeOffset:0];
|
| +}
|
| +
|
| +void GraphicsLayerCA::removeAnimation(int index, bool reset)
|
| +{
|
| + ASSERT(index >= 0);
|
| +
|
| + AnimatedPropertyID property = m_animations[index].property();
|
| +
|
| + // Set the value of the property and remove the animation.
|
| + String keyPath = propertyIdToString(property);
|
| + String animName = keyPath + "_" + String::number(m_animations[index].index());
|
| + CALayer* layer = animatedLayer(property);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + // If we are not resetting, it means we are pausing. So we need to get the current presentation
|
| + // value into the property before we remove the animation.
|
| + if (!reset) {
|
| + // Put the current value into the property.
|
| + CALayer* presLayer = [layer presentationLayer];
|
| + if (presLayer)
|
| + [layer setValue:[presLayer valueForKeyPath:keyPath] forKeyPath:keyPath];
|
| +
|
| + // Make sure the saved values accurately reflect the value in the layer.
|
| + id val = [layer valueForKeyPath:keyPath];
|
| + switch (property) {
|
| + case AnimatedPropertyWebkitTransform:
|
| + // FIXME: needs comment explaining why the m_transform is not obtained from the layer
|
| + break;
|
| + case AnimatedPropertyBackgroundColor:
|
| + m_backgroundColor = Color(reinterpret_cast<CGColorRef>(val));
|
| + break;
|
| + case AnimatedPropertyOpacity:
|
| + m_opacity = [val floatValue];
|
| + break;
|
| + case AnimatedPropertyInvalid:
|
| + ASSERT_NOT_REACHED();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // If we have reached the end of an animation, we don't want to actually remove the
|
| + // animation from the CALayer. At some point we will be setting the property to its
|
| + // unanimated value and at that point we will remove the animation. That will avoid
|
| + // any flashing between the time the animation is removed and the property is set.
|
| + if (!reset || m_animations[index].isTransition())
|
| + [layer removeAnimationForKey:animName];
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + // Remove the animation entry.
|
| + m_animations.remove(index);
|
| +}
|
| +
|
| +PlatformLayer* GraphicsLayerCA::hostLayerForSublayers() const
|
| +{
|
| + return m_transformLayer ? m_transformLayer.get() : m_layer.get();
|
| +}
|
| +
|
| +PlatformLayer* GraphicsLayerCA::layerForSuperlayer() const
|
| +{
|
| + if (m_transformLayer)
|
| + return m_transformLayer.get();
|
| +
|
| + return m_layer.get();
|
| +}
|
| +
|
| +PlatformLayer* GraphicsLayerCA::platformLayer() const
|
| +{
|
| + return primaryLayer();
|
| +}
|
| +
|
| +#ifndef NDEBUG
|
| +void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
|
| +{
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + if (color.isValid())
|
| + setLayerBackgroundColor(m_layer.get(), color);
|
| + else
|
| + clearLayerBackgroundColor(m_layer.get());
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth)
|
| +{
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + if (color.isValid()) {
|
| + setLayerBorderColor(m_layer.get(), color);
|
| + [m_layer.get() setBorderWidth:borderWidth];
|
| + } else {
|
| + clearBorderColor(m_layer.get());
|
| + [m_layer.get() setBorderWidth:0];
|
| + }
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setZPosition(float position)
|
| +{
|
| + GraphicsLayer::setZPosition(position);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| + [primaryLayer() setZPosition:position];
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +#endif
|
| +
|
| +bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
|
| +{
|
| + if (!m_drawsContent)
|
| + return false;
|
| +
|
| + // FIXME: catch zero-size height or width here (or earlier)?
|
| + return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension;
|
| +}
|
| +
|
| +void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer)
|
| +{
|
| + if (userTiledLayer == m_usingTiledLayer)
|
| + return;
|
| +
|
| + CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize);
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + RetainPtr<CALayer> oldLayer = m_layer.get();
|
| +
|
| + Class layerClass = userTiledLayer ? [WebTiledLayer self] : [WebLayer self];
|
| + m_layer.adoptNS([[layerClass alloc] init]);
|
| +
|
| + if (userTiledLayer) {
|
| + WebTiledLayer* tiledLayer = (WebTiledLayer*)m_layer.get();
|
| + [tiledLayer setTileSize:tileSize];
|
| + [tiledLayer setLevelsOfDetail:1];
|
| + [tiledLayer setLevelsOfDetailBias:0];
|
| +
|
| + if (GraphicsLayer::graphicsContextsFlipped())
|
| + [tiledLayer setContentsGravity:@"bottomLeft"];
|
| + else
|
| + [tiledLayer setContentsGravity:@"topLeft"];
|
| + }
|
| +
|
| + [m_layer.get() setLayerOwner:this];
|
| + [m_layer.get() setSublayers:[oldLayer.get() sublayers]];
|
| +
|
| + [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()];
|
| +
|
| + [m_layer.get() setBounds:[oldLayer.get() bounds]];
|
| + [m_layer.get() setPosition:[oldLayer.get() position]];
|
| + [m_layer.get() setAnchorPoint:[oldLayer.get() anchorPoint]];
|
| + [m_layer.get() setOpaque:[oldLayer.get() isOpaque]];
|
| + [m_layer.get() setOpacity:[oldLayer.get() opacity]];
|
| + [m_layer.get() setTransform:[oldLayer.get() transform]];
|
| + [m_layer.get() setSublayerTransform:[oldLayer.get() sublayerTransform]];
|
| + [m_layer.get() setDoubleSided:[oldLayer.get() isDoubleSided]];
|
| +#ifndef NDEBUG
|
| + [m_layer.get() setZPosition:[oldLayer.get() zPosition]];
|
| +#endif
|
| +
|
| +#ifndef NDEBUG
|
| + String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name;
|
| + [m_layer.get() setName:name];
|
| +#endif
|
| +
|
| + // move over animations
|
| + moveAnimation(AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get());
|
| + moveAnimation(AnimatedPropertyOpacity, oldLayer.get(), m_layer.get());
|
| + moveAnimation(AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get());
|
| +
|
| + // need to tell new layer to draw itself
|
| + setNeedsDisplay();
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + m_usingTiledLayer = userTiledLayer;
|
| +
|
| +#ifndef NDEBUG
|
| + updateDebugIndicators();
|
| +#endif
|
| +}
|
| +
|
| +void GraphicsLayerCA::setHasContentsLayer(bool hasLayer)
|
| +{
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + if (hasLayer && !m_contentsLayer) {
|
| + // create the inner layer
|
| + WebLayer* contentsLayer = [WebLayer layer];
|
| +#ifndef NDEBUG
|
| + [contentsLayer setName:@"Contents Layer"];
|
| +#endif
|
| + setContentsLayer(contentsLayer);
|
| +
|
| + } else if (!hasLayer && m_contentsLayer)
|
| + setContentsLayer(0);
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer)
|
| +{
|
| + if (contentsLayer == m_contentsLayer)
|
| + return;
|
| +
|
| + BEGIN_BLOCK_OBJC_EXCEPTIONS
|
| +
|
| + if (m_contentsLayer) {
|
| + [m_contentsLayer.get() removeFromSuperlayer];
|
| + m_contentsLayer = 0;
|
| + }
|
| +
|
| + if (contentsLayer) {
|
| + // Turn off implicit animations on the inner layer.
|
| + [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
|
| +
|
| + m_contentsLayer.adoptNS([contentsLayer retain]);
|
| + [m_contentsLayer.get() setAnchorPoint:CGPointZero];
|
| + [m_layer.get() addSublayer:m_contentsLayer.get()];
|
| +
|
| + updateContentsRect();
|
| +
|
| + // Set contents to nil if the layer does not draw its own content.
|
| + if (m_client && !drawsContent())
|
| + [m_layer.get() setContents:nil];
|
| +
|
| +#ifndef NDEBUG
|
| + if (showDebugBorders()) {
|
| + setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180));
|
| + [m_contentsLayer.get() setBorderWidth:1.0f];
|
| + }
|
| +#endif
|
| + }
|
| +#ifndef NDEBUG
|
| + updateDebugIndicators();
|
| +#endif
|
| +
|
| + END_BLOCK_OBJC_EXCEPTIONS
|
| +}
|
| +
|
| +} // namespace WebCore
|
| +
|
| +
|
| +#endif // USE(ACCELERATED_COMPOSITING)
|
|
|