[WIP] Add Context to SkDrawLooper.
SkDrawLooper carries some state during draws. This CL extracts this state into a separate class Context, which is then passed by the users of SkDrawLooper into the appropriate methods. This is a step towards making SkDrawLooper immutable. BUG=skia:2141 R=scroggo@google.com, reed@google.com, sugoi@google.com Author: dominikg@chromium.org Review URL: https://codereview.chromium.org/155513012 git-svn-id: http://skia.googlecode.com/svn/trunk@13760 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
ad07e69d4c
commit
79fbb40bca
@ -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 (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.
|
||||
* 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 init().
|
||||
* 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,
|
||||
* that the canvas has been restored to the state it was initially, before
|
||||
* init() was first called.
|
||||
* 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*, SkPaint* paint) = 0;
|
||||
virtual bool next(SkCanvas* canvas, SkPaint* paint) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 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)
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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
|
||||
class LayerDrawLooperContext : public SkDrawLooper::Context {
|
||||
public:
|
||||
explicit LayerDrawLooperContext(const SkLayerDrawLooper* looper);
|
||||
|
||||
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:
|
||||
|
@ -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<SkDrawLooper::Context>(
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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<SkDrawLooper::Context>(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<SkDrawLooper::Context>(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);
|
||||
|
@ -96,20 +96,21 @@ public:
|
||||
return static_cast<T*>(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<typename T> void* reserveT() {
|
||||
template<typename T> 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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
|
||||
looper->init(&canvas);
|
||||
SkSmallAllocator<1, 32> allocator;
|
||||
void* buffer = allocator.reserveT<SkDrawLooper::Context>(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<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
|
||||
looper->init(&canvas);
|
||||
SkSmallAllocator<1, 32> allocator;
|
||||
void* buffer = allocator.reserveT<SkDrawLooper::Context>(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<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
|
||||
looper->init(&canvas);
|
||||
SkSmallAllocator<1, 32> allocator;
|
||||
void* buffer = allocator.reserveT<SkDrawLooper::Context>(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) {
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDrawLooper.h"
|
||||
#include "SkTypes.h"
|
||||
#include "Test.h"
|
||||
|
||||
/*
|
||||
@ -14,12 +15,25 @@
|
||||
*/
|
||||
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 size_t contextSize() const SK_OVERRIDE { return sizeof(TestDrawLooperContext); }
|
||||
|
||||
#ifdef SK_DEVELOPER
|
||||
virtual void toString(SkString* str) const SK_OVERRIDE {
|
||||
str->append("TestLooper:");
|
||||
}
|
||||
#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;
|
||||
@ -28,12 +42,9 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef SK_DEVELOPER
|
||||
virtual void toString(SkString* str) const SK_OVERRIDE {
|
||||
str->append("TestLooper:");
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
bool fOnce;
|
||||
};
|
||||
|
||||
SK_DECLARE_UNFLATTENABLE_OBJECT()
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user