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