diff options
Diffstat (limited to 'WebCore/platform/graphics/mac/GraphicsLayerCA.mm')
-rw-r--r-- | WebCore/platform/graphics/mac/GraphicsLayerCA.mm | 243 |
1 files changed, 114 insertions, 129 deletions
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index 395a691..d4cd851 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -55,6 +55,8 @@ using namespace std; namespace WebCore { +static NSString * const WebKitAnimationBeginTimeSetKey = @"WebKitAnimationBeginTimeSet"; + // 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. @@ -101,11 +103,8 @@ static double mediaTimeToCurrentTime(CFTimeInterval t) - (void)animationDidStart:(CAAnimation *)animation { - if (!m_graphicsLayer) - return; - - double startTime = WebCore::mediaTimeToCurrentTime([animation beginTime]); - m_graphicsLayer->client()->notifyAnimationStarted(m_graphicsLayer, startTime); + if (m_graphicsLayer) + m_graphicsLayer->animationDidStart(animation); } - (WebCore::GraphicsLayerCA*)graphicsLayer @@ -197,7 +196,7 @@ static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, } #if HAVE_MODERN_QUARTZCORE -static NSString* getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType) +static NSString *getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType) { // Use literal strings to avoid link-time dependency on those symbols. switch (transformType) { @@ -247,20 +246,9 @@ static String propertyIdToString(AnimatedPropertyID property) return ""; } -static String animationIdentifier(AnimatedPropertyID property, const String& keyframesName, int index) +static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index) { - StringBuilder builder; - - builder.append(propertyIdToString(property)); - builder.append("_"); - - if (!keyframesName.isEmpty()) { - builder.append(keyframesName); - builder.append("_"); - } - builder.append("_"); - builder.append(String::number(index)); - return builder.toString(); + return animationName + String::format("_%d_%d", property, index); } static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction* timingFunction) @@ -550,39 +538,40 @@ void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t) noteLayerPropertyChanged(ChildrenTransformChanged); } -void GraphicsLayerCA::moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer *fromLayer, CALayer *toLayer) +void GraphicsLayerCA::moveOrCopyLayerAnimation(MoveOrCopy operation, const String& animationIdentifier, CALayer *fromLayer, CALayer *toLayer) { - for (int index = 0; ; ++index) { - String animName = animationIdentifier(property, keyframesName, index); + NSString *animationID = animationIdentifier; + CAAnimation *anim = [fromLayer animationForKey:animationID]; + if (!anim) + return; - CAAnimation* anim = [fromLayer animationForKey:animName]; - if (!anim) + switch (operation) { + case Move: + [anim retain]; + [fromLayer removeAnimationForKey:animationID]; + [toLayer addAnimation:anim forKey:animationID]; + [anim release]; break; - switch (operation) { - case Move: - [anim retain]; - [fromLayer removeAnimationForKey:animName]; - [toLayer addAnimation:anim forKey:animName]; - [anim release]; - break; - - case Copy: - [toLayer addAnimation:anim forKey:animName]; - break; - } + case Copy: + [toLayer addAnimation:anim forKey:animationID]; + break; } } void GraphicsLayerCA::moveOrCopyAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, CALayer *fromLayer, CALayer *toLayer) { - // Move transitions for this property. - moveOrCopyAllAnimationsForProperty(operation, property, "", fromLayer, toLayer); - // Look for running animations affecting this property. - KeyframeAnimationsMap::const_iterator end = m_runningKeyframeAnimations.end(); - for (KeyframeAnimationsMap::const_iterator it = m_runningKeyframeAnimations.begin(); it != end; ++it) - moveOrCopyAllAnimationsForProperty(operation, property, it->first, fromLayer, toLayer); + AnimationsMap::const_iterator end = m_runningAnimations.end(); + for (AnimationsMap::const_iterator it = m_runningAnimations.begin(); it != end; ++it) { + const Vector<LayerPropertyAnimation>& propertyAnimations = it->second; + size_t numAnimations = propertyAnimations.size(); + for (size_t i = 0; i < numAnimations; ++i) { + const LayerPropertyAnimation& currAnimation = propertyAnimations[i]; + if (currAnimation.m_property == property) + moveOrCopyLayerAnimation(operation, animationIdentifier(currAnimation.m_name, currAnimation.m_property, currAnimation.m_index), fromLayer, toLayer); + } + } } void GraphicsLayerCA::setPreserves3D(bool preserves3D) @@ -704,8 +693,10 @@ void GraphicsLayerCA::setContentsRect(const IntRect& rect) noteLayerPropertyChanged(ContentsRectChanged); } -bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset) +bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& animationName, double timeOffset) { + ASSERT(!animationName.isEmpty()); + if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2) return false; @@ -723,9 +714,9 @@ bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const Int bool createdAnimations = false; if (valueList.property() == AnimatedPropertyWebkitTransform) - createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, timeOffset, boxSize); + createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize); else - createdAnimations = createAnimationFromKeyframes(valueList, anim, keyframesName, timeOffset); + createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset); if (createdAnimations) noteLayerPropertyChanged(AnimationChanged); @@ -733,39 +724,46 @@ bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const Int return createdAnimations; } -void GraphicsLayerCA::removeAnimationsForProperty(AnimatedPropertyID property) +void GraphicsLayerCA::pauseAnimation(const String& animationName, double timeOffset) { - if (m_transitionPropertiesToRemove.find(property) != m_transitionPropertiesToRemove.end()) + if (!animationIsRunning(animationName)) return; - m_transitionPropertiesToRemove.add(property); + AnimationsToProcessMap::iterator it = m_animationsToProcess.find(animationName); + if (it != m_animationsToProcess.end()) { + AnimationProcessingAction& processingInfo = it->second; + // If an animation is scheduled to be removed, don't change the remove to a pause. + if (processingInfo.action != Remove) + processingInfo.action = Pause; + } else + m_animationsToProcess.add(animationName, AnimationProcessingAction(Pause, timeOffset)); + noteLayerPropertyChanged(AnimationChanged); } -void GraphicsLayerCA::removeAnimationsForKeyframes(const String& animationName) +void GraphicsLayerCA::removeAnimation(const String& animationName) { if (!animationIsRunning(animationName)) return; - m_keyframeAnimationsToProcess.add(animationName, AnimationProcessingAction(Remove)); + m_animationsToProcess.add(animationName, AnimationProcessingAction(Remove)); noteLayerPropertyChanged(AnimationChanged); } -void GraphicsLayerCA::pauseAnimation(const String& keyframesName, double timeOffset) +void GraphicsLayerCA::animationDidStart(CAAnimation* caAnimation) { - if (!animationIsRunning(keyframesName)) - return; + bool hadNonZeroBeginTime = [[caAnimation valueForKey:WebKitAnimationBeginTimeSetKey] boolValue]; - AnimationsToProcessMap::iterator it = m_keyframeAnimationsToProcess.find(keyframesName); - if (it != m_keyframeAnimationsToProcess.end()) { - AnimationProcessingAction& processingInfo = it->second; - // If an animation is scheduled to be removed, don't change the remove to a pause. - if (processingInfo.action != Remove) - processingInfo.action = Pause; + double startTime; + if (hadNonZeroBeginTime) { + // We don't know what time CA used to commit the animation, so just use the current time + // (even though this will be slightly off). + startTime = WebCore::mediaTimeToCurrentTime(CACurrentMediaTime()); } else - m_keyframeAnimationsToProcess.add(keyframesName, AnimationProcessingAction(Pause, timeOffset)); + startTime = WebCore::mediaTimeToCurrentTime([caAnimation beginTime]); - noteLayerPropertyChanged(AnimationChanged); + if (m_client) + m_client->notifyAnimationStarted(this, startTime); } void GraphicsLayerCA::setContentsToImage(Image* image) @@ -1496,68 +1494,49 @@ CALayer *GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState) void GraphicsLayerCA::updateLayerAnimations() { - if (m_transitionPropertiesToRemove.size()) { - HashSet<int>::const_iterator end = m_transitionPropertiesToRemove.end(); - for (HashSet<AnimatedProperty>::const_iterator it = m_transitionPropertiesToRemove.begin(); it != end; ++it) { - AnimatedPropertyID currProperty = static_cast<AnimatedPropertyID>(*it); - // Remove all animations with this property in the key. - for (int index = 0; ; ++index) { - if (!removeAnimationFromLayer(currProperty, "", index)) - break; - } - } - - m_transitionPropertiesToRemove.clear(); - } - - if (m_keyframeAnimationsToProcess.size()) { - AnimationsToProcessMap::const_iterator end = m_keyframeAnimationsToProcess.end(); - for (AnimationsToProcessMap::const_iterator it = m_keyframeAnimationsToProcess.begin(); it != end; ++it) { - const String& currKeyframeName = it->first; - KeyframeAnimationsMap::iterator animationIt = m_runningKeyframeAnimations.find(currKeyframeName); - if (animationIt == m_runningKeyframeAnimations.end()) + if (m_animationsToProcess.size()) { + AnimationsToProcessMap::const_iterator end = m_animationsToProcess.end(); + for (AnimationsToProcessMap::const_iterator it = m_animationsToProcess.begin(); it != end; ++it) { + const String& currAnimationName = it->first; + AnimationsMap::iterator animationIt = m_runningAnimations.find(currAnimationName); + if (animationIt == m_runningAnimations.end()) continue; const AnimationProcessingAction& processingInfo = it->second; - const Vector<AnimationPair>& animations = animationIt->second; + const Vector<LayerPropertyAnimation>& animations = animationIt->second; for (size_t i = 0; i < animations.size(); ++i) { - const AnimationPair& currPair = animations[i]; + const LayerPropertyAnimation& currAnimation = animations[i]; switch (processingInfo.action) { case Remove: - removeAnimationFromLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second); + removeCAAnimationFromLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index); break; case Pause: - pauseAnimationOnLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second, processingInfo.timeOffset); + pauseCAAnimationOnLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, processingInfo.timeOffset); break; } } if (processingInfo.action == Remove) - m_runningKeyframeAnimations.remove(currKeyframeName); + m_runningAnimations.remove(currAnimationName); } - m_keyframeAnimationsToProcess.clear(); + m_animationsToProcess.clear(); } size_t numAnimations; if ((numAnimations = m_uncomittedAnimations.size())) { for (size_t i = 0; i < numAnimations; ++i) { - const LayerAnimation& pendingAnimation = m_uncomittedAnimations[i]; - setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_keyframesName, pendingAnimation.m_index, pendingAnimation.m_timeOffset); + const LayerPropertyAnimation& pendingAnimation = m_uncomittedAnimations[i]; + setCAAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_name, pendingAnimation.m_index, pendingAnimation.m_timeOffset); - if (!pendingAnimation.m_keyframesName.isEmpty()) { - // If this is a keyframe anim, we have to remember the association of keyframes name to property/index pairs, - // so we can remove the animations later if needed. - // For transitions, we can just generate animation names with property and index. - KeyframeAnimationsMap::iterator it = m_runningKeyframeAnimations.find(pendingAnimation.m_keyframesName); - if (it == m_runningKeyframeAnimations.end()) { - Vector<AnimationPair> firstPair; - firstPair.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index)); - m_runningKeyframeAnimations.add(pendingAnimation.m_keyframesName, firstPair); - } else { - Vector<AnimationPair>& animPairs = it->second; - animPairs.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index)); - } + AnimationsMap::iterator it = m_runningAnimations.find(pendingAnimation.m_name); + if (it == m_runningAnimations.end()) { + Vector<LayerPropertyAnimation> animations; + animations.append(pendingAnimation); + m_runningAnimations.add(pendingAnimation.m_name, animations); + } else { + Vector<LayerPropertyAnimation>& animations = it->second; + animations.append(pendingAnimation); } } @@ -1565,16 +1544,19 @@ void GraphicsLayerCA::updateLayerAnimations() } } -void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset) +void GraphicsLayerCA::setCAAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, const String& animationName, int index, double timeOffset) { PlatformLayer* layer = animatedLayer(property); - [caAnim setTimeOffset:timeOffset]; - - String animationName = animationIdentifier(property, keyframesName, index); - - [layer removeAnimationForKey:animationName]; - [layer addAnimation:caAnim forKey:animationName]; + if (timeOffset) { + [caAnim setBeginTime:CACurrentMediaTime() - timeOffset]; + [caAnim setValue:[NSNumber numberWithBool:YES] forKey:WebKitAnimationBeginTimeSetKey]; + } + + NSString *animationID = animationIdentifier(animationName, property, index); + + [layer removeAnimationForKey:animationID]; + [layer addAnimation:caAnim forKey:animationID]; if (LayerMap* layerCloneMap = animatedLayerClones(property)) { LayerMap::const_iterator end = layerCloneMap->end(); @@ -1583,8 +1565,8 @@ void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedP if (m_replicaLayer && isReplicatedRootClone(it->first)) continue; CALayer *currLayer = it->second.get(); - [currLayer removeAnimationForKey:animationName]; - [currLayer addAnimation:caAnim forKey:animationName]; + [currLayer removeAnimationForKey:animationID]; + [currLayer addAnimation:caAnim forKey:animationID]; } } } @@ -1604,16 +1586,16 @@ static void bug7311367Workaround(CALayer* transformLayer, const TransformationMa [transformLayer setTransform:caTransform]; } -bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, const String& keyframesName, int index) +bool GraphicsLayerCA::removeCAAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index) { PlatformLayer* layer = animatedLayer(property); - String animationName = animationIdentifier(property, keyframesName, index); + NSString *animationID = animationIdentifier(animationName, property, index); - if (![layer animationForKey:animationName]) + if (![layer animationForKey:animationID]) return false; - [layer removeAnimationForKey:animationName]; + [layer removeAnimationForKey:animationID]; bug7311367Workaround(m_structuralLayer.get(), m_transform); if (LayerMap* layerCloneMap = animatedLayerClones(property)) { @@ -1624,7 +1606,7 @@ bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, cons continue; CALayer *currLayer = it->second.get(); - [currLayer removeAnimationForKey:animationName]; + [currLayer removeAnimationForKey:animationID]; } } return true; @@ -1644,15 +1626,18 @@ static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimati #if HAVE_MODERN_QUARTZCORE [to setValueFunction:[from valueFunction]]; #endif + + if (id object = [from valueForKey:WebKitAnimationBeginTimeSetKey]) + [to setValue:object forKey:WebKitAnimationBeginTimeSetKey]; } -void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset) +void GraphicsLayerCA::pauseCAAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, double timeOffset) { PlatformLayer* layer = animatedLayer(property); - String animationName = animationIdentifier(property, keyframesName, index); + NSString *animationID = animationIdentifier(animationName, property, index); - CAAnimation* caAnim = [layer animationForKey:animationName]; + CAAnimation *caAnim = [layer animationForKey:animationID]; if (!caAnim) return; @@ -1679,7 +1664,7 @@ void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const S [pausedAnim setSpeed:0]; [pausedAnim setTimeOffset:timeOffset]; - [layer addAnimation:pausedAnim forKey:animationName]; // This will replace the running animation. + [layer addAnimation:pausedAnim forKey:animationID]; // This will replace the running animation. // Pause the animations on the clones too. if (LayerMap* layerCloneMap = animatedLayerClones(property)) { @@ -1689,7 +1674,7 @@ void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const S if (m_replicaLayer && isReplicatedRootClone(it->first)) continue; CALayer *currLayer = it->second.get(); - [currLayer addAnimation:pausedAnim forKey:animationName]; + [currLayer addAnimation:pausedAnim forKey:animationID]; } } } @@ -1726,7 +1711,7 @@ void GraphicsLayerCA::updateContentsNeedsDisplay() [m_contentsLayer.get() setNeedsDisplay]; } -bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset) +bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset) { ASSERT(valueList.property() != AnimatedPropertyWebkitTransform); @@ -1752,14 +1737,14 @@ bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valu if (!valuesOK) return false; - m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset)); + m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset)); END_BLOCK_OBJC_EXCEPTIONS; return true; } -bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset, const IntSize& boxSize) +bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const IntSize& boxSize) { ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); @@ -1810,7 +1795,7 @@ bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValue if (!validMatrices) break; - m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset)); + m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset)); } END_BLOCK_OBJC_EXCEPTIONS; @@ -1844,7 +1829,7 @@ void GraphicsLayerCA::setupAnimation(CAPropertyAnimation* propertyAnim, const An else if (anim->direction() == Animation::AnimationDirectionAlternate) repeatCount /= 2; - NSString* fillMode = 0; + NSString *fillMode = 0; switch (anim->fillMode()) { case AnimationFillModeNone: fillMode = kCAFillModeForwards; // Use "forwards" rather than "removed" because the style system will remove the animation when it is finished. This avoids a flash. @@ -1983,7 +1968,7 @@ bool GraphicsLayerCA::setTransformAnimationEndpoints(const KeyframeValueList& va [basicAnim setToValue:toValue]; #if HAVE_MODERN_QUARTZCORE - if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOp)) + if (NSString *valueFunctionName = getValueFunctionNameForTransformOperation(transformOp)) [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]]; #endif @@ -2028,7 +2013,7 @@ bool GraphicsLayerCA::setTransformAnimationKeyframes(const KeyframeValueList& va [keyframeAnim setTimingFunctions:timingFunctions.get()]; #if HAVE_MODERN_QUARTZCORE - if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOpType)) + if (NSString *valueFunctionName = getValueFunctionNameForTransformOperation(transformOpType)) [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]]; #endif return true; @@ -2045,7 +2030,7 @@ void GraphicsLayerCA::suspendAnimations(double time) LayerMap::const_iterator end = layerCloneMap->end(); for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { CALayer *currLayer = it->second.get(); - [currLayer setSpeed:0 ]; + [currLayer setSpeed:0]; [currLayer setTimeOffset:t]; } } |