OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org> | 2 * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org> |
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org> | 3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org> |
4 * Copyright (C) 2008 Apple Inc. All rights reserved. | 4 * Copyright (C) 2008 Apple Inc. All rights reserved. |
5 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 5 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
6 * | 6 * |
7 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
8 * modify it under the terms of the GNU Library General Public | 8 * modify it under the terms of the GNU Library General Public |
9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
10 * version 2 of the License, or (at your option) any later version. | 10 * version 2 of the License, or (at your option) any later version. |
11 * | 11 * |
12 * This library is distributed in the hope that it will be useful, | 12 * This library is distributed in the hope that it will be useful, |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 * Library General Public License for more details. | 15 * Library General Public License for more details. |
16 * | 16 * |
17 * You should have received a copy of the GNU Library General Public License | 17 * You should have received a copy of the GNU Library General Public License |
18 * along with this library; see the file COPYING.LIB. If not, write to | 18 * along with this library; see the file COPYING.LIB. If not, write to |
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 * Boston, MA 02110-1301, USA. | 20 * Boston, MA 02110-1301, USA. |
21 */ | 21 */ |
22 | 22 |
23 #include "core/svg/SVGAnimateElement.h" | 23 #include "core/svg/SVGAnimateElement.h" |
24 | 24 |
25 #include "core/CSSPropertyNames.h" | |
26 #include "core/css/CSSComputedStyleDeclaration.h" | 25 #include "core/css/CSSComputedStyleDeclaration.h" |
27 #include "core/css/StylePropertySet.h" | 26 #include "core/css/StylePropertySet.h" |
28 #include "core/dom/Document.h" | 27 #include "core/dom/Document.h" |
29 #include "core/dom/QualifiedName.h" | 28 #include "core/dom/QualifiedName.h" |
30 #include "core/dom/StyleChangeReason.h" | 29 #include "core/dom/StyleChangeReason.h" |
31 #include "core/svg/properties/SVGProperty.h" | 30 #include "core/svg/properties/SVGProperty.h" |
32 | 31 |
33 namespace blink { | 32 namespace blink { |
34 | 33 |
35 namespace { | 34 namespace { |
36 | 35 |
37 bool isTargetAttributeCSSProperty(SVGElement& targetElement, | 36 bool isTargetAttributeCSSProperty(const SVGElement& targetElement, |
38 const QualifiedName& attributeName) { | 37 const QualifiedName& attributeName) { |
39 return SVGElement::isAnimatableCSSProperty(attributeName) || | 38 return SVGElement::isAnimatableCSSProperty(attributeName) || |
40 targetElement.isPresentationAttribute(attributeName); | 39 targetElement.isPresentationAttribute(attributeName); |
41 } | 40 } |
42 | 41 |
43 String computeCSSPropertyValue(SVGElement* element, CSSPropertyID id) { | 42 String computeCSSPropertyValue(SVGElement* element, CSSPropertyID id) { |
44 DCHECK(element); | 43 DCHECK(element); |
45 // TODO(fs): StyleEngine doesn't support document without a frame. | 44 // TODO(fs): StyleEngine doesn't support document without a frame. |
46 // Refer to comment in Element::computedStyle. | 45 // Refer to comment in Element::computedStyle. |
47 DCHECK(element->inActiveDocument()); | 46 DCHECK(element->inActiveDocument()); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 animationAttributeChanged(); | 117 animationAttributeChanged(); |
119 return; | 118 return; |
120 } | 119 } |
121 SVGAnimationElement::svgAttributeChanged(attrName); | 120 SVGAnimationElement::svgAttributeChanged(attrName); |
122 } | 121 } |
123 | 122 |
124 AnimatedPropertyType SVGAnimateElement::animatedPropertyType() { | 123 AnimatedPropertyType SVGAnimateElement::animatedPropertyType() { |
125 if (!targetElement()) | 124 if (!targetElement()) |
126 return AnimatedUnknown; | 125 return AnimatedUnknown; |
127 | 126 |
128 m_animator.reset(targetElement()); | 127 m_animator.reset(*targetElement()); |
129 return m_animator.type(); | 128 return m_animator.type(); |
130 } | 129 } |
131 | 130 |
132 bool SVGAnimateElement::hasValidTarget() { | 131 bool SVGAnimateElement::hasValidTarget() { |
133 return SVGAnimationElement::hasValidTarget() && hasValidAttributeName() && | 132 return SVGAnimationElement::hasValidTarget() && hasValidAttributeName() && |
134 hasValidAttributeType(); | 133 hasValidAttributeType(); |
135 } | 134 } |
136 | 135 |
137 bool SVGAnimateElement::hasValidAttributeName() const { | 136 bool SVGAnimateElement::hasValidAttributeName() const { |
138 return attributeName() != anyQName(); | 137 return attributeName() != anyQName(); |
139 } | 138 } |
140 | 139 |
141 bool SVGAnimateElement::hasValidAttributeType() { | 140 bool SVGAnimateElement::hasValidAttributeType() { |
142 if (!targetElement()) | 141 if (!targetElement()) |
143 return false; | 142 return false; |
144 return animatedPropertyType() != AnimatedUnknown && | 143 return animatedPropertyType() != AnimatedUnknown && |
145 !hasInvalidCSSAttributeType(); | 144 !hasInvalidCSSAttributeType(); |
146 } | 145 } |
147 | 146 |
148 SVGAnimateElement::ShouldApplyAnimationType | 147 bool SVGAnimateElement::shouldApplyAnimation( |
149 SVGAnimateElement::shouldApplyAnimation(SVGElement* targetElement, | 148 const SVGElement& targetElement, |
150 const QualifiedName& attributeName) { | 149 const QualifiedName& attributeName) { |
151 if (!hasValidTarget() || !targetElement->parentNode()) | 150 if (!hasValidTarget() || !targetElement.parentNode()) |
152 return DontApplyAnimation; | 151 return false; |
153 | 152 |
154 // Always animate CSS properties using the ApplyCSSAnimation code path, | 153 // Always animate CSS properties using the ApplyCSSAnimation code path, |
155 // regardless of the attributeType value. | 154 // regardless of the attributeType value. |
156 if (isTargetAttributeCSSProperty(*targetElement, attributeName)) { | 155 if (isTargetAttributeCSSProperty(targetElement, attributeName)) |
157 if (targetElement->isPresentationAttributeWithSVGDOM(attributeName)) | 156 return true; |
158 return ApplyXMLandCSSAnimation; | |
159 | 157 |
160 return ApplyCSSAnimation; | |
161 } | |
162 // If attributeType="CSS" and attributeName doesn't point to a CSS property, | 158 // If attributeType="CSS" and attributeName doesn't point to a CSS property, |
163 // ignore the animation. | 159 // ignore the animation. |
164 if (getAttributeType() == AttributeTypeCSS) | 160 return getAttributeType() != AttributeTypeCSS; |
165 return DontApplyAnimation; | |
166 | |
167 return ApplyXMLAnimation; | |
168 } | 161 } |
169 | 162 |
170 SVGPropertyBase* SVGAnimateElement::adjustForInheritance( | 163 SVGPropertyBase* SVGAnimateElement::adjustForInheritance( |
171 SVGPropertyBase* propertyValue, | 164 SVGPropertyBase* propertyValue, |
172 AnimatedPropertyValueType valueType) const { | 165 AnimatedPropertyValueType valueType) const { |
173 if (valueType != InheritValue) | 166 if (valueType != InheritValue) |
174 return propertyValue; | 167 return propertyValue; |
175 // TODO(fs): At the moment the computed style gets returned as a String and | 168 // TODO(fs): At the moment the computed style gets returned as a String and |
176 // needs to get parsed again. In the future we might want to work with the | 169 // needs to get parsed again. In the future we might want to work with the |
177 // value type directly to avoid the String parsing. | 170 // value type directly to avoid the String parsing. |
178 DCHECK(targetElement()); | 171 DCHECK(targetElement()); |
179 Element* parent = targetElement()->parentElement(); | 172 Element* parent = targetElement()->parentElement(); |
180 if (!parent || !parent->isSVGElement()) | 173 if (!parent || !parent->isSVGElement()) |
181 return propertyValue; | 174 return propertyValue; |
182 SVGElement* svgParent = toSVGElement(parent); | 175 SVGElement* svgParent = toSVGElement(parent); |
183 // Replace 'inherit' by its computed property value. | 176 // Replace 'inherit' by its computed property value. |
184 String value = computeCSSPropertyValue( | 177 String value = computeCSSPropertyValue(svgParent, m_animator.cssProperty()); |
185 svgParent, cssPropertyID(attributeName().localName())); | |
186 return m_animator.createPropertyForAnimation(value); | 178 return m_animator.createPropertyForAnimation(value); |
187 } | 179 } |
188 | 180 |
189 void SVGAnimateElement::calculateAnimatedValue(float percentage, | 181 void SVGAnimateElement::calculateAnimatedValue(float percentage, |
190 unsigned repeatCount, | 182 unsigned repeatCount, |
191 SVGSMILElement* resultElement) { | 183 SVGSMILElement* resultElement) { |
192 DCHECK(resultElement); | 184 DCHECK(resultElement); |
193 DCHECK(targetElement()); | 185 DCHECK(targetElement()); |
194 if (!isSVGAnimateElement(*resultElement)) | 186 if (!isSVGAnimateElement(*resultElement)) |
195 return; | 187 return; |
(...skipping 13 matching lines...) Expand all Loading... |
209 animatedPropertyType()); | 201 animatedPropertyType()); |
210 | 202 |
211 if (isSVGSetElement(*this)) | 203 if (isSVGSetElement(*this)) |
212 percentage = 1; | 204 percentage = 1; |
213 | 205 |
214 if (getCalcMode() == CalcModeDiscrete) | 206 if (getCalcMode() == CalcModeDiscrete) |
215 percentage = percentage < 0.5 ? 0 : 1; | 207 percentage = percentage < 0.5 ? 0 : 1; |
216 | 208 |
217 // Target element might have changed. | 209 // Target element might have changed. |
218 SVGElement* targetElement = this->targetElement(); | 210 SVGElement* targetElement = this->targetElement(); |
219 m_animator.setContextElement(targetElement); | |
220 | 211 |
221 // Values-animation accumulates using the last values entry corresponding to | 212 // Values-animation accumulates using the last values entry corresponding to |
222 // the end of duration time. | 213 // the end of duration time. |
223 SVGPropertyBase* animatedValue = resultAnimationElement->m_animatedProperty; | 214 SVGPropertyBase* animatedValue = resultAnimationElement->m_animatedProperty; |
224 SVGPropertyBase* toAtEndOfDurationValue = | 215 SVGPropertyBase* toAtEndOfDurationValue = |
225 m_toAtEndOfDurationProperty ? m_toAtEndOfDurationProperty : m_toProperty; | 216 m_toAtEndOfDurationProperty ? m_toAtEndOfDurationProperty : m_toProperty; |
226 SVGPropertyBase* fromValue = | 217 SVGPropertyBase* fromValue = |
227 getAnimationMode() == ToAnimation ? animatedValue : m_fromProperty.get(); | 218 getAnimationMode() == ToAnimation ? animatedValue : m_fromProperty.get(); |
228 SVGPropertyBase* toValue = m_toProperty; | 219 SVGPropertyBase* toValue = m_toProperty; |
229 | 220 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 m_toProperty = m_animator.createPropertyForAnimation(byString); | 266 m_toProperty = m_animator.createPropertyForAnimation(byString); |
276 m_toPropertyValueType = propertyValueType(attributeName(), byString); | 267 m_toPropertyValueType = propertyValueType(attributeName(), byString); |
277 m_toProperty->add(m_fromProperty, targetElement()); | 268 m_toProperty->add(m_fromProperty, targetElement()); |
278 return true; | 269 return true; |
279 } | 270 } |
280 | 271 |
281 void SVGAnimateElement::resetAnimatedType() { | 272 void SVGAnimateElement::resetAnimatedType() { |
282 SVGElement* targetElement = this->targetElement(); | 273 SVGElement* targetElement = this->targetElement(); |
283 const QualifiedName& attributeName = this->attributeName(); | 274 const QualifiedName& attributeName = this->attributeName(); |
284 | 275 |
285 m_animator.reset(targetElement); | 276 m_animator.reset(*targetElement); |
286 | 277 |
287 ShouldApplyAnimationType shouldApply = | 278 if (!shouldApplyAnimation(*targetElement, attributeName)) |
288 shouldApplyAnimation(targetElement, attributeName); | |
289 if (shouldApply == DontApplyAnimation) | |
290 return; | 279 return; |
291 if (shouldApply == ApplyXMLAnimation || | 280 if (m_animator.isAnimatingSVGDom()) { |
292 shouldApply == ApplyXMLandCSSAnimation) { | |
293 // SVG DOM animVal animation code-path. | 281 // SVG DOM animVal animation code-path. |
294 m_animatedProperty = m_animator.createAnimatedValue(); | 282 m_animatedProperty = m_animator.createAnimatedValue(); |
295 targetElement->setAnimatedAttribute(attributeName, m_animatedProperty); | 283 targetElement->setAnimatedAttribute(attributeName, m_animatedProperty); |
296 return; | 284 return; |
297 } | 285 } |
298 DCHECK_EQ(shouldApply, ApplyCSSAnimation); | 286 DCHECK(m_animator.isAnimatingCSSProperty()); |
| 287 // Presentation attributes which has an SVG DOM representation should use the |
| 288 // "SVG DOM" code-path (above.) |
| 289 DCHECK(SVGElement::isAnimatableCSSProperty(attributeName)); |
299 | 290 |
300 // CSS properties animation code-path. | 291 // CSS properties animation code-path. |
301 DCHECK(isTargetAttributeCSSProperty(*targetElement, attributeName)); | 292 String baseValue = |
302 String baseValue = computeCSSPropertyValue( | 293 computeCSSPropertyValue(targetElement, m_animator.cssProperty()); |
303 targetElement, cssPropertyID(attributeName.localName())); | |
304 m_animatedProperty = m_animator.createPropertyForAnimation(baseValue); | 294 m_animatedProperty = m_animator.createPropertyForAnimation(baseValue); |
305 } | 295 } |
306 | 296 |
307 void SVGAnimateElement::clearAnimatedType() { | 297 void SVGAnimateElement::clearAnimatedType() { |
308 if (!m_animatedProperty) | 298 if (!m_animatedProperty) |
309 return; | 299 return; |
310 | 300 |
311 // The animated property lock is held for the "result animation" (see | 301 // The animated property lock is held for the "result animation" (see |
312 // SMILTimeContainer::updateAnimations()) while we're processing an animation | 302 // SMILTimeContainer::updateAnimations()) while we're processing an animation |
313 // group. We will very likely crash later if we clear the animated type while | 303 // group. We will very likely crash later if we clear the animated type while |
314 // the lock is held. See crbug.com/581546. | 304 // the lock is held. See crbug.com/581546. |
315 DCHECK(!animatedTypeIsLocked()); | 305 DCHECK(!animatedTypeIsLocked()); |
316 | 306 |
317 SVGElement* targetElement = this->targetElement(); | 307 SVGElement* targetElement = this->targetElement(); |
318 if (!targetElement) { | 308 if (!targetElement) { |
319 m_animatedProperty.clear(); | 309 m_animatedProperty.clear(); |
320 return; | 310 return; |
321 } | 311 } |
322 | 312 |
323 ShouldApplyAnimationType shouldApply = | 313 bool shouldApply = shouldApplyAnimation(*targetElement, attributeName()); |
324 shouldApplyAnimation(targetElement, attributeName()); | 314 if (m_animator.isAnimatingCSSProperty()) { |
325 if (shouldApply == ApplyXMLandCSSAnimation || | |
326 m_animator.isAnimatingCSSProperty()) { | |
327 // CSS properties animation code-path. | 315 // CSS properties animation code-path. |
328 if (shouldApply != DontApplyAnimation) { | 316 if (shouldApply) { |
329 CSSPropertyID id = cssPropertyID(attributeName().localName()); | 317 MutableStylePropertySet* propertySet = |
330 targetElement->ensureAnimatedSMILStyleProperties()->removeProperty(id); | 318 targetElement->ensureAnimatedSMILStyleProperties(); |
331 targetElement->setNeedsStyleRecalc( | 319 if (propertySet->removeProperty(m_animator.cssProperty())) { |
332 LocalStyleChange, | 320 targetElement->setNeedsStyleRecalc( |
333 StyleChangeReasonForTracing::create(StyleChangeReason::Animation)); | 321 LocalStyleChange, |
| 322 StyleChangeReasonForTracing::create(StyleChangeReason::Animation)); |
| 323 } |
334 } | 324 } |
335 } | 325 } |
336 if (shouldApply == ApplyXMLandCSSAnimation || | 326 if (m_animator.isAnimatingSVGDom()) { |
337 m_animator.isAnimatingSVGDom()) { | |
338 // SVG DOM animVal animation code-path. | 327 // SVG DOM animVal animation code-path. |
339 targetElement->clearAnimatedAttribute(attributeName()); | 328 targetElement->clearAnimatedAttribute(attributeName()); |
340 if (shouldApply != DontApplyAnimation) | 329 if (shouldApply) |
341 targetElement->invalidateAnimatedAttribute(attributeName()); | 330 targetElement->invalidateAnimatedAttribute(attributeName()); |
342 } | 331 } |
343 | 332 |
344 m_animatedProperty.clear(); | 333 m_animatedProperty.clear(); |
345 m_animator.clear(); | 334 m_animator.clear(); |
346 } | 335 } |
347 | 336 |
348 void SVGAnimateElement::applyResultsToTarget() { | 337 void SVGAnimateElement::applyResultsToTarget() { |
349 ASSERT(animatedPropertyType() != AnimatedTransformList || | 338 ASSERT(animatedPropertyType() != AnimatedTransformList || |
350 isSVGAnimateTransformElement(*this)); | 339 isSVGAnimateTransformElement(*this)); |
351 ASSERT(animatedPropertyType() != AnimatedUnknown); | 340 ASSERT(animatedPropertyType() != AnimatedUnknown); |
352 | 341 |
353 // Early exit if our animated type got destructed by a previous | 342 // Early exit if our animated type got destructed by a previous |
354 // endedActiveInterval(). | 343 // endedActiveInterval(). |
355 if (!m_animatedProperty) | 344 if (!m_animatedProperty) |
356 return; | 345 return; |
357 | 346 |
| 347 if (!shouldApplyAnimation(*targetElement(), attributeName())) |
| 348 return; |
| 349 |
358 // We do update the style and the animation property independent of each | 350 // We do update the style and the animation property independent of each |
359 // other. | 351 // other. |
360 ShouldApplyAnimationType shouldApply = | 352 if (m_animator.isAnimatingCSSProperty()) { |
361 shouldApplyAnimation(targetElement(), attributeName()); | |
362 if (shouldApply == DontApplyAnimation) | |
363 return; | |
364 if (shouldApply == ApplyXMLandCSSAnimation || | |
365 m_animator.isAnimatingCSSProperty()) { | |
366 // CSS properties animation code-path. | 353 // CSS properties animation code-path. |
367 // Convert the result of the animation to a String and apply it as CSS | 354 // Convert the result of the animation to a String and apply it as CSS |
368 // property on the target. | 355 // property on the target. |
369 CSSPropertyID id = cssPropertyID(attributeName().localName()); | |
370 MutableStylePropertySet* propertySet = | 356 MutableStylePropertySet* propertySet = |
371 targetElement()->ensureAnimatedSMILStyleProperties(); | 357 targetElement()->ensureAnimatedSMILStyleProperties(); |
372 if (propertySet->setProperty(id, m_animatedProperty->valueAsString(), false, | 358 if (propertySet->setProperty(m_animator.cssProperty(), |
373 0)) | 359 m_animatedProperty->valueAsString(), false, |
| 360 0)) { |
374 targetElement()->setNeedsStyleRecalc( | 361 targetElement()->setNeedsStyleRecalc( |
375 LocalStyleChange, | 362 LocalStyleChange, |
376 StyleChangeReasonForTracing::create(StyleChangeReason::Animation)); | 363 StyleChangeReasonForTracing::create(StyleChangeReason::Animation)); |
| 364 } |
377 } | 365 } |
378 if (shouldApply == ApplyXMLandCSSAnimation || | 366 if (m_animator.isAnimatingSVGDom()) { |
379 m_animator.isAnimatingSVGDom()) { | |
380 // SVG DOM animVal animation code-path. | 367 // SVG DOM animVal animation code-path. |
381 // At this point the SVG DOM values are already changed, unlike for CSS. | 368 // At this point the SVG DOM values are already changed, unlike for CSS. |
382 // We only have to trigger update notifications here. | 369 // We only have to trigger update notifications here. |
383 targetElement()->invalidateAnimatedAttribute(attributeName()); | 370 targetElement()->invalidateAnimatedAttribute(attributeName()); |
384 } | 371 } |
385 } | 372 } |
386 | 373 |
387 bool SVGAnimateElement::animatedPropertyTypeSupportsAddition() { | 374 bool SVGAnimateElement::animatedPropertyTypeSupportsAddition() { |
388 // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties. | 375 // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties. |
389 switch (animatedPropertyType()) { | 376 switch (animatedPropertyType()) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
473 DEFINE_TRACE(SVGAnimateElement) { | 460 DEFINE_TRACE(SVGAnimateElement) { |
474 visitor->trace(m_fromProperty); | 461 visitor->trace(m_fromProperty); |
475 visitor->trace(m_toProperty); | 462 visitor->trace(m_toProperty); |
476 visitor->trace(m_toAtEndOfDurationProperty); | 463 visitor->trace(m_toAtEndOfDurationProperty); |
477 visitor->trace(m_animatedProperty); | 464 visitor->trace(m_animatedProperty); |
478 visitor->trace(m_animator); | 465 visitor->trace(m_animator); |
479 SVGAnimationElement::trace(visitor); | 466 SVGAnimationElement::trace(visitor); |
480 } | 467 } |
481 | 468 |
482 } // namespace blink | 469 } // namespace blink |
OLD | NEW |