diff --git a/include/core/SkDrawLooper.h b/include/core/SkDrawLooper.h index 4609c1dcf9..65650d88e8 100644 --- a/include/core/SkDrawLooper.h +++ b/include/core/SkDrawLooper.h @@ -30,24 +30,49 @@ public: SK_DECLARE_INST_COUNT(SkDrawLooper) /** - * Called right before something is being drawn. This will be followed by - * calls to next() until next() returns false. + * Holds state during a draw. Users call next() until it returns false. + * + * Subclasses of SkDrawLooper should create a subclass of this object to + * hold state specific to their subclass. */ - virtual void init(SkCanvas*) = 0; + class SK_API Context : public SkNoncopyable { + public: + Context() {} + virtual ~Context() {} + + /** + * Called in a loop on objects returned by SkDrawLooper::createContext(). + * Each time true is returned, the object is drawn (possibly with a modified + * canvas and/or paint). When false is finally returned, drawing for the object + * stops. + * + * On each call, the paint will be in its original state, but the + * canvas will be as it was following the previous call to next() or + * createContext(). + * + * The implementation must ensure that, when next() finally returns + * false, the canvas has been restored to the state it was + * initially, before createContext() was first called. + */ + virtual bool next(SkCanvas* canvas, SkPaint* paint) = 0; + }; /** - * Called in a loop (after init()). Each time true is returned, the object - * is drawn (possibly with a modified canvas and/or paint). When false is - * finally returned, drawing for the object stops. - * - * On each call, the paint will be in its original state, but the canvas - * will be as it was following the previous call to next() or init(). - * - * The implementation must ensure that, when next() finally returns false, - * that the canvas has been restored to the state it was initially, before - * init() was first called. + * Called right before something is being drawn. Returns a Context + * whose next() method should be called until it returns false. + * The caller has to ensure that the storage pointer provides enough + * memory for the Context. The required size can be queried by calling + * contextSize(). It is also the caller's responsibility to destroy the + * object after use. */ - virtual bool next(SkCanvas*, SkPaint* paint) = 0; + virtual Context* createContext(SkCanvas*, void* storage) const = 0; + + /** + * Returns the number of bytes needed to store subclasses of Context (belonging to the + * corresponding SkDrawLooper subclass). + */ + virtual size_t contextSize() const = 0; + /** * The fast bounds functions are used to enable the paint to be culled early @@ -59,9 +84,9 @@ public: * storage rect, where the storage rect is with the union of the src rect * and the looper's bounding rect. */ - virtual bool canComputeFastBounds(const SkPaint& paint); + virtual bool canComputeFastBounds(const SkPaint& paint) const; virtual void computeFastBounds(const SkPaint& paint, - const SkRect& src, SkRect* dst); + const SkRect& src, SkRect* dst) const; SkDEVCODE(virtual void toString(SkString* str) const = 0;) SK_DEFINE_FLATTENABLE_TYPE(SkDrawLooper) diff --git a/include/effects/SkBlurDrawLooper.h b/include/effects/SkBlurDrawLooper.h index 46b154debc..9a230e59ff 100644 --- a/include/effects/SkBlurDrawLooper.h +++ b/include/effects/SkBlurDrawLooper.h @@ -43,9 +43,9 @@ public: uint32_t flags = kNone_BlurFlag); virtual ~SkBlurDrawLooper(); - // overrides from SkDrawLooper - virtual void init(SkCanvas*); - virtual bool next(SkCanvas*, SkPaint* paint); + virtual SkDrawLooper::Context* createContext(SkCanvas*, void* storage) const SK_OVERRIDE; + + virtual size_t contextSize() const SK_OVERRIDE { return sizeof(BlurDrawLooperContext); } SK_DEVELOPER_TO_STRING() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurDrawLooper) @@ -66,7 +66,17 @@ private: kAfterEdge, kDone }; - State fState; + + class BlurDrawLooperContext : public SkDrawLooper::Context { + public: + explicit BlurDrawLooperContext(const SkBlurDrawLooper* looper); + + virtual bool next(SkCanvas* canvas, SkPaint* paint) SK_OVERRIDE; + + private: + const SkBlurDrawLooper* fLooper; + State fState; + }; void init(SkScalar sigma, SkScalar dx, SkScalar dy, SkColor color, uint32_t flags); diff --git a/include/effects/SkLayerDrawLooper.h b/include/effects/SkLayerDrawLooper.h index 241b3b2494..7a13b7a7b9 100644 --- a/include/effects/SkLayerDrawLooper.h +++ b/include/effects/SkLayerDrawLooper.h @@ -94,9 +94,9 @@ public: /// Similar to addLayer, but adds a layer to the top. SkPaint* addLayerOnTop(const LayerInfo&); - // overrides from SkDrawLooper - virtual void init(SkCanvas*); - virtual bool next(SkCanvas*, SkPaint* paint); + virtual SkDrawLooper::Context* createContext(SkCanvas*, void* storage) const SK_OVERRIDE; + + virtual size_t contextSize() const SK_OVERRIDE { return sizeof(LayerDrawLooperContext); } SK_DEVELOPER_TO_STRING() @@ -118,9 +118,18 @@ private: int fCount; // state-machine during the init/next cycle - Rec* fCurrRec; + class LayerDrawLooperContext : public SkDrawLooper::Context { + public: + explicit LayerDrawLooperContext(const SkLayerDrawLooper* looper); - static void ApplyInfo(SkPaint* dst, const SkPaint& src, const LayerInfo&); + protected: + virtual bool next(SkCanvas*, SkPaint* paint) SK_OVERRIDE; + + private: + Rec* fCurrRec; + + static void ApplyInfo(SkPaint* dst, const SkPaint& src, const LayerInfo&); + }; class MyRegistrar : public SkFlattenable::Registrar { public: diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index bd75f7dbde..3b7cc5bea0 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -19,6 +19,7 @@ #include "SkPicture.h" #include "SkRasterClip.h" #include "SkRRect.h" +#include "SkSmallAllocator.h" #include "SkSurface_Base.h" #include "SkTemplates.h" #include "SkTextFormatParams.h" @@ -337,7 +338,6 @@ public: bool skipLayerForImageFilter = false, const SkRect* bounds = NULL) : fOrigPaint(paint) { fCanvas = canvas; - fLooper = paint.getLooper(); fFilter = canvas->getDrawFilter(); fPaint = NULL; fSaveCount = canvas->getSaveCount(); @@ -354,10 +354,13 @@ public: fDoClearImageFilter = true; } - if (fLooper) { - fLooper->init(canvas); + if (SkDrawLooper* looper = paint.getLooper()) { + void* buffer = fLooperContextAllocator.reserveT( + looper->contextSize()); + fLooperContext = looper->createContext(canvas, buffer); fIsSimple = false; } else { + fLooperContext = NULL; // can we be marked as simple? fIsSimple = !fFilter && !fDoClearImageFilter; } @@ -391,13 +394,14 @@ private: SkLazyPaint fLazyPaint; SkCanvas* fCanvas; const SkPaint& fOrigPaint; - SkDrawLooper* fLooper; SkDrawFilter* fFilter; const SkPaint* fPaint; int fSaveCount; bool fDoClearImageFilter; bool fDone; bool fIsSimple; + SkDrawLooper::Context* fLooperContext; + SkSmallAllocator<1, 32> fLooperContextAllocator; bool doNext(SkDrawFilter::Type drawType); }; @@ -405,7 +409,7 @@ private: bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { fPaint = NULL; SkASSERT(!fIsSimple); - SkASSERT(fLooper || fFilter || fDoClearImageFilter); + SkASSERT(fLooperContext || fFilter || fDoClearImageFilter); SkPaint* paint = fLazyPaint.set(fOrigPaint); @@ -413,7 +417,7 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { paint->setImageFilter(NULL); } - if (fLooper && !fLooper->next(fCanvas, paint)) { + if (fLooperContext && !fLooperContext->next(fCanvas, paint)) { fDone = true; return false; } @@ -422,7 +426,7 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { fDone = true; return false; } - if (NULL == fLooper) { + if (NULL == fLooperContext) { // no looper means we only draw once fDone = true; } @@ -430,7 +434,7 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { fPaint = paint; // if we only came in here for the imagefilter, mark us as done - if (!fLooper && !fFilter) { + if (!fLooperContext && !fFilter) { fDone = true; } diff --git a/src/core/SkDrawLooper.cpp b/src/core/SkDrawLooper.cpp index bac2d969c0..c620cd08da 100644 --- a/src/core/SkDrawLooper.cpp +++ b/src/core/SkDrawLooper.cpp @@ -10,14 +10,17 @@ #include "SkMatrix.h" #include "SkPaint.h" #include "SkRect.h" +#include "SkSmallAllocator.h" -bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) { +bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) const { SkCanvas canvas; + SkSmallAllocator<1, 32> allocator; + void* buffer = allocator.reserveT(this->contextSize()); - this->init(&canvas); + SkDrawLooper::Context* context = this->createContext(&canvas, buffer); for (;;) { SkPaint p(paint); - if (this->next(&canvas, &p)) { + if (context->next(&canvas, &p)) { p.setLooper(NULL); if (!p.canComputeFastBounds()) { return false; @@ -30,14 +33,16 @@ bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) { } void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& src, - SkRect* dst) { + SkRect* dst) const { SkCanvas canvas; + SkSmallAllocator<1, 32> allocator; + void* buffer = allocator.reserveT(this->contextSize()); *dst = src; // catch case where there are no loops - this->init(&canvas); + SkDrawLooper::Context* context = this->createContext(&canvas, buffer); for (bool firstTime = true;; firstTime = false) { SkPaint p(paint); - if (this->next(&canvas, &p)) { + if (context->next(&canvas, &p)) { SkRect r(src); p.setLooper(NULL); diff --git a/src/core/SkSmallAllocator.h b/src/core/SkSmallAllocator.h index d5ebf3b7d4..2eddb510cd 100644 --- a/src/core/SkSmallAllocator.h +++ b/src/core/SkSmallAllocator.h @@ -96,20 +96,21 @@ public: return static_cast(buf); } -private: /* - * Helper function to provide space for one T. The space will be in - * fStorage if there is room, or on the heap otherwise. Either way, this - * class will call ~T() in its destructor and free the heap allocation if - * necessary. + * Reserve a specified amount of space (must be enough space for one T). + * The space will be in fStorage if there is room, or on the heap otherwise. + * Either way, this class will call ~T() in its destructor and free the heap + * allocation if necessary. + * Unlike createT(), this method will not call the constructor of T. */ - template void* reserveT() { + template void* reserveT(size_t storageRequired = sizeof(T)) { SkASSERT(fNumObjects < kMaxObjects); + SkASSERT(storageRequired >= sizeof(T)); if (kMaxObjects == fNumObjects) { return NULL; } const size_t storageRemaining = SkAlign4(kTotalBytes) - fStorageUsed; - const size_t storageRequired = SkAlign4(sizeof(T)); + storageRequired = SkAlign4(storageRequired); Rec* rec = &fRecs[fNumObjects]; if (storageRequired > storageRemaining) { // Allocate on the heap. Ideally we want to avoid this situation, diff --git a/src/effects/SkBlurDrawLooper.cpp b/src/effects/SkBlurDrawLooper.cpp index 3a5c697371..0bbc184049 100644 --- a/src/effects/SkBlurDrawLooper.cpp +++ b/src/effects/SkBlurDrawLooper.cpp @@ -33,7 +33,6 @@ void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy, fDy = dy; fBlurColor = color; fBlurFlags = flags; - fState = kDone; SkASSERT(flags <= kAll_BlurFlag); if (sigma > 0) { @@ -90,11 +89,16 @@ void SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const { buffer.writeUInt(fBlurFlags); } -void SkBlurDrawLooper::init(SkCanvas*) { - fState = kBeforeEdge; +SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const { + return SkNEW_PLACEMENT_ARGS(storage, BlurDrawLooperContext, (this)); } -bool SkBlurDrawLooper::next(SkCanvas* canvas, SkPaint* paint) { +SkBlurDrawLooper::BlurDrawLooperContext::BlurDrawLooperContext( + const SkBlurDrawLooper* looper) + : fLooper(looper), fState(SkBlurDrawLooper::kBeforeEdge) {} + +bool SkBlurDrawLooper::BlurDrawLooperContext::next(SkCanvas* canvas, + SkPaint* paint) { switch (fState) { case kBeforeEdge: // we do nothing if a maskfilter is already installed @@ -104,23 +108,23 @@ bool SkBlurDrawLooper::next(SkCanvas* canvas, SkPaint* paint) { } #ifdef SK_BUILD_FOR_ANDROID SkColor blurColor; - blurColor = fBlurColor; + blurColor = fLooper->fBlurColor; if (SkColorGetA(blurColor) == 255) { blurColor = SkColorSetA(blurColor, paint->getAlpha()); } paint->setColor(blurColor); #else - paint->setColor(fBlurColor); + paint->setColor(fLooper->fBlurColor); #endif - paint->setMaskFilter(fBlur); - paint->setColorFilter(fColorFilter); + paint->setMaskFilter(fLooper->fBlur); + paint->setColorFilter(fLooper->fColorFilter); canvas->save(SkCanvas::kMatrix_SaveFlag); - if (fBlurFlags & kIgnoreTransform_BlurFlag) { + if (fLooper->fBlurFlags & kIgnoreTransform_BlurFlag) { SkMatrix transform(canvas->getTotalMatrix()); - transform.postTranslate(fDx, fDy); + transform.postTranslate(fLooper->fDx, fLooper->fDy); canvas->setMatrix(transform); } else { - canvas->translate(fDx, fDy); + canvas->translate(fLooper->fDx, fLooper->fDy); } fState = kAfterEdge; return true; diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp index cfe673db92..6d31c23a06 100644 --- a/src/effects/SkLayerDrawLooper.cpp +++ b/src/effects/SkLayerDrawLooper.cpp @@ -24,8 +24,7 @@ SkLayerDrawLooper::LayerInfo::LayerInfo() { SkLayerDrawLooper::SkLayerDrawLooper() : fRecs(NULL), fTopRec(NULL), - fCount(0), - fCurrRec(NULL) { + fCount(0) { } SkLayerDrawLooper::~SkLayerDrawLooper() { @@ -75,9 +74,9 @@ SkPaint* SkLayerDrawLooper::addLayerOnTop(const LayerInfo& info) { return &rec->fPaint; } -void SkLayerDrawLooper::init(SkCanvas* canvas) { - fCurrRec = fRecs; +SkLayerDrawLooper::Context* SkLayerDrawLooper::createContext(SkCanvas* canvas, void* storage) const { canvas->save(SkCanvas::kMatrix_SaveFlag); + return SkNEW_PLACEMENT_ARGS(storage, LayerDrawLooperContext, (this)); } static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) { @@ -98,8 +97,8 @@ static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) { // Even with kEntirePaint_Bits, we always ensure that the master paint's // text-encoding is respected, since that controls how we interpret the // text/length parameters of a draw[Pos]Text call. -void SkLayerDrawLooper::ApplyInfo(SkPaint* dst, const SkPaint& src, - const LayerInfo& info) { +void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo( + SkPaint* dst, const SkPaint& src, const LayerInfo& info) { dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode)); @@ -167,7 +166,11 @@ static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) { canvas->setMatrix(m); } -bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) { +SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext( + const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {} + +bool SkLayerDrawLooper::LayerDrawLooperContext::next(SkCanvas* canvas, + SkPaint* paint) { canvas->restore(); if (NULL == fCurrRec) { return false; @@ -180,7 +183,8 @@ bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) { postTranslate(canvas, fCurrRec->fInfo.fOffset.fX, fCurrRec->fInfo.fOffset.fY); } else { - canvas->translate(fCurrRec->fInfo.fOffset.fX, fCurrRec->fInfo.fOffset.fY); + canvas->translate(fCurrRec->fInfo.fOffset.fX, + fCurrRec->fInfo.fOffset.fY); } fCurrRec = fCurrRec->fNext; diff --git a/tests/LayerDrawLooperTest.cpp b/tests/LayerDrawLooperTest.cpp index 68dd5e06e7..1facb23b51 100644 --- a/tests/LayerDrawLooperTest.cpp +++ b/tests/LayerDrawLooperTest.cpp @@ -15,6 +15,7 @@ #include "SkRect.h" #include "SkRefCnt.h" #include "SkScalar.h" +#include "SkSmallAllocator.h" #include "SkXfermode.h" #include "Test.h" @@ -57,10 +58,12 @@ static void test_frontToBack(skiatest::Reporter* reporter) { SkCanvas canvas(&device); SkPaint paint; SkAutoTUnref looper(looperBuilder.detachLooper()); - looper->init(&canvas); + SkSmallAllocator<1, 32> allocator; + void* buffer = allocator.reserveT(looper->contextSize()); + SkDrawLooper::Context* context = looper->createContext(&canvas, buffer); // The back layer should come first. - REPORTER_ASSERT(reporter, looper->next(&canvas, &paint)); + REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode)); canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX()); @@ -68,14 +71,14 @@ static void test_frontToBack(skiatest::Reporter* reporter) { paint.reset(); // Then the front layer. - REPORTER_ASSERT(reporter, looper->next(&canvas, &paint)); + REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)); canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX()); REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY()); // Only two layers were added, so that should be the end. - REPORTER_ASSERT(reporter, !looper->next(&canvas, &paint)); + REPORTER_ASSERT(reporter, !context->next(&canvas, &paint)); } static void test_backToFront(skiatest::Reporter* reporter) { @@ -95,10 +98,12 @@ static void test_backToFront(skiatest::Reporter* reporter) { SkCanvas canvas(&device); SkPaint paint; SkAutoTUnref looper(looperBuilder.detachLooper()); - looper->init(&canvas); + SkSmallAllocator<1, 32> allocator; + void* buffer = allocator.reserveT(looper->contextSize()); + SkDrawLooper::Context* context = looper->createContext(&canvas, buffer); // The back layer should come first. - REPORTER_ASSERT(reporter, looper->next(&canvas, &paint)); + REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)); canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX()); @@ -106,14 +111,14 @@ static void test_backToFront(skiatest::Reporter* reporter) { paint.reset(); // Then the front layer. - REPORTER_ASSERT(reporter, looper->next(&canvas, &paint)); + REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode)); canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX()); REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY()); // Only two layers were added, so that should be the end. - REPORTER_ASSERT(reporter, !looper->next(&canvas, &paint)); + REPORTER_ASSERT(reporter, !context->next(&canvas, &paint)); } static void test_mixed(skiatest::Reporter* reporter) { @@ -133,10 +138,12 @@ static void test_mixed(skiatest::Reporter* reporter) { SkCanvas canvas(&device); SkPaint paint; SkAutoTUnref looper(looperBuilder.detachLooper()); - looper->init(&canvas); + SkSmallAllocator<1, 32> allocator; + void* buffer = allocator.reserveT(looper->contextSize()); + SkDrawLooper::Context* context = looper->createContext(&canvas, buffer); // The back layer should come first. - REPORTER_ASSERT(reporter, looper->next(&canvas, &paint)); + REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)); canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX()); @@ -144,14 +151,14 @@ static void test_mixed(skiatest::Reporter* reporter) { paint.reset(); // Then the front layer. - REPORTER_ASSERT(reporter, looper->next(&canvas, &paint)); + REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode)); canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX()); REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY()); // Only two layers were added, so that should be the end. - REPORTER_ASSERT(reporter, !looper->next(&canvas, &paint)); + REPORTER_ASSERT(reporter, !context->next(&canvas, &paint)); } DEF_TEST(LayerDrawLooper, reporter) { diff --git a/tests/QuickRejectTest.cpp b/tests/QuickRejectTest.cpp index 2d367389bb..ef145525e9 100644 --- a/tests/QuickRejectTest.cpp +++ b/tests/QuickRejectTest.cpp @@ -7,6 +7,7 @@ #include "SkCanvas.h" #include "SkDrawLooper.h" +#include "SkTypes.h" #include "Test.h" /* @@ -14,20 +15,12 @@ */ class TestLooper : public SkDrawLooper { public: - bool fOnce; - virtual void init(SkCanvas*) SK_OVERRIDE { - fOnce = true; + virtual SkDrawLooper::Context* createContext(SkCanvas*, void* storage) const SK_OVERRIDE { + return SkNEW_PLACEMENT(storage, TestDrawLooperContext); } - virtual bool next(SkCanvas* canvas, SkPaint*) SK_OVERRIDE { - if (fOnce) { - fOnce = false; - canvas->translate(SkIntToScalar(10), 0); - return true; - } - return false; - } + virtual size_t contextSize() const SK_OVERRIDE { return sizeof(TestDrawLooperContext); } #ifdef SK_DEVELOPER virtual void toString(SkString* str) const SK_OVERRIDE { @@ -35,6 +28,24 @@ public: } #endif +private: + class TestDrawLooperContext : public SkDrawLooper::Context { + public: + TestDrawLooperContext() : fOnce(true) {} + virtual ~TestDrawLooperContext() {} + + virtual bool next(SkCanvas* canvas, SkPaint*) SK_OVERRIDE { + if (fOnce) { + fOnce = false; + canvas->translate(SkIntToScalar(10), 0); + return true; + } + return false; + } + private: + bool fOnce; + }; + SK_DECLARE_UNFLATTENABLE_OBJECT() };