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, 2007 Rob Buis <buis@kde.org> | 3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> |
4 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> | 4 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
5 * Copyright (C) 2008 Apple Inc. All rights reserved. | 5 * Copyright (C) 2008 Apple Inc. All rights reserved. |
6 * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> | 6 * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> |
7 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | 7 * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
8 * | 8 * |
9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
10 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
11 * License as published by the Free Software Foundation; either | 11 * License as published by the Free Software Foundation; either |
12 * version 2 of the License, or (at your option) any later version. | 12 * version 2 of the License, or (at your option) any later version. |
13 * | 13 * |
14 * This library is distributed in the hope that it will be useful, | 14 * This library is distributed in the hope that it will be useful, |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 * Library General Public License for more details. | 17 * Library General Public License for more details. |
18 * | 18 * |
19 * You should have received a copy of the GNU Library General Public License | 19 * You should have received a copy of the GNU Library General Public License |
20 * along with this library; see the file COPYING.LIB. If not, write to | 20 * along with this library; see the file COPYING.LIB. If not, write to |
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
22 * Boston, MA 02110-1301, USA. | 22 * Boston, MA 02110-1301, USA. |
23 */ | 23 */ |
24 | 24 |
25 #include "core/svg/SVGAnimationElement.h" | 25 #include "core/svg/SVGAnimationElement.h" |
26 | 26 |
27 #include "bindings/core/v8/ExceptionState.h" | 27 #include "bindings/core/v8/ExceptionState.h" |
28 #include "core/CSSPropertyNames.h" | |
29 #include "core/SVGNames.h" | 28 #include "core/SVGNames.h" |
30 #include "core/css/CSSComputedStyleDeclaration.h" | |
31 #include "core/css/parser/CSSParser.h" | |
32 #include "core/frame/UseCounter.h" | 29 #include "core/frame/UseCounter.h" |
33 #include "core/svg/SVGAnimateElement.h" | 30 #include "core/svg/SVGAnimateElement.h" |
34 #include "core/svg/SVGElement.h" | |
35 #include "core/svg/SVGParserUtilities.h" | 31 #include "core/svg/SVGParserUtilities.h" |
36 #include "wtf/MathExtras.h" | 32 #include "wtf/MathExtras.h" |
37 | 33 |
38 namespace blink { | 34 namespace blink { |
39 | 35 |
40 SVGAnimationElement::SVGAnimationElement(const QualifiedName& tagName, | 36 SVGAnimationElement::SVGAnimationElement(const QualifiedName& tagName, |
41 Document& document) | 37 Document& document) |
42 : SVGSMILElement(tagName, document), | 38 : SVGSMILElement(tagName, document), |
43 m_fromPropertyValueType(RegularPropertyValue), | |
44 m_toPropertyValueType(RegularPropertyValue), | |
45 m_animationValid(false), | 39 m_animationValid(false), |
46 m_attributeType(AttributeTypeAuto), | 40 m_attributeType(AttributeTypeAuto), |
47 m_hasInvalidCSSAttributeType(false), | 41 m_hasInvalidCSSAttributeType(false), |
48 m_calcMode(CalcModeLinear), | 42 m_calcMode(CalcModeLinear), |
49 m_animationMode(NoAnimation) { | 43 m_animationMode(NoAnimation) { |
50 ASSERT(RuntimeEnabledFeatures::smilEnabled()); | 44 ASSERT(RuntimeEnabledFeatures::smilEnabled()); |
51 UseCounter::count(document, UseCounter::SVGAnimationElement); | 45 UseCounter::count(document, UseCounter::SVGAnimationElement); |
52 } | 46 } |
53 | 47 |
54 bool SVGAnimationElement::parseValues(const String& value, | 48 bool SVGAnimationElement::parseValues(const String& value, |
55 Vector<String>& result) { | 49 Vector<String>& result) { |
56 // Per the SMIL specification, leading and trailing white space, | 50 // Per the SMIL specification, leading and trailing white space, and white |
57 // and white space before and after semicolon separators, is allowed and will
be ignored. | 51 // space before and after semicolon separators, is allowed and will be |
| 52 // ignored. |
58 // http://www.w3.org/TR/SVG11/animate.html#ValuesAttribute | 53 // http://www.w3.org/TR/SVG11/animate.html#ValuesAttribute |
59 result.clear(); | 54 result.clear(); |
60 Vector<String> parseList; | 55 Vector<String> parseList; |
61 value.split(';', true, parseList); | 56 value.split(';', true, parseList); |
62 unsigned last = parseList.size() - 1; | 57 unsigned last = parseList.size() - 1; |
63 for (unsigned i = 0; i <= last; ++i) { | 58 for (unsigned i = 0; i <= last; ++i) { |
64 if (parseList[i].isEmpty()) { | 59 if (parseList[i].isEmpty()) { |
65 // Tolerate trailing ';' | 60 // Tolerate trailing ';' |
66 if (i < last) | 61 if (i < last) |
67 goto fail; | 62 goto fail; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 } | 167 } |
173 | 168 |
174 if (name == SVGNames::keyTimesAttr) { | 169 if (name == SVGNames::keyTimesAttr) { |
175 if (!parseKeyTimes(value, m_keyTimes, true)) | 170 if (!parseKeyTimes(value, m_keyTimes, true)) |
176 reportAttributeParsingError(SVGParseStatus::ParsingFailed, name, value); | 171 reportAttributeParsingError(SVGParseStatus::ParsingFailed, name, value); |
177 return; | 172 return; |
178 } | 173 } |
179 | 174 |
180 if (name == SVGNames::keyPointsAttr) { | 175 if (name == SVGNames::keyPointsAttr) { |
181 if (isSVGAnimateMotionElement(*this)) { | 176 if (isSVGAnimateMotionElement(*this)) { |
182 // This is specified to be an animateMotion attribute only but it is simpl
er to put it here | 177 // This is specified to be an animateMotion attribute only but it is |
183 // where the other timing calculatations are. | 178 // simpler to put it here where the other timing calculatations are. |
184 if (!parseKeyTimes(value, m_keyPoints, false)) | 179 if (!parseKeyTimes(value, m_keyPoints, false)) |
185 reportAttributeParsingError(SVGParseStatus::ParsingFailed, name, value); | 180 reportAttributeParsingError(SVGParseStatus::ParsingFailed, name, value); |
186 } | 181 } |
187 return; | 182 return; |
188 } | 183 } |
189 | 184 |
190 if (name == SVGNames::keySplinesAttr) { | 185 if (name == SVGNames::keySplinesAttr) { |
191 if (!parseKeySplines(value, m_keySplines)) | 186 if (!parseKeySplines(value, m_keySplines)) |
192 reportAttributeParsingError(SVGParseStatus::ParsingFailed, name, value); | 187 reportAttributeParsingError(SVGParseStatus::ParsingFailed, name, value); |
193 return; | 188 return; |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 } | 358 } |
364 | 359 |
365 SVGAnimationElement::ShouldApplyAnimationType | 360 SVGAnimationElement::ShouldApplyAnimationType |
366 SVGAnimationElement::shouldApplyAnimation(SVGElement* targetElement, | 361 SVGAnimationElement::shouldApplyAnimation(SVGElement* targetElement, |
367 const QualifiedName& attributeName) { | 362 const QualifiedName& attributeName) { |
368 if (!hasValidAttributeType() || attributeName == anyQName() || | 363 if (!hasValidAttributeType() || attributeName == anyQName() || |
369 !targetElement || !targetElement->inActiveDocument() || | 364 !targetElement || !targetElement->inActiveDocument() || |
370 !targetElement->parentNode()) | 365 !targetElement->parentNode()) |
371 return DontApplyAnimation; | 366 return DontApplyAnimation; |
372 | 367 |
373 // Always animate CSS properties, using the ApplyCSSAnimation code path, regar
dless of the attributeType value. | 368 // Always animate CSS properties using the ApplyCSSAnimation code path, |
| 369 // regardless of the attributeType value. |
374 if (isTargetAttributeCSSProperty(targetElement, attributeName)) { | 370 if (isTargetAttributeCSSProperty(targetElement, attributeName)) { |
375 if (targetElement->isPresentationAttributeWithSVGDOM(attributeName)) | 371 if (targetElement->isPresentationAttributeWithSVGDOM(attributeName)) |
376 return ApplyXMLandCSSAnimation; | 372 return ApplyXMLandCSSAnimation; |
377 | 373 |
378 return ApplyCSSAnimation; | 374 return ApplyCSSAnimation; |
379 } | 375 } |
380 // If attributeType="CSS" and attributeName doesn't point to a CSS property, i
gnore the animation. | 376 // If attributeType="CSS" and attributeName doesn't point to a CSS property, |
| 377 // ignore the animation. |
381 if (getAttributeType() == AttributeTypeCSS) | 378 if (getAttributeType() == AttributeTypeCSS) |
382 return DontApplyAnimation; | 379 return DontApplyAnimation; |
383 | 380 |
384 return ApplyXMLAnimation; | 381 return ApplyXMLAnimation; |
385 } | 382 } |
386 | 383 |
387 void SVGAnimationElement::calculateKeyTimesForCalcModePaced() { | 384 void SVGAnimationElement::calculateKeyTimesForCalcModePaced() { |
388 ASSERT(getCalcMode() == CalcModePaced); | 385 ASSERT(getCalcMode() == CalcModePaced); |
389 ASSERT(getAnimationMode() == ValuesAnimation); | 386 ASSERT(getAnimationMode() == ValuesAnimation); |
390 | 387 |
391 unsigned valuesCount = m_values.size(); | 388 unsigned valuesCount = m_values.size(); |
392 ASSERT(valuesCount >= 1); | 389 ASSERT(valuesCount >= 1); |
393 if (valuesCount == 1) | 390 if (valuesCount == 1) |
394 return; | 391 return; |
395 | 392 |
396 // FIXME, webkit.org/b/109010: m_keyTimes should not be modified in this funct
ion. | 393 // FIXME, webkit.org/b/109010: m_keyTimes should not be modified in this |
| 394 // function. |
397 m_keyTimes.clear(); | 395 m_keyTimes.clear(); |
398 | 396 |
399 Vector<float> keyTimesForPaced; | 397 Vector<float> keyTimesForPaced; |
400 float totalDistance = 0; | 398 float totalDistance = 0; |
401 keyTimesForPaced.append(0); | 399 keyTimesForPaced.append(0); |
402 for (unsigned n = 0; n < valuesCount - 1; ++n) { | 400 for (unsigned n = 0; n < valuesCount - 1; ++n) { |
403 // Distance in any units | 401 // Distance in any units |
404 float distance = calculateDistance(m_values[n], m_values[n + 1]); | 402 float distance = calculateDistance(m_values[n], m_values[n + 1]); |
405 if (distance < 0) | 403 if (distance < 0) |
406 return; | 404 return; |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
604 return; | 602 return; |
605 if ((animationMode == FromToAnimation || animationMode == FromByAnimation || | 603 if ((animationMode == FromToAnimation || animationMode == FromByAnimation || |
606 animationMode == ToAnimation || animationMode == ByAnimation) && | 604 animationMode == ToAnimation || animationMode == ByAnimation) && |
607 (fastHasAttribute(SVGNames::keyPointsAttr) && | 605 (fastHasAttribute(SVGNames::keyPointsAttr) && |
608 fastHasAttribute(SVGNames::keyTimesAttr) && | 606 fastHasAttribute(SVGNames::keyTimesAttr) && |
609 (m_keyTimes.size() < 2 || m_keyTimes.size() != m_keyPoints.size()))) | 607 (m_keyTimes.size() < 2 || m_keyTimes.size() != m_keyPoints.size()))) |
610 return; | 608 return; |
611 if (animationMode == FromToAnimation) { | 609 if (animationMode == FromToAnimation) { |
612 m_animationValid = calculateFromAndToValues(from, to); | 610 m_animationValid = calculateFromAndToValues(from, to); |
613 } else if (animationMode == ToAnimation) { | 611 } else if (animationMode == ToAnimation) { |
614 // For to-animations the from value is the current accumulated value from lo
wer priority animations. | 612 // For to-animations the from value is the current accumulated value from |
| 613 // lower priority animations. |
615 // The value is not static and is determined during the animation. | 614 // The value is not static and is determined during the animation. |
616 m_animationValid = calculateFromAndToValues(emptyString(), to); | 615 m_animationValid = calculateFromAndToValues(emptyString(), to); |
617 } else if (animationMode == FromByAnimation) { | 616 } else if (animationMode == FromByAnimation) { |
618 m_animationValid = calculateFromAndByValues(from, by); | 617 m_animationValid = calculateFromAndByValues(from, by); |
619 } else if (animationMode == ByAnimation) { | 618 } else if (animationMode == ByAnimation) { |
620 m_animationValid = calculateFromAndByValues(emptyString(), by); | 619 m_animationValid = calculateFromAndByValues(emptyString(), by); |
621 } else if (animationMode == ValuesAnimation) { | 620 } else if (animationMode == ValuesAnimation) { |
622 m_animationValid = | 621 m_animationValid = |
623 m_values.size() >= 1 && (calcMode == CalcModePaced || | 622 m_values.size() >= 1 && (calcMode == CalcModePaced || |
624 !fastHasAttribute(SVGNames::keyTimesAttr) || | 623 !fastHasAttribute(SVGNames::keyTimesAttr) || |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 effectivePercent = | 673 effectivePercent = |
675 calculatePercentForSpline(percent, calculateKeyTimesIndex(percent)); | 674 calculatePercentForSpline(percent, calculateKeyTimesIndex(percent)); |
676 else if (animationMode == FromToAnimation || animationMode == ToAnimation) | 675 else if (animationMode == FromToAnimation || animationMode == ToAnimation) |
677 effectivePercent = calculatePercentForFromTo(percent); | 676 effectivePercent = calculatePercentForFromTo(percent); |
678 else | 677 else |
679 effectivePercent = percent; | 678 effectivePercent = percent; |
680 | 679 |
681 calculateAnimatedValue(effectivePercent, repeatCount, resultElement); | 680 calculateAnimatedValue(effectivePercent, repeatCount, resultElement); |
682 } | 681 } |
683 | 682 |
684 void SVGAnimationElement::computeCSSPropertyValue(SVGElement* element, | |
685 CSSPropertyID id, | |
686 String& value) { | |
687 ASSERT(element); | |
688 // FIXME: StyleEngine doesn't support document without a frame. | |
689 // Refer to comment in Element::computedStyle. | |
690 ASSERT(element->inActiveDocument()); | |
691 | |
692 // Don't include any properties resulting from CSS Transitions/Animations or S
MIL animations, as we want to retrieve the "base value". | |
693 element->setUseOverrideComputedStyle(true); | |
694 value = CSSComputedStyleDeclaration::create(element)->getPropertyValue(id); | |
695 element->setUseOverrideComputedStyle(false); | |
696 } | |
697 | |
698 void SVGAnimationElement::adjustForInheritance( | |
699 SVGElement* targetElement, | |
700 const QualifiedName& attributeName, | |
701 String& value) { | |
702 // FIXME: At the moment the computed style gets returned as a String and needs
to get parsed again. | |
703 // In the future we might want to work with the value type directly to avoid t
he String parsing. | |
704 ASSERT(targetElement); | |
705 | |
706 Element* parent = targetElement->parentElement(); | |
707 if (!parent || !parent->isSVGElement()) | |
708 return; | |
709 | |
710 SVGElement* svgParent = toSVGElement(parent); | |
711 computeCSSPropertyValue(svgParent, cssPropertyID(attributeName.localName()), | |
712 value); | |
713 } | |
714 | |
715 static bool inheritsFromProperty(SVGElement* targetElement, | |
716 const QualifiedName& attributeName, | |
717 const String& value) { | |
718 ASSERT(targetElement); | |
719 DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit")); | |
720 | |
721 if (value.isEmpty() || value != inherit) | |
722 return false; | |
723 return SVGElement::isAnimatableCSSProperty(attributeName); | |
724 } | |
725 | |
726 void SVGAnimationElement::determinePropertyValueTypes(const String& from, | |
727 const String& to) { | |
728 SVGElement* targetElement = this->targetElement(); | |
729 ASSERT(targetElement); | |
730 | |
731 const QualifiedName& attributeName = this->attributeName(); | |
732 if (inheritsFromProperty(targetElement, attributeName, from)) | |
733 m_fromPropertyValueType = InheritValue; | |
734 if (inheritsFromProperty(targetElement, attributeName, to)) | |
735 m_toPropertyValueType = InheritValue; | |
736 } | |
737 | |
738 void SVGAnimationElement::setTargetElement(SVGElement* target) { | 683 void SVGAnimationElement::setTargetElement(SVGElement* target) { |
739 SVGSMILElement::setTargetElement(target); | 684 SVGSMILElement::setTargetElement(target); |
740 checkInvalidCSSAttributeType(); | 685 checkInvalidCSSAttributeType(); |
741 } | 686 } |
742 | 687 |
743 void SVGAnimationElement::setAttributeName(const QualifiedName& attributeName) { | 688 void SVGAnimationElement::setAttributeName(const QualifiedName& attributeName) { |
744 SVGSMILElement::setAttributeName(attributeName); | 689 SVGSMILElement::setAttributeName(attributeName); |
745 checkInvalidCSSAttributeType(); | 690 checkInvalidCSSAttributeType(); |
746 } | 691 } |
747 | 692 |
(...skipping 12 matching lines...) Expand all Loading... |
760 if (!hasInvalidCSSAttributeType) | 705 if (!hasInvalidCSSAttributeType) |
761 schedule(); | 706 schedule(); |
762 } | 707 } |
763 | 708 |
764 // Clear values that may depend on the previous target. | 709 // Clear values that may depend on the previous target. |
765 if (targetElement()) | 710 if (targetElement()) |
766 clearAnimatedType(); | 711 clearAnimatedType(); |
767 } | 712 } |
768 | 713 |
769 } // namespace blink | 714 } // namespace blink |
OLD | NEW |