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