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 "SkDrawPath.h"
11#include "SkAnimateMaker.h"
12#include "SkCanvas.h"
13#include "SkMath.h"
14#include "SkMatrixParts.h"
15#include "SkPaint.h"
16#include "SkPathParts.h"
17
18enum SkPath_Properties {
19    SK_PROPERTY(fillType),
20    SK_PROPERTY(length)
21};
22
23#if SK_USE_CONDENSED_INFO == 0
24
25const SkMemberInfo SkDrawPath::fInfo[] = {
26    SK_MEMBER(d, String),
27    SK_MEMBER_PROPERTY(fillType, FillType),
28    SK_MEMBER_PROPERTY(length, Float)
29};
30
31#endif
32
33DEFINE_GET_MEMBER(SkDrawPath);
34
35SkDrawPath::SkDrawPath()
36{
37    fParent = NULL;
38    fLength = SK_ScalarNaN;
39    fChildHasID = false;
40    fDirty = false;
41}
42
43SkDrawPath::~SkDrawPath() {
44    for (SkPathPart** part = fParts.begin(); part < fParts.end();  part++)
45        delete *part;
46}
47
48bool SkDrawPath::addChild(SkAnimateMaker& maker, SkDisplayable* child) {
49    SkASSERT(child && child->isPathPart());
50    SkPathPart* part = (SkPathPart*) child;
51    *fParts.append() = part;
52    if (part->add())
53        maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToPath);
54    fDirty = false;
55    return true;
56}
57
58bool SkDrawPath::childrenNeedDisposing() const {
59    return false;
60}
61
62void SkDrawPath::dirty() {
63    fDirty = true;
64    fLength = SK_ScalarNaN;
65    if (fParent)
66        fParent->dirty();
67}
68
69bool SkDrawPath::draw(SkAnimateMaker& maker) {
70    SkPath& path = getPath();
71    SkBoundableAuto boundable(this, maker);
72    maker.fCanvas->drawPath(path, *maker.fPaint);
73    return false;
74}
75
76SkDisplayable* SkDrawPath::getParent() const {
77    return fParent;
78}
79
80#ifdef SK_DUMP_ENABLED
81void SkDrawPath::dump(SkAnimateMaker* maker) {
82    dumpBase(maker);
83    dumpAttrs(maker);
84    bool closedYet = false;
85    SkDisplayList::fIndent += 4;
86    for(SkPathPart** part = fParts.begin(); part < fParts.end(); part++) {
87        if (closedYet == false) {
88            SkDebugf(">\n");
89            closedYet = true;
90        }
91        (*part)->dump(maker);
92    }
93    SkDisplayList::fIndent -= 4;
94    if (closedYet)
95        dumpEnd(maker);
96    else
97        SkDebugf("/>\n");
98}
99#endif
100
101SkPath& SkDrawPath::getPath() {
102    if (fDirty == false)
103        return fPath;
104    if (d.size() > 0)
105    {
106        parseSVG();
107        d.reset();
108    }
109    else
110    {
111        fPath.reset();
112        for (SkPathPart** part = fParts.begin(); part < fParts.end();  part++)
113            (*part)->add();
114    }
115    fDirty = false;
116    return fPath;
117}
118
119void SkDrawPath::onEndElement(SkAnimateMaker& ) {
120    if (d.size() > 0) {
121        parseSVG();
122        d.reset();
123        fDirty = false;
124        return;
125    }
126    if (fChildHasID == false) {
127        for (SkPathPart** part = fParts.begin(); part < fParts.end();  part++)
128            delete *part;
129        fParts.reset();
130        fDirty = false;
131    }
132}
133
134bool SkDrawPath::getProperty(int index, SkScriptValue* value) const {
135    switch (index) {
136        case SK_PROPERTY(length):
137            if (SkScalarIsNaN(fLength)) {
138                const SkPath& path = ((SkDrawPath*) this)->getPath();
139                SkPathMeasure pathMeasure(path, false);
140                fLength = pathMeasure.getLength();
141            }
142            value->fType = SkType_Float;
143            value->fOperand.fScalar = fLength;
144            break;
145        case SK_PROPERTY(fillType):
146            value->fType = SkType_FillType;
147            value->fOperand.fS32 = (int) fPath.getFillType();
148            break;
149        default:
150            SkASSERT(0);
151            return false;
152    }
153    return true;
154}
155
156void SkDrawPath::setChildHasID() {
157    fChildHasID = true;
158}
159
160bool SkDrawPath::setParent(SkDisplayable* parent) {
161    fParent = parent;
162    return false;
163}
164
165bool SkDrawPath::setProperty(int index, SkScriptValue& value)
166{
167    switch (index) {
168        case SK_PROPERTY(fillType):
169            SkASSERT(value.fType == SkType_FillType);
170            SkASSERT(value.fOperand.fS32 >= SkPath::kWinding_FillType &&
171                value.fOperand.fS32 <= SkPath::kEvenOdd_FillType);
172            fPath.setFillType((SkPath::FillType) value.fOperand.fS32);
173            break;
174        default:
175            SkASSERT(0);
176            return false;
177    }
178    return true;
179}
180
181#if SK_USE_CONDENSED_INFO == 0
182
183const SkMemberInfo SkPolyline::fInfo[] = {
184    SK_MEMBER_ARRAY(points, Float)
185};
186
187#endif
188
189DEFINE_GET_MEMBER(SkPolyline);
190
191bool SkPolyline::addChild(SkAnimateMaker& , SkDisplayable*) {
192    return false;
193}
194
195void SkPolyline::onEndElement(SkAnimateMaker& maker) {
196    INHERITED::onEndElement(maker);
197    if (points.count() <= 0)
198        return;
199    fPath.reset();
200    fPath.moveTo(points[0], points[1]);
201    int count = points.count();
202    for (int index = 2; index < count; index += 2)
203        fPath.lineTo(points[index], points[index+1]);
204}
205
206
207#if SK_USE_CONDENSED_INFO == 0
208
209const SkMemberInfo SkPolygon::fInfo[] = {
210    SK_MEMBER_INHERITED
211};
212
213#endif
214
215DEFINE_GET_MEMBER(SkPolygon);
216
217void SkPolygon::onEndElement(SkAnimateMaker& maker) {
218    INHERITED::onEndElement(maker);
219    fPath.close();
220}
221