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
44static int gGeneratedMatrixID = 0;
45
46SkSVGParser::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
63SkSVGParser::~SkSVGParser() {
64}
65
66void 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
74int 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
91const 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
116SkString& 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
130bool 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
152bool SkSVGParser::onAddAttribute(const char name[], const char value[]) {
153    return onAddAttributeLen(name, value, strlen(value));
154}
155
156bool 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
181bool 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
191bool SkSVGParser::onStartElement(const char name[]) {
192    return onStartElementLen(name, strlen(name));
193}
194
195bool 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
221bool 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
232static int32_t strokeFillID = 0;
233
234void 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
272void 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
320static bool is_whitespace(char ch) {
321    return ch > 0 && ch <= ' ';
322}
323
324void 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    }
351undoLastComma:
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
360SkSVGElement* 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
410const 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
436const int kSVGTypeNamesSize = SK_ARRAY_COUNT(gSVGTypeNames);
437
438SkSVGTypes 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