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 
19 class SkDrawShapePathEffect : public SkDrawPathEffect {
20     DECLARE_PRIVATE_MEMBER_INFO(DrawShapePathEffect);
21     SkDrawShapePathEffect();
22     virtual ~SkDrawShapePathEffect();
23     bool addChild(SkAnimateMaker& , SkDisplayable* ) override;
24     SkPathEffect* getPathEffect() override;
25 protected:
26     SkADrawable* addPath;
27     SkADrawable* addMatrix;
28     SkDrawPath* path;
29     SkPathEffect* fPathEffect;
30     friend class SkShape1DPathEffect;
31     friend class SkShape2DPathEffect;
32 };
33 
34 class SkDrawShape1DPathEffect : public SkDrawShapePathEffect {
35     DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape1DPathEffect);
36     SkDrawShape1DPathEffect(SkDisplayTypes );
37     virtual ~SkDrawShape1DPathEffect();
38     void onEndElement(SkAnimateMaker& ) override;
39 private:
40     SkString phase;
41     SkString spacing;
42     friend class SkShape1DPathEffect;
43     typedef SkDrawShapePathEffect INHERITED;
44 };
45 
46 class SkDrawShape2DPathEffect : public SkDrawShapePathEffect {
47     DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape2DPathEffect);
48     SkDrawShape2DPathEffect(SkDisplayTypes );
49     virtual ~SkDrawShape2DPathEffect();
50     void onEndElement(SkAnimateMaker& ) override;
51 private:
52     SkDrawMatrix* matrix;
53     friend class SkShape2DPathEffect;
54     typedef SkDrawShapePathEffect INHERITED;
55 };
56 
57 class 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;
64 private:
65     SkDrawPathEffect* effect1;
66     SkDrawPathEffect* effect2;
67 };
68 
69 class SkDrawCornerPathEffect : public SkDrawPathEffect {
70     DECLARE_EXTRAS_MEMBER_INFO(SkDrawCornerPathEffect);
71     SkDrawCornerPathEffect(SkDisplayTypes );
72     virtual ~SkDrawCornerPathEffect();
73     SkPathEffect* getPathEffect() override;
74 private:
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 
86 class SkShape1DPathEffect : public Sk1DPathEffect {
87 public:
SkShape1DPathEffect(SkDrawShape1DPathEffect * draw,SkAnimateMaker * maker)88     SkShape1DPathEffect(SkDrawShape1DPathEffect* draw, SkAnimateMaker* maker) :
89         fDraw(draw), fMaker(maker) {
90     }
91 
92     // For serialization.  This will never be called.
getFactory() const93     Factory getFactory() const override { sk_throw(); return nullptr; }
94 
95 protected:
begin(SkScalar contourLength) const96     SkScalar begin(SkScalar contourLength) const override {
97         SkScriptValue value;
98         SkAnimatorScript engine(*fMaker, nullptr, 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 
next(SkPath * dst,SkScalar distance,SkPathMeasure &) const105     SkScalar next(SkPath* dst, SkScalar distance, SkPathMeasure&) const override {
106         fMaker->setExtraPropertyCallBack(fDraw->fType, GetDistance, &distance);
107         SkDrawPath* drawPath = nullptr;
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, nullptr, 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
toString(SkString * str) const143     void toString(SkString* str) const override {
144         str->appendf("SkShape1DPathEffect: (");
145         // TODO: fill in
146         str->appendf(")");
147     }
148 #endif
149 
150 private:
GetContourLength(const char * token,size_t len,void * clen,SkScriptValue * value)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 
GetDistance(const char * token,size_t len,void * dist,SkScriptValue * value)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 
177 const 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 
185 DEFINE_GET_MEMBER(SkDrawShapePathEffect);
186 
SkDrawShapePathEffect()187 SkDrawShapePathEffect::SkDrawShapePathEffect() :
188     addPath(nullptr), addMatrix(nullptr), path(nullptr), fPathEffect(nullptr) {
189 }
190 
~SkDrawShapePathEffect()191 SkDrawShapePathEffect::~SkDrawShapePathEffect() {
192     SkSafeUnref(fPathEffect);
193 }
194 
addChild(SkAnimateMaker &,SkDisplayable * child)195 bool SkDrawShapePathEffect::addChild(SkAnimateMaker& , SkDisplayable* child) {
196     path = (SkDrawPath*) child;
197     return true;
198 }
199 
getPathEffect()200 SkPathEffect* SkDrawShapePathEffect::getPathEffect() {
201     fPathEffect->ref();
202     return fPathEffect;
203 }
204 
205 //////////// SkDrawShape1DPathEffect
206 
207 #if SK_USE_CONDENSED_INFO == 0
208 
209 const SkMemberInfo SkDrawShape1DPathEffect::fInfo[] = {
210     SK_MEMBER_INHERITED,
211     SK_MEMBER(phase, String),
212     SK_MEMBER(spacing, String),
213 };
214 
215 #endif
216 
217 DEFINE_GET_MEMBER(SkDrawShape1DPathEffect);
218 
SkDrawShape1DPathEffect(SkDisplayTypes type)219 SkDrawShape1DPathEffect::SkDrawShape1DPathEffect(SkDisplayTypes type) : fType(type) {
220 }
221 
~SkDrawShape1DPathEffect()222 SkDrawShape1DPathEffect::~SkDrawShape1DPathEffect() {
223 }
224 
onEndElement(SkAnimateMaker & maker)225 void SkDrawShape1DPathEffect::onEndElement(SkAnimateMaker& maker) {
226     if (addPath == nullptr || (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 
234 class SkShape2DPathEffect : public Sk2DPathEffect {
235 public:
SkShape2DPathEffect(SkDrawShape2DPathEffect * draw,SkAnimateMaker * maker,const SkMatrix & matrix)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.
getFactory() const241     Factory getFactory() const override { sk_throw(); return nullptr; }
242 
243 protected:
begin(const SkIRect & uvBounds,SkPath *) const244     void begin(const SkIRect& uvBounds, SkPath*) const override {
245         const_cast<SkShape2DPathEffect*>(this)->setUVBounds(uvBounds);
246     }
247 
next(const SkPoint & loc,int u,int v,SkPath * dst) const248     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 
252 private:
setUVBounds(const SkIRect & uvBounds)253     void setUVBounds(const SkIRect& uvBounds) {
254         fUVBounds.set(SkIntToScalar(uvBounds.fLeft), SkIntToScalar(uvBounds.fTop),
255             SkIntToScalar(uvBounds.fRight), SkIntToScalar(uvBounds.fBottom));
256     }
257 
addPath(const SkPoint & loc,int u,int v,SkPath * dst)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 == nullptr)
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());
291 clearCallBack:
292         fMaker->clearExtraPropertyCallBack(fDraw->fType);
293     }
294 
Get2D(const char * token,size_t len,void * s2D,SkScriptValue * value)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 
328 const SkMemberInfo SkDrawShape2DPathEffect::fInfo[] = {
329     SK_MEMBER_INHERITED,
330     SK_MEMBER(matrix, Matrix)
331 };
332 
333 #endif
334 
335 DEFINE_GET_MEMBER(SkDrawShape2DPathEffect);
336 
SkDrawShape2DPathEffect(SkDisplayTypes type)337 SkDrawShape2DPathEffect::SkDrawShape2DPathEffect(SkDisplayTypes type) : fType(type) {
338 }
339 
~SkDrawShape2DPathEffect()340 SkDrawShape2DPathEffect::~SkDrawShape2DPathEffect() {
341 }
342 
onEndElement(SkAnimateMaker & maker)343 void SkDrawShape2DPathEffect::onEndElement(SkAnimateMaker& maker) {
344     if (addPath == nullptr || (addPath->isPath() == false && addPath->isApply() == false) ||
345             matrix == nullptr)
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 
355 const SkMemberInfo SkDrawComposePathEffect::fInfo[] = {
356     SK_MEMBER(effect1, PathEffect),
357     SK_MEMBER(effect2, PathEffect)
358 };
359 
360 #endif
361 
362 DEFINE_GET_MEMBER(SkDrawComposePathEffect);
363 
SkDrawComposePathEffect(SkDisplayTypes type)364 SkDrawComposePathEffect::SkDrawComposePathEffect(SkDisplayTypes type) : fType(type),
365     effect1(nullptr), effect2(nullptr) {
366 }
367 
~SkDrawComposePathEffect()368 SkDrawComposePathEffect::~SkDrawComposePathEffect() {
369     delete effect1;
370     delete effect2;
371 }
372 
addChild(SkAnimateMaker &,SkDisplayable * child)373 bool SkDrawComposePathEffect::addChild(SkAnimateMaker& , SkDisplayable* child) {
374     if (effect1 == nullptr)
375         effect1 = (SkDrawPathEffect*) child;
376     else
377         effect2 = (SkDrawPathEffect*) child;
378     return true;
379 }
380 
getPathEffect()381 SkPathEffect* 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 
isPaint() const390 bool SkDrawComposePathEffect::isPaint() const {
391     return true;
392 }
393 
394 //////////// SkDrawCornerPathEffect
395 
396 #if SK_USE_CONDENSED_INFO == 0
397 
398 const SkMemberInfo SkDrawCornerPathEffect::fInfo[] = {
399     SK_MEMBER(radius, Float)
400 };
401 
402 #endif
403 
404 DEFINE_GET_MEMBER(SkDrawCornerPathEffect);
405 
SkDrawCornerPathEffect(SkDisplayTypes type)406 SkDrawCornerPathEffect::SkDrawCornerPathEffect(SkDisplayTypes type):
407     fType(type), radius(0) {
408 }
409 
~SkDrawCornerPathEffect()410 SkDrawCornerPathEffect::~SkDrawCornerPathEffect() {
411 }
412 
getPathEffect()413 SkPathEffect* SkDrawCornerPathEffect::getPathEffect() {
414     return SkCornerPathEffect::Create(radius);
415 }
416 
417 /////////
418 
419 #include "SkExtras.h"
420 
421 const char kDrawShape1DPathEffectName[] = "pathEffect:shape1D";
422 const char kDrawShape2DPathEffectName[] = "pathEffect:shape2D";
423 const char kDrawComposePathEffectName[] = "pathEffect:compose";
424 const char kDrawCornerPathEffectName[]  = "pathEffect:corner";
425 
426 class SkExtraPathEffects : public SkExtras {
427 public:
SkExtraPathEffects()428     SkExtraPathEffects() :
429             skDrawShape1DPathEffectType(SkType_Unknown),
430             skDrawShape2DPathEffectType(SkType_Unknown),
431             skDrawComposePathEffectType(SkType_Unknown),
432             skDrawCornerPathEffectType(SkType_Unknown) {
433     }
434 
createInstance(SkDisplayTypes type)435     virtual SkDisplayable* createInstance(SkDisplayTypes type) {
436         SkDisplayable* result = nullptr;
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 
definesType(SkDisplayTypes type)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
getMembers(SkDisplayTypes type,int * infoCountPtr)456     virtual const SkMemberInfo* getMembers(SkDisplayTypes type, int* infoCountPtr) {
457         const SkMemberInfo* info = nullptr;
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
getName(SkDisplayTypes type)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 nullptr;
489     }
490 #endif
491 
getType(const char name[],size_t len)492     virtual SkDisplayTypes getType(const char name[], size_t len ) {
493         SkDisplayTypes* type = nullptr;
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 
510 private:
511     SkDisplayTypes skDrawShape1DPathEffectType;
512     SkDisplayTypes skDrawShape2DPathEffectType;
513     SkDisplayTypes skDrawComposePathEffectType;
514     SkDisplayTypes skDrawCornerPathEffectType;
515 };
516 
InitializeSkExtraPathEffects(SkAnimator * animator)517 void InitializeSkExtraPathEffects(SkAnimator* animator) {
518     animator->addExtras(new SkExtraPathEffects());
519 }
520 
521 ////////////////
522 
523 
SkExtras()524 SkExtras::SkExtras() : fExtraCallBack(nullptr), fExtraStorage(nullptr) {
525 }
526