Home | History | Annotate | Download | only in svg
      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(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 
     65 SkSVGParser::~SkSVGParser() {
     66 }
     67 
     68 void 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 
     76 int 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 
     93 const 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 
    118 SkString& 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 
    132 bool 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 
    154 bool SkSVGParser::onAddAttribute(const char name[], const char value[]) {
    155     return onAddAttributeLen(name, value, strlen(value));
    156 }
    157 
    158 bool 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 
    183 bool 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 
    193 bool SkSVGParser::onStartElement(const char name[]) {
    194     return onStartElementLen(name, strlen(name));
    195 }
    196 
    197 bool 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 
    225 bool 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 
    236 static int32_t strokeFillID = 0;
    237 
    238 void 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 
    276 void 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 
    324 static bool is_whitespace(char ch) {
    325     return ch > 0 && ch <= ' ';
    326 }
    327 
    328 void 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     }
    355 undoLastComma:
    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 
    364 SkSVGElement* 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 
    414 const 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 
    440 const int kSVGTypeNamesSize = SK_ARRAY_COUNT(gSVGTypeNames);
    441 
    442 SkSVGTypes 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