OLD | NEW |
| (Empty) |
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; in
dex++) { | |
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(Sk
String)); | |
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** fillS
tate) { | |
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, tru
e); | |
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(); brea
k | |
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 } | |
OLD | NEW |