Builder class for SkLayerDrawLooper.

SkLayerDrawLooper provides methods like addLayer() to build up a linked list
of layers. Working towards making this class immutable, this patch introduces
the SkLayerDrawLooperBuilder class which is used to accumulate all the layers
first. Once all layers are in place, it creates a new SkLayerDrawLooper object
and hands over the list of layers to that object.

For now we keep the addLayer methods in SkLayerDrawLooper so we don't break
Chrome and Blink when this is landed. Once we've updated all users, we can
remove the methods.

BUG=skia:2141
R=reed@google.com, scroggo@google.com, mtklein@google.com, reed@chromium.org

Author: dominikg@chromium.org

Review URL: https://codereview.chromium.org/133813005

git-svn-id: http://skia.googlecode.com/svn/trunk@13448 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2014-02-14 10:06:42 +00:00
parent 02d6f54616
commit 74ba2f62dc
3 changed files with 127 additions and 20 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -35,21 +35,22 @@ private:
};
static void test_frontToBack(skiatest::Reporter* reporter) {
SkAutoTUnref<SkLayerDrawLooper> 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<SkLayerDrawLooper> 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<SkLayerDrawLooper> 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<SkLayerDrawLooper> 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<SkLayerDrawLooper> 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<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
looper->init(&canvas);
// The back layer should come first.