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
diff --git a/include/effects/SkLayerDrawLooper.h b/include/effects/SkLayerDrawLooper.h
index 682a9dc..b487a88 100644
--- a/include/effects/SkLayerDrawLooper.h
+++ b/include/effects/SkLayerDrawLooper.h
@@ -2,6 +2,7 @@
#define SkLayerDrawLooper_DEFINED
#include "SkDrawLooper.h"
+#include "SkXfermode.h"
struct SkPoint;
@@ -10,37 +11,77 @@
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 @@
struct Rec {
Rec* fNext;
SkPaint fPaint;
- SkPoint fOffset;
- uint32_t fBits;
-
+ LayerInfo fInfo;
+
static Rec* Reverse(Rec*);
};
Rec* fRecs;
@@ -74,7 +114,8 @@
// 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:
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index db64133..b3f3886 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -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 @@
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 @@
#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 @@
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 @@
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);