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 "SkSVGGradient.h"
11#include "SkSVGParser.h"
12#include "SkSVGStop.h"
13
14SkSVGGradient::SkSVGGradient() {
15}
16
17SkSVGElement* SkSVGGradient::getGradient() {
18    return this;
19}
20
21bool SkSVGGradient::isDef() {
22    return true;
23}
24
25bool SkSVGGradient::isNotDef() {
26    return false;
27}
28
29void SkSVGGradient::translate(SkSVGParser& parser, bool defState) {
30    INHERITED::translate(parser, defState);
31    // !!! no support for 'objectBoundingBox' yet
32    bool first = true;
33    bool addedFirst = false;
34    bool addedLast = false;
35    SkString offsets("[");
36    SkString* lastOffset = NULL;
37    for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
38        SkASSERT((*ptr)->getType() == SkSVGType_Stop);
39        SkSVGStop* stop = (SkSVGStop*) *ptr;
40        if (first && stop->f_offset.equals("0") == false) {
41            addedFirst = true;
42            offsets.append("0,");
43        }
44        SkString* thisOffset = &stop->f_offset;
45        if (lastOffset && thisOffset->equals(*lastOffset)) {
46            if (thisOffset->equals("1")) {
47                offsets.remove(offsets.size() - 2, 2);
48                offsets.append(".999,");
49            } else {
50                SkASSERT(0); // !!! need to write this case
51            }
52        }
53        offsets.append(*thisOffset);
54        if (ptr == fChildren.end() - 1) { // last
55            if (stop->f_offset.equals("1") == false) {
56                offsets.append(",1");
57                addedLast = true;
58            }
59        } else
60            offsets.appendUnichar(',');
61        first = false;
62        lastOffset = thisOffset;
63    }
64    offsets.appendUnichar(']');
65    parser._addAttribute("offsets", offsets);
66    if (addedFirst)
67        parser.translate(*fChildren.begin(), defState);
68    for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++)
69        parser.translate(*ptr, defState);
70    if (addedLast)
71        parser.translate(*(fChildren.end() - 1), defState);
72}
73
74void SkSVGGradient::translateGradientUnits(SkString& units) {
75    // !!! no support for 'objectBoundingBox' yet
76    SkASSERT(strcmp(units.c_str(), "userSpaceOnUse") == 0);
77}
78
79void SkSVGGradient::write(SkSVGParser& parser, SkString& baseColor) {
80    if (baseColor.c_str()[0] != '#')
81        return;
82    SkSVGPaint* saveHead = parser.fHead;
83    parser.fHead = &fPaintState;
84    parser.fSuppressPaint = true;
85    SkString originalID(f_id);
86    f_id.set("mask"); // write out gradient named given name + color (less initial #)
87    f_id.append(baseColor.c_str() + 1);
88    SkString originalColors;
89    for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
90        SkSVGStop* colorElement = (SkSVGStop*) *ptr;
91        SkString& color = colorElement->fPaintState.f_stopColor;
92        originalColors.append(color);
93        originalColors.appendUnichar(',');
94        SkASSERT(color.c_str()[0] == '#');
95        SkString replacement;
96        replacement.set("0x");
97        replacement.append(color.c_str() + 1, 2); // add stop colors using given color, turning existing stop color into alpha
98        SkASSERT(baseColor.c_str()[0] == '#');
99        SkASSERT(baseColor.size() == 7);
100        replacement.append(baseColor.c_str() + 1);
101        color.set(replacement);
102    }
103    translate(parser, true);
104    const char* originalPtr = originalColors.c_str(); // restore original gradient values
105    for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
106        SkSVGStop* color = (SkSVGStop*) *ptr;
107        const char* originalEnd = strchr(originalPtr, ',');
108        color->fPaintState.f_stopColor.set(originalPtr, originalEnd - originalPtr);
109        originalPtr = originalEnd + 1;
110    }
111    f_id.set(originalID);
112    parser.fSuppressPaint = false;
113    parser.fHead = saveHead;
114}
115
116