|
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 |
|
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 |
|
57 SkSVGParser::~SkSVGParser() { |
|
58 } |
|
59 |
|
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 |
|
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 |
|
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 |
|
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 |
|
148 bool SkSVGParser::onAddAttribute(const char name[], const char value[]) { |
|
149 return onAddAttributeLen(name, value, strlen(value)); |
|
150 } |
|
151 |
|
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 |
|
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 |
|
187 bool SkSVGParser::onStartElement(const char name[]) { |
|
188 return onStartElementLen(name, strlen(name)); |
|
189 } |
|
190 |
|
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 |
|
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 |
|
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 |
|
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 |
|
318 static bool is_whitespace(char ch) { |
|
319 return ch > 0 && ch <= ' '; |
|
320 } |
|
321 |
|
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 |
|
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 |
|
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 } |