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.
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"
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"));
46 template<> unsigned short getMaxExposedEnumValue
<SVGMarkerOrientType
>()
48 return SVGMarkerOrientAngle
;
51 SVGMarkerOrientEnumeration::SVGMarkerOrientEnumeration(SVGAngle
* angle
)
52 : SVGEnumeration
<SVGMarkerOrientType
>(SVGMarkerOrientAngle
)
57 SVGMarkerOrientEnumeration::~SVGMarkerOrientEnumeration()
61 DEFINE_TRACE(SVGMarkerOrientEnumeration
)
63 visitor
->trace(m_angle
);
64 SVGEnumeration
<SVGMarkerOrientType
>::trace(visitor
);
67 void SVGMarkerOrientEnumeration::notifyChange()
70 m_angle
->orientTypeChanged();
73 void SVGMarkerOrientEnumeration::add(PassRefPtrWillBeRawPtr
<SVGPropertyBase
>, SVGElement
*)
75 // SVGMarkerOrientEnumeration is only animated via SVGAngle
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
85 float SVGMarkerOrientEnumeration::calculateDistance(PassRefPtrWillBeRawPtr
<SVGPropertyBase
> to
, SVGElement
* contextElement
)
87 // SVGMarkerOrientEnumeration is only animated via 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();
141 void SVGAngle::setValue(float value
)
143 switch (m_unitType
) {
144 case SVG_ANGLETYPE_GRAD
:
145 m_valueInSpecifiedUnits
= deg2grad(value
);
147 case SVG_ANGLETYPE_RAD
:
148 m_valueInSpecifiedUnits
= deg2rad(value
);
150 case SVG_ANGLETYPE_TURN
:
151 m_valueInSpecifiedUnits
= deg2turn(value
);
153 case SVG_ANGLETYPE_UNSPECIFIED
:
154 case SVG_ANGLETYPE_UNKNOWN
:
155 case SVG_ANGLETYPE_DEG
:
156 m_valueInSpecifiedUnits
= value
;
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.
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
))
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();
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
))
233 unitType
= stringToAngleType(ptr
, end
);
234 if (unitType
== SVGAngle::SVG_ANGLETYPE_UNKNOWN
)
240 void SVGAngle::setValueAsString(const String
& value
, ExceptionState
& exceptionState
)
242 if (value
.isEmpty()) {
243 newValueSpecifiedUnits(SVG_ANGLETYPE_UNSPECIFIED
, 0);
247 if (value
== "auto") {
248 newValueSpecifiedUnits(SVG_ANGLETYPE_UNSPECIFIED
, 0);
249 m_orientType
->setEnumValue(SVGMarkerOrientAuto
);
252 if (value
== "auto-start-reverse") {
253 newValueSpecifiedUnits(SVG_ANGLETYPE_UNSPECIFIED
, 0);
254 m_orientType
->setEnumValue(SVGMarkerOrientAutoStartReverse
);
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
);
264 exceptionState
.throwDOMException(SyntaxError
, "The value provided ('" + value
+ "') is invalid.");
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.");
287 if (unitType
== m_unitType
)
290 switch (m_unitType
) {
291 case SVG_ANGLETYPE_TURN
:
293 case SVG_ANGLETYPE_GRAD
:
294 m_valueInSpecifiedUnits
= turn2grad(m_valueInSpecifiedUnits
);
296 case SVG_ANGLETYPE_UNSPECIFIED
:
297 case SVG_ANGLETYPE_DEG
:
298 m_valueInSpecifiedUnits
= turn2deg(m_valueInSpecifiedUnits
);
300 case SVG_ANGLETYPE_RAD
:
301 m_valueInSpecifiedUnits
= deg2rad(turn2deg(m_valueInSpecifiedUnits
));
303 case SVG_ANGLETYPE_TURN
:
304 case SVG_ANGLETYPE_UNKNOWN
:
305 ASSERT_NOT_REACHED();
309 case SVG_ANGLETYPE_RAD
:
311 case SVG_ANGLETYPE_GRAD
:
312 m_valueInSpecifiedUnits
= rad2grad(m_valueInSpecifiedUnits
);
314 case SVG_ANGLETYPE_UNSPECIFIED
:
315 case SVG_ANGLETYPE_DEG
:
316 m_valueInSpecifiedUnits
= rad2deg(m_valueInSpecifiedUnits
);
318 case SVG_ANGLETYPE_TURN
:
319 m_valueInSpecifiedUnits
= deg2turn(rad2deg(m_valueInSpecifiedUnits
));
321 case SVG_ANGLETYPE_RAD
:
322 case SVG_ANGLETYPE_UNKNOWN
:
323 ASSERT_NOT_REACHED();
327 case SVG_ANGLETYPE_GRAD
:
329 case SVG_ANGLETYPE_RAD
:
330 m_valueInSpecifiedUnits
= grad2rad(m_valueInSpecifiedUnits
);
332 case SVG_ANGLETYPE_UNSPECIFIED
:
333 case SVG_ANGLETYPE_DEG
:
334 m_valueInSpecifiedUnits
= grad2deg(m_valueInSpecifiedUnits
);
336 case SVG_ANGLETYPE_TURN
:
337 m_valueInSpecifiedUnits
= grad2turn(m_valueInSpecifiedUnits
);
339 case SVG_ANGLETYPE_GRAD
:
340 case SVG_ANGLETYPE_UNKNOWN
:
341 ASSERT_NOT_REACHED();
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
:
349 case SVG_ANGLETYPE_RAD
:
350 m_valueInSpecifiedUnits
= deg2rad(m_valueInSpecifiedUnits
);
352 case SVG_ANGLETYPE_GRAD
:
353 m_valueInSpecifiedUnits
= deg2grad(m_valueInSpecifiedUnits
);
355 case SVG_ANGLETYPE_TURN
:
356 m_valueInSpecifiedUnits
= deg2turn(m_valueInSpecifiedUnits
);
358 case SVG_ANGLETYPE_UNSPECIFIED
:
359 case SVG_ANGLETYPE_DEG
:
361 case SVG_ANGLETYPE_UNKNOWN
:
362 ASSERT_NOT_REACHED();
366 case SVG_ANGLETYPE_UNKNOWN
:
367 ASSERT_NOT_REACHED();
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
)
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());
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
);
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
);
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
);
430 // If the enumeration value is not angle or auto, its unknown.
432 m_valueInSpecifiedUnits
= 0;
433 orientType()->setEnumValue(SVGMarkerOrientUnknown
);
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;