1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkSVGParser.h"
11 #include "SkSVGCircle.h"
12 #include "SkSVGClipPath.h"
13 #include "SkSVGDefs.h"
14 #include "SkSVGEllipse.h"
15 #include "SkSVGFeColorMatrix.h"
16 #include "SkSVGFilter.h"
17 #include "SkSVGG.h"
18 #include "SkSVGImage.h"
19 #include "SkSVGLine.h"
20 #include "SkSVGLinearGradient.h"
21 #include "SkSVGMask.h"
22 #include "SkSVGMetadata.h"
23 #include "SkSVGPath.h"
24 #include "SkSVGPolygon.h"
25 #include "SkSVGPolyline.h"
26 #include "SkSVGRadialGradient.h"
27 #include "SkSVGRect.h"
28 #include "SkSVGSVG.h"
29 #include "SkSVGStop.h"
30 #include "SkSVGSymbol.h"
31 #include "SkSVGText.h"
32 #include "SkSVGUse.h"
33 #include "SkTSearch.h"
34 #include <stdio.h>
35 
36 static int gGeneratedMatrixID = 0;
37 
SkSVGParser(SkXMLParserError * errHandler)38 SkSVGParser::SkSVGParser(SkXMLParserError* errHandler) :
39     SkXMLParser(errHandler),
40     fHead(&fEmptyPaint), fIDs(256),
41         fXMLWriter(&fStream), fCurrElement(NULL), fInSVG(false), fSuppressPaint(false) {
42     fLastTransform.reset();
43     fEmptyPaint.f_fill.set("black");
44     fEmptyPaint.f_stroke.set("none");
45     fEmptyPaint.f_strokeMiterlimit.set("4");
46     fEmptyPaint.f_fillRule.set("winding");
47     fEmptyPaint.f_opacity.set("1");
48     fEmptyPaint.fNext = NULL;
49     for (int index = SkSVGPaint::kInitial + 1; index < SkSVGPaint::kTerminal; index++) {
50         SkString* initial = fEmptyPaint[index];
51         if (initial->size() == 0)
52             continue;
53         fLastFlush[index]->set(*initial);
54     }
55 }
56 
~SkSVGParser()57 SkSVGParser::~SkSVGParser() {
58 }
59 
Delete(SkTDArray<SkSVGElement * > & fChildren)60 void SkSVGParser::Delete(SkTDArray<SkSVGElement*>& fChildren) {
61     SkSVGElement** ptr;
62     for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
63         Delete((*ptr)->fChildren);
64         delete *ptr;
65     }
66 }
67 
findAttribute(SkSVGBase * element,const char * attrValue,size_t len,bool isPaint)68 int SkSVGParser::findAttribute(SkSVGBase* element, const char* attrValue,
69         size_t len, bool isPaint) {
70     const SkSVGAttribute* attributes;
71     size_t count = element->getAttributes(&attributes);
72     size_t result = 0;
73     while (result < count) {
74         if (strncmp(attributes->fName, attrValue, len) == 0 && strlen(attributes->fName) == len) {
75             SkASSERT(result == (attributes->fOffset -
76                 (isPaint ? sizeof(SkString) : sizeof(SkSVGElement))) / sizeof(SkString));
77             return result;
78         }
79         attributes++;
80         result++;
81     }
82     return -1;
83 }
84 
85 #if 0
86 const char* SkSVGParser::getFinal() {
87     _startElement("screenplay");
88     // generate defs
89     SkSVGElement** ptr;
90     for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
91         SkSVGElement* element = *ptr;
92         translate(element, true);
93     }
94     // generate onLoad
95     _startElement("event");
96     _addAttribute("kind", "onLoad");
97     _startElement("paint");
98     _addAttribute("antiAlias", "true");
99     _endElement();
100     for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
101         SkSVGElement* element = *ptr;
102         translate(element, false);
103     }
104     _endElement(); // event
105     _endElement(); // screenplay
106     Delete(fChildren);
107     fStream.write("", 1);
108     return fStream.getStream();
109 }
110 #endif
111 
getPaintLast(SkSVGPaint::Field field)112 SkString& SkSVGParser::getPaintLast(SkSVGPaint::Field field) {
113     SkSVGPaint* state = fHead;
114     do {
115         SkString* attr = (*state)[field];
116         SkASSERT(attr);
117         if (attr->size() > 0)
118             return *attr;
119         state = state->fNext;
120     } while (state);
121     SkASSERT(0);
122     SkASSERT(fEmptyPaint[field]);
123     return *fEmptyPaint[field];
124 }
125 
isStrokeAndFill(SkSVGPaint ** strokeState,SkSVGPaint ** fillState)126 bool SkSVGParser::isStrokeAndFill(  SkSVGPaint** strokeState, SkSVGPaint** fillState) {
127     SkSVGPaint* walking = fHead;
128     bool stroke = false;
129     bool fill = false;
130     bool strokeSet = false;
131     bool fillSet = false;
132     while (walking != NULL) {
133         if (strokeSet == false && walking->f_stroke.size() > 0) {
134             stroke = walking->f_stroke.equals("none") == false;
135             *strokeState = walking;
136             strokeSet = true;
137         }
138         if (fillSet == false && walking->f_fill.size() > 0) {
139             fill = walking->f_fill.equals("none") == false;
140             *fillState = walking;
141             fillSet = true;
142         }
143         walking = walking->fNext;
144     }
145     return stroke && fill;
146 }
147 
onAddAttribute(const char name[],const char value[])148 bool SkSVGParser::onAddAttribute(const char name[], const char value[]) {
149     return onAddAttributeLen(name, value, strlen(value));
150 }
151 
onAddAttributeLen(const char name[],const char value[],size_t len)152 bool SkSVGParser::onAddAttributeLen(const char name[], const char value[], size_t len) {
153     if (fCurrElement == NULL)    // this signals we should ignore attributes for this element
154         return true;
155     if (fCurrElement->fIsDef == false && fCurrElement->fIsNotDef == false)
156         return false; // also an ignored element
157     size_t nameLen = strlen(name);
158     int attrIndex = findAttribute(fCurrElement, name, nameLen, false);
159     if (attrIndex == -1) {
160         attrIndex = findAttribute(&fCurrElement->fPaintState, name, nameLen, true);
161         if (attrIndex >= 0) {
162             fCurrElement->fPaintState.addAttribute(*this, attrIndex, value, len);
163             return false;
164         }
165         if (nameLen == 2 && strncmp("id", name, nameLen) == 0) {
166             fCurrElement->f_id.set(value, len);
167             return false;
168         }
169         if (strchr(name, ':') != 0) // part of a different namespace
170             return false;
171     }
172     SkASSERT(attrIndex >= 0);
173     fCurrElement->addAttribute(*this, attrIndex, value, len);
174     return false;
175 }
176 
onEndElement(const char elem[])177 bool SkSVGParser::onEndElement(const char elem[]) {
178     int parentIndex = fParents.count() - 1;
179     if (parentIndex >= 0) {
180         SkSVGElement* element = fParents[parentIndex];
181         element->onEndElement(*this);
182         fParents.remove(parentIndex);
183     }
184     return false;
185 }
186 
onStartElement(const char name[])187 bool SkSVGParser::onStartElement(const char name[]) {
188     return onStartElementLen(name, strlen(name));
189 }
190 
onStartElementLen(const char name[],size_t len)191 bool SkSVGParser::onStartElementLen(const char name[], size_t len) {
192     if (strncmp(name, "svg", len) == 0) {
193         fInSVG = true;
194     } else if (fInSVG == false)
195         return false;
196     const char* nextColon = strchr(name, ':');
197     if (nextColon && (size_t)(nextColon - name) < len)
198         return false;
199     SkSVGTypes type = GetType(name, len);
200 //    SkASSERT(type >= 0);
201     if (type < 0) {
202         type = SkSVGType_G;
203 //        return true;
204     }
205     SkSVGElement* parent = fParents.count() > 0 ? fParents.top() : NULL;
206     SkSVGElement* element = CreateElement(type, parent);
207     bool result = false;
208     if (parent) {
209         element->fParent = parent;
210         result = fParents.top()->onStartElement(element);
211     } else
212         *fChildren.append() = element;
213     if (strncmp(name, "svg", len) != 0)
214         *fParents.append() = element;
215     fCurrElement = element;
216     return result;
217 }
218 
onText(const char text[],int len)219 bool SkSVGParser::onText(const char text[], int len) {
220     if (fInSVG == false)
221         return false;
222     SkSVGTypes type = fCurrElement->getType();
223     if (type != SkSVGType_Text && type != SkSVGType_Tspan)
224         return false;
225     SkSVGText* textElement = (SkSVGText*) fCurrElement;
226     textElement->f_text.set(text, len);
227     return false;
228 }
229 
230 static int32_t strokeFillID = 0;
231 
translate(SkSVGElement * element,bool isDef)232 void SkSVGParser::translate(SkSVGElement* element, bool isDef) {
233     SkSVGPaint::Push(&fHead, &element->fPaintState);
234     bool isFlushable = element->isFlushable();
235     if ((element->fIsDef == false && element->fIsNotDef == false) ||
236         (element->fIsDef && isDef == false && element->fIsNotDef == false) ||
237         (element->fIsDef == false && isDef && element->fIsNotDef)) {
238         isFlushable = false;
239     }
240     SkSVGPaint* strokeState = NULL, * fillState = NULL;
241     if (isFlushable)
242         element->fPaintState.setSave(*this);
243     if (isFlushable && isStrokeAndFill(&strokeState, &fillState)) {
244         SkString& elementID = element->f_id;
245         if (elementID.size() == 0) {
246             elementID.set("sf");
247             elementID.appendS32(++strokeFillID);
248         }
249         SkString saveStroke(strokeState->f_stroke);
250         SkString saveFill(fillState->f_fill);
251         strokeState->f_stroke.set("none");
252         element->fPaintState.flush(*this, isFlushable, isDef);
253         element->translate(*this, isDef);
254         strokeState->f_stroke.set(saveStroke);
255         fillState->f_fill.set("none");
256         if (element->fPaintState.flush(*this, isFlushable, isDef)) {
257             _startElement("add");
258             _addAttributeLen("use", elementID.c_str(), elementID.size());
259             _endElement();  // add
260         }
261         fillState->f_fill.set(saveFill);
262     } else {
263         element->fPaintState.flush(*this, isFlushable, isDef);
264         if (isFlushable || element->isGroup())
265             element->translate(*this, isDef);
266     }
267     SkSVGPaint::Pop(&fHead);
268 }
269 
translateMatrix(SkString & string,SkString * stringID)270 void SkSVGParser::translateMatrix(SkString& string, SkString* stringID) {
271     if (string.size() == 0)
272         return;
273     if (stringID->size() > 0) {
274         _startElement("add");
275         _addAttribute("use", stringID->c_str());
276         _endElement(); // add
277         return;
278     }
279     SkASSERT(strncmp(string.c_str(), "matrix", 6) == 0);
280     ++gGeneratedMatrixID;
281     _startElement("matrix");
282     char idStr[24];
283     strcpy(idStr, "sk_matrix");
284     sprintf(idStr + strlen(idStr), "%d", gGeneratedMatrixID);
285     _addAttribute("id", idStr);
286     stringID->set(idStr);
287     const char* str = string.c_str();
288     SkASSERT(strncmp(str, "matrix(", 7) == 0);
289     str += 6;
290     const char* strEnd = strrchr(str, ')');
291     SkASSERT(strEnd != NULL);
292     SkString mat(str, strEnd - str);
293     ConvertToArray(mat);
294     const char* elems[6];
295     static const int order[] = {0, 3, 1, 4, 2, 5};
296     const int* orderPtr = order;
297     str = mat.c_str();
298     strEnd = str + mat.size();
299     while (str < strEnd) {
300         elems[*orderPtr++] = str;
301         while (str < strEnd && *str != ',' )
302             str++;
303         str++;
304     }
305     string.reset();
306     for (int index = 0; index < 6; index++) {
307         const char* end = strchr(elems[index], ',');
308         if (end == NULL)
309             end= strchr(elems[index], ']');
310         string.append(elems[index], end - elems[index] + 1);
311     }
312     string.remove(string.size() - 1, 1);
313     string.append(",0,0,1]");
314     _addAttribute("matrix", string);
315     _endElement();  // matrix
316 }
317 
is_whitespace(char ch)318 static bool is_whitespace(char ch) {
319     return ch > 0 && ch <= ' ';
320 }
321 
ConvertToArray(SkString & vals)322 void SkSVGParser::ConvertToArray(SkString& vals) {
323     vals.appendUnichar(']');
324     char* valCh = (char*) vals.c_str();
325     valCh[0] = '[';
326     int index = 1;
327     while (valCh[index] != ']') {
328         while (is_whitespace(valCh[index]))
329             index++;
330         bool foundComma = false;
331         char next;
332         do {
333             next = valCh[index++];
334             if (next == ',') {
335                 foundComma = true;
336                 continue;
337             }
338             if (next == ']') {
339                 index--;
340                 goto undoLastComma;
341             }
342             if (next == ' ')
343                 break;
344             foundComma = false;
345         } while (is_whitespace(next) == false);
346         if (foundComma == false)
347             valCh[index - 1] = ',';
348     }
349 undoLastComma:
350     while (is_whitespace(valCh[--index]))
351         ;
352     if (valCh[index] == ',')
353         valCh[index] = ' ';
354 }
355 
356 #define CASE_NEW(type) case SkSVGType_##type : created = new SkSVG##type(); break
357 
CreateElement(SkSVGTypes type,SkSVGElement * parent)358 SkSVGElement* SkSVGParser::CreateElement(SkSVGTypes type, SkSVGElement* parent) {
359     SkSVGElement* created = NULL;
360     switch (type) {
361         CASE_NEW(Circle);
362         CASE_NEW(ClipPath);
363         CASE_NEW(Defs);
364         CASE_NEW(Ellipse);
365         CASE_NEW(FeColorMatrix);
366         CASE_NEW(Filter);
367         CASE_NEW(G);
368         CASE_NEW(Image);
369         CASE_NEW(Line);
370         CASE_NEW(LinearGradient);
371         CASE_NEW(Mask);
372         CASE_NEW(Metadata);
373         CASE_NEW(Path);
374         CASE_NEW(Polygon);
375         CASE_NEW(Polyline);
376         CASE_NEW(RadialGradient);
377         CASE_NEW(Rect);
378         CASE_NEW(Stop);
379         CASE_NEW(SVG);
380         CASE_NEW(Symbol);
381         CASE_NEW(Text);
382         CASE_NEW(Tspan);
383         CASE_NEW(Use);
384         default:
385             SkASSERT(0);
386             return NULL;
387     }
388     created->fParent = parent;
389     bool isDef = created->fIsDef = created->isDef();
390     bool isNotDef = created->fIsNotDef = created->isNotDef();
391     if (isDef) {
392         SkSVGElement* up = parent;
393         while (up && up->fIsDef == false) {
394             up->fIsDef = true;
395             up = up->fParent;
396         }
397     }
398     if (isNotDef) {
399         SkSVGElement* up = parent;
400         while (up && up->fIsNotDef == false) {
401             up->fIsNotDef = true;
402             up = up->fParent;
403         }
404     }
405     return created;
406 }
407 
408 const SkSVGTypeName gSVGTypeNames[] = {
409     {"circle", SkSVGType_Circle},
410     {"clipPath", SkSVGType_ClipPath},
411     {"defs", SkSVGType_Defs},
412     {"ellipse", SkSVGType_Ellipse},
413     {"feColorMatrix", SkSVGType_FeColorMatrix},
414     {"filter", SkSVGType_Filter},
415     {"g", SkSVGType_G},
416     {"image", SkSVGType_Image},
417     {"line", SkSVGType_Line},
418     {"linearGradient", SkSVGType_LinearGradient},
419     {"mask", SkSVGType_Mask},
420     {"metadata", SkSVGType_Metadata},
421     {"path", SkSVGType_Path},
422     {"polygon", SkSVGType_Polygon},
423     {"polyline", SkSVGType_Polyline},
424     {"radialGradient", SkSVGType_RadialGradient},
425     {"rect", SkSVGType_Rect},
426     {"stop", SkSVGType_Stop},
427     {"svg", SkSVGType_SVG},
428     {"symbol", SkSVGType_Symbol},
429     {"text", SkSVGType_Text},
430     {"tspan", SkSVGType_Tspan},
431     {"use", SkSVGType_Use}
432 };
433 
434 const int kSVGTypeNamesSize = SK_ARRAY_COUNT(gSVGTypeNames);
435 
GetType(const char match[],size_t len)436 SkSVGTypes SkSVGParser::GetType(const char match[], size_t len ) {
437     int index = SkStrSearch(&gSVGTypeNames[0].fName, kSVGTypeNamesSize, match,
438         len, sizeof(gSVGTypeNames[0]));
439     return index >= 0 && index < kSVGTypeNamesSize ? gSVGTypeNames[index].fType :
440         (SkSVGTypes) -1;
441 }
442