Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / svg / SVGAngle.cpp
blob9189ceb60d04364fda502e76b7cdd4bb09027f70
1 /*
2 * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include "config.h"
23 #include "core/svg/SVGAngle.h"
25 #include "bindings/core/v8/ExceptionState.h"
26 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
27 #include "core/dom/ExceptionCode.h"
28 #include "core/svg/SVGAnimationElement.h"
29 #include "core/svg/SVGParserUtilities.h"
30 #include "wtf/MathExtras.h"
31 #include "wtf/text/WTFString.h"
33 namespace blink {
35 template<> const SVGEnumerationStringEntries& getStaticStringEntries<SVGMarkerOrientType>()
37 DEFINE_STATIC_LOCAL(SVGEnumerationStringEntries, entries, ());
38 if (entries.isEmpty()) {
39 entries.append(std::make_pair(SVGMarkerOrientAuto, "auto"));
40 entries.append(std::make_pair(SVGMarkerOrientAngle, "angle"));
41 entries.append(std::make_pair(SVGMarkerOrientAutoStartReverse, "auto-start-reverse"));
43 return entries;
46 template<> unsigned short getMaxExposedEnumValue<SVGMarkerOrientType>()
48 return SVGMarkerOrientAngle;
51 SVGMarkerOrientEnumeration::SVGMarkerOrientEnumeration(SVGAngle* angle)
52 : SVGEnumeration<SVGMarkerOrientType>(SVGMarkerOrientAngle)
53 , m_angle(angle)
57 SVGMarkerOrientEnumeration::~SVGMarkerOrientEnumeration()
61 DEFINE_TRACE(SVGMarkerOrientEnumeration)
63 visitor->trace(m_angle);
64 SVGEnumeration<SVGMarkerOrientType>::trace(visitor);
67 void SVGMarkerOrientEnumeration::notifyChange()
69 ASSERT(m_angle);
70 m_angle->orientTypeChanged();
73 void SVGMarkerOrientEnumeration::add(PassRefPtrWillBeRawPtr<SVGPropertyBase>, SVGElement*)
75 // SVGMarkerOrientEnumeration is only animated via SVGAngle
76 ASSERT_NOT_REACHED();
79 void SVGMarkerOrientEnumeration::calculateAnimatedValue(SVGAnimationElement*, float percentage, unsigned repeatCount, PassRefPtrWillBeRawPtr<SVGPropertyBase> from, PassRefPtrWillBeRawPtr<SVGPropertyBase> to, PassRefPtrWillBeRawPtr<SVGPropertyBase> toAtEndOfDurationValue, SVGElement* contextElement)
81 // SVGMarkerOrientEnumeration is only animated via SVGAngle
82 ASSERT_NOT_REACHED();
85 float SVGMarkerOrientEnumeration::calculateDistance(PassRefPtrWillBeRawPtr<SVGPropertyBase> to, SVGElement* contextElement)
87 // SVGMarkerOrientEnumeration is only animated via SVGAngle
88 ASSERT_NOT_REACHED();
89 return -1.0;
92 SVGAngle::SVGAngle()
93 : m_unitType(SVG_ANGLETYPE_UNSPECIFIED)
94 , m_valueInSpecifiedUnits(0)
95 , m_orientType(SVGMarkerOrientEnumeration::create(this))
99 SVGAngle::SVGAngle(SVGAngleType unitType, float valueInSpecifiedUnits, SVGMarkerOrientType orientType)
100 : m_unitType(unitType)
101 , m_valueInSpecifiedUnits(valueInSpecifiedUnits)
102 , m_orientType(SVGMarkerOrientEnumeration::create(this))
104 m_orientType->setEnumValue(orientType);
107 SVGAngle::~SVGAngle()
111 DEFINE_TRACE(SVGAngle)
113 visitor->trace(m_orientType);
114 SVGPropertyHelper<SVGAngle>::trace(visitor);
117 PassRefPtrWillBeRawPtr<SVGAngle> SVGAngle::clone() const
119 return adoptRefWillBeNoop(new SVGAngle(m_unitType, m_valueInSpecifiedUnits, m_orientType->enumValue()));
122 float SVGAngle::value() const
124 switch (m_unitType) {
125 case SVG_ANGLETYPE_GRAD:
126 return grad2deg(m_valueInSpecifiedUnits);
127 case SVG_ANGLETYPE_RAD:
128 return rad2deg(m_valueInSpecifiedUnits);
129 case SVG_ANGLETYPE_TURN:
130 return turn2deg(m_valueInSpecifiedUnits);
131 case SVG_ANGLETYPE_UNSPECIFIED:
132 case SVG_ANGLETYPE_UNKNOWN:
133 case SVG_ANGLETYPE_DEG:
134 return m_valueInSpecifiedUnits;
137 ASSERT_NOT_REACHED();
138 return 0;
141 void SVGAngle::setValue(float value)
143 switch (m_unitType) {
144 case SVG_ANGLETYPE_GRAD:
145 m_valueInSpecifiedUnits = deg2grad(value);
146 break;
147 case SVG_ANGLETYPE_RAD:
148 m_valueInSpecifiedUnits = deg2rad(value);
149 break;
150 case SVG_ANGLETYPE_TURN:
151 m_valueInSpecifiedUnits = deg2turn(value);
152 break;
153 case SVG_ANGLETYPE_UNSPECIFIED:
154 case SVG_ANGLETYPE_UNKNOWN:
155 case SVG_ANGLETYPE_DEG:
156 m_valueInSpecifiedUnits = value;
157 break;
159 m_orientType->setEnumValue(SVGMarkerOrientAngle);
162 template<typename CharType>
163 static SVGAngle::SVGAngleType stringToAngleType(const CharType*& ptr, const CharType* end)
165 // If there's no unit given, the angle type is unspecified.
166 if (ptr == end)
167 return SVGAngle::SVG_ANGLETYPE_UNSPECIFIED;
169 SVGAngle::SVGAngleType type = SVGAngle::SVG_ANGLETYPE_UNKNOWN;
170 const CharType firstChar = *ptr++;
172 if (isHTMLSpace<CharType>(firstChar)) {
173 type = SVGAngle::SVG_ANGLETYPE_UNSPECIFIED;
174 } else if (end - ptr >= 2) {
175 const CharType secondChar = *ptr++;
176 const CharType thirdChar = *ptr++;
177 if (firstChar == 'd' && secondChar == 'e' && thirdChar == 'g') {
178 type = SVGAngle::SVG_ANGLETYPE_DEG;
179 } else if (firstChar == 'r' && secondChar == 'a' && thirdChar == 'd') {
180 type = SVGAngle::SVG_ANGLETYPE_RAD;
181 } else if (ptr != end) {
182 const CharType fourthChar = *ptr++;
183 if (firstChar == 'g' && secondChar == 'r' && thirdChar == 'a' && fourthChar == 'd')
184 type = SVGAngle::SVG_ANGLETYPE_GRAD;
185 else if (firstChar == 't' && secondChar == 'u' && thirdChar == 'r' && fourthChar == 'n')
186 type = SVGAngle::SVG_ANGLETYPE_TURN;
190 if (!skipOptionalSVGSpaces(ptr, end))
191 return type;
193 return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
196 String SVGAngle::valueAsString() const
198 switch (m_unitType) {
199 case SVG_ANGLETYPE_DEG: {
200 DEFINE_STATIC_LOCAL(String, degString, ("deg"));
201 return String::number(m_valueInSpecifiedUnits) + degString;
203 case SVG_ANGLETYPE_RAD: {
204 DEFINE_STATIC_LOCAL(String, radString, ("rad"));
205 return String::number(m_valueInSpecifiedUnits) + radString;
207 case SVG_ANGLETYPE_GRAD: {
208 DEFINE_STATIC_LOCAL(String, gradString, ("grad"));
209 return String::number(m_valueInSpecifiedUnits) + gradString;
211 case SVG_ANGLETYPE_TURN: {
212 DEFINE_STATIC_LOCAL(String, turnString, ("turn"));
213 return String::number(m_valueInSpecifiedUnits) + turnString;
215 case SVG_ANGLETYPE_UNSPECIFIED:
216 case SVG_ANGLETYPE_UNKNOWN:
217 return String::number(m_valueInSpecifiedUnits);
220 ASSERT_NOT_REACHED();
221 return String();
224 template<typename CharType>
225 static bool parseValue(const String& value, float& valueInSpecifiedUnits, SVGAngle::SVGAngleType& unitType)
227 const CharType* ptr = value.getCharacters<CharType>();
228 const CharType* end = ptr + value.length();
230 if (!parseNumber(ptr, end, valueInSpecifiedUnits, AllowLeadingWhitespace))
231 return false;
233 unitType = stringToAngleType(ptr, end);
234 if (unitType == SVGAngle::SVG_ANGLETYPE_UNKNOWN)
235 return false;
237 return true;
240 void SVGAngle::setValueAsString(const String& value, ExceptionState& exceptionState)
242 if (value.isEmpty()) {
243 newValueSpecifiedUnits(SVG_ANGLETYPE_UNSPECIFIED, 0);
244 return;
247 if (value == "auto") {
248 newValueSpecifiedUnits(SVG_ANGLETYPE_UNSPECIFIED, 0);
249 m_orientType->setEnumValue(SVGMarkerOrientAuto);
250 return;
252 if (value == "auto-start-reverse") {
253 newValueSpecifiedUnits(SVG_ANGLETYPE_UNSPECIFIED, 0);
254 m_orientType->setEnumValue(SVGMarkerOrientAutoStartReverse);
255 return;
258 float valueInSpecifiedUnits = 0;
259 SVGAngleType unitType = SVG_ANGLETYPE_UNKNOWN;
261 bool success = value.is8Bit() ? parseValue<LChar>(value, valueInSpecifiedUnits, unitType)
262 : parseValue<UChar>(value, valueInSpecifiedUnits, unitType);
263 if (!success) {
264 exceptionState.throwDOMException(SyntaxError, "The value provided ('" + value + "') is invalid.");
265 return;
268 m_orientType->setEnumValue(SVGMarkerOrientAngle);
269 m_unitType = unitType;
270 m_valueInSpecifiedUnits = valueInSpecifiedUnits;
273 void SVGAngle::newValueSpecifiedUnits(SVGAngleType unitType, float valueInSpecifiedUnits)
275 m_orientType->setEnumValue(SVGMarkerOrientAngle);
276 m_unitType = unitType;
277 m_valueInSpecifiedUnits = valueInSpecifiedUnits;
280 void SVGAngle::convertToSpecifiedUnits(SVGAngleType unitType, ExceptionState& exceptionState)
282 if (m_unitType == SVG_ANGLETYPE_UNKNOWN) {
283 exceptionState.throwDOMException(NotSupportedError, "Cannot convert from unknown or invalid units.");
284 return;
287 if (unitType == m_unitType)
288 return;
290 switch (m_unitType) {
291 case SVG_ANGLETYPE_TURN:
292 switch (unitType) {
293 case SVG_ANGLETYPE_GRAD:
294 m_valueInSpecifiedUnits = turn2grad(m_valueInSpecifiedUnits);
295 break;
296 case SVG_ANGLETYPE_UNSPECIFIED:
297 case SVG_ANGLETYPE_DEG:
298 m_valueInSpecifiedUnits = turn2deg(m_valueInSpecifiedUnits);
299 break;
300 case SVG_ANGLETYPE_RAD:
301 m_valueInSpecifiedUnits = deg2rad(turn2deg(m_valueInSpecifiedUnits));
302 break;
303 case SVG_ANGLETYPE_TURN:
304 case SVG_ANGLETYPE_UNKNOWN:
305 ASSERT_NOT_REACHED();
306 break;
308 break;
309 case SVG_ANGLETYPE_RAD:
310 switch (unitType) {
311 case SVG_ANGLETYPE_GRAD:
312 m_valueInSpecifiedUnits = rad2grad(m_valueInSpecifiedUnits);
313 break;
314 case SVG_ANGLETYPE_UNSPECIFIED:
315 case SVG_ANGLETYPE_DEG:
316 m_valueInSpecifiedUnits = rad2deg(m_valueInSpecifiedUnits);
317 break;
318 case SVG_ANGLETYPE_TURN:
319 m_valueInSpecifiedUnits = deg2turn(rad2deg(m_valueInSpecifiedUnits));
320 break;
321 case SVG_ANGLETYPE_RAD:
322 case SVG_ANGLETYPE_UNKNOWN:
323 ASSERT_NOT_REACHED();
324 break;
326 break;
327 case SVG_ANGLETYPE_GRAD:
328 switch (unitType) {
329 case SVG_ANGLETYPE_RAD:
330 m_valueInSpecifiedUnits = grad2rad(m_valueInSpecifiedUnits);
331 break;
332 case SVG_ANGLETYPE_UNSPECIFIED:
333 case SVG_ANGLETYPE_DEG:
334 m_valueInSpecifiedUnits = grad2deg(m_valueInSpecifiedUnits);
335 break;
336 case SVG_ANGLETYPE_TURN:
337 m_valueInSpecifiedUnits = grad2turn(m_valueInSpecifiedUnits);
338 break;
339 case SVG_ANGLETYPE_GRAD:
340 case SVG_ANGLETYPE_UNKNOWN:
341 ASSERT_NOT_REACHED();
342 break;
344 break;
345 case SVG_ANGLETYPE_UNSPECIFIED:
346 // Spec: For angles, a unitless value is treated the same as if degrees were specified.
347 case SVG_ANGLETYPE_DEG:
348 switch (unitType) {
349 case SVG_ANGLETYPE_RAD:
350 m_valueInSpecifiedUnits = deg2rad(m_valueInSpecifiedUnits);
351 break;
352 case SVG_ANGLETYPE_GRAD:
353 m_valueInSpecifiedUnits = deg2grad(m_valueInSpecifiedUnits);
354 break;
355 case SVG_ANGLETYPE_TURN:
356 m_valueInSpecifiedUnits = deg2turn(m_valueInSpecifiedUnits);
357 break;
358 case SVG_ANGLETYPE_UNSPECIFIED:
359 case SVG_ANGLETYPE_DEG:
360 break;
361 case SVG_ANGLETYPE_UNKNOWN:
362 ASSERT_NOT_REACHED();
363 break;
365 break;
366 case SVG_ANGLETYPE_UNKNOWN:
367 ASSERT_NOT_REACHED();
368 break;
371 m_unitType = unitType;
372 m_orientType->setEnumValue(SVGMarkerOrientAngle);
375 void SVGAngle::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement*)
377 RefPtrWillBeRawPtr<SVGAngle> otherAngle = toSVGAngle(other);
379 // Only respect by animations, if from and by are both specified in angles (and not eg. 'auto').
380 if (orientType()->enumValue() != SVGMarkerOrientAngle || otherAngle->orientType()->enumValue() != SVGMarkerOrientAngle)
381 return;
383 setValue(value() + otherAngle->value());
386 void SVGAngle::assign(const SVGAngle& other)
388 SVGMarkerOrientType otherOrientType = other.orientType()->enumValue();
389 if (otherOrientType == SVGMarkerOrientAngle)
390 newValueSpecifiedUnits(other.unitType(), other.valueInSpecifiedUnits());
391 else
392 m_orientType->setEnumValue(otherOrientType);
395 void SVGAngle::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtrWillBeRawPtr<SVGPropertyBase> from, PassRefPtrWillBeRawPtr<SVGPropertyBase> to, PassRefPtrWillBeRawPtr<SVGPropertyBase> toAtEndOfDuration, SVGElement*)
397 ASSERT(animationElement);
398 bool isToAnimation = animationElement->animationMode() == ToAnimation;
400 RefPtrWillBeRawPtr<SVGAngle> fromAngle = isToAnimation ? PassRefPtrWillBeRawPtr<SVGAngle>(this) : toSVGAngle(from);
401 RefPtrWillBeRawPtr<SVGAngle> toAngle = toSVGAngle(to);
402 SVGMarkerOrientType fromOrientType = fromAngle->orientType()->enumValue();
403 SVGMarkerOrientType toOrientType = toAngle->orientType()->enumValue();
405 if (fromOrientType != toOrientType) {
406 // Fall back to discrete animation.
407 assign(percentage < 0.5f ? *fromAngle : *toAngle);
408 return;
411 switch (fromOrientType) {
412 // From 'auto' to 'auto', or 'auto-start-reverse' to 'auto-start-reverse'
413 case SVGMarkerOrientAuto:
414 case SVGMarkerOrientAutoStartReverse:
415 orientType()->setEnumValue(fromOrientType);
416 return;
418 // Regular from angle to angle animation, with all features like additive etc.
419 case SVGMarkerOrientAngle:
421 float animatedValue = value();
422 RefPtrWillBeRawPtr<SVGAngle> toAtEndOfDurationAngle = toSVGAngle(toAtEndOfDuration);
424 animationElement->animateAdditiveNumber(percentage, repeatCount, fromAngle->value(), toAngle->value(), toAtEndOfDurationAngle->value(), animatedValue);
425 orientType()->setEnumValue(SVGMarkerOrientAngle);
426 setValue(animatedValue);
428 return;
430 // If the enumeration value is not angle or auto, its unknown.
431 default:
432 m_valueInSpecifiedUnits = 0;
433 orientType()->setEnumValue(SVGMarkerOrientUnknown);
434 return;
438 float SVGAngle::calculateDistance(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement*)
440 return fabsf(value() - toSVGAngle(other)->value());
443 void SVGAngle::orientTypeChanged()
445 if (orientType()->enumValue() == SVGMarkerOrientAuto || orientType()->enumValue() == SVGMarkerOrientAutoStartReverse) {
446 m_unitType = SVG_ANGLETYPE_UNSPECIFIED;
447 m_valueInSpecifiedUnits = 0;