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
36static int gGeneratedMatrixID = 0;
37
38SkSVGParser::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
57SkSVGParser::~SkSVGParser() {
58}
59
60void 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
68int 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
86const 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
112SkString& 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
126bool 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
148bool SkSVGParser::onAddAttribute(const char name[], const char value[]) {
149    return onAddAttributeLen(name, value, strlen(value));
150}
151
152bool 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
177bool 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
187bool SkSVGParser::onStartElement(const char name[]) {
188    return onStartElementLen(name, strlen(name));
189}
190
191bool 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
219bool 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
230static int32_t strokeFillID = 0;
231
232void 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
270void 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
318static bool is_whitespace(char ch) {
319    return ch > 0 && ch <= ' ';
320}
321
322void 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    }
349undoLastComma:
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
358SkSVGElement* 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
408const 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
434const int kSVGTypeNamesSize = SK_ARRAY_COUNT(gSVGTypeNames);
435
436SkSVGTypes 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}
442