• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3                   2004, 2005 Rob Buis <buis@kde.org>
4     Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5 
6     This file is part of the WebKit 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 #include "config.h"
25 
26 #if ENABLE(SVG)
27 #include "SVGPathSegList.h"
28 
29 #include "FloatPoint.h"
30 #include "Path.h"
31 #include "PathTraversalState.h"
32 #include "SVGPathSegArc.h"
33 #include "SVGPathSegClosePath.h"
34 #include "SVGPathSegMoveto.h"
35 #include "SVGPathSegLineto.h"
36 #include "SVGPathSegLinetoHorizontal.h"
37 #include "SVGPathSegLinetoVertical.h"
38 #include "SVGPathSegCurvetoCubic.h"
39 #include "SVGPathSegCurvetoCubicSmooth.h"
40 #include "SVGPathSegCurvetoQuadratic.h"
41 #include "SVGPathSegCurvetoQuadraticSmooth.h"
42 
43 namespace WebCore {
44 
SVGPathSegList(const QualifiedName & attributeName)45 SVGPathSegList::SVGPathSegList(const QualifiedName& attributeName)
46     : SVGList<RefPtr<SVGPathSeg> >(attributeName)
47 {
48 }
49 
~SVGPathSegList()50 SVGPathSegList::~SVGPathSegList()
51 {
52 }
53 
getPathSegAtLength(double,ExceptionCode & ec)54 unsigned SVGPathSegList::getPathSegAtLength(double, ExceptionCode& ec)
55 {
56     // FIXME : to be useful this will need to support non-normalized SVGPathSegLists
57     int len = numberOfItems();
58     // FIXME: Eventually this will likely move to a "path applier"-like model, until then PathTraversalState is less useful as we could just use locals
59     PathTraversalState traversalState(PathTraversalState::TraversalSegmentAtLength);
60     for (int i = 0; i < len; ++i) {
61         SVGPathSeg* segment = getItem(i, ec).get();
62         if (ec)
63             return 0;
64         float segmentLength = 0;
65         switch (segment->pathSegType()) {
66         case SVGPathSeg::PATHSEG_MOVETO_ABS:
67         {
68             SVGPathSegMovetoAbs* moveTo = static_cast<SVGPathSegMovetoAbs*>(segment);
69             segmentLength = traversalState.moveTo(FloatPoint(moveTo->x(), moveTo->y()));
70             break;
71         }
72         case SVGPathSeg::PATHSEG_LINETO_ABS:
73         {
74             SVGPathSegLinetoAbs* lineTo = static_cast<SVGPathSegLinetoAbs*>(segment);
75             segmentLength = traversalState.lineTo(FloatPoint(lineTo->x(), lineTo->y()));
76             break;
77         }
78         case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
79         {
80             SVGPathSegCurvetoCubicAbs* curveTo = static_cast<SVGPathSegCurvetoCubicAbs*>(segment);
81             segmentLength = traversalState.cubicBezierTo(FloatPoint(curveTo->x1(), curveTo->y1()),
82                                       FloatPoint(curveTo->x2(), curveTo->y2()),
83                                       FloatPoint(curveTo->x(), curveTo->y()));
84             break;
85         }
86         case SVGPathSeg::PATHSEG_CLOSEPATH:
87             segmentLength = traversalState.closeSubpath();
88             break;
89         default:
90             ASSERT(false); // FIXME: This only works with normalized/processed path data.
91             break;
92         }
93         traversalState.m_totalLength += segmentLength;
94         if ((traversalState.m_action == PathTraversalState::TraversalSegmentAtLength)
95             && (traversalState.m_totalLength > traversalState.m_desiredLength)) {
96             return traversalState.m_segmentIndex;
97         }
98         traversalState.m_segmentIndex++;
99     }
100 
101     return 0; // The SVG spec is unclear as to what to return when the distance is not on the path
102 }
103 
toPathData()104 Path SVGPathSegList::toPathData()
105 {
106     // FIXME : This should also support non-normalized PathSegLists
107     Path pathData;
108     int len = numberOfItems();
109     ExceptionCode ec = 0;
110     for (int i = 0; i < len; ++i) {
111         SVGPathSeg* segment = getItem(i, ec).get();
112         if (ec)
113             return Path();
114         switch (segment->pathSegType()) {
115             case SVGPathSeg::PATHSEG_MOVETO_ABS:
116             {
117                 SVGPathSegMovetoAbs* moveTo = static_cast<SVGPathSegMovetoAbs*>(segment);
118                 pathData.moveTo(FloatPoint(moveTo->x(), moveTo->y()));
119                 break;
120             }
121             case SVGPathSeg::PATHSEG_LINETO_ABS:
122             {
123                 SVGPathSegLinetoAbs* lineTo = static_cast<SVGPathSegLinetoAbs*>(segment);
124                 pathData.addLineTo(FloatPoint(lineTo->x(), lineTo->y()));
125                 break;
126             }
127             case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
128             {
129                 SVGPathSegCurvetoCubicAbs* curveTo = static_cast<SVGPathSegCurvetoCubicAbs*>(segment);
130                 pathData.addBezierCurveTo(FloatPoint(curveTo->x1(), curveTo->y1()),
131                                           FloatPoint(curveTo->x2(), curveTo->y2()),
132                                           FloatPoint(curveTo->x(), curveTo->y()));
133                 break;
134             }
135             case SVGPathSeg::PATHSEG_CLOSEPATH:
136                 pathData.closeSubpath();
137                 break;
138             default:
139                 ASSERT(false); // FIXME: This only works with normalized/processed path data.
140                 break;
141         }
142     }
143 
144     return pathData;
145 }
146 
blendFunc(float from,float to,float progress)147 static inline float blendFunc(float from, float to, float progress)
148 {
149     return (to - from) * progress + from;
150 }
151 
152 #define BLENDPATHSEG1(class, attr1) \
153     class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress))
154 
155 #define BLENDPATHSEG2(class, attr1, attr2) \
156     class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
157                     blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress))
158 
159 #define BLENDPATHSEG4(class, attr1, attr2, attr3, attr4) \
160     class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
161                 blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress), \
162                 blendFunc(static_cast<class*>(from)->attr3(), static_cast<class*>(to)->attr3(), progress), \
163                 blendFunc(static_cast<class*>(from)->attr4(), static_cast<class*>(to)->attr4(), progress))
164 
165 #define BLENDPATHSEG6(class, attr1, attr2, attr3, attr4, attr5, attr6) \
166     class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
167                 blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress), \
168                 blendFunc(static_cast<class*>(from)->attr3(), static_cast<class*>(to)->attr3(), progress), \
169                 blendFunc(static_cast<class*>(from)->attr4(), static_cast<class*>(to)->attr4(), progress), \
170                 blendFunc(static_cast<class*>(from)->attr5(), static_cast<class*>(to)->attr5(), progress), \
171                 blendFunc(static_cast<class*>(from)->attr6(), static_cast<class*>(to)->attr6(), progress))
172 
173 #define BLENDPATHSEG7(class, attr1, attr2, attr3, attr4, attr5, bool1, bool2) \
174     class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
175                 blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress), \
176                 blendFunc(static_cast<class*>(from)->attr3(), static_cast<class*>(to)->attr3(), progress), \
177                 blendFunc(static_cast<class*>(from)->attr4(), static_cast<class*>(to)->attr4(), progress), \
178                 blendFunc(static_cast<class*>(from)->attr5(), static_cast<class*>(to)->attr5(), progress), \
179                 static_cast<bool>(blendFunc(static_cast<class*>(from)->bool1(), static_cast<class*>(to)->bool1(), progress)), \
180                 static_cast<bool>(blendFunc(static_cast<class*>(from)->bool2(), static_cast<class*>(to)->bool2(), progress)))
181 
createAnimated(const SVGPathSegList * fromList,const SVGPathSegList * toList,float progress)182 PassRefPtr<SVGPathSegList> SVGPathSegList::createAnimated(const SVGPathSegList* fromList, const SVGPathSegList* toList, float progress)
183 {
184     unsigned itemCount = fromList->numberOfItems();
185     if (!itemCount || itemCount != toList->numberOfItems())
186         return 0;
187     RefPtr<SVGPathSegList> result = create(fromList->associatedAttributeName());
188     ExceptionCode ec = 0;
189     for (unsigned n = 0; n < itemCount; ++n) {
190         SVGPathSeg* from = fromList->getItem(n, ec).get();
191         if (ec)
192             return 0;
193         SVGPathSeg* to = toList->getItem(n, ec).get();
194         if (ec)
195             return 0;
196         if (from->pathSegType() == SVGPathSeg::PATHSEG_UNKNOWN || from->pathSegType() != to->pathSegType())
197             return 0;
198         RefPtr<SVGPathSeg> segment = 0;
199         switch (static_cast<SVGPathSeg::SVGPathSegType>(from->pathSegType())) {
200         case SVGPathSeg::PATHSEG_CLOSEPATH:
201             segment = SVGPathSegClosePath::create();
202             break;
203         case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
204             segment = BLENDPATHSEG1(SVGPathSegLinetoHorizontalAbs, x);
205             break;
206         case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
207             segment = BLENDPATHSEG1(SVGPathSegLinetoHorizontalRel, x);
208             break;
209         case SVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
210             segment = BLENDPATHSEG1(SVGPathSegLinetoVerticalAbs, y);
211             break;
212         case SVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
213             segment = BLENDPATHSEG1(SVGPathSegLinetoVerticalRel, y);
214             break;
215         case SVGPathSeg::PATHSEG_MOVETO_ABS:
216             segment = BLENDPATHSEG2(SVGPathSegMovetoAbs, x, y);
217             break;
218         case SVGPathSeg::PATHSEG_MOVETO_REL:
219             segment = BLENDPATHSEG2(SVGPathSegMovetoRel, x, y);
220             break;
221         case SVGPathSeg::PATHSEG_LINETO_ABS:
222             segment = BLENDPATHSEG2(SVGPathSegLinetoAbs, x, y);
223             break;
224         case SVGPathSeg::PATHSEG_LINETO_REL:
225             segment = BLENDPATHSEG2(SVGPathSegLinetoRel, x, y);
226             break;
227         case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
228             segment = BLENDPATHSEG6(SVGPathSegCurvetoCubicAbs, x, y, x1, y1, x2, y2);
229             break;
230         case SVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
231             segment = BLENDPATHSEG6(SVGPathSegCurvetoCubicRel, x, y, x1, y1, x2, y2);
232             break;
233         case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
234             segment = BLENDPATHSEG4(SVGPathSegCurvetoCubicSmoothAbs, x, y, x2, y2);
235             break;
236         case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
237             segment = BLENDPATHSEG4(SVGPathSegCurvetoCubicSmoothRel, x, y, x2, y2);
238             break;
239         case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
240             segment = BLENDPATHSEG4(SVGPathSegCurvetoQuadraticAbs, x, y, x1, y1);
241             break;
242         case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
243             segment = BLENDPATHSEG4(SVGPathSegCurvetoQuadraticRel, x, y, x1, y1);
244             break;
245         case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
246             segment = BLENDPATHSEG2(SVGPathSegCurvetoQuadraticSmoothAbs, x, y);
247             break;
248         case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
249             segment = BLENDPATHSEG2(SVGPathSegCurvetoQuadraticSmoothRel, x, y);
250             break;
251         case SVGPathSeg::PATHSEG_ARC_ABS:
252             segment = BLENDPATHSEG7(SVGPathSegArcAbs, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
253             break;
254         case SVGPathSeg::PATHSEG_ARC_REL:
255             segment = BLENDPATHSEG7(SVGPathSegArcRel, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
256             break;
257         case SVGPathSeg::PATHSEG_UNKNOWN:
258             ASSERT_NOT_REACHED();
259         }
260         result->appendItem(segment, ec);
261         if (ec)
262             return 0;
263     }
264     return result.release();
265 }
266 
267 }
268 
269 #endif // ENABLE(SVG)
270