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