diff --git a/include/effects/SkLayerDrawLooper.h b/include/effects/SkLayerDrawLooper.h index 6955192b53..e1fae57cb8 100644 --- a/include/effects/SkLayerDrawLooper.h +++ b/include/effects/SkLayerDrawLooper.h @@ -107,10 +107,12 @@ public: virtual bool next(SkCanvas*, SkPaint* paint); SK_DEVELOPER_TO_STRING() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLayerDrawLooper) + + /// Implements Flattenable. + virtual Factory getFactory() const SK_OVERRIDE { return CreateProc; } + static SkFlattenable* CreateProc(SkReadBuffer& buffer); protected: - SkLayerDrawLooper(SkReadBuffer&); virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; private: @@ -134,6 +136,44 @@ private: }; typedef SkDrawLooper INHERITED; + +public: + class SK_API Builder { + public: + Builder(); + ~Builder(); + + /** + * Call for each layer you want to add (from top to bottom). + * This returns a paint you can modify, but that ptr is only valid until + * the next call made to addLayer(). + */ + SkPaint* addLayer(const LayerInfo&); + + /** + * This layer will draw with the original paint, at the specified offset + */ + void addLayer(SkScalar dx, SkScalar dy); + + /** + * This layer will with the original paint and no offset. + */ + void addLayer() { this->addLayer(0, 0); } + + /// Similar to addLayer, but adds a layer to the top. + SkPaint* addLayerOnTop(const LayerInfo&); + + /** + * Pass list of layers on to newly built looper and return it. This will + * also reset the builder, so it can be used to build another looper. + */ + SkLayerDrawLooper* detachLooper(); + + private: + Rec* fRecs; + Rec* fTopRec; + int fCount; + }; }; #endif diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp index 6c7c3cef0c..49263fbbb5 100644 --- a/src/effects/SkLayerDrawLooper.cpp +++ b/src/effects/SkLayerDrawLooper.cpp @@ -221,14 +221,10 @@ void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const { } } -SkLayerDrawLooper::SkLayerDrawLooper(SkReadBuffer& buffer) - : INHERITED(buffer), - fRecs(NULL), - fTopRec(NULL), - fCount(0), - fCurrRec(NULL) { +SkFlattenable* SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) { int count = buffer.readInt(); + Builder builder; for (int i = 0; i < count; i++) { LayerInfo info; info.fFlagsMask = buffer.readInt(); @@ -236,13 +232,14 @@ SkLayerDrawLooper::SkLayerDrawLooper(SkReadBuffer& buffer) info.fColorMode = (SkXfermode::Mode)buffer.readInt(); buffer.readPoint(&info.fOffset); info.fPostTranslate = buffer.readBool(); - buffer.readPaint(this->addLayerOnTop(info)); + buffer.readPaint(builder.addLayerOnTop(info)); } - SkASSERT(count == fCount); + SkLayerDrawLooper* looper = builder.detachLooper(); + SkASSERT(count == looper->fCount); #ifdef SK_DEBUG { - Rec* rec = fRecs; + Rec* rec = looper->fRecs; int n = 0; while (rec) { rec = rec->fNext; @@ -251,6 +248,8 @@ SkLayerDrawLooper::SkLayerDrawLooper(SkReadBuffer& buffer) SkASSERT(count == n); } #endif + + return looper; } #ifdef SK_DEVELOPER @@ -347,3 +346,68 @@ void SkLayerDrawLooper::toString(SkString* str) const { } } #endif + +SkLayerDrawLooper::Builder::Builder() + : fRecs(NULL), + fTopRec(NULL), + fCount(0) { +} + +SkLayerDrawLooper::Builder::~Builder() { + Rec* rec = fRecs; + while (rec) { + Rec* next = rec->fNext; + SkDELETE(rec); + rec = next; + } +} + +SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) { + fCount += 1; + + Rec* rec = SkNEW(Rec); + rec->fNext = fRecs; + rec->fInfo = info; + fRecs = rec; + if (NULL == fTopRec) { + fTopRec = rec; + } + + return &rec->fPaint; +} + +void SkLayerDrawLooper::Builder::addLayer(SkScalar dx, SkScalar dy) { + LayerInfo info; + + info.fOffset.set(dx, dy); + (void)this->addLayer(info); +} + +SkPaint* SkLayerDrawLooper::Builder::addLayerOnTop(const LayerInfo& info) { + fCount += 1; + + Rec* rec = SkNEW(Rec); + rec->fNext = NULL; + rec->fInfo = info; + if (NULL == fRecs) { + fRecs = rec; + } else { + SkASSERT(NULL != fTopRec); + fTopRec->fNext = rec; + } + fTopRec = rec; + + return &rec->fPaint; +} + +SkLayerDrawLooper* SkLayerDrawLooper::Builder::detachLooper() { + SkLayerDrawLooper* looper = SkNEW(SkLayerDrawLooper); + looper->fCount = fCount; + looper->fRecs = fRecs; + + fCount = 0; + fRecs = NULL; + fTopRec = NULL; + + return looper; +} diff --git a/tests/LayerDrawLooperTest.cpp b/tests/LayerDrawLooperTest.cpp index a1319a50de..8f8a6b6eb0 100644 --- a/tests/LayerDrawLooperTest.cpp +++ b/tests/LayerDrawLooperTest.cpp @@ -35,21 +35,22 @@ private: }; static void test_frontToBack(skiatest::Reporter* reporter) { - SkAutoTUnref looper(SkNEW(SkLayerDrawLooper)); + SkLayerDrawLooper::Builder looperBuilder; SkLayerDrawLooper::LayerInfo layerInfo; // Add the front layer, with the defaults. - (void)looper->addLayer(layerInfo); + (void)looperBuilder.addLayer(layerInfo); // Add the back layer, with some layer info set. layerInfo.fOffset.set(10.0f, 20.0f); layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit; - SkPaint* layerPaint = looper->addLayer(layerInfo); + SkPaint* layerPaint = looperBuilder.addLayer(layerInfo); layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode); FakeDevice device; SkCanvas canvas(&device); SkPaint paint; + SkAutoTUnref looper(looperBuilder.detachLooper()); looper->init(&canvas); // The back layer should come first. @@ -72,21 +73,22 @@ static void test_frontToBack(skiatest::Reporter* reporter) { } static void test_backToFront(skiatest::Reporter* reporter) { - SkAutoTUnref looper(SkNEW(SkLayerDrawLooper)); + SkLayerDrawLooper::Builder looperBuilder; SkLayerDrawLooper::LayerInfo layerInfo; // Add the back layer, with the defaults. - (void)looper->addLayerOnTop(layerInfo); + (void)looperBuilder.addLayerOnTop(layerInfo); // Add the front layer, with some layer info set. layerInfo.fOffset.set(10.0f, 20.0f); layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit; - SkPaint* layerPaint = looper->addLayerOnTop(layerInfo); + SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo); layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode); FakeDevice device; SkCanvas canvas(&device); SkPaint paint; + SkAutoTUnref looper(looperBuilder.detachLooper()); looper->init(&canvas); // The back layer should come first. @@ -109,21 +111,22 @@ static void test_backToFront(skiatest::Reporter* reporter) { } static void test_mixed(skiatest::Reporter* reporter) { - SkAutoTUnref looper(SkNEW(SkLayerDrawLooper)); + SkLayerDrawLooper::Builder looperBuilder; SkLayerDrawLooper::LayerInfo layerInfo; // Add the back layer, with the defaults. - (void)looper->addLayer(layerInfo); + (void)looperBuilder.addLayer(layerInfo); // Add the front layer, with some layer info set. layerInfo.fOffset.set(10.0f, 20.0f); layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit; - SkPaint* layerPaint = looper->addLayerOnTop(layerInfo); + SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo); layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode); FakeDevice device; SkCanvas canvas(&device); SkPaint paint; + SkAutoTUnref looper(looperBuilder.detachLooper()); looper->init(&canvas); // The back layer should come first.