expand SkLayerDrawLooper to allow for an xfermode when transfering the paint's color,
and allow that the offset be applied pre or post git-svn-id: http://skia.googlecode.com/svn/trunk@1115 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
ea2ee8a854
commit
0716c63332
@ -2,6 +2,7 @@
|
||||
#define SkLayerDrawLooper_DEFINED
|
||||
|
||||
#include "SkDrawLooper.h"
|
||||
#include "SkXfermode.h"
|
||||
|
||||
struct SkPoint;
|
||||
|
||||
@ -10,37 +11,77 @@ public:
|
||||
SkLayerDrawLooper();
|
||||
virtual ~SkLayerDrawLooper();
|
||||
|
||||
/**
|
||||
* Bits specifies which aspects of the layer's paint should replace the
|
||||
* corresponding aspects on the draw's paint.
|
||||
* kEntirePaint_Bits means use the layer's paint completely.
|
||||
* 0 means ignore the layer's paint.
|
||||
*/
|
||||
enum Bits {
|
||||
kAlpha_Bit = 1 << 0, //!< use this layer's alpha
|
||||
kColor_Bit = 1 << 1, //!< use this layer's color
|
||||
kStyle_Bit = 1 << 2, //!< use this layer's Style/stroke settings
|
||||
kTextSkewX_Bit = 1 << 3, //!< use this layer's textskewx
|
||||
kPathEffect_Bit = 1 << 4, //!< use this layer's patheffect
|
||||
kMaskFilter_Bit = 1 << 5, //!< use this layer's maskfilter
|
||||
kShader_Bit = 1 << 6, //!< use this layer's shader
|
||||
kColorFilter_Bit = 1 << 7, //!< use this layer's colorfilter
|
||||
kXfermode_Bit = 1 << 8, //!< use this layer's xfermode
|
||||
kStyle_Bit = 1 << 0, //!< use this layer's Style/stroke settings
|
||||
kTextSkewX_Bit = 1 << 1, //!< use this layer's textskewx
|
||||
kPathEffect_Bit = 1 << 2, //!< use this layer's patheffect
|
||||
kMaskFilter_Bit = 1 << 3, //!< use this layer's maskfilter
|
||||
kShader_Bit = 1 << 4, //!< use this layer's shader
|
||||
kColorFilter_Bit = 1 << 5, //!< use this layer's colorfilter
|
||||
kXfermode_Bit = 1 << 6, //!< use this layer's xfermode
|
||||
|
||||
kEntirePaint_Bits = -1, //!< use this layer's paint entirely
|
||||
};
|
||||
typedef int32_t BitFlags;
|
||||
|
||||
|
||||
/**
|
||||
* Info for how to apply the layer's paint and offset.
|
||||
*
|
||||
* fColorMode controls how we compute the final color for the layer:
|
||||
* The layer's paint's color is treated as the SRC
|
||||
* The draw's paint's color is treated as the DST
|
||||
* final-color = Mode(layers-color, draws-color);
|
||||
* Any SkXfermode::Mode will work. Two common choices are:
|
||||
* kSrc_Mode: to use the layer's color, ignoring the draw's
|
||||
* kDst_Mode: to just keep the draw's color, ignoring the layer's
|
||||
*/
|
||||
struct LayerInfo {
|
||||
BitFlags fPaintBits;
|
||||
SkXfermode::Mode fColorMode;
|
||||
SkVector fOffset;
|
||||
bool fPostTranslate; //!< applies to fOffset
|
||||
|
||||
/**
|
||||
* Initial the LayerInfo. Defaults to settings that will draw the
|
||||
* layer with no changes: e.g.
|
||||
* fPaintBits == 0
|
||||
* fColorMode == kDst_Mode
|
||||
* fOffset == (0, 0)
|
||||
*/
|
||||
LayerInfo();
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 this object.
|
||||
*
|
||||
* The optional bits parameter specifies which aspects of this paint
|
||||
* should replace the paint that is passed to the draw call. If 0 is
|
||||
* specified, then this layer's paint will be ignored.
|
||||
*/
|
||||
SkPaint* addLayer(SkScalar dx, SkScalar dy, BitFlags = kEntirePaint_Bits);
|
||||
SkPaint* addLayer(const LayerInfo&);
|
||||
|
||||
/**
|
||||
* 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 this object.
|
||||
* The returned paint will be ignored, and only the offset will be applied
|
||||
*
|
||||
* DEPRECATED: call addLayer(const LayerInfo&)
|
||||
*/
|
||||
SkPaint* addLayer(SkScalar dx, SkScalar dy);
|
||||
|
||||
/**
|
||||
* Helper for addLayer() which passes (0, 0) for the offset parameters
|
||||
* Helper for addLayer() which passes (0, 0) for the offset parameters.
|
||||
* This layer will not affect the drawing in any way.
|
||||
*
|
||||
* DEPRECATED: call addLayer(const LayerInfo&)
|
||||
*/
|
||||
SkPaint* addLayer(BitFlags bits = kEntirePaint_Bits) {
|
||||
return this->addLayer(0, 0, bits);
|
||||
SkPaint* addLayer() {
|
||||
return this->addLayer(0, 0);
|
||||
}
|
||||
|
||||
// overrides from SkDrawLooper
|
||||
@ -63,9 +104,8 @@ private:
|
||||
struct Rec {
|
||||
Rec* fNext;
|
||||
SkPaint fPaint;
|
||||
SkPoint fOffset;
|
||||
uint32_t fBits;
|
||||
|
||||
LayerInfo fInfo;
|
||||
|
||||
static Rec* Reverse(Rec*);
|
||||
};
|
||||
Rec* fRecs;
|
||||
@ -74,7 +114,8 @@ private:
|
||||
// state-machine during the init/next cycle
|
||||
Rec* fCurrRec;
|
||||
|
||||
static void ApplyBits(SkPaint* dst, const SkPaint& src, BitFlags bits);
|
||||
static void ApplyBits(SkPaint* dst, const SkPaint& src, BitFlags,
|
||||
SkXfermode::Mode);
|
||||
|
||||
class MyRegistrar : public SkFlattenable::Registrar {
|
||||
public:
|
||||
|
@ -1,6 +1,15 @@
|
||||
#include "SkCanvas.h"
|
||||
#include "SkColor.h"
|
||||
#include "SkLayerDrawLooper.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkUnPreMultiply.h"
|
||||
|
||||
SkLayerDrawLooper::LayerInfo::LayerInfo() {
|
||||
fPaintBits = 0; // ignore out paint
|
||||
fColorMode = SkXfermode::kDst_Mode; // ignore our color
|
||||
fOffset.set(0, 0);
|
||||
fPostTranslate = false;
|
||||
}
|
||||
|
||||
SkLayerDrawLooper::SkLayerDrawLooper() {
|
||||
fRecs = NULL;
|
||||
@ -15,45 +24,60 @@ SkLayerDrawLooper::~SkLayerDrawLooper() {
|
||||
rec = next;
|
||||
}
|
||||
}
|
||||
|
||||
SkPaint* SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy, BitFlags bits) {
|
||||
|
||||
SkPaint* SkLayerDrawLooper::addLayer(const LayerInfo& info) {
|
||||
fCount += 1;
|
||||
|
||||
Rec* rec = SkNEW(Rec);
|
||||
rec->fNext = fRecs;
|
||||
rec->fOffset.set(dx, dy);
|
||||
rec->fBits = bits;
|
||||
rec->fInfo = info;
|
||||
fRecs = rec;
|
||||
|
||||
return &rec->fPaint;
|
||||
}
|
||||
|
||||
SkPaint* SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) {
|
||||
LayerInfo info;
|
||||
|
||||
info.fOffset.set(dx, dy);
|
||||
return this->addLayer(info);
|
||||
}
|
||||
|
||||
void SkLayerDrawLooper::init(SkCanvas* canvas) {
|
||||
fCurrRec = fRecs;
|
||||
canvas->save(SkCanvas::kMatrix_SaveFlag);
|
||||
}
|
||||
|
||||
static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) {
|
||||
switch (mode) {
|
||||
case SkXfermode::kSrc_Mode:
|
||||
return src;
|
||||
case SkXfermode::kDst_Mode:
|
||||
return dst;
|
||||
default: {
|
||||
SkPMColor pmS = SkPreMultiplyColor(src);
|
||||
SkPMColor pmD = SkPreMultiplyColor(dst);
|
||||
SkPMColor result = SkXfermode::GetProc(mode)(pmS, pmD);
|
||||
return SkUnPreMultiply::PMColorToColor(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkLayerDrawLooper::ApplyBits(SkPaint* dst, const SkPaint& src,
|
||||
BitFlags bits) {
|
||||
BitFlags bits, SkXfermode::Mode colorMode) {
|
||||
dst->setColor(xferColor(src.getColor(), dst->getColor(), colorMode));
|
||||
|
||||
if (0 == bits) {
|
||||
return;
|
||||
}
|
||||
if (kEntirePaint_Bits == bits) {
|
||||
// we've already compute the color, so save it from the assignment
|
||||
SkColor c = dst->getColor();
|
||||
*dst = src;
|
||||
dst->setColor(c);
|
||||
return;
|
||||
}
|
||||
|
||||
SkColor c = dst->getColor();
|
||||
if (bits & kAlpha_Bit) {
|
||||
c &= 0x00FFFFFF;
|
||||
c |= src.getColor() & 0xFF000000;
|
||||
}
|
||||
if (bits & kColor_Bit) {
|
||||
c &= 0xFF000000;
|
||||
c |= src.getColor() & 0x00FFFFFF;
|
||||
}
|
||||
dst->setColor(c);
|
||||
|
||||
if (bits & kStyle_Bit) {
|
||||
dst->setStyle(src.getStyle());
|
||||
dst->setStrokeWidth(src.getStrokeWidth());
|
||||
@ -96,15 +120,29 @@ void SkLayerDrawLooper::ApplyBits(SkPaint* dst, const SkPaint& src,
|
||||
#endif
|
||||
}
|
||||
|
||||
// Should we add this to canvas?
|
||||
static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
|
||||
SkMatrix m = canvas->getTotalMatrix();
|
||||
m.postTranslate(dx, dy);
|
||||
canvas->setMatrix(m);
|
||||
}
|
||||
|
||||
bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
|
||||
canvas->restore();
|
||||
if (NULL == fCurrRec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ApplyBits(paint, fCurrRec->fPaint, fCurrRec->fBits);
|
||||
ApplyBits(paint, fCurrRec->fPaint, fCurrRec->fInfo.fPaintBits,
|
||||
fCurrRec->fInfo.fColorMode);
|
||||
|
||||
canvas->save(SkCanvas::kMatrix_SaveFlag);
|
||||
canvas->translate(fCurrRec->fOffset.fX, fCurrRec->fOffset.fY);
|
||||
if (fCurrRec->fInfo.fPostTranslate) {
|
||||
postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
|
||||
fCurrRec->fInfo.fOffset.fY);
|
||||
} else {
|
||||
canvas->translate(fCurrRec->fInfo.fOffset.fX, fCurrRec->fInfo.fOffset.fY);
|
||||
}
|
||||
fCurrRec = fCurrRec->fNext;
|
||||
|
||||
return true;
|
||||
@ -143,8 +181,11 @@ void SkLayerDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) {
|
||||
|
||||
Rec* rec = fRecs;
|
||||
for (int i = 0; i < fCount; i++) {
|
||||
buffer.writeScalar(rec->fOffset.fX);
|
||||
buffer.writeScalar(rec->fOffset.fY);
|
||||
buffer.writeInt(rec->fInfo.fPaintBits);
|
||||
buffer.writeInt(rec->fInfo.fColorMode);
|
||||
buffer.writeScalar(rec->fInfo.fOffset.fX);
|
||||
buffer.writeScalar(rec->fInfo.fOffset.fY);
|
||||
buffer.writeBool(rec->fInfo.fPostTranslate);
|
||||
rec->fPaint.flatten(buffer);
|
||||
rec = rec->fNext;
|
||||
}
|
||||
@ -158,9 +199,13 @@ SkLayerDrawLooper::SkLayerDrawLooper(SkFlattenableReadBuffer& buffer)
|
||||
int count = buffer.readInt();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
SkScalar dx = buffer.readScalar();
|
||||
SkScalar dy = buffer.readScalar();
|
||||
this->addLayer(dx, dy)->unflatten(buffer);
|
||||
LayerInfo info;
|
||||
info.fPaintBits = buffer.readInt();
|
||||
info.fColorMode = (SkXfermode::Mode)buffer.readInt();
|
||||
info.fOffset.fX = buffer.readScalar();
|
||||
info.fOffset.fY = buffer.readScalar();
|
||||
info.fPostTranslate = buffer.readBool();
|
||||
this->addLayer(info)->unflatten(buffer);
|
||||
}
|
||||
SkASSERT(count == fCount);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user