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