OLD | NEW |
| (Empty) |
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 | |
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; in
dex++) { | |
56 SkString* initial = fEmptyPaint[index]; | |
57 if (initial->size() == 0) | |
58 continue; | |
59 fLastFlush[index]->set(*initial); | |
60 } | |
61 } | |
62 | |
63 SkSVGParser::~SkSVGParser() { | |
64 } | |
65 | |
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 | |
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(Sk
String)); | |
83 return result; | |
84 } | |
85 attributes++; | |
86 result++; | |
87 } | |
88 return -1; | |
89 } | |
90 | |
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 | |
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 | |
130 bool SkSVGParser::isStrokeAndFill( SkSVGPaint** strokeState, SkSVGPaint** fillS
tate) { | |
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 | |
152 bool SkSVGParser::onAddAttribute(const char name[], const char value[]) { | |
153 return onAddAttributeLen(name, value, strlen(value)); | |
154 } | |
155 | |
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, tru
e); | |
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 | |
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 | |
191 bool SkSVGParser::onStartElement(const char name[]) { | |
192 return onStartElementLen(name, strlen(name)); | |
193 } | |
194 | |
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 | |
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 | |
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 | |
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 | |
320 static bool is_whitespace(char ch) { | |
321 return ch > 0 && ch <= ' '; | |
322 } | |
323 | |
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(); brea
k | |
359 | |
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 | |
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 } | |
OLD | NEW |