KHtml

SVGAnimateElement.cpp
1 /*
2  Copyright (C) 2004, 2005 Nikolas Zimmermann <[email protected]>
3  2004, 2005, 2006 Rob Buis <[email protected]>
4  Copyright (C) 2008 Apple Inc. All rights reserved.
5 
6  This file is part of the KDE project
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 */
23 
24 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
25 #include "SVGAnimateElement.h"
26 
27 #include "ColorDistance.h"
28 #include "FloatConversion.h"
29 #include "SVGColor.h"
30 #include "SVGParserUtilities.h"
31 #include <math.h>
32 
33 using namespace std;
34 
35 namespace WebCore
36 {
37 
38 SVGAnimateElement::SVGAnimateElement(const QualifiedName &tagName, Document *doc)
39  : SVGAnimationElement(tagName, doc)
40  , m_propertyType(StringProperty)
41  , m_fromNumber(0)
42  , m_toNumber(0)
43  , m_animatedNumber(numeric_limits<double>::infinity())
44 {
45 }
46 
47 SVGAnimateElement::~SVGAnimateElement()
48 {
49 }
50 
51 static bool parseNumberValueAndUnit(const String &in, double &value, String &unit)
52 {
53  // FIXME: These are from top of my head, figure out all property types that can be animated as numbers.
54  unsigned unitLength = 0;
55  String parse = in.stripWhiteSpace();
56  if (parse.endsWith("%")) {
57  unitLength = 1;
58  } else if (parse.endsWith("px") || parse.endsWith("pt") || parse.endsWith("em")) {
59  unitLength = 2;
60  } else if (parse.endsWith("deg") || parse.endsWith("rad")) {
61  unitLength = 3;
62  } else if (parse.endsWith("grad")) {
63  unitLength = 4;
64  }
65  String newUnit = parse.right(unitLength);
66  String number = parse.left(parse.length() - unitLength);
67  if (!unit.isEmpty() && newUnit != unit || number.isEmpty()) {
68  return false;
69  }
70  UChar last = number[number.length() - 1];
71  if (last < '0' || last > '9') {
72  return false;
73  }
74  unit = newUnit;
75  bool ok;
76  value = number.toDouble(&ok);
77  return ok;
78 }
79 
80 SVGAnimateElement::PropertyType SVGAnimateElement::determinePropertyType(const String &attribute) const
81 {
82  // FIXME: We need a full property table for figuring this out reliably.
83  if (hasTagName(SVGNames::animateColorTag)) {
84  return ColorProperty;
85  }
86  if (attribute == "color" || attribute == "fill" || attribute == "stroke") {
87  return ColorProperty;
88  }
89  return NumberProperty;
90 }
91 
92 void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement *resultElement)
93 {
94  ASSERT(percentage >= 0.f && percentage <= 1.f);
95  ASSERT(resultElement);
96  if (hasTagName(SVGNames::setTag)) {
97  percentage = 1.f;
98  }
99  if (!resultElement->hasTagName(SVGNames::animateTag) && !resultElement->hasTagName(SVGNames::animateColorTag)
100  && !resultElement->hasTagName(SVGNames::setTag)) {
101  return;
102  }
103  SVGAnimateElement *results = static_cast<SVGAnimateElement *>(resultElement);
104  // Can't accumulate over a string property.
105  if (results->m_propertyType == StringProperty && m_propertyType != StringProperty) {
106  return;
107  }
108  if (m_propertyType == NumberProperty) {
109  // To animation uses contributions from the lower priority animations as the base value.
110  if (animationMode() == ToAnimation) {
111  m_fromNumber = results->m_animatedNumber;
112  }
113 
114  double number = (m_toNumber - m_fromNumber) * percentage + m_fromNumber;
115 
116  // FIXME: This is not correct for values animation.
117  if (isAccumulated() && repeat) {
118  number += m_toNumber * repeat;
119  }
120  if (isAdditive() && animationMode() != ToAnimation) {
121  results->m_animatedNumber += number;
122  } else {
123  results->m_animatedNumber = number;
124  }
125  return;
126  }
127  if (m_propertyType == ColorProperty) {
128  if (animationMode() == ToAnimation) {
129  m_fromColor = results->m_animatedColor;
130  }
131  Color color = ColorDistance(m_fromColor, m_toColor).scaledDistance(percentage).addToColorAndClamp(m_fromColor);
132  // FIXME: Accumulate colors.
133  if (isAdditive() && animationMode() != ToAnimation) {
134  results->m_animatedColor = ColorDistance::addColorsAndClamp(results->m_animatedColor, color);
135  } else {
136  results->m_animatedColor = color;
137  }
138  return;
139  }
140  AnimationMode animationMode = this->animationMode();
141  ASSERT(animationMode == FromToAnimation || animationMode == ToAnimation || animationMode == ValuesAnimation);
142  if ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1.0f) {
143  results->m_animatedString = m_toString;
144  } else {
145  results->m_animatedString = m_fromString;
146  }
147  // Higher priority replace animation overrides any additive results so far.
148  results->m_propertyType = StringProperty;
149 }
150 
151 bool SVGAnimateElement::calculateFromAndToValues(const String &fromString, const String &toString)
152 {
153  // FIXME: Needs more solid way determine target attribute type.
154  m_propertyType = determinePropertyType(attributeName());
155  if (m_propertyType == ColorProperty) {
156  m_fromColor = SVGColor::colorFromRGBColorString(fromString);
157  m_toColor = SVGColor::colorFromRGBColorString(toString);
158  if (m_fromColor.isValid() && m_toColor.isValid()) {
159  return true;
160  }
161  } else if (m_propertyType == NumberProperty) {
162  m_numberUnit = String();
163  if (parseNumberValueAndUnit(toString, m_toNumber, m_numberUnit)) {
164  // For to-animations the from number is calculated later
165  if (animationMode() == ToAnimation || parseNumberValueAndUnit(fromString, m_fromNumber, m_numberUnit)) {
166  return true;
167  }
168  }
169  }
170  m_fromString = fromString;
171  m_toString = toString;
172  m_propertyType = StringProperty;
173  return true;
174 }
175 
176 bool SVGAnimateElement::calculateFromAndByValues(const String &fromString, const String &byString)
177 {
178  ASSERT(!hasTagName(SVGNames::setTag));
179  m_propertyType = determinePropertyType(attributeName());
180  if (m_propertyType == ColorProperty) {
181  m_fromColor = fromString.isEmpty() ? Color() : SVGColor::colorFromRGBColorString(fromString);
182  m_toColor = ColorDistance::addColorsAndClamp(m_fromColor, SVGColor::colorFromRGBColorString(byString));
183  if (!m_fromColor.isValid() || !m_toColor.isValid()) {
184  return false;
185  }
186  } else {
187  m_numberUnit = String();
188  m_fromNumber = 0;
189  if (!fromString.isEmpty() && !parseNumberValueAndUnit(fromString, m_fromNumber, m_numberUnit)) {
190  return false;
191  }
192  if (!parseNumberValueAndUnit(byString, m_toNumber, m_numberUnit)) {
193  return false;
194  }
195  m_toNumber += m_fromNumber;
196  }
197  return true;
198 }
199 
200 void SVGAnimateElement::resetToBaseValue(const String &baseString)
201 {
202  m_animatedString = baseString;
203  m_propertyType = determinePropertyType(attributeName());
204  if (m_propertyType == ColorProperty) {
205  m_animatedColor = baseString.isEmpty() ? Color() : SVGColor::colorFromRGBColorString(baseString);
206  if (m_animatedColor.isValid()) {
207  return;
208  }
209  } else if (m_propertyType == NumberProperty) {
210  if (baseString.isEmpty()) {
211  m_animatedNumber = 0;
212  m_numberUnit = String();
213  return;
214  }
215  if (parseNumberValueAndUnit(baseString, m_animatedNumber, m_numberUnit)) {
216  return;
217  }
218  }
219  m_propertyType = StringProperty;
220 }
221 
222 void SVGAnimateElement::applyResultsToTarget()
223 {
224  String valueToApply;
225  if (m_propertyType == ColorProperty) {
226  valueToApply = m_animatedColor.name();
227  } else if (m_propertyType == NumberProperty) {
228  valueToApply = String::number(m_animatedNumber) + m_numberUnit;
229  } else {
230  valueToApply = m_animatedString;
231  }
232 
233  setTargetAttributeAnimatedValue(valueToApply);
234 }
235 
236 float SVGAnimateElement::calculateDistance(const String &fromString, const String &toString)
237 {
238  m_propertyType = determinePropertyType(attributeName());
239  if (m_propertyType == NumberProperty) {
240  double from;
241  double to;
242  String unit;
243  if (!parseNumberValueAndUnit(fromString, from, unit)) {
244  return -1.f;
245  }
246  if (!parseNumberValueAndUnit(toString, to, unit)) {
247  return -1.f;
248  }
249  return narrowPrecisionToFloat(fabs(to - from));
250  } else if (m_propertyType == ColorProperty) {
251  Color from = SVGColor::colorFromRGBColorString(fromString);
252  if (!from.isValid()) {
253  return -1.f;
254  }
255  Color to = SVGColor::colorFromRGBColorString(toString);
256  if (!to.isValid()) {
257  return -1.f;
258  }
259  return ColorDistance(from, to).distance();
260  }
261  return -1.f;
262 }
263 
264 }
265 
266 #endif // ENABLE(SVG)
267 
KIOCORE_EXPORT QString number(KIO::filesize_t size)
KHEALTHCERTIFICATE_EXPORT QVariant parse(const QByteArray &data)
QString left(int n) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:09 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.