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