| /* | |
| * Copyright 2006 The Android Open Source Project | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "SkDrawExtraPathEffect.h" | |
| #include "SkDrawPath.h" | |
| #include "Sk1DPathEffect.h" | |
| #include "Sk2DPathEffect.h" | |
| #include "SkMemberInfo.h" | |
| #include "SkPaintPart.h" | |
| #include "SkPathEffect.h" | |
| #include "SkCornerPathEffect.h" | |
| #include "SkDashPathEffect.h" | |
| class SkDrawShapePathEffect : public SkDrawPathEffect { | |
| DECLARE_PRIVATE_MEMBER_INFO(DrawShapePathEffect); | |
| SkDrawShapePathEffect(); | |
| virtual ~SkDrawShapePathEffect(); | |
| bool addChild(SkAnimateMaker& , SkDisplayable* ) override; | |
| SkPathEffect* getPathEffect() override; | |
| protected: | |
| SkADrawable* addPath; | |
| SkADrawable* addMatrix; | |
| SkDrawPath* path; | |
| SkPathEffect* fPathEffect; | |
| friend class SkShape1DPathEffect; | |
| friend class SkShape2DPathEffect; | |
| }; | |
| class SkDrawShape1DPathEffect : public SkDrawShapePathEffect { | |
| DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape1DPathEffect); | |
| SkDrawShape1DPathEffect(SkDisplayTypes ); | |
| virtual ~SkDrawShape1DPathEffect(); | |
| void onEndElement(SkAnimateMaker& ) override; | |
| private: | |
| SkString phase; | |
| SkString spacing; | |
| friend class SkShape1DPathEffect; | |
| typedef SkDrawShapePathEffect INHERITED; | |
| }; | |
| class SkDrawShape2DPathEffect : public SkDrawShapePathEffect { | |
| DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape2DPathEffect); | |
| SkDrawShape2DPathEffect(SkDisplayTypes ); | |
| virtual ~SkDrawShape2DPathEffect(); | |
| void onEndElement(SkAnimateMaker& ) override; | |
| private: | |
| SkDrawMatrix* matrix; | |
| friend class SkShape2DPathEffect; | |
| typedef SkDrawShapePathEffect INHERITED; | |
| }; | |
| class SkDrawComposePathEffect : public SkDrawPathEffect { | |
| DECLARE_EXTRAS_MEMBER_INFO(SkDrawComposePathEffect); | |
| SkDrawComposePathEffect(SkDisplayTypes ); | |
| virtual ~SkDrawComposePathEffect(); | |
| bool addChild(SkAnimateMaker& , SkDisplayable* ) override; | |
| SkPathEffect* getPathEffect() override; | |
| bool isPaint() const override; | |
| private: | |
| SkDrawPathEffect* effect1; | |
| SkDrawPathEffect* effect2; | |
| }; | |
| class SkDrawCornerPathEffect : public SkDrawPathEffect { | |
| DECLARE_EXTRAS_MEMBER_INFO(SkDrawCornerPathEffect); | |
| SkDrawCornerPathEffect(SkDisplayTypes ); | |
| virtual ~SkDrawCornerPathEffect(); | |
| SkPathEffect* getPathEffect() override; | |
| private: | |
| SkScalar radius; | |
| }; | |
| //////////// SkShape1DPathEffect | |
| #include "SkAnimateMaker.h" | |
| #include "SkAnimatorScript.h" | |
| #include "SkDisplayApply.h" | |
| #include "SkDrawMatrix.h" | |
| #include "SkPaint.h" | |
| class SkShape1DPathEffect : public Sk1DPathEffect { | |
| public: | |
| SkShape1DPathEffect(SkDrawShape1DPathEffect* draw, SkAnimateMaker* maker) : | |
| fDraw(draw), fMaker(maker) { | |
| } | |
| // For serialization. This will never be called. | |
| Factory getFactory() const override { sk_throw(); return nullptr; } | |
| protected: | |
| SkScalar begin(SkScalar contourLength) const override { | |
| SkScriptValue value; | |
| SkAnimatorScript engine(*fMaker, nullptr, SkType_Float); | |
| engine.propertyCallBack(GetContourLength, &contourLength); | |
| value.fOperand.fScalar = 0; | |
| engine.evaluate(fDraw->phase.c_str(), &value, SkType_Float); | |
| return value.fOperand.fScalar; | |
| } | |
| SkScalar next(SkPath* dst, SkScalar distance, SkPathMeasure&) const override { | |
| fMaker->setExtraPropertyCallBack(fDraw->fType, GetDistance, &distance); | |
| SkDrawPath* drawPath = nullptr; | |
| if (fDraw->addPath->isPath()) { | |
| drawPath = (SkDrawPath*) fDraw->addPath; | |
| } else { | |
| SkApply* apply = (SkApply*) fDraw->addPath; | |
| apply->refresh(*fMaker); | |
| apply->activate(*fMaker); | |
| apply->interpolate(*fMaker, SkScalarRoundToInt(distance * 1000)); | |
| drawPath = (SkDrawPath*) apply->getScope(); | |
| } | |
| SkMatrix m; | |
| m.reset(); | |
| if (fDraw->addMatrix) { | |
| SkDrawMatrix* matrix; | |
| if (fDraw->addMatrix->getType() == SkType_Matrix) | |
| matrix = (SkDrawMatrix*) fDraw->addMatrix; | |
| else { | |
| SkApply* apply = (SkApply*) fDraw->addMatrix; | |
| apply->refresh(*fMaker); | |
| apply->activate(*fMaker); | |
| apply->interpolate(*fMaker, SkScalarRoundToInt(distance * 1000)); | |
| matrix = (SkDrawMatrix*) apply->getScope(); | |
| } | |
| if (matrix) { | |
| m = matrix->getMatrix(); | |
| } | |
| } | |
| SkScalar result = 0; | |
| SkAnimatorScript::EvaluateFloat(*fMaker, nullptr, fDraw->spacing.c_str(), &result); | |
| if (drawPath) | |
| dst->addPath(drawPath->getPath(), m); | |
| fMaker->clearExtraPropertyCallBack(fDraw->fType); | |
| return result; | |
| } | |
| #ifndef SK_IGNORE_TO_STRING | |
| void toString(SkString* str) const override { | |
| str->appendf("SkShape1DPathEffect: ("); | |
| // TODO: fill in | |
| str->appendf(")"); | |
| } | |
| #endif | |
| private: | |
| static bool GetContourLength(const char* token, size_t len, void* clen, SkScriptValue* value) { | |
| if (SK_LITERAL_STR_EQUAL("contourLength", token, len)) { | |
| value->fOperand.fScalar = *(SkScalar*) clen; | |
| value->fType = SkType_Float; | |
| return true; | |
| } | |
| return false; | |
| } | |
| static bool GetDistance(const char* token, size_t len, void* dist, SkScriptValue* value) { | |
| if (SK_LITERAL_STR_EQUAL("distance", token, len)) { | |
| value->fOperand.fScalar = *(SkScalar*) dist; | |
| value->fType = SkType_Float; | |
| return true; | |
| } | |
| return false; | |
| } | |
| SkDrawShape1DPathEffect* fDraw; | |
| SkAnimateMaker* fMaker; | |
| }; | |
| //////////// SkDrawShapePathEffect | |
| #if SK_USE_CONDENSED_INFO == 0 | |
| const SkMemberInfo SkDrawShapePathEffect::fInfo[] = { | |
| SK_MEMBER(addMatrix, Drawable), // either matrix or apply | |
| SK_MEMBER(addPath, Drawable), // either path or apply | |
| SK_MEMBER(path, Path), | |
| }; | |
| #endif | |
| DEFINE_GET_MEMBER(SkDrawShapePathEffect); | |
| SkDrawShapePathEffect::SkDrawShapePathEffect() : | |
| addPath(nullptr), addMatrix(nullptr), path(nullptr), fPathEffect(nullptr) { | |
| } | |
| SkDrawShapePathEffect::~SkDrawShapePathEffect() { | |
| SkSafeUnref(fPathEffect); | |
| } | |
| bool SkDrawShapePathEffect::addChild(SkAnimateMaker& , SkDisplayable* child) { | |
| path = (SkDrawPath*) child; | |
| return true; | |
| } | |
| SkPathEffect* SkDrawShapePathEffect::getPathEffect() { | |
| fPathEffect->ref(); | |
| return fPathEffect; | |
| } | |
| //////////// SkDrawShape1DPathEffect | |
| #if SK_USE_CONDENSED_INFO == 0 | |
| const SkMemberInfo SkDrawShape1DPathEffect::fInfo[] = { | |
| SK_MEMBER_INHERITED, | |
| SK_MEMBER(phase, String), | |
| SK_MEMBER(spacing, String), | |
| }; | |
| #endif | |
| DEFINE_GET_MEMBER(SkDrawShape1DPathEffect); | |
| SkDrawShape1DPathEffect::SkDrawShape1DPathEffect(SkDisplayTypes type) : fType(type) { | |
| } | |
| SkDrawShape1DPathEffect::~SkDrawShape1DPathEffect() { | |
| } | |
| void SkDrawShape1DPathEffect::onEndElement(SkAnimateMaker& maker) { | |
| if (addPath == nullptr || (addPath->isPath() == false && addPath->isApply() == false)) | |
| maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error | |
| else | |
| fPathEffect = new SkShape1DPathEffect(this, &maker); | |
| } | |
| ////////// SkShape2DPathEffect | |
| class SkShape2DPathEffect : public Sk2DPathEffect { | |
| public: | |
| SkShape2DPathEffect(SkDrawShape2DPathEffect* draw, SkAnimateMaker* maker, | |
| const SkMatrix& matrix) : Sk2DPathEffect(matrix), fDraw(draw), fMaker(maker) { | |
| } | |
| // For serialization. This will never be called. | |
| Factory getFactory() const override { sk_throw(); return nullptr; } | |
| protected: | |
| void begin(const SkIRect& uvBounds, SkPath*) const override { | |
| const_cast<SkShape2DPathEffect*>(this)->setUVBounds(uvBounds); | |
| } | |
| void next(const SkPoint& loc, int u, int v, SkPath* dst) const override { | |
| const_cast<SkShape2DPathEffect*>(this)->addPath(loc, u, v, dst); | |
| } | |
| private: | |
| void setUVBounds(const SkIRect& uvBounds) { | |
| fUVBounds.set(SkIntToScalar(uvBounds.fLeft), SkIntToScalar(uvBounds.fTop), | |
| SkIntToScalar(uvBounds.fRight), SkIntToScalar(uvBounds.fBottom)); | |
| } | |
| void addPath(const SkPoint& loc, int u, int v, SkPath* dst) { | |
| fLoc = loc; | |
| fU = u; | |
| fV = v; | |
| SkDrawPath* drawPath; | |
| fMaker->setExtraPropertyCallBack(fDraw->fType, Get2D, this); | |
| if (fDraw->addPath->isPath()) { | |
| drawPath = (SkDrawPath*) fDraw->addPath; | |
| } else { | |
| SkApply* apply = (SkApply*) fDraw->addPath; | |
| apply->refresh(*fMaker); | |
| apply->activate(*fMaker); | |
| apply->interpolate(*fMaker, v); | |
| drawPath = (SkDrawPath*) apply->getScope(); | |
| } | |
| if (drawPath == nullptr) | |
| goto clearCallBack; | |
| if (fDraw->matrix) { | |
| SkDrawMatrix* matrix; | |
| if (fDraw->matrix->getType() == SkType_Matrix) | |
| matrix = (SkDrawMatrix*) fDraw->matrix; | |
| else { | |
| SkApply* apply = (SkApply*) fDraw->matrix; | |
| apply->activate(*fMaker); | |
| apply->interpolate(*fMaker, v); | |
| matrix = (SkDrawMatrix*) apply->getScope(); | |
| } | |
| if (matrix) { | |
| dst->addPath(drawPath->getPath(), matrix->getMatrix()); | |
| goto clearCallBack; | |
| } | |
| } | |
| dst->addPath(drawPath->getPath()); | |
| clearCallBack: | |
| fMaker->clearExtraPropertyCallBack(fDraw->fType); | |
| } | |
| static bool Get2D(const char* token, size_t len, void* s2D, SkScriptValue* value) { | |
| static const char match[] = "locX|locY|left|top|right|bottom|u|v" ; | |
| SkShape2DPathEffect* shape2D = (SkShape2DPathEffect*) s2D; | |
| int index; | |
| if (SkAnimatorScript::MapEnums(match, token, len, &index) == false) | |
| return false; | |
| SkASSERT((sizeof(SkPoint) + sizeof(SkRect)) / sizeof(SkScalar) == 6); | |
| if (index < 6) { | |
| value->fType = SkType_Float; | |
| value->fOperand.fScalar = (&shape2D->fLoc.fX)[index]; | |
| } else { | |
| value->fType = SkType_Int; | |
| value->fOperand.fS32 = (&shape2D->fU)[index - 6]; | |
| } | |
| return true; | |
| } | |
| SkPoint fLoc; | |
| SkRect fUVBounds; | |
| int32_t fU; | |
| int32_t fV; | |
| SkDrawShape2DPathEffect* fDraw; | |
| SkAnimateMaker* fMaker; | |
| // illegal | |
| SkShape2DPathEffect(const SkShape2DPathEffect&); | |
| SkShape2DPathEffect& operator=(const SkShape2DPathEffect&); | |
| }; | |
| ////////// SkDrawShape2DPathEffect | |
| #if SK_USE_CONDENSED_INFO == 0 | |
| const SkMemberInfo SkDrawShape2DPathEffect::fInfo[] = { | |
| SK_MEMBER_INHERITED, | |
| SK_MEMBER(matrix, Matrix) | |
| }; | |
| #endif | |
| DEFINE_GET_MEMBER(SkDrawShape2DPathEffect); | |
| SkDrawShape2DPathEffect::SkDrawShape2DPathEffect(SkDisplayTypes type) : fType(type) { | |
| } | |
| SkDrawShape2DPathEffect::~SkDrawShape2DPathEffect() { | |
| } | |
| void SkDrawShape2DPathEffect::onEndElement(SkAnimateMaker& maker) { | |
| if (addPath == nullptr || (addPath->isPath() == false && addPath->isApply() == false) || | |
| matrix == nullptr) | |
| maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error | |
| else | |
| fPathEffect = new SkShape2DPathEffect(this, &maker, matrix->getMatrix()); | |
| } | |
| ////////// SkDrawComposePathEffect | |
| #if SK_USE_CONDENSED_INFO == 0 | |
| const SkMemberInfo SkDrawComposePathEffect::fInfo[] = { | |
| SK_MEMBER(effect1, PathEffect), | |
| SK_MEMBER(effect2, PathEffect) | |
| }; | |
| #endif | |
| DEFINE_GET_MEMBER(SkDrawComposePathEffect); | |
| SkDrawComposePathEffect::SkDrawComposePathEffect(SkDisplayTypes type) : fType(type), | |
| effect1(nullptr), effect2(nullptr) { | |
| } | |
| SkDrawComposePathEffect::~SkDrawComposePathEffect() { | |
| delete effect1; | |
| delete effect2; | |
| } | |
| bool SkDrawComposePathEffect::addChild(SkAnimateMaker& , SkDisplayable* child) { | |
| if (effect1 == nullptr) | |
| effect1 = (SkDrawPathEffect*) child; | |
| else | |
| effect2 = (SkDrawPathEffect*) child; | |
| return true; | |
| } | |
| SkPathEffect* SkDrawComposePathEffect::getPathEffect() { | |
| SkPathEffect* e1 = effect1->getPathEffect(); | |
| SkPathEffect* e2 = effect2->getPathEffect(); | |
| SkPathEffect* composite = SkComposePathEffect::Create(e1, e2); | |
| e1->unref(); | |
| e2->unref(); | |
| return composite; | |
| } | |
| bool SkDrawComposePathEffect::isPaint() const { | |
| return true; | |
| } | |
| //////////// SkDrawCornerPathEffect | |
| #if SK_USE_CONDENSED_INFO == 0 | |
| const SkMemberInfo SkDrawCornerPathEffect::fInfo[] = { | |
| SK_MEMBER(radius, Float) | |
| }; | |
| #endif | |
| DEFINE_GET_MEMBER(SkDrawCornerPathEffect); | |
| SkDrawCornerPathEffect::SkDrawCornerPathEffect(SkDisplayTypes type): | |
| fType(type), radius(0) { | |
| } | |
| SkDrawCornerPathEffect::~SkDrawCornerPathEffect() { | |
| } | |
| SkPathEffect* SkDrawCornerPathEffect::getPathEffect() { | |
| return SkCornerPathEffect::Create(radius); | |
| } | |
| ///////// | |
| #include "SkExtras.h" | |
| const char kDrawShape1DPathEffectName[] = "pathEffect:shape1D"; | |
| const char kDrawShape2DPathEffectName[] = "pathEffect:shape2D"; | |
| const char kDrawComposePathEffectName[] = "pathEffect:compose"; | |
| const char kDrawCornerPathEffectName[] = "pathEffect:corner"; | |
| class SkExtraPathEffects : public SkExtras { | |
| public: | |
| SkExtraPathEffects() : | |
| skDrawShape1DPathEffectType(SkType_Unknown), | |
| skDrawShape2DPathEffectType(SkType_Unknown), | |
| skDrawComposePathEffectType(SkType_Unknown), | |
| skDrawCornerPathEffectType(SkType_Unknown) { | |
| } | |
| virtual SkDisplayable* createInstance(SkDisplayTypes type) { | |
| SkDisplayable* result = nullptr; | |
| if (skDrawShape1DPathEffectType == type) | |
| result = new SkDrawShape1DPathEffect(type); | |
| else if (skDrawShape2DPathEffectType == type) | |
| result = new SkDrawShape2DPathEffect(type); | |
| else if (skDrawComposePathEffectType == type) | |
| result = new SkDrawComposePathEffect(type); | |
| else if (skDrawCornerPathEffectType == type) | |
| result = new SkDrawCornerPathEffect(type); | |
| return result; | |
| } | |
| virtual bool definesType(SkDisplayTypes type) { | |
| return type == skDrawShape1DPathEffectType || | |
| type == skDrawShape2DPathEffectType || | |
| type == skDrawComposePathEffectType || | |
| type == skDrawCornerPathEffectType; | |
| } | |
| #if SK_USE_CONDENSED_INFO == 0 | |
| virtual const SkMemberInfo* getMembers(SkDisplayTypes type, int* infoCountPtr) { | |
| const SkMemberInfo* info = nullptr; | |
| int infoCount = 0; | |
| if (skDrawShape1DPathEffectType == type) { | |
| info = SkDrawShape1DPathEffect::fInfo; | |
| infoCount = SkDrawShape1DPathEffect::fInfoCount; | |
| } else if (skDrawShape2DPathEffectType == type) { | |
| info = SkDrawShape2DPathEffect::fInfo; | |
| infoCount = SkDrawShape2DPathEffect::fInfoCount; | |
| } else if (skDrawComposePathEffectType == type) { | |
| info = SkDrawComposePathEffect::fInfo; | |
| infoCount = SkDrawShape1DPathEffect::fInfoCount; | |
| } else if (skDrawCornerPathEffectType == type) { | |
| info = SkDrawCornerPathEffect::fInfo; | |
| infoCount = SkDrawCornerPathEffect::fInfoCount; | |
| } | |
| if (infoCountPtr) | |
| *infoCountPtr = infoCount; | |
| return info; | |
| } | |
| #endif | |
| #ifdef SK_DEBUG | |
| virtual const char* getName(SkDisplayTypes type) { | |
| if (skDrawShape1DPathEffectType == type) | |
| return kDrawShape1DPathEffectName; | |
| else if (skDrawShape2DPathEffectType == type) | |
| return kDrawShape2DPathEffectName; | |
| else if (skDrawComposePathEffectType == type) | |
| return kDrawComposePathEffectName; | |
| else if (skDrawCornerPathEffectType == type) | |
| return kDrawCornerPathEffectName; | |
| return nullptr; | |
| } | |
| #endif | |
| virtual SkDisplayTypes getType(const char name[], size_t len ) { | |
| SkDisplayTypes* type = nullptr; | |
| if (SK_LITERAL_STR_EQUAL(kDrawShape1DPathEffectName, name, len)) | |
| type = &skDrawShape1DPathEffectType; | |
| else if (SK_LITERAL_STR_EQUAL(kDrawShape2DPathEffectName, name, len)) | |
| type = &skDrawShape2DPathEffectType; | |
| else if (SK_LITERAL_STR_EQUAL(kDrawComposePathEffectName, name, len)) | |
| type = &skDrawComposePathEffectType; | |
| else if (SK_LITERAL_STR_EQUAL(kDrawCornerPathEffectName, name, len)) | |
| type = &skDrawCornerPathEffectType; | |
| if (type) { | |
| if (*type == SkType_Unknown) | |
| *type = SkDisplayType::RegisterNewType(); | |
| return *type; | |
| } | |
| return SkType_Unknown; | |
| } | |
| private: | |
| SkDisplayTypes skDrawShape1DPathEffectType; | |
| SkDisplayTypes skDrawShape2DPathEffectType; | |
| SkDisplayTypes skDrawComposePathEffectType; | |
| SkDisplayTypes skDrawCornerPathEffectType; | |
| }; | |
| void InitializeSkExtraPathEffects(SkAnimator* animator) { | |
| animator->addExtras(new SkExtraPathEffects()); | |
| } | |
| //////////////// | |
| SkExtras::SkExtras() : fExtraCallBack(nullptr), fExtraStorage(nullptr) { | |
| } |