• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "config.h"
22 #include "core/svg/SVGPointList.h"
23 
24 #include "core/svg/SVGAnimationElement.h"
25 #include "core/svg/SVGParserUtilities.h"
26 #include "platform/geometry/FloatPoint.h"
27 #include "wtf/text/StringBuilder.h"
28 #include "wtf/text/WTFString.h"
29 
30 namespace WebCore {
31 
toSVGPointList(PassRefPtr<SVGPropertyBase> passBase)32 inline PassRefPtr<SVGPointList> toSVGPointList(PassRefPtr<SVGPropertyBase> passBase)
33 {
34     RefPtr<SVGPropertyBase> base = passBase;
35     ASSERT(base->type() == SVGPointList::classType());
36     return static_pointer_cast<SVGPointList>(base.release());
37 }
38 
SVGPointList()39 SVGPointList::SVGPointList()
40 {
41 }
42 
~SVGPointList()43 SVGPointList::~SVGPointList()
44 {
45 }
46 
clone()47 PassRefPtr<SVGPointList> SVGPointList::clone()
48 {
49     RefPtr<SVGPointList> svgPointList = SVGPointList::create();
50     svgPointList->deepCopy(this);
51     return svgPointList.release();
52 }
53 
cloneForAnimation(const String & value) const54 PassRefPtr<SVGPropertyBase> SVGPointList::cloneForAnimation(const String& value) const
55 {
56     RefPtr<SVGPointList> svgPointList = SVGPointList::create();
57     svgPointList->setValueAsString(value, IGNORE_EXCEPTION);
58     return svgPointList.release();
59 }
60 
valueAsString() const61 String SVGPointList::valueAsString() const
62 {
63     StringBuilder builder;
64 
65     ConstIterator it = begin();
66     ConstIterator itEnd = end();
67     if (it != itEnd) {
68         builder.append(it->valueAsString());
69         ++it;
70 
71         for (; it != itEnd; ++it) {
72             builder.append(' ');
73             builder.append(it->valueAsString());
74         }
75     }
76 
77     return builder.toString();
78 }
79 
80 template <typename CharType>
parse(const CharType * & ptr,const CharType * end)81 bool SVGPointList::parse(const CharType*& ptr, const CharType* end)
82 {
83     clear();
84 
85     skipOptionalSVGSpaces(ptr, end);
86     if (ptr >= end)
87         return true;
88 
89     for (;;) {
90         float x = 0.0f;
91         float y = 0.0f;
92         bool valid = parseNumber(ptr, end, x) && parseNumber(ptr, end, y, DisallowWhitespace);
93         if (!valid) {
94             return false;
95         }
96         append(SVGPoint::create(FloatPoint(x, y)));
97 
98         skipOptionalSVGSpaces(ptr, end);
99         if (ptr < end && *ptr == ',') {
100             ++ptr;
101             skipOptionalSVGSpaces(ptr, end);
102 
103             // ',' requires the list to be continued
104             continue;
105         }
106 
107         // check end of list
108         if (ptr >= end)
109             return true;
110     }
111 }
112 
setValueAsString(const String & value,ExceptionState & exceptionState)113 void SVGPointList::setValueAsString(const String& value, ExceptionState& exceptionState)
114 {
115     if (value.isEmpty()) {
116         clear();
117         return;
118     }
119 
120     bool valid = false;
121     if (value.is8Bit()) {
122         const LChar* ptr = value.characters8();
123         const LChar* end = ptr + value.length();
124         valid = parse(ptr, end);
125     } else {
126         const UChar* ptr = value.characters16();
127         const UChar* end = ptr + value.length();
128         valid = parse(ptr, end);
129     }
130 
131     if (!valid)
132         exceptionState.throwDOMException(SyntaxError, "Problem parsing points=\""+value+"\"");
133 }
134 
add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other,SVGElement * contextElement)135 void SVGPointList::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement* contextElement)
136 {
137     RefPtr<SVGPointList> otherList = toSVGPointList(other);
138 
139     if (length() != otherList->length())
140         return;
141 
142     for (size_t i = 0; i < length(); ++i)
143         at(i)->setValue(at(i)->value() + otherList->at(i)->value());
144 }
145 
adjustFromToListValues(PassRefPtr<SVGPointList> passFromList,PassRefPtr<SVGPointList> passToList,float percentage,bool isToAnimation,bool resizeAnimatedListIfNeeded)146 bool SVGPointList::adjustFromToListValues(PassRefPtr<SVGPointList> passFromList, PassRefPtr<SVGPointList> passToList, float percentage, bool isToAnimation, bool resizeAnimatedListIfNeeded)
147 {
148     RefPtr<SVGPointList> fromList = passFromList;
149     RefPtr<SVGPointList> toList = passToList;
150 
151     // If no 'to' value is given, nothing to animate.
152     size_t toListSize = toList->length();
153     if (!toListSize)
154         return false;
155 
156     // If the 'from' value is given and it's length doesn't match the 'to' value list length, fallback to a discrete animation.
157     size_t fromListSize = fromList->length();
158     if (fromListSize != toListSize && fromListSize) {
159         if (percentage < 0.5) {
160             if (!isToAnimation)
161                 deepCopy(fromList);
162         } else {
163             deepCopy(toList);
164         }
165 
166         return false;
167     }
168 
169     ASSERT(!fromListSize || fromListSize == toListSize);
170     if (resizeAnimatedListIfNeeded && length() < toListSize) {
171         size_t paddingCount = toListSize - length();
172         for (size_t i = 0; i < paddingCount; ++i)
173             append(SVGPoint::create());
174     }
175 
176     return true;
177 }
178 
calculateAnimatedValue(SVGAnimationElement * animationElement,float percentage,unsigned repeatCount,PassRefPtr<SVGPropertyBase> fromValue,PassRefPtr<SVGPropertyBase> toValue,PassRefPtr<SVGPropertyBase> toAtEndOfDurationValue,SVGElement * contextElement)179 void SVGPointList::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtr<SVGPropertyBase> fromValue, PassRefPtr<SVGPropertyBase> toValue, PassRefPtr<SVGPropertyBase> toAtEndOfDurationValue, SVGElement* contextElement)
180 {
181     RefPtr<SVGPointList> fromList = toSVGPointList(fromValue);
182     RefPtr<SVGPointList> toList = toSVGPointList(toValue);
183     RefPtr<SVGPointList> toAtEndOfDurationList = toSVGPointList(toAtEndOfDurationValue);
184 
185     size_t fromPointListSize = fromList->length();
186     size_t toPointListSize = toList->length();
187     size_t toAtEndOfDurationListSize = toAtEndOfDurationList->length();
188 
189     if (!adjustFromToListValues(fromList, toList, percentage, animationElement->animationMode() == ToAnimation, true))
190         return;
191 
192     for (size_t i = 0; i < toPointListSize; ++i) {
193         float animatedX = at(i)->x();
194         float animatedY = at(i)->y();
195 
196         FloatPoint effectiveFrom;
197         if (fromPointListSize)
198             effectiveFrom = fromList->at(i)->value();
199         FloatPoint effectiveTo = toList->at(i)->value();
200         FloatPoint effectiveToAtEnd;
201         if (i < toAtEndOfDurationListSize)
202             effectiveToAtEnd = toAtEndOfDurationList->at(i)->value();
203 
204         animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom.x(), effectiveTo.x(), effectiveToAtEnd.x(), animatedX);
205         animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom.y(), effectiveTo.y(), effectiveToAtEnd.y(), animatedY);
206         at(i)->setValue(FloatPoint(animatedX, animatedY));
207     }
208 }
209 
calculateDistance(PassRefPtr<SVGPropertyBase> to,SVGElement *)210 float SVGPointList::calculateDistance(PassRefPtr<SVGPropertyBase> to, SVGElement*)
211 {
212     // FIXME: Distance calculation is not possible for SVGPointList right now. We need the distance for every single value.
213     return -1;
214 }
215 
216 }
217