Home | History | Annotate | Download | only in svg
      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; index++) {
     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(SkString));
     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** 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 
    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, 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 
    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(); break
    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 }
    442