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