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 "SkSVGPaintState.h"
     11 #include "SkSVGElements.h"
     12 #include "SkSVGParser.h"
     13 #include "SkParse.h"
     14 
     15 SkSVGAttribute SkSVGPaint::gAttributes[] = {
     16     SVG_LITERAL_ATTRIBUTE(clip-path, f_clipPath),
     17     SVG_LITERAL_ATTRIBUTE(clip-rule, f_clipRule),
     18     SVG_LITERAL_ATTRIBUTE(enable-background, f_enableBackground),
     19     SVG_ATTRIBUTE(fill),
     20     SVG_LITERAL_ATTRIBUTE(fill-rule, f_fillRule),
     21     SVG_ATTRIBUTE(filter),
     22     SVG_LITERAL_ATTRIBUTE(font-family, f_fontFamily),
     23     SVG_LITERAL_ATTRIBUTE(font-size, f_fontSize),
     24     SVG_LITERAL_ATTRIBUTE(letter-spacing, f_letterSpacing),
     25     SVG_ATTRIBUTE(mask),
     26     SVG_ATTRIBUTE(opacity),
     27     SVG_LITERAL_ATTRIBUTE(stop-color, f_stopColor),
     28     SVG_LITERAL_ATTRIBUTE(stop-opacity, f_stopOpacity),
     29     SVG_ATTRIBUTE(stroke),
     30     SVG_LITERAL_ATTRIBUTE(stroke-dasharray, f_strokeDasharray),
     31     SVG_LITERAL_ATTRIBUTE(stroke-linecap, f_strokeLinecap),
     32     SVG_LITERAL_ATTRIBUTE(stroke-linejoin, f_strokeLinejoin),
     33     SVG_LITERAL_ATTRIBUTE(stroke-miterlimit, f_strokeMiterlimit),
     34     SVG_LITERAL_ATTRIBUTE(stroke-width, f_strokeWidth),
     35     SVG_ATTRIBUTE(style),
     36     SVG_ATTRIBUTE(transform)
     37 };
     38 
     39 const int SkSVGPaint::kAttributesSize = SK_ARRAY_COUNT(SkSVGPaint::gAttributes);
     40 
     41 SkSVGPaint::SkSVGPaint() : fNext(NULL) {
     42 }
     43 
     44 SkString* SkSVGPaint::operator[](int index) {
     45     SkASSERT(index >= 0);
     46     SkASSERT(index < &fTerminal - &fInitial);
     47     SkASSERT(&fTerminal - &fInitial == kTerminal - kInitial);
     48     SkString* result = &fInitial + index + 1;
     49     return result;
     50 }
     51 
     52 void SkSVGPaint::addAttribute(SkSVGParser& parser, int attrIndex,
     53         const char* attrValue, size_t attrLength) {
     54     SkString* attr = (*this)[attrIndex];
     55     switch(attrIndex) {
     56         case kClipPath:
     57         case kClipRule:
     58         case kEnableBackground:
     59         case kFill:
     60         case kFillRule:
     61         case kFilter:
     62         case kFontFamily:
     63         case kFontSize:
     64         case kLetterSpacing:
     65         case kMask:
     66         case kOpacity:
     67         case kStopColor:
     68         case kStopOpacity:
     69         case kStroke:
     70         case kStroke_Dasharray:
     71         case kStroke_Linecap:
     72         case kStroke_Linejoin:
     73         case kStroke_Miterlimit:
     74         case kStroke_Width:
     75         case kTransform:
     76             attr->set(attrValue, attrLength);
     77             return;
     78         case kStyle: {
     79             // iterate through colon / semi-colon delimited pairs
     80             int pairs = SkParse::Count(attrValue, ';');
     81             const char* attrEnd = attrValue + attrLength;
     82             do {
     83                 const char* end = strchr(attrValue, ';');
     84                 if (end == NULL)
     85                     end = attrEnd;
     86                 const char* delimiter = strchr(attrValue, ':');
     87                 SkASSERT(delimiter != 0 && delimiter < end);
     88                 int index = parser.findAttribute(this, attrValue, (int) (delimiter - attrValue), true);
     89                 SkASSERT(index >= 0);
     90                 delimiter++;
     91                 addAttribute(parser, index, delimiter, (int) (end - delimiter));
     92                 attrValue = end + 1;
     93             } while (--pairs);
     94             return;
     95             }
     96         default:
     97             SkASSERT(0);
     98     }
     99 }
    100 
    101 bool SkSVGPaint::flush(SkSVGParser& parser, bool isFlushable, bool isDef) {
    102     SkSVGPaint current;
    103     SkSVGPaint* walking = parser.fHead;
    104     int index;
    105     while (walking != NULL) {
    106         for (index = kInitial + 1; index < kTerminal; index++) {
    107             SkString* lastAttr = (*walking)[index];
    108             if (lastAttr->size() == 0)
    109                 continue;
    110             if (current[index]->size() > 0)
    111                 continue;
    112             current[index]->set(*lastAttr);
    113         }
    114         walking = walking->fNext;
    115     }
    116     bool paintChanged = false;
    117     SkSVGPaint& lastState = parser.fLastFlush;
    118     if (isFlushable == false) {
    119         if (isDef == true) {
    120             if (current.f_mask.size() > 0 && current.f_mask.equals(lastState.f_mask) == false) {
    121                 SkSVGElement* found;
    122                 const char* idStart = strchr(current.f_mask.c_str(), '#');
    123                 SkASSERT(idStart);
    124                 SkString id(idStart + 1, strlen(idStart) - 2);
    125                 bool itsFound = parser.fIDs.find(id.c_str(), &found);
    126                 SkASSERT(itsFound);
    127                 SkSVGElement* gradient = found->getGradient();
    128                 if (gradient) {
    129                     gradient->write(parser, current.f_fill);
    130                     gradient->write(parser, current.f_stroke);
    131                 }
    132             }
    133         }
    134         goto setLast;
    135     }
    136     {
    137         bool changed[kTerminal];
    138         memset(changed, 0, sizeof(changed));
    139         for (index = kInitial + 1; index < kTerminal; index++) {
    140             if (index == kTransform || index == kClipPath || index == kStopColor || index == kStopOpacity ||
    141                     index == kClipRule || index == kFillRule)
    142                 continue;
    143             SkString* lastAttr = lastState[index];
    144             SkString* currentAttr = current[index];
    145             paintChanged |= changed[index] = lastAttr->equals(*currentAttr) == false;
    146         }
    147         if (paintChanged) {
    148             if (current.f_mask.size() > 0) {
    149                 if (current.f_fill.equals("none") == false && strncmp(current.f_fill.c_str(), "url(#", 5) != 0) {
    150                     SkASSERT(current.f_fill.c_str()[0] == '#');
    151                     SkString replacement("url(#mask");
    152                     replacement.append(current.f_fill.c_str() + 1);
    153                     replacement.appendUnichar(')');
    154                     current.f_fill.set(replacement);
    155                 }
    156                 if (current.f_stroke.equals("none") == false && strncmp(current.f_stroke.c_str(), "url(#", 5) != 0) {
    157                     SkASSERT(current.f_stroke.c_str()[0] == '#');
    158                     SkString replacement("url(#mask");
    159                     replacement.append(current.f_stroke.c_str() + 1);
    160                     replacement.appendUnichar(')');
    161                     current.f_stroke.set(replacement);
    162                 }
    163             }
    164             if (current.f_fill.equals("none") && current.f_stroke.equals("none"))
    165                 current.f_opacity.set("0");
    166             if (parser.fSuppressPaint == false) {
    167                 parser._startElement("paint");
    168                 bool success = writeChangedAttributes(parser, current, changed);
    169                 if (success == false)
    170                     return paintChanged;
    171                 success = writeChangedElements(parser, current, changed);
    172                 if (success == false)
    173                     return paintChanged;
    174                 parser._endElement(); // paint
    175             }
    176         }
    177     }
    178 setLast:
    179     for (index = kInitial + 1; index < kTerminal; index++) {
    180         SkString* lastAttr = lastState[index];
    181         SkString* currentAttr = current[index];
    182         lastAttr->set(*currentAttr);
    183     }
    184     return paintChanged;
    185 }
    186 
    187 int SkSVGPaint::getAttributes(const SkSVGAttribute** attrPtr) {
    188     *attrPtr = gAttributes;
    189     return kAttributesSize;
    190 }
    191 
    192 void SkSVGPaint::setSave(SkSVGParser& parser) {
    193     SkTDArray<SkString*> clips;
    194     SkSVGPaint* walking = parser.fHead;
    195     int index;
    196     SkMatrix sum;
    197     sum.reset();
    198     while (walking != NULL) {
    199         for (index = kInitial + 1; index < kTerminal; index++) {
    200             SkString* lastAttr = (*walking)[index];
    201             if (lastAttr->size() == 0)
    202                 continue;
    203             if (index == kTransform) {
    204                 const char* str = lastAttr->c_str();
    205                 SkASSERT(strncmp(str, "matrix(", 7) == 0);
    206                 str += 6;
    207                 const char* strEnd = strrchr(str, ')');
    208                 SkASSERT(strEnd != NULL);
    209                 SkString mat(str, strEnd - str);
    210                 SkSVGParser::ConvertToArray(mat);
    211                 SkScalar values[6];
    212                 SkParse::FindScalars(mat.c_str() + 1, values, 6);
    213                 SkMatrix matrix;
    214                 matrix.reset();
    215                 matrix.setScaleX(values[0]);
    216                 matrix.setSkewY(values[1]);
    217                 matrix.setSkewX(values[2]);
    218                 matrix.setScaleY(values[3]);
    219                 matrix.setTranslateX(values[4]);
    220                 matrix.setTranslateY(values[5]);
    221                 sum.setConcat(matrix, sum);
    222                 continue;
    223             }
    224             if ( index == kClipPath)
    225                 *clips.insert(0) = lastAttr;
    226         }
    227         walking = walking->fNext;
    228     }
    229     if ((sum == parser.fLastTransform) == false) {
    230         SkMatrix inverse;
    231         bool success = parser.fLastTransform.invert(&inverse);
    232         SkASSERT(success == true);
    233         SkMatrix output;
    234         output.setConcat(inverse, sum);
    235         parser.fLastTransform = sum;
    236         SkString outputStr;
    237         outputStr.appendUnichar('[');
    238         outputStr.appendScalar(output.getScaleX());
    239         outputStr.appendUnichar(',');
    240         outputStr.appendScalar(output.getSkewX());
    241         outputStr.appendUnichar(',');
    242         outputStr.appendScalar(output.getTranslateX());
    243         outputStr.appendUnichar(',');
    244         outputStr.appendScalar(output.getSkewY());
    245         outputStr.appendUnichar(',');
    246         outputStr.appendScalar(output.getScaleY());
    247         outputStr.appendUnichar(',');
    248         outputStr.appendScalar(output.getTranslateY());
    249         outputStr.appendUnichar(',');
    250         outputStr.appendScalar(output.getPerspX());
    251         outputStr.appendUnichar(',');
    252         outputStr.appendScalar(output.getPerspY());
    253         outputStr.append(",1]");
    254         parser._startElement("matrix");
    255         parser._addAttributeLen("matrix", outputStr.c_str(), outputStr.size());
    256         parser._endElement();
    257     }
    258 #if 0   // incomplete
    259     if (parser.fTransformClips.size() > 0) {
    260         // need to reset the clip when the 'g' scope is ended
    261         parser._startElement("add");
    262         const char* start = strchr(current->f_clipPath.c_str(), '#') + 1;
    263         SkASSERT(start);
    264         parser._addAttributeLen("use", start, strlen(start) - 1);
    265         parser._endElement();   // clip
    266     }
    267 #endif
    268 }
    269 
    270 bool SkSVGPaint::writeChangedAttributes(SkSVGParser& parser,
    271         SkSVGPaint& current, bool* changed) {
    272     SkSVGPaint& lastState = parser.fLastFlush;
    273     for (int index = kInitial + 1; index < kTerminal; index++) {
    274         if (changed[index] == false)
    275                 continue;
    276         SkString* topAttr = current[index];
    277         size_t attrLength = topAttr->size();
    278         if (attrLength == 0)
    279             continue;
    280         const char* attrValue = topAttr->c_str();
    281         SkString* lastAttr = lastState[index];
    282         switch(index) {
    283             case kClipPath:
    284             case kClipRule:
    285             case kEnableBackground:
    286                 break;
    287             case kFill:
    288                 if (topAttr->equals("none") == false && lastAttr->equals("none") == true)
    289                     parser._addAttribute("stroke", "false");
    290                 goto fillStrokeAttrCommon;
    291             case kFillRule:
    292             case kFilter:
    293             case kFontFamily:
    294                 break;
    295             case kFontSize:
    296                 parser._addAttributeLen("textSize", attrValue, attrLength);
    297                 break;
    298             case kLetterSpacing:
    299                 parser._addAttributeLen("textTracking", attrValue, attrLength);
    300                 break;
    301             case kMask:
    302                 break;
    303             case kOpacity:
    304                 break;
    305             case kStopColor:
    306                 break;
    307             case kStopOpacity:
    308                 break;
    309             case kStroke:
    310                 if (topAttr->equals("none") == false && lastAttr->equals("none") == true)
    311                     parser._addAttribute("stroke", "true");
    312 fillStrokeAttrCommon:
    313                 if (strncmp(attrValue, "url(", 4) == 0) {
    314                     SkASSERT(attrValue[4] == '#');
    315                     const char* idStart = attrValue + 5;
    316                     const char* idEnd = strrchr(attrValue, ')');
    317                     SkASSERT(idStart < idEnd);
    318                     SkString id(idStart, idEnd - idStart);
    319                     SkSVGElement* found;
    320                     if (strncmp(id.c_str(), "mask", 4) != 0) {
    321                         bool itsFound = parser.fIDs.find(id.c_str(), &found);
    322                         SkASSERT(itsFound);
    323                         SkASSERT(found->getType() == SkSVGType_LinearGradient ||
    324                             found->getType() == SkSVGType_RadialGradient);
    325                     }
    326                     parser._addAttribute("shader", id.c_str());
    327                 }
    328                 break;
    329             case kStroke_Dasharray:
    330                 break;
    331             case kStroke_Linecap:
    332                 parser._addAttributeLen("strokeCap", attrValue, attrLength);
    333                 break;
    334             case kStroke_Linejoin:
    335                 parser._addAttributeLen("strokeJoin", attrValue, attrLength);
    336                 break;
    337             case kStroke_Miterlimit:
    338                 parser._addAttributeLen("strokeMiter", attrValue, attrLength);
    339                 break;
    340             case kStroke_Width:
    341                 parser._addAttributeLen("strokeWidth", attrValue, attrLength);
    342             case kStyle:
    343             case kTransform:
    344                 break;
    345         default:
    346             SkASSERT(0);
    347             return false;
    348         }
    349     }
    350     return true;
    351 }
    352 
    353 bool SkSVGPaint::writeChangedElements(SkSVGParser& parser,
    354         SkSVGPaint& current, bool* changed) {
    355     SkSVGPaint& lastState = parser.fLastFlush;
    356     for (int index = kInitial + 1; index < kTerminal; index++) {
    357         SkString* topAttr = current[index];
    358         size_t attrLength = topAttr->size();
    359         if (attrLength == 0)
    360             continue;
    361         const char* attrValue = topAttr->c_str();
    362         SkString* lastAttr = lastState[index];
    363         switch(index) {
    364             case kClipPath:
    365             case kClipRule:
    366                 // !!! need to add this outside of paint
    367                 break;
    368             case kEnableBackground:
    369                 // !!! don't know what to do with this
    370                 break;
    371             case kFill:
    372                 goto addColor;
    373             case kFillRule:
    374             case kFilter:
    375                 break;
    376             case kFontFamily:
    377                 parser._startElement("typeface");
    378                 parser._addAttributeLen("fontName", attrValue, attrLength);
    379                 parser._endElement();   // typeface
    380                 break;
    381             case kFontSize:
    382             case kLetterSpacing:
    383                 break;
    384             case kMask:
    385             case kOpacity:
    386                 if (changed[kStroke] == false && changed[kFill] == false) {
    387                     parser._startElement("color");
    388                     SkString& opacity = current.f_opacity;
    389                     parser._addAttributeLen("color", parser.fLastColor.c_str(), parser.fLastColor.size());
    390                     parser._addAttributeLen("alpha", opacity.c_str(), opacity.size());
    391                     parser._endElement();   // color
    392                 }
    393                 break;
    394             case kStopColor:
    395                 break;
    396             case kStopOpacity:
    397                 break;
    398             case kStroke:
    399 addColor:
    400                 if (strncmp(lastAttr->c_str(), "url(", 4) == 0 && strncmp(attrValue, "url(", 4) != 0) {
    401                     parser._startElement("shader");
    402                     parser._endElement();
    403                 }
    404                 if (topAttr->equals(*lastAttr))
    405                     continue;
    406                 {
    407                     bool urlRef = strncmp(attrValue, "url(", 4) == 0;
    408                     bool colorNone = strcmp(attrValue, "none") == 0;
    409                     bool lastEqual = parser.fLastColor.equals(attrValue, attrLength);
    410                     bool newColor = urlRef == false && colorNone == false && lastEqual == false;
    411                     if (newColor || changed[kOpacity]) {
    412                         parser._startElement("color");
    413                         if (newColor || changed[kOpacity]) {
    414                             parser._addAttributeLen("color", attrValue, attrLength);
    415                             parser.fLastColor.set(attrValue, attrLength);
    416                         }
    417                         if (changed[kOpacity]) {
    418                             SkString& opacity = current.f_opacity;
    419                             parser._addAttributeLen("alpha", opacity.c_str(), opacity.size());
    420                         }
    421                         parser._endElement();   // color
    422                     }
    423                 }
    424                 break;
    425             case kStroke_Dasharray:
    426                 parser._startElement("dash");
    427                 SkSVGParser::ConvertToArray(*topAttr);
    428                 parser._addAttribute("intervals", topAttr->c_str());
    429                 parser._endElement();   // dash
    430             break;
    431             case kStroke_Linecap:
    432             case kStroke_Linejoin:
    433             case kStroke_Miterlimit:
    434             case kStroke_Width:
    435             case kStyle:
    436             case kTransform:
    437                 break;
    438         default:
    439             SkASSERT(0);
    440             return false;
    441         }
    442     }
    443     return true;
    444 }
    445 
    446 void SkSVGPaint::Push(SkSVGPaint** head, SkSVGPaint* newRecord) {
    447     newRecord->fNext = *head;
    448     *head = newRecord;
    449 }
    450 
    451 void SkSVGPaint::Pop(SkSVGPaint** head) {
    452     SkSVGPaint* next = (*head)->fNext;
    453     *head = next;
    454 }
    455