| 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 |