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(SkXMLParserError* errHandler) :
47	SkXMLParser(errHandler),
48	fHead(&fEmptyPaint), fIDs(256),
49        fXMLWriter(&fStream), fCurrElement(NULL), fInSVG(false), fSuppressPaint(false) {
50    fLastTransform.reset();
51    fEmptyPaint.f_fill.set("black");
52    fEmptyPaint.f_stroke.set("none");
53    fEmptyPaint.f_strokeMiterlimit.set("4");
54    fEmptyPaint.f_fillRule.set("winding");
55    fEmptyPaint.f_opacity.set("1");
56    fEmptyPaint.fNext = NULL;
57    for (int index = SkSVGPaint::kInitial + 1; index < SkSVGPaint::kTerminal; index++) {
58        SkString* initial = fEmptyPaint[index];
59        if (initial->size() == 0)
60            continue;
61        fLastFlush[index]->set(*initial);
62    }
63}
64
65SkSVGParser::~SkSVGParser() {
66}
67
68void SkSVGParser::Delete(SkTDArray<SkSVGElement*>& fChildren) {
69    SkSVGElement** ptr;
70    for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
71        Delete((*ptr)->fChildren);
72        delete *ptr;
73    }
74}
75
76int SkSVGParser::findAttribute(SkSVGBase* element, const char* attrValue,
77        size_t len, bool isPaint) {
78    const SkSVGAttribute* attributes;
79    size_t count = element->getAttributes(&attributes);
80    size_t result = 0;
81    while (result < count) {
82        if (strncmp(attributes->fName, attrValue, len) == 0 && strlen(attributes->fName) == len) {
83            SkASSERT(result == (attributes->fOffset -
84                (isPaint ? sizeof(SkString) : sizeof(SkSVGElement))) / sizeof(SkString));
85            return result;
86        }
87        attributes++;
88        result++;
89    }
90    return -1;
91}
92
93const char* SkSVGParser::getFinal() {
94    _startElement("screenplay");
95    // generate defs
96    SkSVGElement** ptr;
97    for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
98        SkSVGElement* element = *ptr;
99        translate(element, true);
100    }
101    // generate onLoad
102    _startElement("event");
103    _addAttribute("kind", "onLoad");
104    _startElement("paint");
105    _addAttribute("antiAlias", "true");
106    _endElement();
107    for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
108        SkSVGElement* element = *ptr;
109        translate(element, false);
110    }
111    _endElement(); // event
112    _endElement(); // screenplay
113    Delete(fChildren);
114    fStream.write("", 1);
115    return fStream.getStream();
116}
117
118SkString& SkSVGParser::getPaintLast(SkSVGPaint::Field field) {
119    SkSVGPaint* state = fHead;
120    do {
121        SkString* attr = (*state)[field];
122        SkASSERT(attr);
123        if (attr->size() > 0)
124            return *attr;
125        state = state->fNext;
126    } while (state);
127    SkASSERT(0);
128    SkASSERT(fEmptyPaint[field]);
129    return *fEmptyPaint[field];
130}
131
132bool SkSVGParser::isStrokeAndFill(  SkSVGPaint** strokeState, SkSVGPaint** fillState) {
133    SkSVGPaint* walking = fHead;
134    bool stroke = false;
135    bool fill = false;
136    bool strokeSet = false;
137    bool fillSet = false;
138    while (walking != NULL) {
139        if (strokeSet == false && walking->f_stroke.size() > 0) {
140            stroke = walking->f_stroke.equals("none") == false;
141            *strokeState = walking;
142            strokeSet = true;
143        }
144        if (fillSet == false && walking->f_fill.size() > 0) {
145            fill = walking->f_fill.equals("none") == false;
146            *fillState = walking;
147            fillSet = true;
148        }
149        walking = walking->fNext;
150    }
151    return stroke && fill;
152}
153
154bool SkSVGParser::onAddAttribute(const char name[], const char value[]) {
155    return onAddAttributeLen(name, value, strlen(value));
156}
157
158bool SkSVGParser::onAddAttributeLen(const char name[], const char value[], size_t len) {
159    if (fCurrElement == NULL)    // this signals we should ignore attributes for this element
160        return true;
161    if (fCurrElement->fIsDef == false && fCurrElement->fIsNotDef == false)
162        return false; // also an ignored element
163    size_t nameLen = strlen(name);
164    int attrIndex = findAttribute(fCurrElement, name, nameLen, false);
165    if (attrIndex == -1) {
166        attrIndex = findAttribute(&fCurrElement->fPaintState, name, nameLen, true);
167        if (attrIndex >= 0) {
168            fCurrElement->fPaintState.addAttribute(*this, attrIndex, value, len);
169            return false;
170        }
171        if (nameLen == 2 && strncmp("id", name, nameLen) == 0) {
172            fCurrElement->f_id.set(value, len);
173            return false;
174        }
175        if (strchr(name, ':') != 0) // part of a different namespace
176            return false;
177    }
178    SkASSERT(attrIndex >= 0);
179    fCurrElement->addAttribute(*this, attrIndex, value, len);
180    return false;
181}
182
183bool SkSVGParser::onEndElement(const char elem[]) {
184    int parentIndex = fParents.count() - 1;
185    if (parentIndex >= 0) {
186        SkSVGElement* element = fParents[parentIndex];
187        element->onEndElement(*this);
188        fParents.remove(parentIndex);
189    }
190    return false;
191}
192
193bool SkSVGParser::onStartElement(const char name[]) {
194    return onStartElementLen(name, strlen(name));
195}
196
197bool SkSVGParser::onStartElementLen(const char name[], size_t len) {
198    if (strncmp(name, "svg", len) == 0) {
199        fInSVG = true;
200    } else if (fInSVG == false)
201        return false;
202    const char* nextColon = strchr(name, ':');
203    if (nextColon && (size_t)(nextColon - name) < len)
204        return false;
205    SkSVGTypes type = GetType(name, len);
206//    SkASSERT(type >= 0);
207    if (type < 0) {
208		type = SkSVGType_G;
209//        return true;
210	}
211    SkSVGElement* parent = fParents.count() > 0 ? fParents.top() : NULL;
212    SkSVGElement* element = CreateElement(type, parent);
213    bool result = false;
214    if (parent) {
215        element->fParent = parent;
216        result = fParents.top()->onStartElement(element);
217    } else
218        *fChildren.append() = element;
219    if (strncmp(name, "svg", len) != 0)
220        *fParents.append() = element;
221    fCurrElement = element;
222    return result;
223}
224
225bool SkSVGParser::onText(const char text[], int len) {
226    if (fInSVG == false)
227        return false;
228    SkSVGTypes type = fCurrElement->getType();
229    if (type != SkSVGType_Text && type != SkSVGType_Tspan)
230        return false;
231    SkSVGText* textElement = (SkSVGText*) fCurrElement;
232    textElement->f_text.set(text, len);
233    return false;
234}
235
236static int32_t strokeFillID = 0;
237
238void SkSVGParser::translate(SkSVGElement* element, bool isDef) {
239    SkSVGPaint::Push(&fHead, &element->fPaintState);
240    bool isFlushable = element->isFlushable();
241    if ((element->fIsDef == false && element->fIsNotDef == false) ||
242        (element->fIsDef && isDef == false && element->fIsNotDef == false) ||
243        (element->fIsDef == false && isDef && element->fIsNotDef)) {
244        isFlushable = false;
245    }
246    SkSVGPaint* strokeState = NULL, * fillState = NULL;
247    if (isFlushable)
248        element->fPaintState.setSave(*this);
249    if (isFlushable && isStrokeAndFill(&strokeState, &fillState)) {
250        SkString& elementID = element->f_id;
251        if (elementID.size() == 0) {
252            elementID.set("sf");
253            elementID.appendS32(++strokeFillID);
254        }
255        SkString saveStroke(strokeState->f_stroke);
256        SkString saveFill(fillState->f_fill);
257        strokeState->f_stroke.set("none");
258        element->fPaintState.flush(*this, isFlushable, isDef);
259        element->translate(*this, isDef);
260        strokeState->f_stroke.set(saveStroke);
261        fillState->f_fill.set("none");
262        if (element->fPaintState.flush(*this, isFlushable, isDef)) {
263            _startElement("add");
264            _addAttributeLen("use", elementID.c_str(), elementID.size());
265            _endElement();  // add
266        }
267        fillState->f_fill.set(saveFill);
268    } else {
269        element->fPaintState.flush(*this, isFlushable, isDef);
270        if (isFlushable || element->isGroup())
271            element->translate(*this, isDef);
272    }
273    SkSVGPaint::Pop(&fHead);
274}
275
276void SkSVGParser::translateMatrix(SkString& string, SkString* stringID) {
277    if (string.size() == 0)
278        return;
279    if (stringID->size() > 0) {
280        _startElement("add");
281        _addAttribute("use", stringID->c_str());
282        _endElement(); // add
283        return;
284    }
285    SkASSERT(strncmp(string.c_str(), "matrix", 6) == 0);
286    ++gGeneratedMatrixID;
287    _startElement("matrix");
288    char idStr[24];
289    strcpy(idStr, "sk_matrix");
290    sprintf(idStr + strlen(idStr), "%d", gGeneratedMatrixID);
291    _addAttribute("id", idStr);
292    stringID->set(idStr);
293    const char* str = string.c_str();
294    SkASSERT(strncmp(str, "matrix(", 7) == 0);
295    str += 6;
296    const char* strEnd = strrchr(str, ')');
297    SkASSERT(strEnd != NULL);
298    SkString mat(str, strEnd - str);
299    ConvertToArray(mat);
300    const char* elems[6];
301    static const int order[] = {0, 3, 1, 4, 2, 5};
302    const int* orderPtr = order;
303    str = mat.c_str();
304    strEnd = str + mat.size();
305    while (str < strEnd) {
306        elems[*orderPtr++] = str;
307        while (str < strEnd && *str != ',' )
308            str++;
309        str++;
310    }
311    string.reset();
312    for (int index = 0; index < 6; index++) {
313        const char* end = strchr(elems[index], ',');
314        if (end == NULL)
315            end= strchr(elems[index], ']');
316        string.append(elems[index], end - elems[index] + 1);
317    }
318    string.remove(string.size() - 1, 1);
319    string.append(",0,0,1]");
320    _addAttribute("matrix", string);
321    _endElement();  // matrix
322}
323
324static bool is_whitespace(char ch) {
325    return ch > 0 && ch <= ' ';
326}
327
328void SkSVGParser::ConvertToArray(SkString& vals) {
329    vals.appendUnichar(']');
330    char* valCh = (char*) vals.c_str();
331    valCh[0] = '[';
332    int index = 1;
333    while (valCh[index] != ']') {
334        while (is_whitespace(valCh[index]))
335            index++;
336        bool foundComma = false;
337        char next;
338        do {
339            next = valCh[index++];
340            if (next == ',') {
341                foundComma = true;
342                continue;
343            }
344            if (next == ']') {
345                index--;
346                goto undoLastComma;
347            }
348            if (next == ' ')
349                break;
350            foundComma = false;
351        } while (is_whitespace(next) == false);
352        if (foundComma == false)
353            valCh[index - 1] = ',';
354    }
355undoLastComma:
356    while (is_whitespace(valCh[--index]))
357        ;
358    if (valCh[index] == ',')
359        valCh[index] = ' ';
360}
361
362#define CASE_NEW(type) case SkSVGType_##type : created = new SkSVG##type(); break
363
364SkSVGElement* SkSVGParser::CreateElement(SkSVGTypes type, SkSVGElement* parent) {
365    SkSVGElement* created = NULL;
366    switch (type) {
367        CASE_NEW(Circle);
368        CASE_NEW(ClipPath);
369        CASE_NEW(Defs);
370        CASE_NEW(Ellipse);
371        CASE_NEW(FeColorMatrix);
372        CASE_NEW(Filter);
373        CASE_NEW(G);
374        CASE_NEW(Image);
375        CASE_NEW(Line);
376        CASE_NEW(LinearGradient);
377        CASE_NEW(Mask);
378        CASE_NEW(Metadata);
379        CASE_NEW(Path);
380        CASE_NEW(Polygon);
381        CASE_NEW(Polyline);
382        CASE_NEW(RadialGradient);
383        CASE_NEW(Rect);
384        CASE_NEW(Stop);
385        CASE_NEW(SVG);
386        CASE_NEW(Symbol);
387        CASE_NEW(Text);
388        CASE_NEW(Tspan);
389        CASE_NEW(Use);
390        default:
391            SkASSERT(0);
392            return NULL;
393    }
394    created->fParent = parent;
395    bool isDef = created->fIsDef = created->isDef();
396    bool isNotDef = created->fIsNotDef = created->isNotDef();
397    if (isDef) {
398        SkSVGElement* up = parent;
399        while (up && up->fIsDef == false) {
400            up->fIsDef = true;
401            up = up->fParent;
402        }
403    }
404    if (isNotDef) {
405        SkSVGElement* up = parent;
406        while (up && up->fIsNotDef == false) {
407            up->fIsNotDef = true;
408            up = up->fParent;
409        }
410    }
411    return created;
412}
413
414const SkSVGTypeName gSVGTypeNames[] = {
415    {"circle", SkSVGType_Circle},
416    {"clipPath", SkSVGType_ClipPath},
417    {"defs", SkSVGType_Defs},
418    {"ellipse", SkSVGType_Ellipse},
419    {"feColorMatrix", SkSVGType_FeColorMatrix},
420    {"filter", SkSVGType_Filter},
421    {"g", SkSVGType_G},
422    {"image", SkSVGType_Image},
423    {"line", SkSVGType_Line},
424    {"linearGradient", SkSVGType_LinearGradient},
425    {"mask", SkSVGType_Mask},
426    {"metadata", SkSVGType_Metadata},
427    {"path", SkSVGType_Path},
428    {"polygon", SkSVGType_Polygon},
429    {"polyline", SkSVGType_Polyline},
430    {"radialGradient", SkSVGType_RadialGradient},
431    {"rect", SkSVGType_Rect},
432    {"stop", SkSVGType_Stop},
433    {"svg", SkSVGType_SVG},
434    {"symbol", SkSVGType_Symbol},
435    {"text", SkSVGType_Text},
436    {"tspan", SkSVGType_Tspan},
437    {"use", SkSVGType_Use}
438};
439
440const int kSVGTypeNamesSize = SK_ARRAY_COUNT(gSVGTypeNames);
441
442SkSVGTypes SkSVGParser::GetType(const char match[], size_t len ) {
443    int index = SkStrSearch(&gSVGTypeNames[0].fName, kSVGTypeNamesSize, match,
444        len, sizeof(gSVGTypeNames[0]));
445    return index >= 0 && index < kSVGTypeNamesSize ? gSVGTypeNames[index].fType :
446        (SkSVGTypes) -1;
447}
448