gfx/skia/trunk/src/svg/SkSVGPaintState.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/svg/SkSVGPaintState.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,454 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2006 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "SkSVGPaintState.h"
    1.14 +#include "SkSVGElements.h"
    1.15 +#include "SkSVGParser.h"
    1.16 +#include "SkParse.h"
    1.17 +
    1.18 +SkSVGAttribute SkSVGPaint::gAttributes[] = {
    1.19 +    SVG_LITERAL_ATTRIBUTE(clip-path, f_clipPath),
    1.20 +    SVG_LITERAL_ATTRIBUTE(clip-rule, f_clipRule),
    1.21 +    SVG_LITERAL_ATTRIBUTE(enable-background, f_enableBackground),
    1.22 +    SVG_ATTRIBUTE(fill),
    1.23 +    SVG_LITERAL_ATTRIBUTE(fill-rule, f_fillRule),
    1.24 +    SVG_ATTRIBUTE(filter),
    1.25 +    SVG_LITERAL_ATTRIBUTE(font-family, f_fontFamily),
    1.26 +    SVG_LITERAL_ATTRIBUTE(font-size, f_fontSize),
    1.27 +    SVG_LITERAL_ATTRIBUTE(letter-spacing, f_letterSpacing),
    1.28 +    SVG_ATTRIBUTE(mask),
    1.29 +    SVG_ATTRIBUTE(opacity),
    1.30 +    SVG_LITERAL_ATTRIBUTE(stop-color, f_stopColor),
    1.31 +    SVG_LITERAL_ATTRIBUTE(stop-opacity, f_stopOpacity),
    1.32 +    SVG_ATTRIBUTE(stroke),
    1.33 +    SVG_LITERAL_ATTRIBUTE(stroke-dasharray, f_strokeDasharray),
    1.34 +    SVG_LITERAL_ATTRIBUTE(stroke-linecap, f_strokeLinecap),
    1.35 +    SVG_LITERAL_ATTRIBUTE(stroke-linejoin, f_strokeLinejoin),
    1.36 +    SVG_LITERAL_ATTRIBUTE(stroke-miterlimit, f_strokeMiterlimit),
    1.37 +    SVG_LITERAL_ATTRIBUTE(stroke-width, f_strokeWidth),
    1.38 +    SVG_ATTRIBUTE(style),
    1.39 +    SVG_ATTRIBUTE(transform)
    1.40 +};
    1.41 +
    1.42 +const int SkSVGPaint::kAttributesSize = SK_ARRAY_COUNT(SkSVGPaint::gAttributes);
    1.43 +
    1.44 +SkSVGPaint::SkSVGPaint() : fNext(NULL) {
    1.45 +}
    1.46 +
    1.47 +SkString* SkSVGPaint::operator[](int index) {
    1.48 +    SkASSERT(index >= 0);
    1.49 +    SkASSERT(index < &fTerminal - &fInitial);
    1.50 +    SkASSERT(&fTerminal - &fInitial == kTerminal - kInitial);
    1.51 +    SkString* result = &fInitial + index + 1;
    1.52 +    return result;
    1.53 +}
    1.54 +
    1.55 +void SkSVGPaint::addAttribute(SkSVGParser& parser, int attrIndex,
    1.56 +        const char* attrValue, size_t attrLength) {
    1.57 +    SkString* attr = (*this)[attrIndex];
    1.58 +    switch(attrIndex) {
    1.59 +        case kClipPath:
    1.60 +        case kClipRule:
    1.61 +        case kEnableBackground:
    1.62 +        case kFill:
    1.63 +        case kFillRule:
    1.64 +        case kFilter:
    1.65 +        case kFontFamily:
    1.66 +        case kFontSize:
    1.67 +        case kLetterSpacing:
    1.68 +        case kMask:
    1.69 +        case kOpacity:
    1.70 +        case kStopColor:
    1.71 +        case kStopOpacity:
    1.72 +        case kStroke:
    1.73 +        case kStroke_Dasharray:
    1.74 +        case kStroke_Linecap:
    1.75 +        case kStroke_Linejoin:
    1.76 +        case kStroke_Miterlimit:
    1.77 +        case kStroke_Width:
    1.78 +        case kTransform:
    1.79 +            attr->set(attrValue, attrLength);
    1.80 +            return;
    1.81 +        case kStyle: {
    1.82 +            // iterate through colon / semi-colon delimited pairs
    1.83 +            int pairs = SkParse::Count(attrValue, ';');
    1.84 +            const char* attrEnd = attrValue + attrLength;
    1.85 +            do {
    1.86 +                const char* end = strchr(attrValue, ';');
    1.87 +                if (end == NULL)
    1.88 +                    end = attrEnd;
    1.89 +                const char* delimiter = strchr(attrValue, ':');
    1.90 +                SkASSERT(delimiter != 0 && delimiter < end);
    1.91 +                int index = parser.findAttribute(this, attrValue, (int) (delimiter - attrValue), true);
    1.92 +                SkASSERT(index >= 0);
    1.93 +                delimiter++;
    1.94 +                addAttribute(parser, index, delimiter, (int) (end - delimiter));
    1.95 +                attrValue = end + 1;
    1.96 +            } while (--pairs);
    1.97 +            return;
    1.98 +            }
    1.99 +        default:
   1.100 +            SkASSERT(0);
   1.101 +    }
   1.102 +}
   1.103 +
   1.104 +bool SkSVGPaint::flush(SkSVGParser& parser, bool isFlushable, bool isDef) {
   1.105 +    SkSVGPaint current;
   1.106 +    SkSVGPaint* walking = parser.fHead;
   1.107 +    int index;
   1.108 +    while (walking != NULL) {
   1.109 +        for (index = kInitial + 1; index < kTerminal; index++) {
   1.110 +            SkString* lastAttr = (*walking)[index];
   1.111 +            if (lastAttr->size() == 0)
   1.112 +                continue;
   1.113 +            if (current[index]->size() > 0)
   1.114 +                continue;
   1.115 +            current[index]->set(*lastAttr);
   1.116 +        }
   1.117 +        walking = walking->fNext;
   1.118 +    }
   1.119 +    bool paintChanged = false;
   1.120 +    SkSVGPaint& lastState = parser.fLastFlush;
   1.121 +    if (isFlushable == false) {
   1.122 +        if (isDef == true) {
   1.123 +            if (current.f_mask.size() > 0 && current.f_mask.equals(lastState.f_mask) == false) {
   1.124 +                SkSVGElement* found;
   1.125 +                const char* idStart = strchr(current.f_mask.c_str(), '#');
   1.126 +                SkASSERT(idStart);
   1.127 +                SkString id(idStart + 1, strlen(idStart) - 2);
   1.128 +                bool itsFound = parser.fIDs.find(id.c_str(), &found);
   1.129 +                SkASSERT(itsFound);
   1.130 +                SkSVGElement* gradient = found->getGradient();
   1.131 +                if (gradient) {
   1.132 +                    gradient->write(parser, current.f_fill);
   1.133 +                    gradient->write(parser, current.f_stroke);
   1.134 +                }
   1.135 +            }
   1.136 +        }
   1.137 +        goto setLast;
   1.138 +    }
   1.139 +    {
   1.140 +        bool changed[kTerminal];
   1.141 +        memset(changed, 0, sizeof(changed));
   1.142 +        for (index = kInitial + 1; index < kTerminal; index++) {
   1.143 +            if (index == kTransform || index == kClipPath || index == kStopColor || index == kStopOpacity ||
   1.144 +                    index == kClipRule || index == kFillRule)
   1.145 +                continue;
   1.146 +            SkString* lastAttr = lastState[index];
   1.147 +            SkString* currentAttr = current[index];
   1.148 +            paintChanged |= changed[index] = lastAttr->equals(*currentAttr) == false;
   1.149 +        }
   1.150 +        if (paintChanged) {
   1.151 +            if (current.f_mask.size() > 0) {
   1.152 +                if (current.f_fill.equals("none") == false && strncmp(current.f_fill.c_str(), "url(#", 5) != 0) {
   1.153 +                    SkASSERT(current.f_fill.c_str()[0] == '#');
   1.154 +                    SkString replacement("url(#mask");
   1.155 +                    replacement.append(current.f_fill.c_str() + 1);
   1.156 +                    replacement.appendUnichar(')');
   1.157 +                    current.f_fill.set(replacement);
   1.158 +                }
   1.159 +                if (current.f_stroke.equals("none") == false && strncmp(current.f_stroke.c_str(), "url(#", 5) != 0) {
   1.160 +                    SkASSERT(current.f_stroke.c_str()[0] == '#');
   1.161 +                    SkString replacement("url(#mask");
   1.162 +                    replacement.append(current.f_stroke.c_str() + 1);
   1.163 +                    replacement.appendUnichar(')');
   1.164 +                    current.f_stroke.set(replacement);
   1.165 +                }
   1.166 +            }
   1.167 +            if (current.f_fill.equals("none") && current.f_stroke.equals("none"))
   1.168 +                current.f_opacity.set("0");
   1.169 +            if (parser.fSuppressPaint == false) {
   1.170 +                parser._startElement("paint");
   1.171 +                bool success = writeChangedAttributes(parser, current, changed);
   1.172 +                if (success == false)
   1.173 +                    return paintChanged;
   1.174 +                success = writeChangedElements(parser, current, changed);
   1.175 +                if (success == false)
   1.176 +                    return paintChanged;
   1.177 +                parser._endElement(); // paint
   1.178 +            }
   1.179 +        }
   1.180 +    }
   1.181 +setLast:
   1.182 +    for (index = kInitial + 1; index < kTerminal; index++) {
   1.183 +        SkString* lastAttr = lastState[index];
   1.184 +        SkString* currentAttr = current[index];
   1.185 +        lastAttr->set(*currentAttr);
   1.186 +    }
   1.187 +    return paintChanged;
   1.188 +}
   1.189 +
   1.190 +int SkSVGPaint::getAttributes(const SkSVGAttribute** attrPtr) {
   1.191 +    *attrPtr = gAttributes;
   1.192 +    return kAttributesSize;
   1.193 +}
   1.194 +
   1.195 +void SkSVGPaint::setSave(SkSVGParser& parser) {
   1.196 +    SkTDArray<SkString*> clips;
   1.197 +    SkSVGPaint* walking = parser.fHead;
   1.198 +    int index;
   1.199 +    SkMatrix sum;
   1.200 +    sum.reset();
   1.201 +    while (walking != NULL) {
   1.202 +        for (index = kInitial + 1; index < kTerminal; index++) {
   1.203 +            SkString* lastAttr = (*walking)[index];
   1.204 +            if (lastAttr->size() == 0)
   1.205 +                continue;
   1.206 +            if (index == kTransform) {
   1.207 +                const char* str = lastAttr->c_str();
   1.208 +                SkASSERT(strncmp(str, "matrix(", 7) == 0);
   1.209 +                str += 6;
   1.210 +                const char* strEnd = strrchr(str, ')');
   1.211 +                SkASSERT(strEnd != NULL);
   1.212 +                SkString mat(str, strEnd - str);
   1.213 +                SkSVGParser::ConvertToArray(mat);
   1.214 +                SkScalar values[6];
   1.215 +                SkParse::FindScalars(mat.c_str() + 1, values, 6);
   1.216 +                SkMatrix matrix;
   1.217 +                matrix.reset();
   1.218 +                matrix.setScaleX(values[0]);
   1.219 +                matrix.setSkewY(values[1]);
   1.220 +                matrix.setSkewX(values[2]);
   1.221 +                matrix.setScaleY(values[3]);
   1.222 +                matrix.setTranslateX(values[4]);
   1.223 +                matrix.setTranslateY(values[5]);
   1.224 +                sum.setConcat(matrix, sum);
   1.225 +                continue;
   1.226 +            }
   1.227 +            if ( index == kClipPath)
   1.228 +                *clips.insert(0) = lastAttr;
   1.229 +        }
   1.230 +        walking = walking->fNext;
   1.231 +    }
   1.232 +    if ((sum == parser.fLastTransform) == false) {
   1.233 +        SkMatrix inverse;
   1.234 +        bool success = parser.fLastTransform.invert(&inverse);
   1.235 +        SkASSERT(success == true);
   1.236 +        SkMatrix output;
   1.237 +        output.setConcat(inverse, sum);
   1.238 +        parser.fLastTransform = sum;
   1.239 +        SkString outputStr;
   1.240 +        outputStr.appendUnichar('[');
   1.241 +        outputStr.appendScalar(output.getScaleX());
   1.242 +        outputStr.appendUnichar(',');
   1.243 +        outputStr.appendScalar(output.getSkewX());
   1.244 +        outputStr.appendUnichar(',');
   1.245 +        outputStr.appendScalar(output.getTranslateX());
   1.246 +        outputStr.appendUnichar(',');
   1.247 +        outputStr.appendScalar(output.getSkewY());
   1.248 +        outputStr.appendUnichar(',');
   1.249 +        outputStr.appendScalar(output.getScaleY());
   1.250 +        outputStr.appendUnichar(',');
   1.251 +        outputStr.appendScalar(output.getTranslateY());
   1.252 +        outputStr.appendUnichar(',');
   1.253 +        outputStr.appendScalar(output.getPerspX());
   1.254 +        outputStr.appendUnichar(',');
   1.255 +        outputStr.appendScalar(output.getPerspY());
   1.256 +        outputStr.append(",1]");
   1.257 +        parser._startElement("matrix");
   1.258 +        parser._addAttributeLen("matrix", outputStr.c_str(), outputStr.size());
   1.259 +        parser._endElement();
   1.260 +    }
   1.261 +#if 0   // incomplete
   1.262 +    if (parser.fTransformClips.size() > 0) {
   1.263 +        // need to reset the clip when the 'g' scope is ended
   1.264 +        parser._startElement("add");
   1.265 +        const char* start = strchr(current->f_clipPath.c_str(), '#') + 1;
   1.266 +        SkASSERT(start);
   1.267 +        parser._addAttributeLen("use", start, strlen(start) - 1);
   1.268 +        parser._endElement();   // clip
   1.269 +    }
   1.270 +#endif
   1.271 +}
   1.272 +
   1.273 +bool SkSVGPaint::writeChangedAttributes(SkSVGParser& parser,
   1.274 +        SkSVGPaint& current, bool* changed) {
   1.275 +    SkSVGPaint& lastState = parser.fLastFlush;
   1.276 +    for (int index = kInitial + 1; index < kTerminal; index++) {
   1.277 +        if (changed[index] == false)
   1.278 +                continue;
   1.279 +        SkString* topAttr = current[index];
   1.280 +        size_t attrLength = topAttr->size();
   1.281 +        if (attrLength == 0)
   1.282 +            continue;
   1.283 +        const char* attrValue = topAttr->c_str();
   1.284 +        SkString* lastAttr = lastState[index];
   1.285 +        switch(index) {
   1.286 +            case kClipPath:
   1.287 +            case kClipRule:
   1.288 +            case kEnableBackground:
   1.289 +                break;
   1.290 +            case kFill:
   1.291 +                if (topAttr->equals("none") == false && lastAttr->equals("none") == true)
   1.292 +                    parser._addAttribute("stroke", "false");
   1.293 +                goto fillStrokeAttrCommon;
   1.294 +            case kFillRule:
   1.295 +            case kFilter:
   1.296 +            case kFontFamily:
   1.297 +                break;
   1.298 +            case kFontSize:
   1.299 +                parser._addAttributeLen("textSize", attrValue, attrLength);
   1.300 +                break;
   1.301 +            case kLetterSpacing:
   1.302 +                parser._addAttributeLen("textTracking", attrValue, attrLength);
   1.303 +                break;
   1.304 +            case kMask:
   1.305 +                break;
   1.306 +            case kOpacity:
   1.307 +                break;
   1.308 +            case kStopColor:
   1.309 +                break;
   1.310 +            case kStopOpacity:
   1.311 +                break;
   1.312 +            case kStroke:
   1.313 +                if (topAttr->equals("none") == false && lastAttr->equals("none") == true)
   1.314 +                    parser._addAttribute("stroke", "true");
   1.315 +fillStrokeAttrCommon:
   1.316 +                if (strncmp(attrValue, "url(", 4) == 0) {
   1.317 +                    SkASSERT(attrValue[4] == '#');
   1.318 +                    const char* idStart = attrValue + 5;
   1.319 +                    const char* idEnd = strrchr(attrValue, ')');
   1.320 +                    SkASSERT(idStart < idEnd);
   1.321 +                    SkString id(idStart, idEnd - idStart);
   1.322 +                    SkSVGElement* found;
   1.323 +                    if (strncmp(id.c_str(), "mask", 4) != 0) {
   1.324 +                        bool itsFound = parser.fIDs.find(id.c_str(), &found);
   1.325 +                        SkASSERT(itsFound);
   1.326 +                        SkASSERT(found->getType() == SkSVGType_LinearGradient ||
   1.327 +                            found->getType() == SkSVGType_RadialGradient);
   1.328 +                    }
   1.329 +                    parser._addAttribute("shader", id.c_str());
   1.330 +                }
   1.331 +                break;
   1.332 +            case kStroke_Dasharray:
   1.333 +                break;
   1.334 +            case kStroke_Linecap:
   1.335 +                parser._addAttributeLen("strokeCap", attrValue, attrLength);
   1.336 +                break;
   1.337 +            case kStroke_Linejoin:
   1.338 +                parser._addAttributeLen("strokeJoin", attrValue, attrLength);
   1.339 +                break;
   1.340 +            case kStroke_Miterlimit:
   1.341 +                parser._addAttributeLen("strokeMiter", attrValue, attrLength);
   1.342 +                break;
   1.343 +            case kStroke_Width:
   1.344 +                parser._addAttributeLen("strokeWidth", attrValue, attrLength);
   1.345 +            case kStyle:
   1.346 +            case kTransform:
   1.347 +                break;
   1.348 +        default:
   1.349 +            SkASSERT(0);
   1.350 +            return false;
   1.351 +        }
   1.352 +    }
   1.353 +    return true;
   1.354 +}
   1.355 +
   1.356 +bool SkSVGPaint::writeChangedElements(SkSVGParser& parser,
   1.357 +        SkSVGPaint& current, bool* changed) {
   1.358 +    SkSVGPaint& lastState = parser.fLastFlush;
   1.359 +    for (int index = kInitial + 1; index < kTerminal; index++) {
   1.360 +        SkString* topAttr = current[index];
   1.361 +        size_t attrLength = topAttr->size();
   1.362 +        if (attrLength == 0)
   1.363 +            continue;
   1.364 +        const char* attrValue = topAttr->c_str();
   1.365 +        SkString* lastAttr = lastState[index];
   1.366 +        switch(index) {
   1.367 +            case kClipPath:
   1.368 +            case kClipRule:
   1.369 +                // !!! need to add this outside of paint
   1.370 +                break;
   1.371 +            case kEnableBackground:
   1.372 +                // !!! don't know what to do with this
   1.373 +                break;
   1.374 +            case kFill:
   1.375 +                goto addColor;
   1.376 +            case kFillRule:
   1.377 +            case kFilter:
   1.378 +                break;
   1.379 +            case kFontFamily:
   1.380 +                parser._startElement("typeface");
   1.381 +                parser._addAttributeLen("fontName", attrValue, attrLength);
   1.382 +                parser._endElement();   // typeface
   1.383 +                break;
   1.384 +            case kFontSize:
   1.385 +            case kLetterSpacing:
   1.386 +                break;
   1.387 +            case kMask:
   1.388 +            case kOpacity:
   1.389 +                if (changed[kStroke] == false && changed[kFill] == false) {
   1.390 +                    parser._startElement("color");
   1.391 +                    SkString& opacity = current.f_opacity;
   1.392 +                    parser._addAttributeLen("color", parser.fLastColor.c_str(), parser.fLastColor.size());
   1.393 +                    parser._addAttributeLen("alpha", opacity.c_str(), opacity.size());
   1.394 +                    parser._endElement();   // color
   1.395 +                }
   1.396 +                break;
   1.397 +            case kStopColor:
   1.398 +                break;
   1.399 +            case kStopOpacity:
   1.400 +                break;
   1.401 +            case kStroke:
   1.402 +addColor:
   1.403 +                if (strncmp(lastAttr->c_str(), "url(", 4) == 0 && strncmp(attrValue, "url(", 4) != 0) {
   1.404 +                    parser._startElement("shader");
   1.405 +                    parser._endElement();
   1.406 +                }
   1.407 +                if (topAttr->equals(*lastAttr))
   1.408 +                    continue;
   1.409 +                {
   1.410 +                    bool urlRef = strncmp(attrValue, "url(", 4) == 0;
   1.411 +                    bool colorNone = strcmp(attrValue, "none") == 0;
   1.412 +                    bool lastEqual = parser.fLastColor.equals(attrValue, attrLength);
   1.413 +                    bool newColor = urlRef == false && colorNone == false && lastEqual == false;
   1.414 +                    if (newColor || changed[kOpacity]) {
   1.415 +                        parser._startElement("color");
   1.416 +                        if (newColor || changed[kOpacity]) {
   1.417 +                            parser._addAttributeLen("color", attrValue, attrLength);
   1.418 +                            parser.fLastColor.set(attrValue, attrLength);
   1.419 +                        }
   1.420 +                        if (changed[kOpacity]) {
   1.421 +                            SkString& opacity = current.f_opacity;
   1.422 +                            parser._addAttributeLen("alpha", opacity.c_str(), opacity.size());
   1.423 +                        }
   1.424 +                        parser._endElement();   // color
   1.425 +                    }
   1.426 +                }
   1.427 +                break;
   1.428 +            case kStroke_Dasharray:
   1.429 +                parser._startElement("dash");
   1.430 +                SkSVGParser::ConvertToArray(*topAttr);
   1.431 +                parser._addAttribute("intervals", topAttr->c_str());
   1.432 +                parser._endElement();   // dash
   1.433 +            break;
   1.434 +            case kStroke_Linecap:
   1.435 +            case kStroke_Linejoin:
   1.436 +            case kStroke_Miterlimit:
   1.437 +            case kStroke_Width:
   1.438 +            case kStyle:
   1.439 +            case kTransform:
   1.440 +                break;
   1.441 +        default:
   1.442 +            SkASSERT(0);
   1.443 +            return false;
   1.444 +        }
   1.445 +    }
   1.446 +    return true;
   1.447 +}
   1.448 +
   1.449 +void SkSVGPaint::Push(SkSVGPaint** head, SkSVGPaint* newRecord) {
   1.450 +    newRecord->fNext = *head;
   1.451 +    *head = newRecord;
   1.452 +}
   1.453 +
   1.454 +void SkSVGPaint::Pop(SkSVGPaint** head) {
   1.455 +    SkSVGPaint* next = (*head)->fNext;
   1.456 +    *head = next;
   1.457 +}

mercurial