1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkDrawExtraPathEffect.h"
9#include "SkDrawPath.h"
10#include "Sk1DPathEffect.h"
11#include "Sk2DPathEffect.h"
12#include "SkMemberInfo.h"
13#include "SkPaintPart.h"
14#include "SkPathEffect.h"
15#include "SkCornerPathEffect.h"
16
17#include "SkDashPathEffect.h"
18
19class SkDrawShapePathEffect : public SkDrawPathEffect {
20    DECLARE_PRIVATE_MEMBER_INFO(DrawShapePathEffect);
21    SkDrawShapePathEffect();
22    virtual ~SkDrawShapePathEffect();
23    virtual bool addChild(SkAnimateMaker& , SkDisplayable* ) SK_OVERRIDE;
24    virtual SkPathEffect* getPathEffect();
25protected:
26    SkDrawable* addPath;
27    SkDrawable* addMatrix;
28    SkDrawPath* path;
29    SkPathEffect* fPathEffect;
30    friend class SkShape1DPathEffect;
31    friend class SkShape2DPathEffect;
32};
33
34class SkDrawShape1DPathEffect : public SkDrawShapePathEffect {
35    DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape1DPathEffect);
36    SkDrawShape1DPathEffect(SkDisplayTypes );
37    virtual ~SkDrawShape1DPathEffect();
38    virtual void onEndElement(SkAnimateMaker& );
39private:
40    SkString phase;
41    SkString spacing;
42    friend class SkShape1DPathEffect;
43    typedef SkDrawShapePathEffect INHERITED;
44};
45
46class SkDrawShape2DPathEffect : public SkDrawShapePathEffect {
47    DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape2DPathEffect);
48    SkDrawShape2DPathEffect(SkDisplayTypes );
49    virtual ~SkDrawShape2DPathEffect();
50    virtual void onEndElement(SkAnimateMaker& );
51private:
52    SkDrawMatrix* matrix;
53    friend class SkShape2DPathEffect;
54    typedef SkDrawShapePathEffect INHERITED;
55};
56
57class SkDrawComposePathEffect : public SkDrawPathEffect {
58    DECLARE_EXTRAS_MEMBER_INFO(SkDrawComposePathEffect);
59    SkDrawComposePathEffect(SkDisplayTypes );
60    virtual ~SkDrawComposePathEffect();
61    virtual bool addChild(SkAnimateMaker& , SkDisplayable* ) SK_OVERRIDE;
62    virtual SkPathEffect* getPathEffect();
63    virtual bool isPaint() const;
64private:
65    SkDrawPathEffect* effect1;
66    SkDrawPathEffect* effect2;
67};
68
69class SkDrawCornerPathEffect : public SkDrawPathEffect {
70    DECLARE_EXTRAS_MEMBER_INFO(SkDrawCornerPathEffect);
71    SkDrawCornerPathEffect(SkDisplayTypes );
72    virtual ~SkDrawCornerPathEffect();
73    virtual SkPathEffect* getPathEffect();
74private:
75    SkScalar radius;
76};
77
78//////////// SkShape1DPathEffect
79
80#include "SkAnimateMaker.h"
81#include "SkAnimatorScript.h"
82#include "SkDisplayApply.h"
83#include "SkDrawMatrix.h"
84#include "SkPaint.h"
85
86class SkShape1DPathEffect : public Sk1DPathEffect {
87public:
88    SkShape1DPathEffect(SkDrawShape1DPathEffect* draw, SkAnimateMaker* maker) :
89        fDraw(draw), fMaker(maker) {
90    }
91
92    SK_DECLARE_UNFLATTENABLE_OBJECT()
93
94protected:
95    virtual SkScalar begin(SkScalar contourLength) const {
96        SkScriptValue value;
97        SkAnimatorScript engine(*fMaker, NULL, SkType_Float);
98        engine.propertyCallBack(GetContourLength, &contourLength);
99        value.fOperand.fScalar = 0;
100        engine.evaluate(fDraw->phase.c_str(), &value, SkType_Float);
101        return value.fOperand.fScalar;
102    }
103
104    virtual SkScalar next(SkPath* dst, SkScalar distance, SkPathMeasure&) const {
105        fMaker->setExtraPropertyCallBack(fDraw->fType, GetDistance, &distance);
106        SkDrawPath* drawPath = NULL;
107        if (fDraw->addPath->isPath()) {
108            drawPath = (SkDrawPath*) fDraw->addPath;
109        } else {
110            SkApply* apply = (SkApply*) fDraw->addPath;
111            apply->refresh(*fMaker);
112            apply->activate(*fMaker);
113            apply->interpolate(*fMaker, SkScalarRoundToInt(distance * 1000));
114            drawPath = (SkDrawPath*) apply->getScope();
115        }
116        SkMatrix m;
117        m.reset();
118        if (fDraw->addMatrix) {
119            SkDrawMatrix* matrix;
120            if (fDraw->addMatrix->getType() == SkType_Matrix)
121                matrix = (SkDrawMatrix*) fDraw->addMatrix;
122            else {
123                SkApply* apply = (SkApply*) fDraw->addMatrix;
124                apply->refresh(*fMaker);
125                apply->activate(*fMaker);
126                apply->interpolate(*fMaker, SkScalarRoundToInt(distance * 1000));
127                matrix = (SkDrawMatrix*) apply->getScope();
128            }
129            if (matrix) {
130                m = matrix->getMatrix();
131            }
132        }
133        SkScalar result = 0;
134        SkAnimatorScript::EvaluateFloat(*fMaker, NULL, fDraw->spacing.c_str(), &result);
135        if (drawPath)
136            dst->addPath(drawPath->getPath(), m);
137        fMaker->clearExtraPropertyCallBack(fDraw->fType);
138        return result;
139    }
140
141private:
142    static bool GetContourLength(const char* token, size_t len, void* clen, SkScriptValue* value) {
143        if (SK_LITERAL_STR_EQUAL("contourLength", token, len)) {
144            value->fOperand.fScalar = *(SkScalar*) clen;
145            value->fType = SkType_Float;
146            return true;
147        }
148        return false;
149    }
150
151    static bool GetDistance(const char* token, size_t len, void* dist, SkScriptValue* value) {
152        if (SK_LITERAL_STR_EQUAL("distance", token, len)) {
153            value->fOperand.fScalar = *(SkScalar*) dist;
154            value->fType = SkType_Float;
155            return true;
156        }
157        return false;
158    }
159
160    SkDrawShape1DPathEffect* fDraw;
161    SkAnimateMaker* fMaker;
162};
163
164//////////// SkDrawShapePathEffect
165
166#if SK_USE_CONDENSED_INFO == 0
167
168const SkMemberInfo SkDrawShapePathEffect::fInfo[] = {
169    SK_MEMBER(addMatrix, Drawable), // either matrix or apply
170    SK_MEMBER(addPath, Drawable),   // either path or apply
171    SK_MEMBER(path, Path),
172};
173
174#endif
175
176DEFINE_GET_MEMBER(SkDrawShapePathEffect);
177
178SkDrawShapePathEffect::SkDrawShapePathEffect() :
179    addPath(NULL), addMatrix(NULL), path(NULL), fPathEffect(NULL) {
180}
181
182SkDrawShapePathEffect::~SkDrawShapePathEffect() {
183    SkSafeUnref(fPathEffect);
184}
185
186bool SkDrawShapePathEffect::addChild(SkAnimateMaker& , SkDisplayable* child) {
187    path = (SkDrawPath*) child;
188    return true;
189}
190
191SkPathEffect* SkDrawShapePathEffect::getPathEffect() {
192    fPathEffect->ref();
193    return fPathEffect;
194}
195
196//////////// SkDrawShape1DPathEffect
197
198#if SK_USE_CONDENSED_INFO == 0
199
200const SkMemberInfo SkDrawShape1DPathEffect::fInfo[] = {
201    SK_MEMBER_INHERITED,
202    SK_MEMBER(phase, String),
203    SK_MEMBER(spacing, String),
204};
205
206#endif
207
208DEFINE_GET_MEMBER(SkDrawShape1DPathEffect);
209
210SkDrawShape1DPathEffect::SkDrawShape1DPathEffect(SkDisplayTypes type) : fType(type) {
211}
212
213SkDrawShape1DPathEffect::~SkDrawShape1DPathEffect() {
214}
215
216void SkDrawShape1DPathEffect::onEndElement(SkAnimateMaker& maker) {
217    if (addPath == NULL || (addPath->isPath() == false && addPath->isApply() == false))
218        maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error
219    else
220        fPathEffect = new SkShape1DPathEffect(this, &maker);
221}
222
223////////// SkShape2DPathEffect
224
225class SkShape2DPathEffect : public Sk2DPathEffect {
226public:
227    SkShape2DPathEffect(SkDrawShape2DPathEffect* draw, SkAnimateMaker* maker,
228        const SkMatrix& matrix) : Sk2DPathEffect(matrix), fDraw(draw), fMaker(maker) {
229    }
230
231protected:
232    virtual void begin(const SkIRect& uvBounds, SkPath*) const SK_OVERRIDE {
233        const_cast<SkShape2DPathEffect*>(this)->setUVBounds(uvBounds);
234    }
235
236    virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const SK_OVERRIDE {
237        const_cast<SkShape2DPathEffect*>(this)->addPath(loc, u, v, dst);
238    }
239
240private:
241    void setUVBounds(const SkIRect& uvBounds) {
242        fUVBounds.set(SkIntToScalar(uvBounds.fLeft), SkIntToScalar(uvBounds.fTop),
243            SkIntToScalar(uvBounds.fRight), SkIntToScalar(uvBounds.fBottom));
244    }
245
246    void addPath(const SkPoint& loc, int u, int v, SkPath* dst) {
247        fLoc = loc;
248        fU = u;
249        fV = v;
250        SkDrawPath* drawPath;
251        fMaker->setExtraPropertyCallBack(fDraw->fType, Get2D, this);
252        if (fDraw->addPath->isPath()) {
253            drawPath = (SkDrawPath*) fDraw->addPath;
254        } else {
255            SkApply* apply = (SkApply*) fDraw->addPath;
256            apply->refresh(*fMaker);
257            apply->activate(*fMaker);
258            apply->interpolate(*fMaker, v);
259            drawPath = (SkDrawPath*) apply->getScope();
260        }
261        if (drawPath == NULL)
262            goto clearCallBack;
263        if (fDraw->matrix) {
264            SkDrawMatrix* matrix;
265            if (fDraw->matrix->getType() == SkType_Matrix)
266                matrix = (SkDrawMatrix*) fDraw->matrix;
267            else {
268                SkApply* apply = (SkApply*) fDraw->matrix;
269                apply->activate(*fMaker);
270                apply->interpolate(*fMaker, v);
271                matrix = (SkDrawMatrix*) apply->getScope();
272            }
273            if (matrix) {
274                dst->addPath(drawPath->getPath(), matrix->getMatrix());
275                goto clearCallBack;
276            }
277        }
278        dst->addPath(drawPath->getPath());
279clearCallBack:
280        fMaker->clearExtraPropertyCallBack(fDraw->fType);
281    }
282
283    static bool Get2D(const char* token, size_t len, void* s2D, SkScriptValue* value) {
284        static const char match[] = "locX|locY|left|top|right|bottom|u|v" ;
285        SkShape2DPathEffect* shape2D = (SkShape2DPathEffect*) s2D;
286        int index;
287        if (SkAnimatorScript::MapEnums(match, token, len, &index) == false)
288            return false;
289        SkASSERT((sizeof(SkPoint) +     sizeof(SkRect)) / sizeof(SkScalar) == 6);
290        if (index < 6) {
291            value->fType = SkType_Float;
292            value->fOperand.fScalar = (&shape2D->fLoc.fX)[index];
293        } else {
294            value->fType = SkType_Int;
295            value->fOperand.fS32 = (&shape2D->fU)[index - 6];
296        }
297        return true;
298    }
299
300    SkPoint fLoc;
301    SkRect fUVBounds;
302    int32_t fU;
303    int32_t fV;
304    SkDrawShape2DPathEffect* fDraw;
305    SkAnimateMaker* fMaker;
306
307    // illegal
308    SkShape2DPathEffect(const SkShape2DPathEffect&);
309    SkShape2DPathEffect& operator=(const SkShape2DPathEffect&);
310};
311
312////////// SkDrawShape2DPathEffect
313
314#if SK_USE_CONDENSED_INFO == 0
315
316const SkMemberInfo SkDrawShape2DPathEffect::fInfo[] = {
317    SK_MEMBER_INHERITED,
318    SK_MEMBER(matrix, Matrix)
319};
320
321#endif
322
323DEFINE_GET_MEMBER(SkDrawShape2DPathEffect);
324
325SkDrawShape2DPathEffect::SkDrawShape2DPathEffect(SkDisplayTypes type) : fType(type) {
326}
327
328SkDrawShape2DPathEffect::~SkDrawShape2DPathEffect() {
329}
330
331void SkDrawShape2DPathEffect::onEndElement(SkAnimateMaker& maker) {
332    if (addPath == NULL || (addPath->isPath() == false && addPath->isApply() == false) ||
333            matrix == NULL)
334        maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error
335    else
336        fPathEffect = new SkShape2DPathEffect(this, &maker, matrix->getMatrix());
337}
338
339////////// SkDrawComposePathEffect
340
341#if SK_USE_CONDENSED_INFO == 0
342
343const SkMemberInfo SkDrawComposePathEffect::fInfo[] = {
344    SK_MEMBER(effect1, PathEffect),
345    SK_MEMBER(effect2, PathEffect)
346};
347
348#endif
349
350DEFINE_GET_MEMBER(SkDrawComposePathEffect);
351
352SkDrawComposePathEffect::SkDrawComposePathEffect(SkDisplayTypes type) : fType(type),
353    effect1(NULL), effect2(NULL) {
354}
355
356SkDrawComposePathEffect::~SkDrawComposePathEffect() {
357    delete effect1;
358    delete effect2;
359}
360
361bool SkDrawComposePathEffect::addChild(SkAnimateMaker& , SkDisplayable* child) {
362    if (effect1 == NULL)
363        effect1 = (SkDrawPathEffect*) child;
364    else
365        effect2 = (SkDrawPathEffect*) child;
366    return true;
367}
368
369SkPathEffect* SkDrawComposePathEffect::getPathEffect() {
370    SkPathEffect* e1 = effect1->getPathEffect();
371    SkPathEffect* e2 = effect2->getPathEffect();
372    SkPathEffect* composite = SkComposePathEffect::Create(e1, e2);
373    e1->unref();
374    e2->unref();
375    return composite;
376}
377
378bool SkDrawComposePathEffect::isPaint() const {
379    return true;
380}
381
382//////////// SkDrawCornerPathEffect
383
384#if SK_USE_CONDENSED_INFO == 0
385
386const SkMemberInfo SkDrawCornerPathEffect::fInfo[] = {
387    SK_MEMBER(radius, Float)
388};
389
390#endif
391
392DEFINE_GET_MEMBER(SkDrawCornerPathEffect);
393
394SkDrawCornerPathEffect::SkDrawCornerPathEffect(SkDisplayTypes type):
395    fType(type), radius(0) {
396}
397
398SkDrawCornerPathEffect::~SkDrawCornerPathEffect() {
399}
400
401SkPathEffect* SkDrawCornerPathEffect::getPathEffect() {
402    return SkCornerPathEffect::Create(radius);
403}
404
405/////////
406
407#include "SkExtras.h"
408
409const char kDrawShape1DPathEffectName[] = "pathEffect:shape1D";
410const char kDrawShape2DPathEffectName[] = "pathEffect:shape2D";
411const char kDrawComposePathEffectName[] = "pathEffect:compose";
412const char kDrawCornerPathEffectName[]  = "pathEffect:corner";
413
414class SkExtraPathEffects : public SkExtras {
415public:
416    SkExtraPathEffects() :
417            skDrawShape1DPathEffectType(SkType_Unknown),
418            skDrawShape2DPathEffectType(SkType_Unknown),
419            skDrawComposePathEffectType(SkType_Unknown),
420            skDrawCornerPathEffectType(SkType_Unknown) {
421    }
422
423    virtual SkDisplayable* createInstance(SkDisplayTypes type) {
424        SkDisplayable* result = NULL;
425        if (skDrawShape1DPathEffectType == type)
426            result = new SkDrawShape1DPathEffect(type);
427        else if (skDrawShape2DPathEffectType == type)
428            result = new SkDrawShape2DPathEffect(type);
429        else if (skDrawComposePathEffectType == type)
430            result = new SkDrawComposePathEffect(type);
431        else if (skDrawCornerPathEffectType == type)
432            result = new SkDrawCornerPathEffect(type);
433        return result;
434    }
435
436    virtual bool definesType(SkDisplayTypes type) {
437        return type == skDrawShape1DPathEffectType ||
438            type == skDrawShape2DPathEffectType ||
439            type == skDrawComposePathEffectType ||
440            type == skDrawCornerPathEffectType;
441    }
442
443#if SK_USE_CONDENSED_INFO == 0
444    virtual const SkMemberInfo* getMembers(SkDisplayTypes type, int* infoCountPtr) {
445        const SkMemberInfo* info = NULL;
446        int infoCount = 0;
447        if (skDrawShape1DPathEffectType == type) {
448            info = SkDrawShape1DPathEffect::fInfo;
449            infoCount = SkDrawShape1DPathEffect::fInfoCount;
450        } else if (skDrawShape2DPathEffectType == type) {
451            info = SkDrawShape2DPathEffect::fInfo;
452            infoCount = SkDrawShape2DPathEffect::fInfoCount;
453        } else if (skDrawComposePathEffectType == type) {
454            info = SkDrawComposePathEffect::fInfo;
455            infoCount = SkDrawShape1DPathEffect::fInfoCount;
456        } else if (skDrawCornerPathEffectType == type) {
457            info = SkDrawCornerPathEffect::fInfo;
458            infoCount = SkDrawCornerPathEffect::fInfoCount;
459        }
460        if (infoCountPtr)
461            *infoCountPtr = infoCount;
462        return info;
463    }
464#endif
465
466#ifdef SK_DEBUG
467    virtual const char* getName(SkDisplayTypes type) {
468        if (skDrawShape1DPathEffectType == type)
469            return kDrawShape1DPathEffectName;
470        else if (skDrawShape2DPathEffectType == type)
471            return kDrawShape2DPathEffectName;
472        else if (skDrawComposePathEffectType == type)
473            return kDrawComposePathEffectName;
474        else if (skDrawCornerPathEffectType == type)
475            return kDrawCornerPathEffectName;
476        return NULL;
477    }
478#endif
479
480    virtual SkDisplayTypes getType(const char name[], size_t len ) {
481        SkDisplayTypes* type = NULL;
482        if (SK_LITERAL_STR_EQUAL(kDrawShape1DPathEffectName, name, len))
483            type = &skDrawShape1DPathEffectType;
484        else if (SK_LITERAL_STR_EQUAL(kDrawShape2DPathEffectName, name, len))
485            type = &skDrawShape2DPathEffectType;
486        else if (SK_LITERAL_STR_EQUAL(kDrawComposePathEffectName, name, len))
487            type = &skDrawComposePathEffectType;
488        else if (SK_LITERAL_STR_EQUAL(kDrawCornerPathEffectName, name, len))
489            type = &skDrawCornerPathEffectType;
490        if (type) {
491            if (*type == SkType_Unknown)
492                *type = SkDisplayType::RegisterNewType();
493            return *type;
494        }
495        return SkType_Unknown;
496    }
497
498private:
499    SkDisplayTypes skDrawShape1DPathEffectType;
500    SkDisplayTypes skDrawShape2DPathEffectType;
501    SkDisplayTypes skDrawComposePathEffectType;
502    SkDisplayTypes skDrawCornerPathEffectType;
503};
504
505void InitializeSkExtraPathEffects(SkAnimator* animator) {
506    animator->addExtras(new SkExtraPathEffects());
507}
508
509////////////////
510
511
512SkExtras::SkExtras() : fExtraCallBack(NULL), fExtraStorage(NULL) {
513}
514