aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-16 10:16:39 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-16 10:16:39 +0000
commit001f4ed2fb62ecdc98ce2884d925de11b7516d23 (patch)
tree1acb3cdef582b7a33a97e6c6631c62320ca39331
parentd1061e254af7fa8267dc1a5ed444d1c4b1743b6d (diff)
Extract most of the mutable state of SkShader into a separate Context object.
SkShader currently stores some state during draw calls via setContext(...). Move that mutable state into a separate SkShader::Context class that is constructed on demand for the duration of the draw. Calls to setContext() are replaced with createContext() which returns a context corresponding to the shader object or NULL if the parameters to createContext are invalid. TEST=out/Debug/dm BUG=skia:1976 R=scroggo@google.com, skyostil@chromium.org, tomhudson@chromium.org, senorblanco@chromium.org, reed@google.com, bungeman@google.com Author: dominikg@chromium.org Review URL: https://codereview.chromium.org/207683004 git-svn-id: http://skia.googlecode.com/svn/trunk@14216 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--include/core/SkColorShader.h41
-rw-r--r--include/core/SkComposeShader.h37
-rw-r--r--include/core/SkEmptyShader.h26
-rw-r--r--include/core/SkShader.h167
-rw-r--r--include/effects/SkPerlinNoiseShader.h40
-rw-r--r--include/effects/SkTransparentShader.h30
-rw-r--r--src/core/SkBitmapProcShader.cpp118
-rw-r--r--src/core/SkBitmapProcShader.h60
-rw-r--r--src/core/SkBitmapProcState.cpp3
-rw-r--r--src/core/SkBlitter.cpp277
-rw-r--r--src/core/SkBlitter.h7
-rw-r--r--src/core/SkBlitter_A8.cpp29
-rw-r--r--src/core/SkBlitter_ARGB32.cpp76
-rw-r--r--src/core/SkBlitter_RGB16.cpp105
-rw-r--r--src/core/SkCanvas.cpp46
-rw-r--r--src/core/SkComposeShader.cpp97
-rw-r--r--src/core/SkCoreBlitters.h30
-rw-r--r--src/core/SkDraw.cpp103
-rw-r--r--src/core/SkFilterShader.cpp80
-rw-r--r--src/core/SkFilterShader.h29
-rw-r--r--src/core/SkPictureShader.cpp125
-rw-r--r--src/core/SkPictureShader.h41
-rw-r--r--src/core/SkShader.cpp136
-rw-r--r--src/core/SkSmallAllocator.h23
-rw-r--r--src/effects/SkPerlinNoiseShader.cpp65
-rw-r--r--src/effects/SkTransparentShader.cpp42
-rw-r--r--src/effects/gradients/SkGradientShader.cpp273
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h84
-rw-r--r--src/effects/gradients/SkLinearGradient.cpp53
-rw-r--r--src/effects/gradients/SkLinearGradient.h20
-rw-r--r--src/effects/gradients/SkRadialGradient.cpp50
-rw-r--r--src/effects/gradients/SkRadialGradient.h22
-rw-r--r--src/effects/gradients/SkSweepGradient.cpp30
-rw-r--r--src/effects/gradients/SkSweepGradient.h22
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.cpp121
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.h35
-rw-r--r--src/effects/gradients/SkTwoPointRadialGradient.cpp95
-rw-r--r--src/effects/gradients/SkTwoPointRadialGradient.h28
38 files changed, 1669 insertions, 997 deletions
diff --git a/include/core/SkColorShader.h b/include/core/SkColorShader.h
index 975156c0eb..56e5add4a3 100644
--- a/include/core/SkColorShader.h
+++ b/include/core/SkColorShader.h
@@ -30,16 +30,35 @@ public:
*/
SkColorShader(SkColor c);
- virtual ~SkColorShader();
-
- virtual uint32_t getFlags() SK_OVERRIDE;
- virtual uint8_t getSpan16Alpha() const SK_OVERRIDE;
virtual bool isOpaque() const SK_OVERRIDE;
- virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix) SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
- virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE;
+
+ virtual SkShader::Context* createContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ void* storage) const SK_OVERRIDE;
+
+ virtual size_t contextSize() const SK_OVERRIDE {
+ return sizeof(ColorShaderContext);
+ }
+
+ class ColorShaderContext : public SkShader::Context {
+ public:
+ ColorShaderContext(const SkColorShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
+
+ virtual uint32_t getFlags() const SK_OVERRIDE;
+ virtual uint8_t getSpan16Alpha() const SK_OVERRIDE;
+ virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
+ virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE;
+
+ private:
+ SkPMColor fPMColor;
+ uint32_t fFlags;
+ uint16_t fColor16;
+
+ typedef SkShader::Context INHERITED;
+ };
// we return false for this, use asAGradient
virtual BitmapType asABitmap(SkBitmap* outTexture,
@@ -56,11 +75,7 @@ protected:
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
private:
-
SkColor fColor; // ignored if fInheritColor is true
- SkPMColor fPMColor; // cached after setContext()
- uint32_t fFlags; // cached after setContext()
- uint16_t fColor16; // cached after setContext()
SkBool8 fInheritColor;
typedef SkShader INHERITED;
diff --git a/include/core/SkComposeShader.h b/include/core/SkComposeShader.h
index b54e5efa97..9833a9f4ad 100644
--- a/include/core/SkComposeShader.h
+++ b/include/core/SkComposeShader.h
@@ -34,10 +34,38 @@ public:
SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode = NULL);
virtual ~SkComposeShader();
- virtual bool setContext(const SkBitmap&, const SkPaint&,
- const SkMatrix&) SK_OVERRIDE;
- virtual void endContext() SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
+ virtual bool validContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, void*) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
+ class ComposeShaderContext : public SkShader::Context {
+ public:
+ // When this object gets destroyed, it will call contextA and contextB's destructor
+ // but it will NOT free the memory.
+ ComposeShaderContext(const SkComposeShader&, const SkBitmap&,
+ const SkPaint&, const SkMatrix&,
+ SkShader::Context* contextA, SkShader::Context* contextB);
+
+ SkShader::Context* getShaderContextA() const { return fShaderContextA; }
+ SkShader::Context* getShaderContextB() const { return fShaderContextB; }
+
+ virtual ~ComposeShaderContext();
+
+ virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
+
+ private:
+ SkShader::Context* fShaderContextA;
+ SkShader::Context* fShaderContextB;
+
+ typedef SkShader::Context INHERITED;
+ };
+
+#if SK_DEBUG
+ SkShader* getShaderA() { return fShaderA; }
+ SkShader* getShaderB() { return fShaderB; }
+#endif
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeShader)
@@ -47,7 +75,6 @@ protected:
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
private:
-
SkShader* fShaderA;
SkShader* fShaderB;
SkXfermode* fMode;
diff --git a/include/core/SkEmptyShader.h b/include/core/SkEmptyShader.h
index d2ebb61221..7494eff3d0 100644
--- a/include/core/SkEmptyShader.h
+++ b/include/core/SkEmptyShader.h
@@ -15,20 +15,28 @@
/**
* \class SkEmptyShader
- * A Shader that always draws nothing. Its setContext always returns false,
- * so it never expects that its shadeSpan() methods will get called.
+ * A Shader that always draws nothing. Its createContext always returns NULL.
*/
class SK_API SkEmptyShader : public SkShader {
public:
SkEmptyShader() {}
- virtual uint32_t getFlags() SK_OVERRIDE;
- virtual uint8_t getSpan16Alpha() const SK_OVERRIDE;
- virtual bool setContext(const SkBitmap&, const SkPaint&,
- const SkMatrix&) SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
- virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE {
+ // Even though createContext returns NULL we have to return a value of at least
+ // sizeof(SkShader::Context) to satisfy SkSmallAllocator.
+ return sizeof(SkShader::Context);
+ }
+
+ virtual bool validContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE {
+ return false;
+ }
+
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, void*) const SK_OVERRIDE {
+ // validContext returns false.
+ return NULL;
+ }
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkEmptyShader)
diff --git a/include/core/SkShader.h b/include/core/SkShader.h
index 076ecf5460..58e5a6ad2e 100644
--- a/include/core/SkShader.h
+++ b/include/core/SkShader.h
@@ -38,7 +38,7 @@ public:
virtual ~SkShader();
/**
- * Returns true if the local matrix is not an identity matrix.
+ * Returns true if the local matrix is not an identity matrix.
*/
bool hasLocalMatrix() const { return !fLocalMatrix.isIdentity(); }
@@ -96,7 +96,7 @@ public:
*/
kIntrinsicly16_Flag = 0x04,
- /** set (after setContext) if the spans only vary in X (const in Y).
+ /** set if the spans only vary in X (const in Y).
e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient
that varies from left-to-right. This flag specifies this for
shadeSpan().
@@ -112,84 +112,111 @@ public:
};
/**
- * Called sometimes before drawing with this shader. Return the type of
- * alpha your shader will return. The default implementation returns 0.
- * Your subclass should override if it can (even sometimes) report a
- * non-zero value, since that will enable various blitters to perform
- * faster.
- */
- virtual uint32_t getFlags() { return 0; }
-
- /**
* Returns true if the shader is guaranteed to produce only opaque
* colors, subject to the SkPaint using the shader to apply an opaque
* alpha value. Subclasses should override this to allow some
- * optimizations. isOpaque() can be called at any time, unlike getFlags,
- * which only works properly when the context is set.
+ * optimizations.
*/
virtual bool isOpaque() const { return false; }
- /**
- * Return the alpha associated with the data returned by shadeSpan16(). If
- * kHasSpan16_Flag is not set, this value is meaningless.
- */
- virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; }
+ class Context : public ::SkNoncopyable {
+ public:
+ Context(const SkShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
- /**
- * Called once before drawing, with the current paint and device matrix.
- * Return true if your shader supports these parameters, or false if not.
- * If false is returned, nothing will be drawn. If true is returned, then
- * a balancing call to endContext() will be made before the next call to
- * setContext.
- *
- * Subclasses should be sure to call their INHERITED::setContext() if they
- * override this method.
- */
- virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix);
+ virtual ~Context();
- /**
- * Assuming setContext returned true, endContext() will be called when
- * the draw using the shader has completed. It is an error for setContext
- * to be called twice w/o an intervening call to endContext().
- *
- * Subclasses should be sure to call their INHERITED::endContext() if they
- * override this method.
- */
- virtual void endContext();
+ /**
+ * Called sometimes before drawing with this shader. Return the type of
+ * alpha your shader will return. The default implementation returns 0.
+ * Your subclass should override if it can (even sometimes) report a
+ * non-zero value, since that will enable various blitters to perform
+ * faster.
+ */
+ virtual uint32_t getFlags() const { return 0; }
- SkDEBUGCODE(bool setContextHasBeenCalled() const { return SkToBool(fInSetContext); })
+ /**
+ * Return the alpha associated with the data returned by shadeSpan16(). If
+ * kHasSpan16_Flag is not set, this value is meaningless.
+ */
+ virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; }
- /**
- * Called for each span of the object being drawn. Your subclass should
- * set the appropriate colors (with premultiplied alpha) that correspond
- * to the specified device coordinates.
- */
- virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
+ /**
+ * Called for each span of the object being drawn. Your subclass should
+ * set the appropriate colors (with premultiplied alpha) that correspond
+ * to the specified device coordinates.
+ */
+ virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
+
+ typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count);
+ virtual ShadeProc asAShadeProc(void** ctx);
+
+ /**
+ * Called only for 16bit devices when getFlags() returns
+ * kOpaqueAlphaFlag | kHasSpan16_Flag
+ */
+ virtual void shadeSpan16(int x, int y, uint16_t[], int count);
+
+ /**
+ * Similar to shadeSpan, but only returns the alpha-channel for a span.
+ * The default implementation calls shadeSpan() and then extracts the alpha
+ * values from the returned colors.
+ */
+ virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
- typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count);
- virtual ShadeProc asAShadeProc(void** ctx);
+ /**
+ * Helper function that returns true if this shader's shadeSpan16() method
+ * can be called.
+ */
+ bool canCallShadeSpan16() {
+ return SkShader::CanCallShadeSpan16(this->getFlags());
+ }
+
+ protected:
+ // Reference to shader, so we don't have to dupe information.
+ const SkShader& fShader;
+
+ enum MatrixClass {
+ kLinear_MatrixClass, // no perspective
+ kFixedStepInX_MatrixClass, // fast perspective, need to call fixedStepInX() each
+ // scanline
+ kPerspective_MatrixClass // slow perspective, need to mappoints each pixel
+ };
+ static MatrixClass ComputeMatrixClass(const SkMatrix&);
+
+ uint8_t getPaintAlpha() const { return fPaintAlpha; }
+ const SkMatrix& getTotalInverse() const { return fTotalInverse; }
+ MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
+
+ private:
+ SkMatrix fTotalInverse;
+ uint8_t fPaintAlpha;
+ uint8_t fTotalInverseClass;
+
+ typedef SkNoncopyable INHERITED;
+ };
/**
- * Called only for 16bit devices when getFlags() returns
- * kOpaqueAlphaFlag | kHasSpan16_Flag
+ * Subclasses should be sure to call their INHERITED::validContext() if
+ * they override this method.
*/
- virtual void shadeSpan16(int x, int y, uint16_t[], int count);
+ virtual bool validContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse = NULL) const;
/**
- * Similar to shadeSpan, but only returns the alpha-channel for a span.
- * The default implementation calls shadeSpan() and then extracts the alpha
- * values from the returned colors.
+ * Create the actual object that does the shading.
+ * Returns NULL if validContext() returns false.
+ * Size of storage must be >= contextSize.
*/
- virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
+ virtual Context* createContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ void* storage) const = 0;
/**
- * Helper function that returns true if this shader's shadeSpan16() method
- * can be called.
+ * Return the size of a Context returned by createContext.
*/
- bool canCallShadeSpan16() {
- return SkShader::CanCallShadeSpan16(this->getFlags());
- }
+ virtual size_t contextSize() const = 0;
/**
* Helper to check the flags to know if it is legal to call shadeSpan16()
@@ -322,7 +349,7 @@ public:
* The incoming color to the effect has r=g=b=a all extracted from the SkPaint's alpha.
* The output color should be the computed SkShader premul color modulated by the incoming
* color. The GrContext may be used by the effect to create textures. The GPU device does not
- * call setContext. Instead we pass the SkPaint here in case the shader needs paint info.
+ * call createContext. Instead we pass the SkPaint here in case the shader needs paint info.
*/
virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint& paint) const;
@@ -360,26 +387,14 @@ public:
SK_DEFINE_FLATTENABLE_TYPE(SkShader)
protected:
- enum MatrixClass {
- kLinear_MatrixClass, // no perspective
- kFixedStepInX_MatrixClass, // fast perspective, need to call fixedStepInX() each scanline
- kPerspective_MatrixClass // slow perspective, need to mappoints each pixel
- };
- static MatrixClass ComputeMatrixClass(const SkMatrix&);
-
- // These can be called by your subclass after setContext() has been called
- uint8_t getPaintAlpha() const { return fPaintAlpha; }
- const SkMatrix& getTotalInverse() const { return fTotalInverse; }
- MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
SkShader(SkReadBuffer& );
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
+
private:
SkMatrix fLocalMatrix;
- SkMatrix fTotalInverse;
- uint8_t fPaintAlpha;
- uint8_t fTotalInverseClass;
- SkDEBUGCODE(SkBool8 fInSetContext;)
+
+ bool computeTotalInverse(const SkMatrix& matrix, SkMatrix* totalInverse) const;
typedef SkFlattenable INHERITED;
};
diff --git a/include/effects/SkPerlinNoiseShader.h b/include/effects/SkPerlinNoiseShader.h
index dfd5a8c1e7..5b270293b1 100644
--- a/include/effects/SkPerlinNoiseShader.h
+++ b/include/effects/SkPerlinNoiseShader.h
@@ -72,10 +72,32 @@ public:
}
- virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix);
- virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE;
+ virtual SkShader::Context* createContext(
+ const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
+ class PerlinNoiseShaderContext : public SkShader::Context {
+ public:
+ PerlinNoiseShaderContext(const SkPerlinNoiseShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
+ virtual ~PerlinNoiseShaderContext() {}
+
+ virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE;
+
+ private:
+ SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
+ SkScalar calculateTurbulenceValueForPoint(
+ int channel, const PaintingData& paintingData,
+ StitchData& stitchData, const SkPoint& point) const;
+ SkScalar noise2D(int channel, const PaintingData& paintingData,
+ const StitchData& stitchData, const SkPoint& noiseVector) const;
+
+ SkMatrix fMatrix;
+
+ typedef SkShader::Context INHERITED;
+ };
virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint&) const SK_OVERRIDE;
@@ -92,14 +114,6 @@ private:
const SkISize* tileSize);
virtual ~SkPerlinNoiseShader();
- SkScalar noise2D(int channel, const PaintingData& paintingData,
- const StitchData& stitchData, const SkPoint& noiseVector) const;
-
- SkScalar calculateTurbulenceValueForPoint(int channel, const PaintingData& paintingData,
- StitchData& stitchData, const SkPoint& point) const;
-
- SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
-
// TODO (scroggo): Once all SkShaders are created from a factory, and we have removed the
// constructor that creates SkPerlinNoiseShader from an SkReadBuffer, several fields can
// be made constant.
@@ -110,8 +124,6 @@ private:
/*const*/ SkScalar fSeed;
/*const*/ SkISize fTileSize;
/*const*/ bool fStitchTiles;
- // TODO (scroggo): Once setContext creates a new object, place this on that object.
- SkMatrix fMatrix;
PaintingData* fPaintingData;
diff --git a/include/effects/SkTransparentShader.h b/include/effects/SkTransparentShader.h
index 7428d442e3..790e5ae9fd 100644
--- a/include/effects/SkTransparentShader.h
+++ b/include/effects/SkTransparentShader.h
@@ -14,21 +14,31 @@ class SK_API SkTransparentShader : public SkShader {
public:
SkTransparentShader() {}
- virtual uint32_t getFlags() SK_OVERRIDE;
- virtual bool setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const
+ SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
+ class TransparentShaderContext : public SkShader::Context {
+ public:
+ TransparentShaderContext(const SkTransparentShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
+ virtual ~TransparentShaderContext();
+
+ virtual uint32_t getFlags() const SK_OVERRIDE;
+ virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
+
+ private:
+ const SkBitmap* fDevice;
+
+ typedef SkShader::Context INHERITED;
+ };
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTransparentShader)
private:
- // these are a cache from the call to setContext()
- const SkBitmap* fDevice;
- uint8_t fAlpha;
-
SkTransparentShader(SkReadBuffer& buffer) : INHERITED(buffer) {}
typedef SkShader INHERITED;
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index a397b78439..5f5eb1866e 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -34,18 +34,16 @@ bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
TileMode tmx, TileMode tmy) {
fRawBitmap = src;
- fState.fTileModeX = (uint8_t)tmx;
- fState.fTileModeY = (uint8_t)tmy;
- fFlags = 0; // computed in setContext
+ fTileModeX = (uint8_t)tmx;
+ fTileModeY = (uint8_t)tmy;
}
SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer)
: INHERITED(buffer) {
buffer.readBitmap(&fRawBitmap);
fRawBitmap.setImmutable();
- fState.fTileModeX = buffer.readUInt();
- fState.fTileModeY = buffer.readUInt();
- fFlags = 0; // computed in setContext
+ fTileModeX = buffer.readUInt();
+ fTileModeY = buffer.readUInt();
}
SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
@@ -58,8 +56,8 @@ SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
texM->reset();
}
if (xy) {
- xy[0] = (TileMode)fState.fTileModeX;
- xy[1] = (TileMode)fState.fTileModeY;
+ xy[0] = (TileMode)fTileModeX;
+ xy[1] = (TileMode)fTileModeY;
}
return kDefault_BitmapType;
}
@@ -68,8 +66,8 @@ void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writeBitmap(fRawBitmap);
- buffer.writeUInt(fState.fTileModeX);
- buffer.writeUInt(fState.fTileModeY);
+ buffer.writeUInt(fTileModeX);
+ buffer.writeUInt(fTileModeY);
}
static bool only_scale_and_translate(const SkMatrix& matrix) {
@@ -98,25 +96,67 @@ static bool valid_for_drawing(const SkBitmap& bm) {
return true;
}
-bool SkBitmapProcShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
+bool SkBitmapProcShader::validInternal(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse,
+ SkBitmapProcState* state) const {
if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) {
return false;
}
- // do this first, so we have a correct inverse matrix
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
+ // Make sure we can use totalInverse as a cache.
+ SkMatrix totalInverseLocal;
+ if (NULL == totalInverse) {
+ totalInverse = &totalInverseLocal;
}
- fState.fOrigBitmap = fRawBitmap;
- if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
- this->INHERITED::endContext();
+ // Do this first, so we know the matrix can be inverted.
+ if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
return false;
}
- const SkBitmap& bitmap = *fState.fBitmap;
+ SkASSERT(state);
+ state->fTileModeX = fTileModeX;
+ state->fTileModeY = fTileModeY;
+ state->fOrigBitmap = fRawBitmap;
+ return state->chooseProcs(*totalInverse, paint);
+}
+
+bool SkBitmapProcShader::validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse) const {
+ SkBitmapProcState state;
+ return this->validInternal(device, paint, matrix, totalInverse, &state);
+}
+
+SkShader::Context* SkBitmapProcShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
+ SkBitmapProcState* state = SkNEW_PLACEMENT(stateStorage, SkBitmapProcState);
+ if (!this->validInternal(device, paint, matrix, NULL, state)) {
+ state->~SkBitmapProcState();
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, BitmapProcShaderContext,
+ (*this, device, paint, matrix, state));
+}
+
+size_t SkBitmapProcShader::contextSize() const {
+ // The SkBitmapProcState is stored outside of the context object, with the context holding
+ // a pointer to it.
+ return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
+}
+
+SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(
+ const SkBitmapProcShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix, SkBitmapProcState* state)
+ : INHERITED(shader, device, paint, matrix)
+ , fState(state)
+{
+ const SkBitmap& bitmap = *fState->fBitmap;
bool bitmapIsOpaque = bitmap.isOpaque();
// update fFlags
@@ -157,12 +197,12 @@ bool SkBitmapProcShader::setContext(const SkBitmap& device,
}
fFlags = flags;
- return true;
}
-void SkBitmapProcShader::endContext() {
- fState.endContext();
- this->INHERITED::endContext();
+SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
+ // The bitmap proc state has been created outside of the context on memory that will be freed
+ // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
+ fState->~SkBitmapProcState();
}
#define BUF_MAX 128
@@ -176,8 +216,9 @@ void SkBitmapProcShader::endContext() {
#define TEST_BUFFER_EXTRA 0
#endif
-void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
- const SkBitmapProcState& state = fState;
+void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
+ int count) {
+ const SkBitmapProcState& state = *fState;
if (state.getShaderProc32()) {
state.getShaderProc32()(state, x, y, dstC, count);
return;
@@ -186,7 +227,7 @@ void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
- int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
+ int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
SkASSERT(state.fBitmap->getPixels());
SkASSERT(state.fBitmap->pixelRef() == NULL ||
@@ -220,16 +261,17 @@ void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
}
}
-SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
- if (fState.getShaderProc32()) {
- *ctx = &fState;
- return (ShadeProc)fState.getShaderProc32();
+SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
+ if (fState->getShaderProc32()) {
+ *ctx = fState;
+ return (ShadeProc)fState->getShaderProc32();
}
return NULL;
}
-void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
- const SkBitmapProcState& state = fState;
+void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan16(int x, int y, uint16_t dstC[],
+ int count) {
+ const SkBitmapProcState& state = *fState;
if (state.getShaderProc16()) {
state.getShaderProc16()(state, x, y, dstC, count);
return;
@@ -238,7 +280,7 @@ void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
uint32_t buffer[BUF_MAX];
SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
- int max = fState.maxCountForBufferSize(sizeof(buffer));
+ int max = state.maxCountForBufferSize(sizeof(buffer));
SkASSERT(state.fBitmap->getPixels());
SkASSERT(state.fBitmap->pixelRef() == NULL ||
@@ -342,8 +384,8 @@ void SkBitmapProcShader::toString(SkString* str) const {
str->append("BitmapShader: (");
str->appendf("(%s, %s)",
- gTileModeName[fState.fTileModeX],
- gTileModeName[fState.fTileModeY]);
+ gTileModeName[fTileModeX],
+ gTileModeName[fTileModeY]);
str->append(" ");
fRawBitmap.toString(str);
@@ -384,8 +426,8 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
matrix.preConcat(lmInverse);
SkShader::TileMode tm[] = {
- (TileMode)fState.fTileModeX,
- (TileMode)fState.fTileModeY,
+ (TileMode)fTileModeX,
+ (TileMode)fTileModeY,
};
// Must set wrap and filter on the sampler before requesting a texture. In two places below
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h
index 8e225a5e98..e0c78b8e45 100644
--- a/src/core/SkBitmapProcShader.h
+++ b/src/core/SkBitmapProcShader.h
@@ -20,14 +20,16 @@ public:
// overrides from SkShader
virtual bool isOpaque() const SK_OVERRIDE;
- virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
- virtual void endContext() SK_OVERRIDE;
- virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
- virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*) const SK_OVERRIDE;
+ virtual bool validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse = NULL) const SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, void* storage) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
static bool CanDo(const SkBitmap&, TileMode tx, TileMode ty);
SK_TO_STRING_OVERRIDE()
@@ -37,22 +39,54 @@ public:
GrEffectRef* asNewEffect(GrContext*, const SkPaint&) const SK_OVERRIDE;
#endif
+ class BitmapProcShaderContext : public SkShader::Context {
+ public:
+ // The context takes ownership of the state. It will call its destructor
+ // but will NOT free the memory.
+ BitmapProcShaderContext(const SkBitmapProcShader& shader,
+ const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkBitmapProcState* state);
+ virtual ~BitmapProcShaderContext();
+
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+
+ virtual uint32_t getFlags() const SK_OVERRIDE { return fFlags; }
+
+ private:
+ SkBitmapProcState* fState;
+ uint32_t fFlags;
+
+ typedef SkShader::Context INHERITED;
+ };
+
protected:
SkBitmapProcShader(SkReadBuffer& );
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
- SkBitmap fRawBitmap; // experimental for RLE encoding
- SkBitmapProcState fState;
- uint32_t fFlags;
+ SkBitmap fRawBitmap; // experimental for RLE encoding
+ uint8_t fTileModeX, fTileModeY;
private:
+ bool validInternal(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse,
+ SkBitmapProcState* state) const;
+
typedef SkShader INHERITED;
};
-// Commonly used allocator. It currently is only used to allocate up to 2 objects. The total
-// bytes requested is calculated using one of our large shaders plus the size of an Sk3DBlitter
-// in SkDraw.cpp
-typedef SkSmallAllocator<2, sizeof(SkBitmapProcShader) + sizeof(void*) * 2> SkTBlitterAllocator;
+// Commonly used allocator. It currently is only used to allocate up to 3 objects. The total
+// bytes requested is calculated using one of our large shaders, its context size plus the size of
+// an Sk3DBlitter in SkDraw.cpp
+// Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not
+// yet found a situation where the size below isn't big enough.
+typedef SkSmallAllocator<3, sizeof(SkBitmapProcShader) +
+ sizeof(SkBitmapProcShader::BitmapProcShaderContext) +
+ sizeof(SkBitmapProcState) +
+ sizeof(void*) * 2> SkTBlitterAllocator;
// If alloc is non-NULL, it will be used to allocate the returned SkShader, and MUST outlive
// the SkShader.
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp
index cdc582bfee..8874e7b445 100644
--- a/src/core/SkBitmapProcState.cpp
+++ b/src/core/SkBitmapProcState.cpp
@@ -398,6 +398,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
}
// The above logic should have always assigned fBitmap, but in case it
// didn't, we check for that now...
+ // TODO(dominikg): Ask humper@ if we can just use an SkASSERT(fBitmap)?
if (NULL == fBitmap) {
return false;
}
@@ -480,6 +481,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
// shader will perform.
fMatrixProc = this->chooseMatrixProc(trivialMatrix);
+ // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.
if (NULL == fMatrixProc) {
return false;
}
@@ -521,6 +523,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
fPaintPMColor = SkPreMultiplyColor(paint.getColor());
break;
default:
+ // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
return false;
}
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index 52a05eded8..ad51874271 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -26,6 +26,15 @@ SkBlitter::~SkBlitter() {}
bool SkBlitter::isNullBlitter() const { return false; }
+bool SkBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix) {
+ return true;
+}
+
+SkShader::Context* SkBlitter::getShaderContext() const {
+ return NULL;
+}
+
const SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) {
return NULL;
}
@@ -568,102 +577,149 @@ class Sk3DShader : public SkShader {
public:
Sk3DShader(SkShader* proxy) : fProxy(proxy) {
SkSafeRef(proxy);
- fMask = NULL;
}
virtual ~Sk3DShader() {
SkSafeUnref(fProxy);
}
- void setMask(const SkMask* mask) { fMask = mask; }
+ virtual size_t contextSize() const SK_OVERRIDE {
+ size_t size = sizeof(Sk3DShaderContext);
+ if (fProxy) {
+ size += fProxy->contextSize();
+ }
+ return size;
+ }
- virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix) SK_OVERRIDE {
- if (!this->INHERITED::setContext(device, paint, matrix)) {
+ virtual bool validContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse = NULL) const
+ SK_OVERRIDE
+ {
+ if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
return false;
}
if (fProxy) {
- if (!fProxy->setContext(device, paint, matrix)) {
- // must keep our set/end context calls balanced
- this->INHERITED::endContext();
- return false;
- }
- } else {
- fPMColor = SkPreMultiplyColor(paint.getColor());
+ return fProxy->validContext(device, paint, matrix);
}
return true;
}
- virtual void endContext() SK_OVERRIDE {
+ virtual SkShader::Context* createContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ void* storage) const SK_OVERRIDE
+ {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ SkShader::Context* proxyContext;
if (fProxy) {
- fProxy->endContext();
+ char* proxyContextStorage = (char*) storage + sizeof(Sk3DShaderContext);
+ proxyContext = fProxy->createContext(device, paint, matrix, proxyContextStorage);
+ SkASSERT(proxyContext);
+ } else {
+ proxyContext = NULL;
}
- this->INHERITED::endContext();
+ return SkNEW_PLACEMENT_ARGS(storage, Sk3DShaderContext, (*this, device, paint, matrix,
+ proxyContext));
}
- virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE {
- if (fProxy) {
- fProxy->shadeSpan(x, y, span, count);
+ class Sk3DShaderContext : public SkShader::Context {
+ public:
+ // Calls proxyContext's destructor but will NOT free its memory.
+ Sk3DShaderContext(const Sk3DShader& shader, const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkShader::Context* proxyContext)
+ : INHERITED(shader, device, paint, matrix)
+ , fMask(NULL)
+ , fProxyContext(proxyContext)
+ {
+ if (!fProxyContext) {
+ fPMColor = SkPreMultiplyColor(paint.getColor());
+ }
}
- if (fMask == NULL) {
- if (fProxy == NULL) {
- sk_memset32(span, fPMColor, count);
+ virtual ~Sk3DShaderContext() {
+ if (fProxyContext) {
+ fProxyContext->SkShader::Context::~Context();
}
- return;
}
- SkASSERT(fMask->fBounds.contains(x, y));
- SkASSERT(fMask->fBounds.contains(x + count - 1, y));
+ void setMask(const SkMask* mask) { fMask = mask; }
- size_t size = fMask->computeImageSize();
- const uint8_t* alpha = fMask->getAddr8(x, y);
- const uint8_t* mulp = alpha + size;
- const uint8_t* addp = mulp + size;
+ virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE {
+ if (fProxyContext) {
+ fProxyContext->shadeSpan(x, y, span, count);
+ }
- if (fProxy) {
- for (int i = 0; i < count; i++) {
- if (alpha[i]) {
- SkPMColor c = span[i];
- if (c) {
- unsigned a = SkGetPackedA32(c);
- unsigned r = SkGetPackedR32(c);
- unsigned g = SkGetPackedG32(c);
- unsigned b = SkGetPackedB32(c);
+ if (fMask == NULL) {
+ if (fProxyContext == NULL) {
+ sk_memset32(span, fPMColor, count);
+ }
+ return;
+ }
+ SkASSERT(fMask->fBounds.contains(x, y));
+ SkASSERT(fMask->fBounds.contains(x + count - 1, y));
+
+ size_t size = fMask->computeImageSize();
+ const uint8_t* alpha = fMask->getAddr8(x, y);
+ const uint8_t* mulp = alpha + size;
+ const uint8_t* addp = mulp + size;
+
+ if (fProxyContext) {
+ for (int i = 0; i < count; i++) {
+ if (alpha[i]) {
+ SkPMColor c = span[i];
+ if (c) {
+ unsigned a = SkGetPackedA32(c);
+ unsigned r = SkGetPackedR32(c);
+ unsigned g = SkGetPackedG32(c);
+ unsigned b = SkGetPackedB32(c);
+
+ unsigned mul = SkAlpha255To256(mulp[i]);
+ unsigned add = addp[i];
+
+ r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
+ g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
+ b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
+
+ span[i] = SkPackARGB32(a, r, g, b);
+ }
+ } else {
+ span[i] = 0;
+ }
+ }
+ } else { // color
+ unsigned a = SkGetPackedA32(fPMColor);
+ unsigned r = SkGetPackedR32(fPMColor);
+ unsigned g = SkGetPackedG32(fPMColor);
+ unsigned b = SkGetPackedB32(fPMColor);
+ for (int i = 0; i < count; i++) {
+ if (alpha[i]) {
unsigned mul = SkAlpha255To256(mulp[i]);
unsigned add = addp[i];
- r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
- g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
- b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
-
- span[i] = SkPackARGB32(a, r, g, b);
+ span[i] = SkPackARGB32( a,
+ SkFastMin32(SkAlphaMul(r, mul) + add, a),
+ SkFastMin32(SkAlphaMul(g, mul) + add, a),
+ SkFastMin32(SkAlphaMul(b, mul) + add, a));
+ } else {
+ span[i] = 0;
}
- } else {
- span[i] = 0;
- }
- }
- } else { // color
- unsigned a = SkGetPackedA32(fPMColor);
- unsigned r = SkGetPackedR32(fPMColor);
- unsigned g = SkGetPackedG32(fPMColor);
- unsigned b = SkGetPackedB32(fPMColor);
- for (int i = 0; i < count; i++) {
- if (alpha[i]) {
- unsigned mul = SkAlpha255To256(mulp[i]);
- unsigned add = addp[i];
-
- span[i] = SkPackARGB32( a,
- SkFastMin32(SkAlphaMul(r, mul) + add, a),
- SkFastMin32(SkAlphaMul(g, mul) + add, a),
- SkFastMin32(SkAlphaMul(b, mul) + add, a));
- } else {
- span[i] = 0;
}
}
}
- }
+
+ private:
+ // Unowned.
+ const SkMask* fMask;
+ // Memory is unowned, but we need to call the destructor.
+ SkShader::Context* fProxyContext;
+ SkPMColor fPMColor;
+
+ typedef SkShader::Context INHERITED;
+ };
#ifndef SK_IGNORE_TO_STRING
virtual void toString(SkString* str) const SK_OVERRIDE {
@@ -685,29 +741,30 @@ public:
protected:
Sk3DShader(SkReadBuffer& buffer) : INHERITED(buffer) {
fProxy = buffer.readShader();
- fPMColor = buffer.readColor();
- fMask = NULL;
+ // Leaving this here until we bump the picture version, though this
+ // shader should never be recorded.
+ buffer.readColor();
}
virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
this->INHERITED::flatten(buffer);
buffer.writeFlattenable(fProxy);
- buffer.writeColor(fPMColor);
+ // Leaving this here until we bump the picture version, though this
+ // shader should never be recorded.
+ buffer.writeColor(SkColor());
}
private:
SkShader* fProxy;
- SkPMColor fPMColor;
- const SkMask* fMask;
typedef SkShader INHERITED;
};
class Sk3DBlitter : public SkBlitter {
public:
- Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader)
+ Sk3DBlitter(SkBlitter* proxy, Sk3DShader::Sk3DShaderContext* shaderContext)
: fProxy(proxy)
- , f3DShader(SkRef(shader))
+ , f3DShaderContext(shaderContext)
{}
virtual void blitH(int x, int y, int width) {
@@ -729,22 +786,22 @@ public:
virtual void blitMask(const SkMask& mask, const SkIRect& clip) {
if (mask.fFormat == SkMask::k3D_Format) {
- f3DShader->setMask(&mask);
+ f3DShaderContext->setMask(&mask);
((SkMask*)&mask)->fFormat = SkMask::kA8_Format;
fProxy->blitMask(mask, clip);
((SkMask*)&mask)->fFormat = SkMask::k3D_Format;
- f3DShader->setMask(NULL);
+ f3DShaderContext->setMask(NULL);
} else {
fProxy->blitMask(mask, clip);
}
}
private:
- // fProxy is unowned. It will be deleted by SkSmallAllocator.
- SkBlitter* fProxy;
- SkAutoTUnref<Sk3DShader> f3DShader;
+ // Both pointers are unowned. They will be deleted by SkSmallAllocator.
+ SkBlitter* fProxy;
+ Sk3DShader::Sk3DShaderContext* f3DShaderContext;
};
///////////////////////////////////////////////////////////////////////////////
@@ -754,8 +811,7 @@ private:
static bool just_solid_color(const SkPaint& paint) {
if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
SkShader* shader = paint.getShader();
- if (NULL == shader ||
- (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+ if (NULL == shader) {
return true;
}
}
@@ -893,16 +949,22 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
}
/*
- * We need to have balanced calls to the shader:
- * setContext
- * endContext
- * We make the first call here, in case it fails we can abort the draw.
- * The endContext() call is made by the blitter (assuming setContext did
- * not fail) in its destructor.
+ * We create a SkShader::Context object, and store it on the blitter.
*/
- if (shader && !shader->setContext(device, *paint, matrix)) {
- blitter = allocator->createT<SkNullBlitter>();
- return blitter;
+ SkShader::Context* shaderContext;
+ if (shader) {
+ // Try to create the ShaderContext
+ void* storage = allocator->reserveT<SkShader::Context>(shader->contextSize());
+ shaderContext = shader->createContext(device, *paint, matrix, storage);
+ if (!shaderContext) {
+ allocator->freeLast();
+ blitter = allocator->createT<SkNullBlitter>();
+ return blitter;
+ }
+ SkASSERT(shaderContext);
+ SkASSERT((void*) shaderContext == storage);
+ } else {
+ shaderContext = NULL;
}
@@ -913,19 +975,20 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
SkASSERT(NULL == paint->getXfermode());
blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint);
} else if (shader) {
- blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint);
+ blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint, shaderContext);
} else {
blitter = allocator->createT<SkA8_Blitter>(device, *paint);
}
break;
case kRGB_565_SkColorType:
- blitter = SkBlitter_ChooseD565(device, *paint, allocator);
+ blitter = SkBlitter_ChooseD565(device, *paint, shaderContext, allocator);
break;
case kN32_SkColorType:
if (shader) {
- blitter = allocator->createT<SkARGB32_Shader_Blitter>(device, *paint);
+ blitter = allocator->createT<SkARGB32_Shader_Blitter>(
+ device, *paint, shaderContext);
} else if (paint->getColor() == SK_ColorBLACK) {
blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint);
} else if (paint->getAlpha() == 0xFF) {
@@ -944,7 +1007,9 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
if (shader3D) {
SkBlitter* innerBlitter = blitter;
// innerBlitter was allocated by allocator, which will delete it.
- blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shader3D);
+ // We know shaderContext is of type Sk3DShaderContext because it belongs to shader3D.
+ blitter = allocator->createT<Sk3DBlitter>(innerBlitter,
+ static_cast<Sk3DShader::Sk3DShaderContext*>(shaderContext));
}
return blitter;
}
@@ -956,18 +1021,36 @@ const uint32_t gMask_00FF00FF = 0xFF00FF;
///////////////////////////////////////////////////////////////////////////////
-SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint)
- : INHERITED(device) {
- fShader = paint.getShader();
+SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext)
+ : INHERITED(device)
+ , fShader(paint.getShader())
+ , fShaderContext(shaderContext) {
SkASSERT(fShader);
- SkASSERT(fShader->setContextHasBeenCalled());
+ SkASSERT(fShaderContext);
fShader->ref();
- fShaderFlags = fShader->getFlags();
+ fShaderFlags = fShaderContext->getFlags();
}
SkShaderBlitter::~SkShaderBlitter() {
- SkASSERT(fShader->setContextHasBeenCalled());
- fShader->endContext();
fShader->unref();
}
+
+bool SkShaderBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix) {
+ if (!fShader->validContext(device, paint, matrix)) {
+ return false;
+ }
+
+ // Only destroy the old context if we have a new one. We need to ensure to have a
+ // live context in fShaderContext because the storage is owned by an SkSmallAllocator
+ // outside of this class.
+ // The new context will be of the same size as the old one because we use the same
+ // shader to create it. It is therefore safe to re-use the storage.
+ fShaderContext->SkShader::Context::~Context();
+ fShaderContext = fShader->createContext(device, paint, matrix, (void*)fShaderContext);
+ SkASSERT(fShaderContext);
+
+ return true;
+}
diff --git a/src/core/SkBlitter.h b/src/core/SkBlitter.h
index d19a34badc..f76839e8b6 100644
--- a/src/core/SkBlitter.h
+++ b/src/core/SkBlitter.h
@@ -61,6 +61,13 @@ public:
*/
virtual bool isNullBlitter() const;
+ /**
+ * Special methods for SkShaderBlitter. On all other classes this is a no-op.
+ */
+ virtual bool resetShaderContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix);
+ virtual SkShader::Context* getShaderContext() const;
+
///@name non-virtual helpers
void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
void blitRectRegion(const SkIRect& rect, const SkRegion& clip);
diff --git a/src/core/SkBlitter_A8.cpp b/src/core/SkBlitter_A8.cpp
index 983a226e34..11f425903b 100644
--- a/src/core/SkBlitter_A8.cpp
+++ b/src/core/SkBlitter_A8.cpp
@@ -228,11 +228,12 @@ void SkA8_Blitter::blitRect(int x, int y, int width, int height) {
///////////////////////////////////////////////////////////////////////
-SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint)
- : INHERITED(device, paint) {
+SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext)
+ : INHERITED(device, paint, shaderContext) {
if ((fXfermode = paint.getXfermode()) != NULL) {
fXfermode->ref();
- SkASSERT(fShader);
+ SkASSERT(fShaderContext);
}
int width = device.width();
@@ -250,13 +251,14 @@ void SkA8_Shader_Blitter::blitH(int x, int y, int width) {
(unsigned)(x + width) <= (unsigned)fDevice.width());
uint8_t* device = fDevice.getAddr8(x, y);
+ SkShader::Context* shaderContext = fShaderContext;
- if ((fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) && !fXfermode) {
+ if ((shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) && !fXfermode) {
memset(device, 0xFF, width);
} else {
SkPMColor* span = fBuffer;
- fShader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
if (fXfermode) {
fXfermode->xferA8(device, span, width, NULL);
} else {
@@ -282,12 +284,12 @@ static inline uint8_t aa_blend8(SkPMColor src, U8CPU da, int aa) {
void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]) {
- SkShader* shader = fShader;
- SkXfermode* mode = fXfermode;
- uint8_t* aaExpand = fAAExpand;
- SkPMColor* span = fBuffer;
- uint8_t* device = fDevice.getAddr8(x, y);
- int opaque = fShader->getFlags() & SkShader::kOpaqueAlpha_Flag;
+ SkShader::Context* shaderContext = fShaderContext;
+ SkXfermode* mode = fXfermode;
+ uint8_t* aaExpand = fAAExpand;
+ SkPMColor* span = fBuffer;
+ uint8_t* device = fDevice.getAddr8(x, y);
+ int opaque = shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag;
for (;;) {
int count = *runs;
@@ -299,7 +301,7 @@ void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
if (opaque && aa == 255 && mode == NULL) {
memset(device, 0xFF, count);
} else {
- shader->shadeSpan(x, y, span, count);
+ shaderContext->shadeSpan(x, y, span, count);
if (mode) {
memset(aaExpand, aa, count);
mode->xferA8(device, span, count, aaExpand);
@@ -329,11 +331,12 @@ void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
int height = clip.height();
uint8_t* device = fDevice.getAddr8(x, y);
const uint8_t* alpha = mask.getAddr8(x, y);
+ SkShader::Context* shaderContext = fShaderContext;
SkPMColor* span = fBuffer;
while (--height >= 0) {
- fShader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
if (fXfermode) {
fXfermode->xferA8(device, span, width, alpha);
} else {
diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp
index d4bec1bc08..118a1d12f3 100644
--- a/src/core/SkBlitter_ARGB32.cpp
+++ b/src/core/SkBlitter_ARGB32.cpp
@@ -275,14 +275,16 @@ static void blend_srcmode(SkPMColor* SK_RESTRICT device,
}
SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
- const SkPaint& paint) : INHERITED(device, paint) {
+ const SkPaint& paint, SkShader::Context* shaderContext)
+ : INHERITED(device, paint, shaderContext)
+{
fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
fXfermode = paint.getXfermode();
SkSafeRef(fXfermode);
int flags = 0;
- if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+ if (!(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
flags |= SkBlitRow::kSrcPixelAlpha_Flag32;
}
// we call this on the output from the shader
@@ -292,7 +294,7 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
fShadeDirectlyIntoDevice = false;
if (fXfermode == NULL) {
- if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
+ if (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) {
fShadeDirectlyIntoDevice = true;
}
} else {
@@ -305,7 +307,7 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
}
}
- fConstInY = SkToBool(fShader->getFlags() & SkShader::kConstInY32_Flag);
+ fConstInY = SkToBool(shaderContext->getFlags() & SkShader::kConstInY32_Flag);
}
SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
@@ -319,10 +321,10 @@ void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) {
uint32_t* device = fDevice.getAddr32(x, y);
if (fShadeDirectlyIntoDevice) {
- fShader->shadeSpan(x, y, device, width);
+ fShaderContext->shadeSpan(x, y, device, width);
} else {
SkPMColor* span = fBuffer;
- fShader->shadeSpan(x, y, span, width);
+ fShaderContext->shadeSpan(x, y, span, width);
if (fXfermode) {
fXfermode->xfer32(device, span, width, NULL);
} else {
@@ -335,22 +337,22 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
SkASSERT(x >= 0 && y >= 0 &&
x + width <= fDevice.width() && y + height <= fDevice.height());
- uint32_t* device = fDevice.getAddr32(x, y);
- size_t deviceRB = fDevice.rowBytes();
- SkShader* shader = fShader;
- SkPMColor* span = fBuffer;
+ uint32_t* device = fDevice.getAddr32(x, y);
+ size_t deviceRB = fDevice.rowBytes();
+ SkShader::Context* shaderContext = fShaderContext;
+ SkPMColor* span = fBuffer;
if (fConstInY) {
if (fShadeDirectlyIntoDevice) {
// shade the first row directly into the device
- fShader->shadeSpan(x, y, device, width);
+ shaderContext->shadeSpan(x, y, device, width);
span = device;
while (--height > 0) {
device = (uint32_t*)((char*)device + deviceRB);
memcpy(device, span, width << 2);
}
} else {
- fShader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
@@ -372,7 +374,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
if (fShadeDirectlyIntoDevice) {
void* ctx;
- SkShader::ShadeProc shadeProc = fShader->asAShadeProc(&ctx);
+ SkShader::Context::ShadeProc shadeProc = shaderContext->asAShadeProc(&ctx);
if (shadeProc) {
do {
shadeProc(ctx, x, y, device, width);
@@ -381,7 +383,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
} while (--height > 0);
} else {
do {
- shader->shadeSpan(x, y, device, width);
+ shaderContext->shadeSpan(x, y, device, width);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
@@ -390,7 +392,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
- shader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
xfer->xfer32(device, span, width, NULL);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
@@ -398,7 +400,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
} else {
SkBlitRow::Proc32 proc = fProc32;
do {
- shader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
proc(device, span, width, 255);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
@@ -409,9 +411,9 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]) {
- SkPMColor* span = fBuffer;
- uint32_t* device = fDevice.getAddr32(x, y);
- SkShader* shader = fShader;
+ SkPMColor* span = fBuffer;
+ uint32_t* device = fDevice.getAddr32(x, y);
+ SkShader::Context* shaderContext = fShaderContext;
if (fXfermode && !fShadeDirectlyIntoDevice) {
for (;;) {
@@ -422,7 +424,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
break;
int aa = *antialias;
if (aa) {
- shader->shadeSpan(x, y, span, count);
+ shaderContext->shadeSpan(x, y, span, count);
if (aa == 255) {
xfer->xfer32(device, span, count, NULL);
} else {
@@ -438,7 +440,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
x += count;
}
} else if (fShadeDirectlyIntoDevice ||
- (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+ (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
for (;;) {
int count = *runs;
if (count <= 0) {
@@ -448,9 +450,9 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
if (aa) {
if (aa == 255) {
// cool, have the shader draw right into the device
- shader->shadeSpan(x, y, device, count);
+ shaderContext->shadeSpan(x, y, device, count);
} else {
- shader->shadeSpan(x, y, span, count);
+ shaderContext->shadeSpan(x, y, span, count);
fProc32Blend(device, span, count, aa);
}
}
@@ -467,7 +469,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
}
int aa = *antialias;
if (aa) {
- fShader->shadeSpan(x, y, span, count);
+ shaderContext->shadeSpan(x, y, span, count);
if (aa == 255) {
fProc32(device, span, count, 255);
} else {
@@ -491,10 +493,11 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
SkASSERT(mask.fBounds.contains(clip));
+ SkShader::Context* shaderContext = fShaderContext;
SkBlitMask::RowProc proc = NULL;
if (!fXfermode) {
unsigned flags = 0;
- if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
+ if (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) {
flags |= SkBlitMask::kSrcIsOpaque_RowFlag;
}
proc = SkBlitMask::RowFactory(SkBitmap::kARGB_8888_Config, mask.fFormat,
@@ -515,14 +518,13 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
const size_t maskRB = mask.fRowBytes;
- SkShader* shader = fShader;
SkPMColor* span = fBuffer;
if (fXfermode) {
SkASSERT(SkMask::kA8_Format == mask.fFormat);
SkXfermode* xfer = fXfermode;
do {
- shader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
xfer->xfer32((SkPMColor*)dstRow, span, width, maskRow);
dstRow += dstRB;
maskRow += maskRB;
@@ -530,7 +532,7 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
} while (--height > 0);
} else {
do {
- shader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
proc(dstRow, maskRow, span, width);
dstRow += dstRB;
maskRow += maskRB;
@@ -542,13 +544,13 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());
- uint32_t* device = fDevice.getAddr32(x, y);
- size_t deviceRB = fDevice.rowBytes();
- SkShader* shader = fShader;
+ uint32_t* device = fDevice.getAddr32(x, y);
+ size_t deviceRB = fDevice.rowBytes();
+ SkShader::Context* shaderContext = fShaderContext;
if (fConstInY) {
SkPMColor c;
- fShader->shadeSpan(x, y, &c, 1);
+ shaderContext->shadeSpan(x, y, &c, 1);
if (fShadeDirectlyIntoDevice) {
if (255 == alpha) {
@@ -582,7 +584,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
if (fShadeDirectlyIntoDevice) {
void* ctx;
- SkShader::ShadeProc shadeProc = fShader->asAShadeProc(&ctx);
+ SkShader::Context::ShadeProc shadeProc = shaderContext->asAShadeProc(&ctx);
if (255 == alpha) {
if (shadeProc) {
do {
@@ -592,7 +594,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
} while (--height > 0);
} else {
do {
- shader->shadeSpan(x, y, device, 1);
+ shaderContext->shadeSpan(x, y, device, 1);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
@@ -608,7 +610,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
} while (--height > 0);
} else {
do {
- shader->shadeSpan(x, y, &c, 1);
+ shaderContext->shadeSpan(x, y, &c, 1);
*device = SkFourByteInterp(c, *device, alpha);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
@@ -620,7 +622,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
- shader->shadeSpan(x, y, span, 1);
+ shaderContext->shadeSpan(x, y, span, 1);
xfer->xfer32(device, span, 1, &alpha);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
@@ -628,7 +630,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
} else {
SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
do {
- shader->shadeSpan(x, y, span, 1);
+ shaderContext->shadeSpan(x, y, span, 1);
proc(device, span, 1, alpha);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
diff --git a/src/core/SkBlitter_RGB16.cpp b/src/core/SkBlitter_RGB16.cpp
index 21b5a16e3c..e22aac4eda 100644
--- a/src/core/SkBlitter_RGB16.cpp
+++ b/src/core/SkBlitter_RGB16.cpp
@@ -107,7 +107,8 @@ private:
class SkRGB16_Shader_Blitter : public SkShaderBlitter {
public:
- SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkRGB16_Shader_Blitter();
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
@@ -129,7 +130,8 @@ private:
// used only if the shader can perform shadSpan16
class SkRGB16_Shader16_Blitter : public SkRGB16_Shader_Blitter {
public:
- SkRGB16_Shader16_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkRGB16_Shader16_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
const int16_t* runs);
@@ -141,7 +143,8 @@ private:
class SkRGB16_Shader_Xfermode_Blitter : public SkShaderBlitter {
public:
- SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkRGB16_Shader_Xfermode_Blitter();
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
@@ -679,8 +682,9 @@ void SkRGB16_Blitter::blitRect(int x, int y, int width, int height) {
///////////////////////////////////////////////////////////////////////////////
SkRGB16_Shader16_Blitter::SkRGB16_Shader16_Blitter(const SkBitmap& device,
- const SkPaint& paint)
- : SkRGB16_Shader_Blitter(device, paint) {
+ const SkPaint& paint,
+ SkShader::Context* shaderContext)
+ : SkRGB16_Shader_Blitter(device, paint, shaderContext) {
SkASSERT(SkShader::CanCallShadeSpan16(fShaderFlags));
}
@@ -688,28 +692,28 @@ void SkRGB16_Shader16_Blitter::blitH(int x, int y, int width) {
SkASSERT(x + width <= fDevice.width());
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
- SkShader* shader = fShader;
+ SkShader::Context* shaderContext = fShaderContext;
- int alpha = shader->getSpan16Alpha();
+ int alpha = shaderContext->getSpan16Alpha();
if (0xFF == alpha) {
- shader->shadeSpan16(x, y, device, width);
+ shaderContext->shadeSpan16(x, y, device, width);
} else {
uint16_t* span16 = (uint16_t*)fBuffer;
- shader->shadeSpan16(x, y, span16, width);
+ shaderContext->shadeSpan16(x, y, span16, width);
SkBlendRGB16(span16, device, SkAlpha255To256(alpha), width);
}
}
void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
- SkShader* shader = fShader;
- uint16_t* dst = fDevice.getAddr16(x, y);
- size_t dstRB = fDevice.rowBytes();
- int alpha = shader->getSpan16Alpha();
+ SkShader::Context* shaderContext = fShaderContext;
+ uint16_t* dst = fDevice.getAddr16(x, y);
+ size_t dstRB = fDevice.rowBytes();
+ int alpha = shaderContext->getSpan16Alpha();
if (0xFF == alpha) {
if (fShaderFlags & SkShader::kConstInY16_Flag) {
// have the shader blit directly into the device the first time
- shader->shadeSpan16(x, y, dst, width);
+ shaderContext->shadeSpan16(x, y, dst, width);
// and now just memcpy that line on the subsequent lines
if (--height > 0) {
const uint16_t* orig = dst;
@@ -720,7 +724,7 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
}
} else { // need to call shadeSpan16 for every line
do {
- shader->shadeSpan16(x, y, dst, width);
+ shaderContext->shadeSpan16(x, y, dst, width);
y += 1;
dst = (uint16_t*)((char*)dst + dstRB);
} while (--height);
@@ -729,14 +733,14 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
int scale = SkAlpha255To256(alpha);
uint16_t* span16 = (uint16_t*)fBuffer;
if (fShaderFlags & SkShader::kConstInY16_Flag) {
- shader->shadeSpan16(x, y, span16, width);
+ shaderContext->shadeSpan16(x, y, span16, width);
do {
SkBlendRGB16(span16, dst, scale, width);
dst = (uint16_t*)((char*)dst + dstRB);
} while (--height);
} else {
do {
- shader->shadeSpan16(x, y, span16, width);
+ shaderContext->shadeSpan16(x, y, span16, width);
SkBlendRGB16(span16, dst, scale, width);
y += 1;
dst = (uint16_t*)((char*)dst + dstRB);
@@ -748,11 +752,11 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
const int16_t* SK_RESTRICT runs) {
- SkShader* shader = fShader;
+ SkShader::Context* shaderContext = fShaderContext;
SkPMColor* SK_RESTRICT span = fBuffer;
- uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
+ uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
- int alpha = shader->getSpan16Alpha();
+ int alpha = shaderContext->getSpan16Alpha();
uint16_t* span16 = (uint16_t*)span;
if (0xFF == alpha) {
@@ -766,9 +770,9 @@ void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
int aa = *antialias;
if (aa == 255) {
// go direct to the device!
- shader->shadeSpan16(x, y, device, count);
+ shaderContext->shadeSpan16(x, y, device, count);
} else if (aa) {
- shader->shadeSpan16(x, y, span16, count);
+ shaderContext->shadeSpan16(x, y, span16, count);
SkBlendRGB16(span16, device, SkAlpha255To256(aa), count);
}
device += count;
@@ -787,7 +791,7 @@ void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
int aa = SkAlphaMul(*antialias, alpha);
if (aa) {
- shader->shadeSpan16(x, y, span16, count);
+ shaderContext->shadeSpan16(x, y, span16, count);
SkBlendRGB16(span16, device, SkAlpha255To256(aa), count);
}
@@ -802,8 +806,9 @@ void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
///////////////////////////////////////////////////////////////////////////////
SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkBitmap& device,
- const SkPaint& paint)
-: INHERITED(device, paint) {
+ const SkPaint& paint,
+ SkShader::Context* shaderContext)
+: INHERITED(device, paint, shaderContext) {
SkASSERT(paint.getXfermode() == NULL);
fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor));
@@ -834,20 +839,20 @@ SkRGB16_Shader_Blitter::~SkRGB16_Shader_Blitter() {
void SkRGB16_Shader_Blitter::blitH(int x, int y, int width) {
SkASSERT(x + width <= fDevice.width());
- fShader->shadeSpan(x, y, fBuffer, width);
+ fShaderContext->shadeSpan(x, y, fBuffer, width);
// shaders take care of global alpha, so we pass 0xFF (should be ignored)
fOpaqueProc(fDevice.getAddr16(x, y), fBuffer, width, 0xFF, x, y);
}
void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) {
- SkShader* shader = fShader;
- SkBlitRow::Proc proc = fOpaqueProc;
- SkPMColor* buffer = fBuffer;
- uint16_t* dst = fDevice.getAddr16(x, y);
- size_t dstRB = fDevice.rowBytes();
+ SkShader::Context* shaderContext = fShaderContext;
+ SkBlitRow::Proc proc = fOpaqueProc;
+ SkPMColor* buffer = fBuffer;
+ uint16_t* dst = fDevice.getAddr16(x, y);
+ size_t dstRB = fDevice.rowBytes();
if (fShaderFlags & SkShader::kConstInY32_Flag) {
- shader->shadeSpan(x, y, buffer, width);
+ shaderContext->shadeSpan(x, y, buffer, width);
do {
proc(dst, buffer, width, 0xFF, x, y);
y += 1;
@@ -855,7 +860,7 @@ void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) {
} while (--height);
} else {
do {
- shader->shadeSpan(x, y, buffer, width);
+ shaderContext->shadeSpan(x, y, buffer, width);
proc(dst, buffer, width, 0xFF, x, y);
y += 1;
dst = (uint16_t*)((char*)dst + dstRB);
@@ -880,9 +885,9 @@ static inline int count_nonzero_span(const int16_t runs[], const SkAlpha aa[]) {
void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
const int16_t* SK_RESTRICT runs) {
- SkShader* shader = fShader;
+ SkShader::Context* shaderContext = fShaderContext;
SkPMColor* SK_RESTRICT span = fBuffer;
- uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
+ uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
for (;;) {
int count = *runs;
@@ -901,7 +906,7 @@ void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
int nonZeroCount = count + count_nonzero_span(runs + count, antialias + count);
SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer
- shader->shadeSpan(x, y, span, nonZeroCount);
+ shaderContext->shadeSpan(x, y, span, nonZeroCount);
SkPMColor* localSpan = span;
for (;;) {
@@ -928,8 +933,9 @@ void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
///////////////////////////////////////////////////////////////////////
SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter(
- const SkBitmap& device, const SkPaint& paint)
-: INHERITED(device, paint) {
+ const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext)
+: INHERITED(device, paint, shaderContext) {
fXfermode = paint.getXfermode();
SkASSERT(fXfermode);
fXfermode->ref();
@@ -950,18 +956,18 @@ void SkRGB16_Shader_Xfermode_Blitter::blitH(int x, int y, int width) {
uint16_t* device = fDevice.getAddr16(x, y);
SkPMColor* span = fBuffer;
- fShader->shadeSpan(x, y, span, width);
+ fShaderContext->shadeSpan(x, y, span, width);
fXfermode->xfer16(device, span, width, NULL);
}
void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
const int16_t* SK_RESTRICT runs) {
- SkShader* shader = fShader;
- SkXfermode* mode = fXfermode;
+ SkShader::Context* shaderContext = fShaderContext;
+ SkXfermode* mode = fXfermode;
SkPMColor* SK_RESTRICT span = fBuffer;
- uint8_t* SK_RESTRICT aaExpand = fAAExpand;
- uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
+ uint8_t* SK_RESTRICT aaExpand = fAAExpand;
+ uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
for (;;) {
int count = *runs;
@@ -981,7 +987,7 @@ void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
antialias + count);
SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer
- shader->shadeSpan(x, y, span, nonZeroCount);
+ shaderContext->shadeSpan(x, y, span, nonZeroCount);
x += nonZeroCount;
SkPMColor* localSpan = span;
@@ -1012,6 +1018,7 @@ void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
///////////////////////////////////////////////////////////////////////////////
SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext,
SkTBlitterAllocator* allocator) {
SkASSERT(allocator != NULL);
@@ -1023,12 +1030,14 @@ SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
SkASSERT(NULL == mode || NULL != shader);
if (shader) {
+ SkASSERT(shaderContext != NULL);
if (mode) {
- blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint);
- } else if (shader->canCallShadeSpan16()) {
- blitter = allocator->createT<SkRGB16_Shader16_Blitter>(device, paint);
+ blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint,
+ shaderContext);
+ } else if (shaderContext->canCallShadeSpan16()) {
+ blitter = allocator->createT<SkRGB16_Shader16_Blitter>(device, paint, shaderContext);
} else {
- blitter = allocator->createT<SkRGB16_Shader_Blitter>(device, paint);
+ blitter = allocator->createT<SkRGB16_Shader_Blitter>(device, paint, shaderContext);
}
} else {
// no shader, no xfermode, (and we always ignore colorfilter)
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 569e9e59ba..c1d2726d8c 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -91,32 +91,10 @@ private:
};
#endif
-class AutoCheckNoSetContext {
-public:
- AutoCheckNoSetContext(const SkPaint& paint) : fPaint(paint) {
- this->assertNoSetContext(fPaint);
- }
- ~AutoCheckNoSetContext() {
- this->assertNoSetContext(fPaint);
- }
-
-private:
- const SkPaint& fPaint;
-
- void assertNoSetContext(const SkPaint& paint) {
- SkShader* s = paint.getShader();
- if (s) {
- SkASSERT(!s->setContextHasBeenCalled());
- }
- }
-};
-
#define CHECK_LOCKCOUNT_BALANCE(bitmap) AutoCheckLockCountBalance clcb(bitmap)
-#define CHECK_SHADER_NOSETCONTEXT(paint) AutoCheckNoSetContext cshsc(paint)
#else
#define CHECK_LOCKCOUNT_BALANCE(bitmap)
- #define CHECK_SHADER_NOSETCONTEXT(paint)
#endif
typedef SkTLazy<SkPaint> SkLazyPaint;
@@ -1935,8 +1913,6 @@ void SkCanvas::drawPaint(const SkPaint& paint) {
}
void SkCanvas::internalDrawPaint(const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
while (iter.next()) {
@@ -1952,8 +1928,6 @@ void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
return;
}
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect r, storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -1981,8 +1955,6 @@ void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
}
void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -2002,8 +1974,6 @@ void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
}
void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -2023,8 +1993,6 @@ void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
}
void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -2055,8 +2023,6 @@ void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -2076,8 +2042,6 @@ void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
}
void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
if (!path.isFinite()) {
return;
}
@@ -2353,8 +2317,6 @@ void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
void SkCanvas::drawText(const void* text, size_t byteLength,
SkScalar x, SkScalar y, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
while (iter.next()) {
@@ -2369,8 +2331,6 @@ void SkCanvas::drawText(const void* text, size_t byteLength,
void SkCanvas::drawPosText(const void* text, size_t byteLength,
const SkPoint pos[], const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
while (iter.next()) {
@@ -2385,8 +2345,6 @@ void SkCanvas::drawPosText(const void* text, size_t byteLength,
void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
const SkScalar xpos[], SkScalar constY,
const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
while (iter.next()) {
@@ -2401,8 +2359,6 @@ void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
const SkPath& path, const SkMatrix* matrix,
const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
while (iter.next()) {
@@ -2418,8 +2374,6 @@ void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
while (iter.next()) {
diff --git a/src/core/SkComposeShader.cpp b/src/core/SkComposeShader.cpp
index f53eedf876..68c4646cf6 100644
--- a/src/core/SkComposeShader.cpp
+++ b/src/core/SkComposeShader.cpp
@@ -45,6 +45,10 @@ SkComposeShader::~SkComposeShader() {
fShaderA->unref();
}
+size_t SkComposeShader::contextSize() const {
+ return sizeof(ComposeShaderContext) + fShaderA->contextSize() + fShaderB->contextSize();
+}
+
class SkAutoAlphaRestore {
public:
SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
@@ -69,17 +73,16 @@ void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
buffer.writeFlattenable(fMode);
}
-/* We call setContext on our two worker shaders. However, we
- always let them see opaque alpha, and if the paint really
- is translucent, then we apply that after the fact.
+/* We call validContext/createContext on our two worker shaders.
+ However, we always let them see opaque alpha, and if the paint
+ really is translucent, then we apply that after the fact.
- We need to keep the calls to setContext/endContext balanced, since if we
- return false, our endContext() will not be called.
*/
-bool SkComposeShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- if (!this->INHERITED::setContext(device, paint, matrix)) {
+bool SkComposeShader::validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse) const {
+ if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
return false;
}
@@ -90,38 +93,62 @@ bool SkComposeShader::setContext(const SkBitmap& device,
tmpM.setConcat(matrix, this->getLocalMatrix());
- SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF);
+ return fShaderA->validContext(device, paint, tmpM) &&
+ fShaderB->validContext(device, paint, tmpM);
+}
- bool setContextA = fShaderA->setContext(device, paint, tmpM);
- bool setContextB = fShaderB->setContext(device, paint, tmpM);
- if (!setContextA || !setContextB) {
- if (setContextB) {
- fShaderB->endContext();
- }
- else if (setContextA) {
- fShaderA->endContext();
- }
- this->INHERITED::endContext();
- return false;
+SkShader::Context* SkComposeShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
}
- return true;
+
+ // we preconcat our localMatrix (if any) with the device matrix
+ // before calling our sub-shaders
+
+ SkMatrix tmpM;
+
+ tmpM.setConcat(matrix, this->getLocalMatrix());
+
+ SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF);
+
+ char* aStorage = (char*) storage + sizeof(ComposeShaderContext);
+ char* bStorage = aStorage + fShaderA->contextSize();
+
+ SkShader::Context* contextA = fShaderA->createContext(device, paint, tmpM, aStorage);
+ SkShader::Context* contextB = fShaderB->createContext(device, paint, tmpM, bStorage);
+
+ // Both functions must succeed; otherwise validContext should have returned
+ // false.
+ SkASSERT(contextA);
+ SkASSERT(contextB);
+
+ return SkNEW_PLACEMENT_ARGS(storage, ComposeShaderContext,
+ (*this, device, paint, matrix, contextA, contextB));
}
-void SkComposeShader::endContext() {
- fShaderB->endContext();
- fShaderA->endContext();
- this->INHERITED::endContext();
+SkComposeShader::ComposeShaderContext::ComposeShaderContext(
+ const SkComposeShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix,
+ SkShader::Context* contextA, SkShader::Context* contextB)
+ : INHERITED(shader, device, paint, matrix)
+ , fShaderContextA(contextA)
+ , fShaderContextB(contextB) {}
+
+SkComposeShader::ComposeShaderContext::~ComposeShaderContext() {
+ fShaderContextA->SkShader::Context::~Context();
+ fShaderContextB->SkShader::Context::~Context();
}
// larger is better (fewer times we have to loop), but we shouldn't
// take up too much stack-space (each element is 4 bytes)
#define TMP_COLOR_COUNT 64
-void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
- SkShader* shaderA = fShaderA;
- SkShader* shaderB = fShaderB;
- SkXfermode* mode = fMode;
- unsigned scale = SkAlpha255To256(this->getPaintAlpha());
+void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
+ SkShader::Context* shaderContextA = fShaderContextA;
+ SkShader::Context* shaderContextB = fShaderContextB;
+ SkXfermode* mode = static_cast<const SkComposeShader&>(fShader).fMode;
+ unsigned scale = SkAlpha255To256(this->getPaintAlpha());
SkPMColor tmp[TMP_COLOR_COUNT];
@@ -134,8 +161,8 @@ void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
n = TMP_COLOR_COUNT;
}
- shaderA->shadeSpan(x, y, result, n);
- shaderB->shadeSpan(x, y, tmp, n);
+ shaderContextA->shadeSpan(x, y, result, n);
+ shaderContextB->shadeSpan(x, y, tmp, n);
if (256 == scale) {
for (int i = 0; i < n; i++) {
@@ -159,8 +186,8 @@ void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
n = TMP_COLOR_COUNT;
}
- shaderA->shadeSpan(x, y, result, n);
- shaderB->shadeSpan(x, y, tmp, n);
+ shaderContextA->shadeSpan(x, y, result, n);
+ shaderContextB->shadeSpan(x, y, tmp, n);
mode->xfer32(result, tmp, n, NULL);
if (256 == scale) {
diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h
index 285184050b..2d22d38e78 100644
--- a/src/core/SkCoreBlitters.h
+++ b/src/core/SkCoreBlitters.h
@@ -27,12 +27,29 @@ private:
class SkShaderBlitter : public SkRasterBlitter {
public:
- SkShaderBlitter(const SkBitmap& device, const SkPaint& paint);
+ /**
+ * The storage for shaderContext is owned by the caller, but the object itself is not.
+ * The blitter only ensures that the storage always holds a live object, but it may
+ * exchange that object.
+ */
+ SkShaderBlitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkShaderBlitter();
+ /**
+ * Create a new shader context and uses it instead of the old one if successful.
+ * Will create the context at the same location as the old one (this is safe
+ * because the shader itself is unchanged).
+ */
+ virtual bool resetShaderContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix) SK_OVERRIDE;
+
+ virtual SkShader::Context* getShaderContext() const SK_OVERRIDE { return fShaderContext; }
+
protected:
- uint32_t fShaderFlags;
- SkShader* fShader;
+ uint32_t fShaderFlags;
+ const SkShader* fShader;
+ SkShader::Context* fShaderContext;
private:
// illegal
@@ -75,7 +92,8 @@ private:
class SkA8_Shader_Blitter : public SkShaderBlitter {
public:
- SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkA8_Shader_Blitter();
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]);
@@ -141,7 +159,8 @@ private:
class SkARGB32_Shader_Blitter : public SkShaderBlitter {
public:
- SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkARGB32_Shader_Blitter();
virtual void blitH(int x, int y, int width) SK_OVERRIDE;
virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE;
@@ -179,6 +198,7 @@ private:
*/
SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext,
SkTBlitterAllocator* allocator);
#endif
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 7eb0be6b6b..6ddd0d274f 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -2354,9 +2354,26 @@ class SkTriColorShader : public SkShader {
public:
SkTriColorShader() {}
- bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
+ virtual SkShader::Context* createContext(
+ const SkBitmap&, const SkPaint&, const SkMatrix&, void*) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ class TriColorShaderContext : public SkShader::Context {
+ public:
+ TriColorShaderContext(const SkTriColorShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
+ virtual ~TriColorShaderContext();
+
+ bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
+
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+
+ private:
+ SkMatrix fDstToUnit;
+ SkPMColor fColors[3];
+
+ typedef SkShader::Context INHERITED;
+ };
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTriColorShader)
@@ -2365,14 +2382,20 @@ protected:
SkTriColorShader(SkReadBuffer& buffer) : SkShader(buffer) {}
private:
- SkMatrix fDstToUnit;
- SkPMColor fColors[3];
-
typedef SkShader INHERITED;
};
-bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[],
- int index0, int index1, int index2) {
+SkShader::Context* SkTriColorShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, TriColorShaderContext, (*this, device, paint, matrix));
+}
+
+bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[],
+ int index0, int index1, int index2) {
fColors[0] = SkPreMultiplyColor(colors[index0]);
fColors[1] = SkPreMultiplyColor(colors[index1]);
@@ -2407,7 +2430,18 @@ static int ScalarTo256(SkScalar v) {
return SkAlpha255To256(scale);
}
-void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
+
+SkTriColorShader::TriColorShaderContext::TriColorShaderContext(
+ const SkTriColorShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix) {}
+
+SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {}
+
+size_t SkTriColorShader::contextSize() const {
+ return sizeof(TriColorShaderContext);
+}
+void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
SkPoint src;
for (int i = 0; i < count; i++) {
@@ -2492,6 +2526,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
}
// setup the custom shader (if needed)
+ SkAutoTUnref<SkComposeShader> composeShader;
if (NULL != colors) {
if (NULL == textures) {
// just colors (no texture)
@@ -2504,9 +2539,8 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
xmode = SkXfermode::Create(SkXfermode::kModulate_Mode);
releaseMode = true;
}
- SkShader* compose = SkNEW_ARGS(SkComposeShader,
- (&triShader, shader, xmode));
- p.setShader(compose)->unref();
+ composeShader.reset(SkNEW_ARGS(SkComposeShader, (&triShader, shader, xmode)));
+ p.setShader(composeShader);
if (releaseMode) {
xmode->unref();
}
@@ -2514,9 +2548,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
}
SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p);
- // important that we abort early, as below we may manipulate the shader
- // and that is only valid if the shader returned true from setContext.
- // If it returned false, then our blitter will be the NullBlitter.
+ // Abort early if we failed to create a shader context.
if (blitter->isNullBlitter()) {
return;
}
@@ -2532,30 +2564,38 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
savedLocalM = shader->getLocalMatrix();
}
- // setContext has already been called and verified to return true
- // by the constructor of SkAutoBlitterChoose
- bool prevContextSuccess = true;
while (vertProc(&state)) {
if (NULL != textures) {
if (texture_to_matrix(state, vertices, textures, &tempM)) {
tempM.postConcat(savedLocalM);
shader->setLocalMatrix(tempM);
- // Need to recall setContext since we changed the local matrix.
- // However, we also need to balance the calls this with a
- // call to endContext which requires tracking the result of
- // the previous call to setContext.
- if (prevContextSuccess) {
- shader->endContext();
- }
- prevContextSuccess = shader->setContext(*fBitmap, p, *fMatrix);
- if (!prevContextSuccess) {
+ if (!blitter->resetShaderContext(*fBitmap, p, *fMatrix)) {
continue;
}
}
}
if (NULL != colors) {
- if (!triShader.setup(vertices, colors,
- state.f0, state.f1, state.f2)) {
+ // Find the context for triShader.
+ SkTriColorShader::TriColorShaderContext* triColorShaderContext;
+
+ SkShader::Context* shaderContext = blitter->getShaderContext();
+ SkASSERT(shaderContext);
+ if (p.getShader() == &triShader) {
+ triColorShaderContext =
+ static_cast<SkTriColorShader::TriColorShaderContext*>(shaderContext);
+ } else {
+ // The shader is a compose shader and triShader is its first shader.
+ SkASSERT(p.getShader() == composeShader);
+ SkASSERT(composeShader->getShaderA() == &triShader);
+ SkComposeShader::ComposeShaderContext* composeShaderContext =
+ static_cast<SkComposeShader::ComposeShaderContext*>(shaderContext);
+ SkShader::Context* shaderContextA = composeShaderContext->getShaderContextA();
+ triColorShaderContext =
+ static_cast<SkTriColorShader::TriColorShaderContext*>(shaderContextA);
+ }
+
+ if (!triColorShaderContext->setup(vertices, colors,
+ state.f0, state.f1, state.f2)) {
continue;
}
}
@@ -2570,13 +2610,6 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
if (NULL != shader) {
shader->setLocalMatrix(savedLocalM);
}
-
- // If the final call to setContext fails we must make it suceed so that the
- // call to endContext in the destructor for SkAutoBlitterChoose is balanced.
- if (!prevContextSuccess) {
- prevContextSuccess = shader->setContext(*fBitmap, paint, SkMatrix::I());
- SkASSERT(prevContextSuccess);
- }
} else {
// no colors[] and no texture
HairProc hairProc = ChooseHairProc(paint.isAntiAlias());
diff --git a/src/core/SkFilterShader.cpp b/src/core/SkFilterShader.cpp
index 58961913c8..1a0255157d 100644
--- a/src/core/SkFilterShader.cpp
+++ b/src/core/SkFilterShader.cpp
@@ -38,9 +38,11 @@ void SkFilterShader::flatten(SkWriteBuffer& buffer) const {
buffer.writeFlattenable(fFilter);
}
-uint32_t SkFilterShader::getFlags() {
- uint32_t shaderF = fShader->getFlags();
- uint32_t filterF = fFilter->getFlags();
+uint32_t SkFilterShader::FilterShaderContext::getFlags() const {
+ const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
+
+ uint32_t shaderF = fShaderContext->getFlags();
+ uint32_t filterF = filterShader.fFilter->getFlags();
// if the filter doesn't support 16bit, clear the matching bit in the shader
if (!(filterF & SkColorFilter::kHasFilter16_Flag)) {
@@ -53,38 +55,62 @@ uint32_t SkFilterShader::getFlags() {
return shaderF;
}
-bool SkFilterShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- // we need to keep the setContext/endContext calls balanced. If we return
- // false, our endContext() will not be called.
-
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
- }
- if (!fShader->setContext(device, paint, matrix)) {
- this->INHERITED::endContext();
- return false;
+SkShader::Context* SkFilterShader::createContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
}
- return true;
+
+ char* shaderContextStorage = (char*)storage + sizeof(FilterShaderContext);
+ SkShader::Context* shaderContext = fShader->createContext(device, paint, matrix,
+ shaderContextStorage);
+ SkASSERT(shaderContext);
+
+ return SkNEW_PLACEMENT_ARGS(storage, FilterShaderContext,
+ (*this, shaderContext, device, paint, matrix));
+}
+
+size_t SkFilterShader::contextSize() const {
+ return sizeof(FilterShaderContext) + fShader->contextSize();
+}
+
+bool SkFilterShader::validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse) const {
+ return this->INHERITED::validContext(device, paint, matrix, totalInverse) &&
+ fShader->validContext(device, paint, matrix);
}
-void SkFilterShader::endContext() {
- fShader->endContext();
- this->INHERITED::endContext();
+SkFilterShader::FilterShaderContext::FilterShaderContext(const SkFilterShader& filterShader,
+ SkShader::Context* shaderContext,
+ const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix)
+ : INHERITED(filterShader, device, paint, matrix)
+ , fShaderContext(shaderContext) {}
+
+SkFilterShader::FilterShaderContext::~FilterShaderContext() {
+ fShaderContext->SkShader::Context::~Context();
}
-void SkFilterShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
- fShader->shadeSpan(x, y, result, count);
- fFilter->filterSpan(result, count, result);
+void SkFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
+ const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
+
+ fShaderContext->shadeSpan(x, y, result, count);
+ filterShader.fFilter->filterSpan(result, count, result);
}
-void SkFilterShader::shadeSpan16(int x, int y, uint16_t result[], int count) {
- SkASSERT(fShader->getFlags() & SkShader::kHasSpan16_Flag);
- SkASSERT(fFilter->getFlags() & SkColorFilter::kHasFilter16_Flag);
+void SkFilterShader::FilterShaderContext::shadeSpan16(int x, int y, uint16_t result[], int count) {
+ const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
+
+ SkASSERT(fShaderContext->getFlags() & SkShader::kHasSpan16_Flag);
+ SkASSERT(filterShader.fFilter->getFlags() & SkColorFilter::kHasFilter16_Flag);
- fShader->shadeSpan16(x, y, result, count);
- fFilter->filterSpan16(result, count, result);
+ fShaderContext->shadeSpan16(x, y, result, count);
+ filterShader.fFilter->filterSpan16(result, count, result);
}
#ifndef SK_IGNORE_TO_STRING
diff --git a/src/core/SkFilterShader.h b/src/core/SkFilterShader.h
index 11add0cf17..4ef4577248 100644
--- a/src/core/SkFilterShader.h
+++ b/src/core/SkFilterShader.h
@@ -17,12 +17,29 @@ public:
SkFilterShader(SkShader* shader, SkColorFilter* filter);
virtual ~SkFilterShader();
- virtual uint32_t getFlags() SK_OVERRIDE;
- virtual bool setContext(const SkBitmap&, const SkPaint&,
- const SkMatrix&) SK_OVERRIDE;
- virtual void endContext() SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE;
+ virtual bool validContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, void* storage) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
+ class FilterShaderContext : public SkShader::Context {
+ public:
+ // Takes ownership of shaderContext and calls its destructor.
+ FilterShaderContext(const SkFilterShader& filterShader, SkShader::Context* shaderContext,
+ const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix);
+ virtual ~FilterShaderContext();
+
+ virtual uint32_t getFlags() const SK_OVERRIDE;
+
+ virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE;
+
+ private:
+ SkShader::Context* fShaderContext;
+
+ typedef SkShader::Context INHERITED;
+ };
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkFilterShader)
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
index 15df3a37a5..1e9507190c 100644
--- a/src/core/SkPictureShader.cpp
+++ b/src/core/SkPictureShader.cpp
@@ -55,9 +55,9 @@ void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
}
}
-bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
+SkShader* SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
if (!fPicture || (0 == fPicture->width() && 0 == fPicture->height())) {
- return false;
+ return NULL;
}
SkMatrix m;
@@ -78,17 +78,20 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
SkISize tileSize = scaledSize.toRound();
if (tileSize.isEmpty()) {
- return false;
+ return NULL;
}
// The actual scale, compensating for rounding.
SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(),
SkIntToScalar(tileSize.height()) / fPicture->height());
- if (!fCachedShader || tileScale != fCachedTileScale) {
+ SkAutoMutexAcquire ama(fCachedBitmapShaderMutex);
+
+ if (!fCachedBitmapShader || tileScale != fCachedTileScale ||
+ this->getLocalMatrix() != fCachedLocalMatrix) {
SkBitmap bm;
if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) {
- return false;
+ return NULL;
}
bm.eraseColor(SK_ColorTRANSPARENT);
@@ -96,66 +99,96 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
canvas.scale(tileScale.width(), tileScale.height());
canvas.drawPicture(*fPicture);
- fCachedShader.reset(CreateBitmapShader(bm, fTmx, fTmy));
+ fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy));
fCachedTileScale = tileScale;
- }
+ fCachedLocalMatrix = this->getLocalMatrix();
- SkMatrix shaderMatrix = this->getLocalMatrix();
- shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
- fCachedShader->setLocalMatrix(shaderMatrix);
+ SkMatrix shaderMatrix = this->getLocalMatrix();
+ shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
+ fCachedBitmapShader->setLocalMatrix(shaderMatrix);
+ }
- return true;
+ // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
+ // Otherwise, the pointer may have been overwritten on a different thread before the object's
+ // ref count was incremented.
+ fCachedBitmapShader.get()->ref();
+ return fCachedBitmapShader;
}
-bool SkPictureShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- if (!this->buildBitmapShader(matrix)) {
- return false;
+SkShader* SkPictureShader::validInternal(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse) const {
+ if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
+ return NULL;
}
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
+ SkShader* bitmapShader = this->buildBitmapShader(matrix);
+ if (!bitmapShader) {
+ return NULL;
}
- SkASSERT(fCachedShader);
- if (!fCachedShader->setContext(device, paint, matrix)) {
- this->INHERITED::endContext();
- return false;
+ if (!bitmapShader->validContext(device, paint, matrix)) {
+ bitmapShader->unref();
+ return NULL;
}
- return true;
+ return bitmapShader;
}
-void SkPictureShader::endContext() {
- SkASSERT(fCachedShader);
- fCachedShader->endContext();
-
- this->INHERITED::endContext();
+bool SkPictureShader::validContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse) const {
+ SkAutoTUnref<SkShader> shader(this->validInternal(device, paint, matrix, totalInverse));
+ return shader != NULL;
}
-uint32_t SkPictureShader::getFlags() {
- if (NULL != fCachedShader) {
- return fCachedShader->getFlags();
+SkShader::Context* SkPictureShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ SkShader* bitmapShader = this->validInternal(device, paint, matrix, NULL);
+ if (!bitmapShader) {
+ return NULL;
}
- return 0;
+
+ return SkNEW_PLACEMENT_ARGS(storage, PictureShaderContext,
+ (*this, device, paint, matrix, bitmapShader));
}
-SkShader::ShadeProc SkPictureShader::asAShadeProc(void** ctx) {
- if (fCachedShader) {
- return fCachedShader->asAShadeProc(ctx);
- }
- return NULL;
+size_t SkPictureShader::contextSize() const {
+ return sizeof(PictureShaderContext);
+}
+
+SkPictureShader::PictureShaderContext::PictureShaderContext(
+ const SkPictureShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix, SkShader* bitmapShader)
+ : INHERITED(shader, device, paint, matrix)
+ , fBitmapShader(bitmapShader)
+{
+ SkASSERT(fBitmapShader);
+ fBitmapShaderContextStorage = sk_malloc_throw(fBitmapShader->contextSize());
+ fBitmapShaderContext = fBitmapShader->createContext(
+ device, paint, matrix, fBitmapShaderContextStorage);
+ SkASSERT(fBitmapShaderContext);
+}
+
+SkPictureShader::PictureShaderContext::~PictureShaderContext() {
+ fBitmapShaderContext->SkShader::Context::~Context();
+ sk_free(fBitmapShaderContextStorage);
+}
+
+uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
+ return fBitmapShaderContext->getFlags();
+}
+
+SkShader::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) {
+ return fBitmapShaderContext->asAShadeProc(ctx);
}
-void SkPictureShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
- SkASSERT(fCachedShader);
- fCachedShader->shadeSpan(x, y, dstC, count);
+void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
+ SkASSERT(fBitmapShaderContext);
+ fBitmapShaderContext->shadeSpan(x, y, dstC, count);
}
-void SkPictureShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
- SkASSERT(fCachedShader);
- fCachedShader->shadeSpan16(x, y, dstC, count);
+void SkPictureShader::PictureShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
+ SkASSERT(fBitmapShaderContext);
+ fBitmapShaderContext->shadeSpan16(x, y, dstC, count);
}
#ifndef SK_IGNORE_TO_STRING
@@ -176,10 +209,10 @@ void SkPictureShader::toString(SkString* str) const {
#if SK_SUPPORT_GPU
GrEffectRef* SkPictureShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
- if (!this->buildBitmapShader(context->getMatrix())) {
+ SkAutoTUnref<SkShader> bitmapShader(this->buildBitmapShader(context->getMatrix()));
+ if (!bitmapShader) {
return NULL;
}
- SkASSERT(fCachedShader);
- return fCachedShader->asNewEffect(context, paint);
+ return bitmapShader->asNewEffect(context, paint);
}
#endif
diff --git a/src/core/SkPictureShader.h b/src/core/SkPictureShader.h
index ea74b56d73..a0a377d0cd 100644
--- a/src/core/SkPictureShader.h
+++ b/src/core/SkPictureShader.h
@@ -24,13 +24,33 @@ public:
static SkPictureShader* Create(SkPicture*, TileMode, TileMode);
virtual ~SkPictureShader();
- virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
- virtual void endContext() SK_OVERRIDE;
- virtual uint32_t getFlags() SK_OVERRIDE;
+ virtual bool validContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const
+ SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
- virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+ class PictureShaderContext : public SkShader::Context {
+ public:
+ PictureShaderContext(const SkPictureShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix,
+ SkShader* bitmapShader);
+ virtual ~PictureShaderContext();
+
+ virtual uint32_t getFlags() const SK_OVERRIDE;
+
+ virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE;
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+
+ private:
+ SkAutoTUnref<SkShader> fBitmapShader;
+ SkShader::Context* fBitmapShaderContext;
+ void* fBitmapShaderContextStorage;
+
+ typedef SkShader::Context INHERITED;
+ };
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPictureShader)
@@ -46,13 +66,18 @@ protected:
private:
SkPictureShader(SkPicture*, TileMode, TileMode);
- bool buildBitmapShader(const SkMatrix&) const;
+ SkShader* validInternal(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse) const;
+
+ SkShader* buildBitmapShader(const SkMatrix&) const;
SkPicture* fPicture;
TileMode fTmx, fTmy;
- mutable SkAutoTUnref<SkShader> fCachedShader;
+ mutable SkMutex fCachedBitmapShaderMutex;
+ mutable SkAutoTUnref<SkShader> fCachedBitmapShader;
mutable SkSize fCachedTileScale;
+ mutable SkMatrix fCachedLocalMatrix;
typedef SkShader INHERITED;
};
diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp
index e337b7d906..40e52a05cb 100644
--- a/src/core/SkShader.cpp
+++ b/src/core/SkShader.cpp
@@ -17,7 +17,6 @@
SkShader::SkShader() {
fLocalMatrix.reset();
- SkDEBUGCODE(fInSetContext = false;)
}
SkShader::SkShader(SkReadBuffer& buffer)
@@ -27,12 +26,9 @@ SkShader::SkShader(SkReadBuffer& buffer)
} else {
fLocalMatrix.reset();
}
-
- SkDEBUGCODE(fInSetContext = false;)
}
SkShader::~SkShader() {
- SkASSERT(!fInSetContext);
}
void SkShader::flatten(SkWriteBuffer& buffer) const {
@@ -44,39 +40,48 @@ void SkShader::flatten(SkWriteBuffer& buffer) const {
}
}
-bool SkShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- SkASSERT(!this->setContextHasBeenCalled());
-
+bool SkShader::computeTotalInverse(const SkMatrix& matrix, SkMatrix* totalInverse) const {
const SkMatrix* m = &matrix;
SkMatrix total;
- fPaintAlpha = paint.getAlpha();
if (this->hasLocalMatrix()) {
total.setConcat(matrix, this->getLocalMatrix());
m = &total;
}
- if (m->invert(&fTotalInverse)) {
- fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
- SkDEBUGCODE(fInSetContext = true;)
- return true;
- }
- return false;
+
+ return m->invert(totalInverse);
+}
+
+bool SkShader::validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse) const {
+ return this->computeTotalInverse(matrix, totalInverse);
}
-void SkShader::endContext() {
- SkASSERT(fInSetContext);
- SkDEBUGCODE(fInSetContext = false;)
+SkShader::Context::Context(const SkShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : fShader(shader)
+{
+ SkASSERT(fShader.validContext(device, paint, matrix));
+
+ // Because the context parameters must be valid at this point, we know that the matrix is
+ // invertible.
+ SkAssertResult(fShader.computeTotalInverse(matrix, &fTotalInverse));
+ fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
+
+ fPaintAlpha = paint.getAlpha();
}
-SkShader::ShadeProc SkShader::asAShadeProc(void** ctx) {
+SkShader::Context::~Context() {}
+
+SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) {
return NULL;
}
#include "SkColorPriv.h"
-void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) {
+void SkShader::Context::shadeSpan16(int x, int y, uint16_t span16[], int count) {
SkASSERT(span16);
SkASSERT(count > 0);
SkASSERT(this->canCallShadeSpan16());
@@ -94,7 +99,7 @@ void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) {
#define SkU32BitShiftToByteOffset(shift) ((shift) >> 3)
#endif
-void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
+void SkShader::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
SkASSERT(count > 0);
SkPMColor colors[kTempColorCount];
@@ -148,7 +153,7 @@ void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
#endif
}
-SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
+SkShader::Context::MatrixClass SkShader::Context::ComputeMatrixClass(const SkMatrix& mat) {
MatrixClass mc = kLinear_MatrixClass;
if (mat.hasPerspective()) {
@@ -163,8 +168,7 @@ SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
//////////////////////////////////////////////////////////////////////////////
-SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*,
- TileMode*) const {
+SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, TileMode*) const {
return kNone_BitmapType;
}
@@ -199,19 +203,16 @@ void SkShader::toString(SkString* str) const {
#include "SkColorShader.h"
#include "SkUtils.h"
-SkColorShader::SkColorShader() {
- fFlags = 0;
- fInheritColor = true;
+SkColorShader::SkColorShader()
+ : fColor()
+ , fInheritColor(true) {
}
-SkColorShader::SkColorShader(SkColor c) {
- fFlags = 0;
- fColor = c;
- fInheritColor = false;
+SkColorShader::SkColorShader(SkColor c)
+ : fColor(c)
+ , fInheritColor(false) {
}
-SkColorShader::~SkColorShader() {}
-
bool SkColorShader::isOpaque() const {
if (fInheritColor) {
return true; // using paint's alpha
@@ -220,8 +221,6 @@ bool SkColorShader::isOpaque() const {
}
SkColorShader::SkColorShader(SkReadBuffer& b) : INHERITED(b) {
- fFlags = 0; // computed in setContext
-
fInheritColor = b.readBool();
if (fInheritColor) {
return;
@@ -238,32 +237,43 @@ void SkColorShader::flatten(SkWriteBuffer& buffer) const {
buffer.writeColor(fColor);
}
-uint32_t SkColorShader::getFlags() {
+uint32_t SkColorShader::ColorShaderContext::getFlags() const {
return fFlags;
}
-uint8_t SkColorShader::getSpan16Alpha() const {
+uint8_t SkColorShader::ColorShaderContext::getSpan16Alpha() const {
return SkGetPackedA32(fPMColor);
}
-bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix) {
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
+SkShader::Context* SkColorShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
}
+ return SkNEW_PLACEMENT_ARGS(storage, ColorShaderContext, (*this, device, paint, matrix));
+}
+
+SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader,
+ const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix)
+{
unsigned a;
- if (fInheritColor) {
- fColor = paint.getColor();
- a = SkColorGetA(fColor);
+ SkColor color;
+ if (shader.fInheritColor) {
+ color = paint.getColor();
+ a = SkColorGetA(color);
} else {
- a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha()));
+ color = shader.fColor;
+ a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(paint.getAlpha()));
}
- unsigned r = SkColorGetR(fColor);
- unsigned g = SkColorGetG(fColor);
- unsigned b = SkColorGetB(fColor);
+ unsigned r = SkColorGetR(color);
+ unsigned g = SkColorGetG(color);
+ unsigned b = SkColorGetB(color);
// we want this before we apply any alpha
fColor16 = SkPack888ToRGB16(r, g, b);
@@ -282,19 +292,17 @@ bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
fFlags |= kHasSpan16_Flag;
}
}
-
- return true;
}
-void SkColorShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
+void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) {
sk_memset32(span, fPMColor, count);
}
-void SkColorShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
+void SkColorShader::ColorShaderContext::shadeSpan16(int x, int y, uint16_t span[], int count) {
sk_memset16(span, fColor16, count);
}
-void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
+void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
memset(alpha, SkGetPackedA32(fPMColor), count);
}
@@ -334,27 +342,9 @@ void SkColorShader::toString(SkString* str) const {
///////////////////////////////////////////////////////////////////////////////
+#ifndef SK_IGNORE_TO_STRING
#include "SkEmptyShader.h"
-uint32_t SkEmptyShader::getFlags() { return 0; }
-uint8_t SkEmptyShader::getSpan16Alpha() const { return 0; }
-
-bool SkEmptyShader::setContext(const SkBitmap&, const SkPaint&,
- const SkMatrix&) { return false; }
-
-void SkEmptyShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
- SkDEBUGFAIL("should never get called, since setContext() returned false");
-}
-
-void SkEmptyShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
- SkDEBUGFAIL("should never get called, since setContext() returned false");
-}
-
-void SkEmptyShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
- SkDEBUGFAIL("should never get called, since setContext() returned false");
-}
-
-#ifndef SK_IGNORE_TO_STRING
void SkEmptyShader::toString(SkString* str) const {
str->append("SkEmptyShader: (");
diff --git a/src/core/SkSmallAllocator.h b/src/core/SkSmallAllocator.h
index 655008b706..8d4b53a707 100644
--- a/src/core/SkSmallAllocator.h
+++ b/src/core/SkSmallAllocator.h
@@ -117,10 +117,12 @@ public:
// but we're not sure we can catch all callers, so handle it but
// assert false in debug mode.
SkASSERT(false);
+ rec->fStorageSize = 0;
rec->fHeapStorage = sk_malloc_throw(storageRequired);
rec->fObj = static_cast<void*>(rec->fHeapStorage);
} else {
// There is space in fStorage.
+ rec->fStorageSize = storageRequired;
rec->fHeapStorage = NULL;
SkASSERT(SkIsAlign4(fStorageUsed));
rec->fObj = static_cast<void*>(fStorage + (fStorageUsed / 4));
@@ -131,11 +133,26 @@ public:
return rec->fObj;
}
+ /*
+ * Free the memory reserved last without calling the destructor.
+ * Can be used in a nested way, i.e. after reserving A and B, calling
+ * freeLast once will free B and calling it again will free A.
+ */
+ void freeLast() {
+ SkASSERT(fNumObjects > 0);
+ Rec* rec = &fRecs[fNumObjects - 1];
+ sk_free(rec->fHeapStorage);
+ fStorageUsed -= rec->fStorageSize;
+
+ fNumObjects--;
+ }
+
private:
struct Rec {
- void* fObj;
- void* fHeapStorage;
- void (*fKillProc)(void*);
+ size_t fStorageSize; // 0 if allocated on heap
+ void* fObj;
+ void* fHeapStorage;
+ void (*fKillProc)(void*);
};
// Number of bytes used so far.
diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp
index ed63fafae1..5adb582506 100644
--- a/src/effects/SkPerlinNoiseShader.cpp
+++ b/src/effects/SkPerlinNoiseShader.cpp
@@ -278,7 +278,6 @@ SkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type,
, fStitchTiles(!fTileSize.isEmpty())
{
SkASSERT(numOctaves >= 0 && numOctaves < 256);
- fMatrix.reset();
fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY));
}
@@ -293,7 +292,6 @@ SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer)
fStitchTiles = buffer.readBool();
fTileSize.fWidth = buffer.readInt();
fTileSize.fHeight = buffer.readInt();
- fMatrix.reset();
fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY));
buffer.validate(perlin_noise_type_is_valid(fType) &&
(fNumOctaves >= 0) && (fNumOctaves <= 255) &&
@@ -317,9 +315,9 @@ void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const {
buffer.writeInt(fTileSize.fHeight);
}
-SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingData,
- const StitchData& stitchData,
- const SkPoint& noiseVector) const {
+SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::noise2D(
+ int channel, const PaintingData& paintingData,
+ const StitchData& stitchData, const SkPoint& noiseVector) const {
struct Noise {
int noisePositionIntegerValue;
SkScalar noisePositionFractionValue;
@@ -333,8 +331,9 @@ SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingD
Noise noiseX(noiseVector.x());
Noise noiseY(noiseVector.y());
SkScalar u, v;
+ const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader);
// If stitching, adjust lattice points accordingly.
- if (fStitchTiles) {
+ if (perlinNoiseShader.fStitchTiles) {
noiseX.noisePositionIntegerValue =
checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
noiseY.noisePositionIntegerValue =
@@ -365,11 +364,11 @@ SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingD
return SkScalarInterp(a, b, sy);
}
-SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel,
- const PaintingData& paintingData,
- StitchData& stitchData,
- const SkPoint& point) const {
- if (fStitchTiles) {
+SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
+ int channel, const PaintingData& paintingData,
+ StitchData& stitchData, const SkPoint& point) const {
+ const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader);
+ if (perlinNoiseShader.fStitchTiles) {
// Set up TurbulenceInitial stitch values.
stitchData = paintingData.fStitchDataInit;
}
@@ -377,14 +376,14 @@ SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel,
SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), paintingData.fBaseFrequency.fX),
SkScalarMul(point.y(), paintingData.fBaseFrequency.fY)));
SkScalar ratio = SK_Scalar1;
- for (int octave = 0; octave < fNumOctaves; ++octave) {
+ for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
SkScalar noise = noise2D(channel, paintingData, stitchData, noiseVector);
turbulenceFunctionResult += SkScalarDiv(
- (fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio);
+ (perlinNoiseShader.fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio);
noiseVector.fX *= 2;
noiseVector.fY *= 2;
ratio *= 2;
- if (fStitchTiles) {
+ if (perlinNoiseShader.fStitchTiles) {
// Update stitch values
stitchData.fWidth *= 2;
stitchData.fWrapX = stitchData.fWidth + kPerlinNoise;
@@ -395,7 +394,7 @@ SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel,
// The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
// by fractalNoise and (turbulenceFunctionResult) by turbulence.
- if (fType == kFractalNoise_Type) {
+ if (perlinNoiseShader.fType == kFractalNoise_Type) {
turbulenceFunctionResult =
SkScalarMul(turbulenceFunctionResult, SK_ScalarHalf) + SK_ScalarHalf;
}
@@ -409,7 +408,9 @@ SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel,
return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
}
-SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchData) const {
+SkPMColor SkPerlinNoiseShader::PerlinNoiseShaderContext::shade(
+ const SkPoint& point, StitchData& stitchData) const {
+ const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader);
SkPoint newPoint;
fMatrix.mapPoints(&newPoint, &point, 1);
newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
@@ -418,15 +419,32 @@ SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchDat
U8CPU rgba[4];
for (int channel = 3; channel >= 0; --channel) {
rgba[channel] = SkScalarFloorToInt(255 *
- calculateTurbulenceValueForPoint(channel, *fPaintingData, stitchData, newPoint));
+ calculateTurbulenceValueForPoint(channel, *perlinNoiseShader.fPaintingData,
+ stitchData, newPoint));
}
return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
}
-bool SkPerlinNoiseShader::setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix) {
+SkShader::Context* SkPerlinNoiseShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, PerlinNoiseShaderContext, (*this, device, paint, matrix));
+}
+
+size_t SkPerlinNoiseShader::contextSize() const {
+ return sizeof(PerlinNoiseShaderContext);
+}
+
+SkPerlinNoiseShader::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
+ const SkPerlinNoiseShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix)
+{
SkMatrix newMatrix = matrix;
- newMatrix.postConcat(getLocalMatrix());
+ newMatrix.postConcat(shader.getLocalMatrix());
SkMatrix invMatrix;
if (!newMatrix.invert(&invMatrix)) {
invMatrix.reset();
@@ -437,10 +455,10 @@ bool SkPerlinNoiseShader::setContext(const SkBitmap& device, const SkPaint& pain
newMatrix.postConcat(invMatrix);
newMatrix.postConcat(invMatrix);
fMatrix = newMatrix;
- return INHERITED::setContext(device, paint, matrix);
}
-void SkPerlinNoiseShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
+void SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan(
+ int x, int y, SkPMColor result[], int count) {
SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
StitchData stitchData;
for (int i = 0; i < count; ++i) {
@@ -449,7 +467,8 @@ void SkPerlinNoiseShader::shadeSpan(int x, int y, SkPMColor result[], int count)
}
}
-void SkPerlinNoiseShader::shadeSpan16(int x, int y, uint16_t result[], int count) {
+void SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan16(
+ int x, int y, uint16_t result[], int count) {
SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
StitchData stitchData;
DITHER_565_SCAN(y);
diff --git a/src/effects/SkTransparentShader.cpp b/src/effects/SkTransparentShader.cpp
index bd8b99a3c0..0997e62013 100644
--- a/src/effects/SkTransparentShader.cpp
+++ b/src/effects/SkTransparentShader.cpp
@@ -11,26 +11,40 @@
#include "SkColorPriv.h"
#include "SkString.h"
-bool SkTransparentShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- fDevice = &device;
- fAlpha = paint.getAlpha();
+SkShader::Context* SkTransparentShader::createContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, TransparentShaderContext, (*this, device, paint, matrix));
+}
- return this->INHERITED::setContext(device, paint, matrix);
+size_t SkTransparentShader::contextSize() const {
+ return sizeof(TransparentShaderContext);
}
-uint32_t SkTransparentShader::getFlags() {
+SkTransparentShader::TransparentShaderContext::TransparentShaderContext(
+ const SkTransparentShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix)
+ , fDevice(&device) {}
+
+SkTransparentShader::TransparentShaderContext::~TransparentShaderContext() {}
+
+uint32_t SkTransparentShader::TransparentShaderContext::getFlags() const {
uint32_t flags = this->INHERITED::getFlags();
switch (fDevice->colorType()) {
case kRGB_565_SkColorType:
flags |= kHasSpan16_Flag;
- if (fAlpha == 255)
+ if (this->getPaintAlpha() == 255)
flags |= kOpaqueAlpha_Flag;
break;
case kN32_SkColorType:
- if (fAlpha == 255 && fDevice->isOpaque())
+ if (this->getPaintAlpha() == 255 && fDevice->isOpaque())
flags |= kOpaqueAlpha_Flag;
break;
default:
@@ -39,8 +53,9 @@ uint32_t SkTransparentShader::getFlags() {
return flags;
}
-void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
- unsigned scale = SkAlpha255To256(fAlpha);
+void SkTransparentShader::TransparentShaderContext::shadeSpan(int x, int y, SkPMColor span[],
+ int count) {
+ unsigned scale = SkAlpha255To256(this->getPaintAlpha());
switch (fDevice->colorType()) {
case kN32_SkColorType:
@@ -63,7 +78,7 @@ void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
span[i] = SkPixel16ToPixel32(src[i]);
}
} else {
- unsigned alpha = fAlpha;
+ unsigned alpha = this->getPaintAlpha();
for (int i = count - 1; i >= 0; --i) {
uint16_t c = src[i];
unsigned r = SkPacked16ToR32(c);
@@ -97,7 +112,8 @@ void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
}
}
-void SkTransparentShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
+void SkTransparentShader::TransparentShaderContext::shadeSpan16(int x, int y, uint16_t span[],
+ int count) {
SkASSERT(fDevice->colorType() == kRGB_565_SkColorType);
uint16_t* src = fDevice->getAddr16(x, y);
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 2ebb9c71d9..666204e0ae 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -15,8 +15,6 @@
SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
SkASSERT(desc.fCount > 1);
- fCacheAlpha = 256; // init to a value that paint.getAlpha() can't return
-
fMapper = desc.fMapper;
SkSafeRef(fMapper);
fGradFlags = SkToU8(desc.fFlags);
@@ -26,10 +24,6 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
fTileMode = desc.fTileMode;
fTileProc = gTileProcs[desc.fTileMode];
- fCache16 = fCache16Storage = NULL;
- fCache32 = NULL;
- fCache32PixelRef = NULL;
-
/* Note: we let the caller skip the first and/or last position.
i.e. pos[0] = 0.3, pos[1] = 0.7
In these cases, we insert dummy entries to ensure that the final data
@@ -144,14 +138,8 @@ static uint32_t unpack_flags(uint32_t packed) {
}
SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buffer) {
- fCacheAlpha = 256;
-
fMapper = buffer.readUnitMapper();
- fCache16 = fCache16Storage = NULL;
- fCache32 = NULL;
- fCache32PixelRef = NULL;
-
int colorCount = fColorCount = buffer.getArrayCount();
if (colorCount > kColorStorageCount) {
size_t allocSize = (sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec)) * colorCount;
@@ -186,10 +174,6 @@ SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buf
}
SkGradientShaderBase::~SkGradientShaderBase() {
- if (fCache16Storage) {
- sk_free(fCache16Storage);
- }
- SkSafeUnref(fCache32PixelRef);
if (fOrigColors != fStorage) {
sk_free(fOrigColors);
}
@@ -197,7 +181,6 @@ SkGradientShaderBase::~SkGradientShaderBase() {
}
void SkGradientShaderBase::initCommon() {
- fFlags = 0;
unsigned colorAlpha = 0xFF;
for (int i = 0; i < fColorCount; i++) {
colorAlpha &= SkColorGetA(fOrigColors[i]);
@@ -224,49 +207,50 @@ bool SkGradientShaderBase::isOpaque() const {
return fColorsAreOpaque;
}
-bool SkGradientShaderBase::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
- }
-
+SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext(
+ const SkGradientShaderBase& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix)
+ , fCache(shader.getCache(getPaintAlpha()))
+{
const SkMatrix& inverse = this->getTotalInverse();
- fDstToIndex.setConcat(fPtsToUnit, inverse);
+ fDstToIndex.setConcat(shader.fPtsToUnit, inverse);
+
fDstToIndexProc = fDstToIndex.getMapXYProc();
- fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex);
+ fDstToIndexClass = (uint8_t)SkShader::Context::ComputeMatrixClass(fDstToIndex);
// now convert our colors in to PMColors
unsigned paintAlpha = this->getPaintAlpha();
fFlags = this->INHERITED::getFlags();
- if (fColorsAreOpaque && paintAlpha == 0xFF) {
+ if (shader.fColorsAreOpaque && paintAlpha == 0xFF) {
fFlags |= kOpaqueAlpha_Flag;
}
// we can do span16 as long as our individual colors are opaque,
// regardless of the paint's alpha
- if (fColorsAreOpaque) {
+ if (shader.fColorsAreOpaque) {
fFlags |= kHasSpan16_Flag;
}
+}
- this->setCacheAlpha(paintAlpha);
- return true;
+SkGradientShaderBase::GradientShaderCache::GradientShaderCache(
+ U8CPU alpha, const SkGradientShaderBase& shader)
+ : fCacheAlpha(alpha)
+ , fShader(shader)
+ , fCache16Inited(false)
+ , fCache32Inited(false)
+{
+ // Only initialize the cache in getCache16/32.
+ fCache16 = NULL;
+ fCache32 = NULL;
+ fCache16Storage = NULL;
+ fCache32PixelRef = NULL;
}
-void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const {
- // if the new alpha differs from the previous time we were called, inval our cache
- // this will trigger the cache to be rebuilt.
- // we don't care about the first time, since the cache ptrs will already be NULL
- if (fCacheAlpha != alpha) {
- fCache16 = NULL; // inval the cache
- fCache32 = NULL; // inval the cache
- fCacheAlpha = alpha; // record the new alpha
- // inform our subclasses
- if (fCache32PixelRef) {
- fCache32PixelRef->notifyPixelsChanged();
- }
- }
+SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() {
+ sk_free(fCache16Storage);
+ SkSafeUnref(fCache32PixelRef);
}
#define Fixed_To_Dot8(x) (((x) + 0x80) >> 8)
@@ -275,8 +259,8 @@ void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const {
build a 16bit table as long as the original colors are opaque, even if the
paint specifies a non-opaque alpha.
*/
-void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1,
- int count) {
+void SkGradientShaderBase::GradientShaderCache::Build16bitCache(
+ uint16_t cache[], SkColor c0, SkColor c1, int count) {
SkASSERT(count > 1);
SkASSERT(SkColorGetA(c0) == 0xFF);
SkASSERT(SkColorGetA(c1) == 0xFF);
@@ -324,8 +308,9 @@ void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor
*/
typedef uint32_t SkUFixed;
-void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
- int count, U8CPU paintAlpha, uint32_t gradFlags) {
+void SkGradientShaderBase::GradientShaderCache::Build32bitCache(
+ SkPMColor cache[], SkColor c0, SkColor c1,
+ int count, U8CPU paintAlpha, uint32_t gradFlags) {
SkASSERT(count > 1);
// need to apply paintAlpha to our two endpoints
@@ -468,97 +453,121 @@ static inline U16CPU bitsTo16(unsigned x, const unsigned bits) {
return 0;
}
-const uint16_t* SkGradientShaderBase::getCache16() const {
- if (fCache16 == NULL) {
- // double the count for dither entries
- const int entryCount = kCache16Count * 2;
- const size_t allocSize = sizeof(uint16_t) * entryCount;
+const uint16_t* SkGradientShaderBase::GradientShaderCache::getCache16() {
+ SkOnce(&fCache16Inited, &fCache16Mutex, SkGradientShaderBase::GradientShaderCache::initCache16,
+ this);
+ SkASSERT(fCache16);
+ return fCache16;
+}
- if (fCache16Storage == NULL) { // set the storage and our working ptr
- fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
- }
- fCache16 = fCache16Storage;
- if (fColorCount == 2) {
- Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1],
- kCache16Count);
- } else {
- Rec* rec = fRecs;
- int prevIndex = 0;
- for (int i = 1; i < fColorCount; i++) {
- int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
- SkASSERT(nextIndex < kCache16Count);
-
- if (nextIndex > prevIndex)
- Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1);
- prevIndex = nextIndex;
- }
+void SkGradientShaderBase::GradientShaderCache::initCache16(GradientShaderCache* cache) {
+ // double the count for dither entries
+ const int entryCount = kCache16Count * 2;
+ const size_t allocSize = sizeof(uint16_t) * entryCount;
+
+ SkASSERT(NULL == cache->fCache16Storage);
+ cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
+ cache->fCache16 = cache->fCache16Storage;
+ if (cache->fShader.fColorCount == 2) {
+ Build16bitCache(cache->fCache16, cache->fShader.fOrigColors[0],
+ cache->fShader.fOrigColors[1], kCache16Count);
+ } else {
+ Rec* rec = cache->fShader.fRecs;
+ int prevIndex = 0;
+ for (int i = 1; i < cache->fShader.fColorCount; i++) {
+ int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
+ SkASSERT(nextIndex < kCache16Count);
+
+ if (nextIndex > prevIndex)
+ Build16bitCache(cache->fCache16 + prevIndex, cache->fShader.fOrigColors[i-1],
+ cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1);
+ prevIndex = nextIndex;
}
+ }
- if (fMapper) {
- fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
- uint16_t* linear = fCache16; // just computed linear data
- uint16_t* mapped = fCache16Storage; // storage for mapped data
- SkUnitMapper* map = fMapper;
- for (int i = 0; i < kCache16Count; i++) {
- int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift;
- mapped[i] = linear[index];
- mapped[i + kCache16Count] = linear[index + kCache16Count];
- }
- sk_free(fCache16);
- fCache16 = fCache16Storage;
+ if (cache->fShader.fMapper) {
+ cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
+ uint16_t* linear = cache->fCache16; // just computed linear data
+ uint16_t* mapped = cache->fCache16Storage; // storage for mapped data
+ SkUnitMapper* map = cache->fShader.fMapper;
+ for (int i = 0; i < kCache16Count; i++) {
+ int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift;
+ mapped[i] = linear[index];
+ mapped[i + kCache16Count] = linear[index + kCache16Count];
}
+ sk_free(cache->fCache16);
+ cache->fCache16 = cache->fCache16Storage;
}
- return fCache16;
}
-const SkPMColor* SkGradientShaderBase::getCache32() const {
- if (fCache32 == NULL) {
- SkImageInfo info;
- info.fWidth = kCache32Count;
- info.fHeight = 4; // for our 4 dither rows
- info.fAlphaType = kPremul_SkAlphaType;
- info.fColorType = kN32_SkColorType;
+const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() {
+ SkOnce(&fCache32Inited, &fCache32Mutex, SkGradientShaderBase::GradientShaderCache::initCache32,
+ this);
+ SkASSERT(fCache32);
+ return fCache32;
+}
- if (NULL == fCache32PixelRef) {
- fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL);
- }
- fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
- if (fColorCount == 2) {
- Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
- kCache32Count, fCacheAlpha, fGradFlags);
- } else {
- Rec* rec = fRecs;
- int prevIndex = 0;
- for (int i = 1; i < fColorCount; i++) {
- int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
- SkASSERT(nextIndex < kCache32Count);
-
- if (nextIndex > prevIndex)
- Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1],
- fOrigColors[i], nextIndex - prevIndex + 1,
- fCacheAlpha, fGradFlags);
- prevIndex = nextIndex;
- }
+void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* cache) {
+ SkImageInfo info;
+ info.fWidth = kCache32Count;
+ info.fHeight = 4; // for our 4 dither rows
+ info.fAlphaType = kPremul_SkAlphaType;
+ info.fColorType = kN32_SkColorType;
+
+ SkASSERT(NULL == cache->fCache32PixelRef);
+ cache->fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL);
+ cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->getAddr();
+ if (cache->fShader.fColorCount == 2) {
+ Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0],
+ cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha,
+ cache->fShader.fGradFlags);
+ } else {
+ Rec* rec = cache->fShader.fRecs;
+ int prevIndex = 0;
+ for (int i = 1; i < cache->fShader.fColorCount; i++) {
+ int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
+ SkASSERT(nextIndex < kCache32Count);
+
+ if (nextIndex > prevIndex)
+ Build32bitCache(cache->fCache32 + prevIndex, cache->fShader.fOrigColors[i-1],
+ cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1,
+ cache->fCacheAlpha, cache->fShader.fGradFlags);
+ prevIndex = nextIndex;
}
+ }
- if (fMapper) {
- SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL);
- SkPMColor* linear = fCache32; // just computed linear data
- SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data
- SkUnitMapper* map = fMapper;
- for (int i = 0; i < kCache32Count; i++) {
- int index = map->mapUnit16((i << 8) | i) >> 8;
- mapped[i + kCache32Count*0] = linear[index + kCache32Count*0];
- mapped[i + kCache32Count*1] = linear[index + kCache32Count*1];
- mapped[i + kCache32Count*2] = linear[index + kCache32Count*2];
- mapped[i + kCache32Count*3] = linear[index + kCache32Count*3];
- }
- fCache32PixelRef->unref();
- fCache32PixelRef = newPR;
- fCache32 = (SkPMColor*)newPR->getAddr();
+ if (cache->fShader.fMapper) {
+ SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL);
+ SkPMColor* linear = cache->fCache32; // just computed linear data
+ SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data
+ SkUnitMapper* map = cache->fShader.fMapper;
+ for (int i = 0; i < kCache32Count; i++) {
+ int index = map->mapUnit16((i << 8) | i) >> 8;
+ mapped[i + kCache32Count*0] = linear[index + kCache32Count*0];
+ mapped[i + kCache32Count*1] = linear[index + kCache32Count*1];
+ mapped[i + kCache32Count*2] = linear[index + kCache32Count*2];
+ mapped[i + kCache32Count*3] = linear[index + kCache32Count*3];
}
+ cache->fCache32PixelRef->unref();
+ cache->fCache32PixelRef = newPR;
+ cache->fCache32 = (SkPMColor*)newPR->getAddr();
}
- return fCache32;
+}
+
+/*
+ * The gradient holds a cache for the most recent value of alpha. Successive
+ * callers with the same alpha value will share the same cache.
+ */
+SkGradientShaderBase::GradientShaderCache* SkGradientShaderBase::getCache(U8CPU alpha) const {
+ SkAutoMutexAcquire ama(fCacheMutex);
+ if (!fCache || fCache->getAlpha() != alpha) {
+ fCache.reset(SkNEW_ARGS(GradientShaderCache, (alpha, *this)));
+ }
+ // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
+ // Otherwise, the pointer may have been overwritten on a different thread before the object's
+ // ref count was incremented.
+ fCache.get()->ref();
+ return fCache;
}
/*
@@ -572,14 +581,14 @@ const SkPMColor* SkGradientShaderBase::getCache32() const {
void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
// our caller assumes no external alpha, so we ensure that our cache is
// built with 0xFF
- this->setCacheAlpha(0xFF);
+ GradientShaderCache* cache = this->getCache(0xFF);
// don't have a way to put the mapper into our cache-key yet
if (fMapper) {
- // force our cahce32pixelref to be built
- (void)this->getCache32();
+ // force our cache32pixelref to be built
+ (void)cache->getCache32();
bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1));
- bitmap->setPixelRef(fCache32PixelRef);
+ bitmap->setPixelRef(cache->getCache32PixelRef());
return;
}
@@ -618,9 +627,9 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
if (!gCache->find(storage.get(), size, bitmap)) {
// force our cahce32pixelref to be built
- (void)this->getCache32();
+ (void)cache->getCache32();
bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1));
- bitmap->setPixelRef(fCache32PixelRef);
+ bitmap->setPixelRef(cache->getCache32PixelRef());
gCache->add(storage.get(), size, *bitmap);
}
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 83e0789853..e01609462b 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -19,6 +19,7 @@
#include "SkTemplates.h"
#include "SkBitmapCache.h"
#include "SkShader.h"
+#include "SkOnce.h"
static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
int count) {
@@ -101,8 +102,64 @@ public:
SkGradientShaderBase(const Descriptor& desc);
virtual ~SkGradientShaderBase();
- virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
- virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
+ // The cache is initialized on-demand when getCache16/32 is called.
+ class GradientShaderCache : public SkRefCnt {
+ public:
+ GradientShaderCache(U8CPU alpha, const SkGradientShaderBase& shader);
+ ~GradientShaderCache();
+
+ const uint16_t* getCache16();
+ const SkPMColor* getCache32();
+
+ SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; }
+
+ unsigned getAlpha() const { return fCacheAlpha; }
+
+ private:
+ // Working pointers. If either is NULL, we need to recompute the corresponding cache values.
+ uint16_t* fCache16;
+ SkPMColor* fCache32;
+
+ uint16_t* fCache16Storage; // Storage for fCache16, allocated on demand.
+ SkMallocPixelRef* fCache32PixelRef;
+ const unsigned fCacheAlpha; // The alpha value we used when we computed the cache.
+ // Larger than 8bits so we can store uninitialized
+ // value.
+
+ const SkGradientShaderBase& fShader;
+
+ // Make sure we only initialize the caches once.
+ bool fCache16Inited, fCache32Inited;
+ SkMutex fCache16Mutex, fCache32Mutex;
+
+ static void initCache16(GradientShaderCache* cache);
+ static void initCache32(GradientShaderCache* cache);
+
+ static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
+ static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
+ U8CPU alpha, uint32_t gradFlags);
+ };
+
+ class GradientShaderBaseContext : public SkShader::Context {
+ public:
+ GradientShaderBaseContext(const SkGradientShaderBase& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
+ ~GradientShaderBaseContext() {}
+
+ virtual uint32_t getFlags() const SK_OVERRIDE { return fFlags; }
+
+ protected:
+ SkMatrix fDstToIndex;
+ SkMatrix::MapXYProc fDstToIndexProc;
+ uint8_t fDstToIndexClass;
+ uint8_t fFlags;
+
+ SkAutoTUnref<GradientShaderCache> fCache;
+
+ private:
+ typedef SkShader::Context INHERITED;
+ };
+
virtual bool isOpaque() const SK_OVERRIDE;
void getGradientTableBitmap(SkBitmap*) const;
@@ -128,7 +185,6 @@ public:
kDitherStride16 = kCache16Count,
};
-
protected:
SkGradientShaderBase(SkReadBuffer& );
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
@@ -136,13 +192,9 @@ protected:
SkUnitMapper* fMapper;
SkMatrix fPtsToUnit; // set by subclass
- SkMatrix fDstToIndex;
- SkMatrix::MapXYProc fDstToIndexProc;
TileMode fTileMode;
TileProc fTileProc;
int fColorCount;
- uint8_t fDstToIndexClass;
- uint8_t fFlags;
uint8_t fGradFlags;
struct Rec {
@@ -151,9 +203,6 @@ protected:
};
Rec* fRecs;
- const uint16_t* getCache16() const;
- const SkPMColor* getCache32() const;
-
void commonAsAGradient(GradientInfo*) const;
private:
@@ -163,20 +212,13 @@ private:
kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
};
SkColor fStorage[(kStorageSize + 3) >> 2];
- SkColor* fOrigColors; // original colors, before modulation by paint in setContext
+ SkColor* fOrigColors; // original colors, before modulation by paint in context.
bool fColorsAreOpaque;
- mutable uint16_t* fCache16; // working ptr. If this is NULL, we need to recompute the cache values
- mutable SkPMColor* fCache32; // working ptr. If this is NULL, we need to recompute the cache values
-
- mutable uint16_t* fCache16Storage; // storage for fCache16, allocated on demand
- mutable SkMallocPixelRef* fCache32PixelRef;
- mutable unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
+ GradientShaderCache* getCache(U8CPU alpha) const;
+ mutable SkMutex fCacheMutex;
+ mutable SkAutoTUnref<GradientShaderCache> fCache;
- static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
- static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
- U8CPU alpha, uint32_t gradFlags);
- void setCacheAlpha(U8CPU alpha) const;
void initCommon();
typedef SkShader INHERITED;
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index b24a6349c7..e660d7cd2d 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -71,12 +71,24 @@ void SkLinearGradient::flatten(SkWriteBuffer& buffer) const {
buffer.writePoint(fEnd);
}
-bool SkLinearGradient::setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix) {
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
+size_t SkLinearGradient::contextSize() const {
+ return sizeof(LinearGradientContext);
+}
+
+SkShader::Context* SkLinearGradient::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
}
+ return SkNEW_PLACEMENT_ARGS(storage, LinearGradientContext, (*this, device, paint, matrix));
+}
+
+SkLinearGradient::LinearGradientContext::LinearGradientContext(
+ const SkLinearGradient& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix)
+{
unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
if ((fDstToIndex.getType() & ~mask) == 0) {
// when we dither, we are (usually) not const-in-Y
@@ -87,7 +99,6 @@ bool SkLinearGradient::setContext(const SkBitmap& device, const SkPaint& paint,
fFlags |= SkShader::kConstInY16_Flag;
}
}
- return true;
}
#define NO_CHECK_ITER \
@@ -196,14 +207,16 @@ void shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
}
-void SkLinearGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
- int count) {
+void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
+ int count) {
SkASSERT(count > 0);
+ const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader);
+
SkPoint srcPt;
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- TileProc proc = fTileProc;
- const SkPMColor* SK_RESTRICT cache = this->getCache32();
+ TileProc proc = linearGradient.fTileProc;
+ const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
int toggle = init_dither_toggle(x, y);
if (fDstToIndexClass != kPerspective_MatrixClass) {
@@ -223,12 +236,12 @@ void SkLinearGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
LinearShadeProc shadeProc = shadeSpan_linear_repeat;
if (0 == dx) {
shadeProc = shadeSpan_linear_vertical_lerp;
- } else if (SkShader::kClamp_TileMode == fTileMode) {
+ } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) {
shadeProc = shadeSpan_linear_clamp;
- } else if (SkShader::kMirror_TileMode == fTileMode) {
+ } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) {
shadeProc = shadeSpan_linear_mirror;
} else {
- SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
+ SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode);
}
(*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
} else {
@@ -381,14 +394,16 @@ static bool fixed_nearly_zero(SkFixed x) {
return SkAbs32(x) < (SK_Fixed1 >> 12);
}
-void SkLinearGradient::shadeSpan16(int x, int y,
- uint16_t* SK_RESTRICT dstC, int count) {
+void SkLinearGradient::LinearGradientContext::shadeSpan16(int x, int y,
+ uint16_t* SK_RESTRICT dstC, int count) {
SkASSERT(count > 0);
+ const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader);
+
SkPoint srcPt;
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- TileProc proc = fTileProc;
- const uint16_t* SK_RESTRICT cache = this->getCache16();
+ TileProc proc = linearGradient.fTileProc;
+ const uint16_t* SK_RESTRICT cache = fCache->getCache16();
int toggle = init_dither_toggle16(x, y);
if (fDstToIndexClass != kPerspective_MatrixClass) {
@@ -408,12 +423,12 @@ void SkLinearGradient::shadeSpan16(int x, int y,
LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
if (fixed_nearly_zero(dx)) {
shadeProc = shadeSpan16_linear_vertical;
- } else if (SkShader::kClamp_TileMode == fTileMode) {
+ } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) {
shadeProc = shadeSpan16_linear_clamp;
- } else if (SkShader::kMirror_TileMode == fTileMode) {
+ } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) {
shadeProc = shadeSpan16_linear_mirror;
} else {
- SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
+ SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode);
}
(*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
} else {
diff --git a/src/effects/gradients/SkLinearGradient.h b/src/effects/gradients/SkLinearGradient.h
index 013c4499b0..8d806672f8 100644
--- a/src/effects/gradients/SkLinearGradient.h
+++ b/src/effects/gradients/SkLinearGradient.h
@@ -15,9 +15,23 @@ class SkLinearGradient : public SkGradientShaderBase {
public:
SkLinearGradient(const SkPoint pts[2], const Descriptor&);
- virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&,
+ void* storage) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
+ class LinearGradientContext : public SkGradientShaderBase::GradientShaderBaseContext {
+ public:
+ LinearGradientContext(const SkLinearGradient& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
+ ~LinearGradientContext() {}
+
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+
+ private:
+ typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED;
+ };
+
virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*) const SK_OVERRIDE;
virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE;
virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint&) const SK_OVERRIDE;
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 1b9e7258c4..bc2ea3b92b 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -157,16 +157,36 @@ SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius,
rad_to_unit_matrix(center, radius, &fPtsToUnit);
}
-void SkRadialGradient::shadeSpan16(int x, int y, uint16_t* dstCParam,
- int count) {
+size_t SkRadialGradient::contextSize() const {
+ return sizeof(RadialGradientContext);
+}
+
+SkShader::Context* SkRadialGradient::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, RadialGradientContext, (*this, device, paint, matrix));
+}
+
+SkRadialGradient::RadialGradientContext::RadialGradientContext(
+ const SkRadialGradient& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix) {}
+
+void SkRadialGradient::RadialGradientContext::shadeSpan16(int x, int y, uint16_t* dstCParam,
+ int count) {
SkASSERT(count > 0);
+ const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader);
+
uint16_t* SK_RESTRICT dstC = dstCParam;
SkPoint srcPt;
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- TileProc proc = fTileProc;
- const uint16_t* SK_RESTRICT cache = this->getCache16();
+ TileProc proc = radialGradient.fTileProc;
+ const uint16_t* SK_RESTRICT cache = fCache->getCache16();
int toggle = init_dither_toggle16(x, y);
if (fDstToIndexClass != kPerspective_MatrixClass) {
@@ -187,12 +207,12 @@ void SkRadialGradient::shadeSpan16(int x, int y, uint16_t* dstCParam,
}
RadialShade16Proc shadeProc = shadeSpan16_radial_repeat;
- if (SkShader::kClamp_TileMode == fTileMode) {
+ if (SkShader::kClamp_TileMode == radialGradient.fTileMode) {
shadeProc = shadeSpan16_radial_clamp;
- } else if (SkShader::kMirror_TileMode == fTileMode) {
+ } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) {
shadeProc = shadeSpan16_radial_mirror;
} else {
- SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
+ SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode);
}
(*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC,
cache, toggle, count);
@@ -389,14 +409,16 @@ void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
} // namespace
-void SkRadialGradient::shadeSpan(int x, int y,
- SkPMColor* SK_RESTRICT dstC, int count) {
+void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y,
+ SkPMColor* SK_RESTRICT dstC, int count) {
SkASSERT(count > 0);
+ const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader);
+
SkPoint srcPt;
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- TileProc proc = fTileProc;
- const SkPMColor* SK_RESTRICT cache = this->getCache32();
+ TileProc proc = radialGradient.fTileProc;
+ const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
int toggle = init_dither_toggle(x, y);
if (fDstToIndexClass != kPerspective_MatrixClass) {
@@ -416,12 +438,12 @@ void SkRadialGradient::shadeSpan(int x, int y,
}
RadialShadeProc shadeProc = shadeSpan_radial_repeat;
- if (SkShader::kClamp_TileMode == fTileMode) {
+ if (SkShader::kClamp_TileMode == radialGradient.fTileMode) {
shadeProc = shadeSpan_radial_clamp;
- } else if (SkShader::kMirror_TileMode == fTileMode) {
+ } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) {
shadeProc = shadeSpan_radial_mirror;
} else {
- SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
+ SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode);
}
(*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle);
} else { // perspective case
diff --git a/src/effects/gradients/SkRadialGradient.h b/src/effects/gradients/SkRadialGradient.h
index 4a725145b0..a3d04b1aaf 100644
--- a/src/effects/gradients/SkRadialGradient.h
+++ b/src/effects/gradients/SkRadialGradient.h
@@ -14,10 +14,24 @@
class SkRadialGradient : public SkGradientShaderBase {
public:
SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor&);
- virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count)
- SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t* dstCParam,
- int count) SK_OVERRIDE;
+
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&,
+ void* storage) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
+ class RadialGradientContext : public SkGradientShaderBase::GradientShaderBaseContext {
+ public:
+ RadialGradientContext(const SkRadialGradient& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
+ ~RadialGradientContext() {}
+
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+
+ private:
+ typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED;
+ };
+
virtual BitmapType asABitmap(SkBitmap* bitmap,
SkMatrix* matrix,
TileMode* xy) const SK_OVERRIDE;
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 7024945bf0..6dff1e71cd 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -52,6 +52,24 @@ void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
buffer.writePoint(fCenter);
}
+size_t SkSweepGradient::contextSize() const {
+ return sizeof(SweepGradientContext);
+}
+
+SkShader::Context* SkSweepGradient::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, SweepGradientContext, (*this, device, paint, matrix));
+}
+
+SkSweepGradient::SweepGradientContext::SweepGradientContext(
+ const SkSweepGradient& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix) {}
+
// returns angle in a circle [0..2PI) -> [0..255]
static unsigned SkATan2_255(float y, float x) {
// static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
@@ -69,11 +87,11 @@ static unsigned SkATan2_255(float y, float x) {
return ir;
}
-void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
- int count) {
+void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
+ int count) {
SkMatrix::MapXYProc proc = fDstToIndexProc;
const SkMatrix& matrix = fDstToIndex;
- const SkPMColor* SK_RESTRICT cache = this->getCache32();
+ const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
int toggle = init_dither_toggle(x, y);
SkPoint srcPt;
@@ -111,11 +129,11 @@ void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
}
}
-void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
- int count) {
+void SkSweepGradient::SweepGradientContext::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
+ int count) {
SkMatrix::MapXYProc proc = fDstToIndexProc;
const SkMatrix& matrix = fDstToIndex;
- const uint16_t* SK_RESTRICT cache = this->getCache16();
+ const uint16_t* SK_RESTRICT cache = fCache->getCache16();
int toggle = init_dither_toggle16(x, y);
SkPoint srcPt;
diff --git a/src/effects/gradients/SkSweepGradient.h b/src/effects/gradients/SkSweepGradient.h
index ca19da25ba..9998ed16a7 100644
--- a/src/effects/gradients/SkSweepGradient.h
+++ b/src/effects/gradients/SkSweepGradient.h
@@ -14,8 +14,23 @@
class SkSweepGradient : public SkGradientShaderBase {
public:
SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor&);
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&,
+ void* storage) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
+ class SweepGradientContext : public SkGradientShaderBase::GradientShaderBaseContext {
+ public:
+ SweepGradientContext(const SkSweepGradient& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
+ ~SweepGradientContext() {}
+
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+
+ private:
+ typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED;
+ };
virtual BitmapType asABitmap(SkBitmap* bitmap,
SkMatrix* matrix,
@@ -33,8 +48,9 @@ protected:
virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
private:
- typedef SkGradientShaderBase INHERITED;
const SkPoint fCenter;
+
+ typedef SkGradientShaderBase INHERITED;
};
#endif
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index de8c2364c3..b0955a2583 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -9,6 +9,18 @@
#include "SkTwoPointConicalGradient_gpu.h"
+struct TwoPtRadialContext {
+ const TwoPtRadial& fRec;
+ float fRelX, fRelY;
+ const float fIncX, fIncY;
+ float fB;
+ const float fDB;
+
+ TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy,
+ SkScalar dfx, SkScalar dfy);
+ SkFixed nextT();
+};
+
static int valid_divide(float numer, float denom, float* ratio) {
SkASSERT(ratio);
if (0 == denom) {
@@ -77,47 +89,48 @@ void TwoPtRadial::init(const SkPoint& center0, SkScalar rad0,
fRDR = fRadius * fDRadius;
}
-void TwoPtRadial::setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy) {
- fRelX = SkScalarToFloat(fx) - fCenterX;
- fRelY = SkScalarToFloat(fy) - fCenterY;
- fIncX = SkScalarToFloat(dfx);
- fIncY = SkScalarToFloat(dfy);
- fB = -2 * (fDCenterX * fRelX + fDCenterY * fRelY + fRDR);
- fDB = -2 * (fDCenterX * fIncX + fDCenterY * fIncY);
-}
-
-SkFixed TwoPtRadial::nextT() {
+TwoPtRadialContext::TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy,
+ SkScalar dfx, SkScalar dfy)
+ : fRec(rec)
+ , fRelX(SkScalarToFloat(fx) - rec.fCenterX)
+ , fRelY(SkScalarToFloat(fy) - rec.fCenterY)
+ , fIncX(SkScalarToFloat(dfx))
+ , fIncY(SkScalarToFloat(dfy))
+ , fB(-2 * (rec.fDCenterX * fRelX + rec.fDCenterY * fRelY + rec.fRDR))
+ , fDB(-2 * (rec.fDCenterX * fIncX + rec.fDCenterY * fIncY)) {}
+
+SkFixed TwoPtRadialContext::nextT() {
float roots[2];
- float C = sqr(fRelX) + sqr(fRelY) - fRadius2;
- int countRoots = find_quad_roots(fA, fB, C, roots);
+ float C = sqr(fRelX) + sqr(fRelY) - fRec.fRadius2;
+ int countRoots = find_quad_roots(fRec.fA, fB, C, roots);
fRelX += fIncX;
fRelY += fIncY;
fB += fDB;
if (0 == countRoots) {
- return kDontDrawT;
+ return TwoPtRadial::kDontDrawT;
}
// Prefer the bigger t value if both give a radius(t) > 0
// find_quad_roots returns the values sorted, so we start with the last
float t = roots[countRoots - 1];
- float r = lerp(fRadius, fDRadius, t);
+ float r = lerp(fRec.fRadius, fRec.fDRadius, t);
if (r <= 0) {
t = roots[0]; // might be the same as roots[countRoots-1]
- r = lerp(fRadius, fDRadius, t);
+ r = lerp(fRec.fRadius, fRec.fDRadius, t);
if (r <= 0) {
- return kDontDrawT;
+ return TwoPtRadial::kDontDrawT;
}
}
return SkFloatToFixed(t);
}
-typedef void (*TwoPointConicalProc)(TwoPtRadial* rec, SkPMColor* dstC,
+typedef void (*TwoPointConicalProc)(TwoPtRadialContext* rec, SkPMColor* dstC,
const SkPMColor* cache, int toggle, int count);
-static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
+static void twopoint_clamp(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache, int toggle,
int count) {
for (; count > 0; --count) {
@@ -134,7 +147,7 @@ static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
}
}
-static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
+static void twopoint_repeat(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache, int toggle,
int count) {
for (; count > 0; --count) {
@@ -151,7 +164,7 @@ static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
}
}
-static void twopoint_mirror(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
+static void twopoint_mirror(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache, int toggle,
int count) {
for (; count > 0; --count) {
@@ -196,8 +209,39 @@ bool SkTwoPointConicalGradient::isOpaque() const {
return false;
}
-void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
- int count) {
+size_t SkTwoPointConicalGradient::contextSize() const {
+ return sizeof(TwoPointConicalGradientContext);
+}
+
+SkShader::Context* SkTwoPointConicalGradient::createContext(
+ const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, TwoPointConicalGradientContext,
+ (*this, device, paint, matrix));
+}
+
+SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradientContext(
+ const SkTwoPointConicalGradient& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix)
+{
+ // we don't have a span16 proc
+ fFlags &= ~kHasSpan16_Flag;
+
+ // in general, we might discard based on computed-radius, so clear
+ // this flag (todo: sometimes we can detect that we never discard...)
+ fFlags &= ~kOpaqueAlpha_Flag;
+}
+
+void SkTwoPointConicalGradient::TwoPointConicalGradientContext::shadeSpan(
+ int x, int y, SkPMColor* dstCParam, int count) {
+ const SkTwoPointConicalGradient& twoPointConicalGradient =
+ static_cast<const SkTwoPointConicalGradient&>(fShader);
+
int toggle = init_dither_toggle(x, y);
SkASSERT(count > 0);
@@ -206,15 +250,15 @@ void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- const SkPMColor* SK_RESTRICT cache = this->getCache32();
+ const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
TwoPointConicalProc shadeProc = twopoint_repeat;
- if (SkShader::kClamp_TileMode == fTileMode) {
+ if (SkShader::kClamp_TileMode == twoPointConicalGradient.fTileMode) {
shadeProc = twopoint_clamp;
- } else if (SkShader::kMirror_TileMode == fTileMode) {
+ } else if (SkShader::kMirror_TileMode == twoPointConicalGradient.fTileMode) {
shadeProc = twopoint_mirror;
} else {
- SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
+ SkASSERT(SkShader::kRepeat_TileMode == twoPointConicalGradient.fTileMode);
}
if (fDstToIndexClass != kPerspective_MatrixClass) {
@@ -235,16 +279,16 @@ void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
dy = fDstToIndex.getSkewY();
}
- fRec.setup(fx, fy, dx, dy);
- (*shadeProc)(&fRec, dstC, cache, toggle, count);
+ TwoPtRadialContext rec(twoPointConicalGradient.fRec, fx, fy, dx, dy);
+ (*shadeProc)(&rec, dstC, cache, toggle, count);
} else { // perspective case
SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf;
SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf;
for (; count > 0; --count) {
SkPoint srcPt;
dstProc(fDstToIndex, dstX, dstY, &srcPt);
- fRec.setup(srcPt.fX, srcPt.fY, 0, 0);
- (*shadeProc)(&fRec, dstC, cache, toggle, 1);
+ TwoPtRadialContext rec(twoPointConicalGradient.fRec, srcPt.fX, srcPt.fY, 0, 0);
+ (*shadeProc)(&rec, dstC, cache, toggle, 1);
dstX += SK_Scalar1;
toggle = next_dither_toggle(toggle);
@@ -253,23 +297,6 @@ void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
}
}
-bool SkTwoPointConicalGradient::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
- }
-
- // we don't have a span16 proc
- fFlags &= ~kHasSpan16_Flag;
-
- // in general, we might discard based on computed-radius, so clear
- // this flag (todo: sometimes we can detect that we never discard...)
- fFlags &= ~kOpaqueAlpha_Flag;
-
- return true;
-}
-
SkShader::BitmapType SkTwoPointConicalGradient::asABitmap(
SkBitmap* bitmap, SkMatrix* matrix, SkShader::TileMode* xy) const {
SkPoint diff = fCenter2 - fCenter1;
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.h b/src/effects/gradients/SkTwoPointConicalGradient.h
index 041f8b8be4..4c049172d3 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.h
+++ b/src/effects/gradients/SkTwoPointConicalGradient.h
@@ -11,6 +11,8 @@
#include "SkGradientShaderPriv.h"
+// TODO(dominikg): Worth making it truly immutable (i.e. set values in constructor)?
+// Should only be initialized once via init(). Immutable afterwards.
struct TwoPtRadial {
enum {
kDontDrawT = 0x80000000
@@ -27,13 +29,6 @@ struct TwoPtRadial {
void init(const SkPoint& center0, SkScalar rad0,
const SkPoint& center1, SkScalar rad1);
- // used by setup and nextT
- float fRelX, fRelY, fIncX, fIncY;
- float fB, fDB;
-
- void setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy);
- SkFixed nextT();
-
static bool DontDrawT(SkFixed t) {
return kDontDrawT == (uint32_t)t;
}
@@ -49,11 +44,24 @@ public:
const SkPoint& end, SkScalar endRadius,
const Descriptor&);
- virtual void shadeSpan(int x, int y, SkPMColor* dstCParam,
- int count) SK_OVERRIDE;
- virtual bool setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) SK_OVERRIDE;
+
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&,
+ void* storage) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
+ class TwoPointConicalGradientContext : public SkGradientShaderBase::GradientShaderBaseContext {
+ public:
+ TwoPointConicalGradientContext(const SkTwoPointConicalGradient& shader,
+ const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix);
+ ~TwoPointConicalGradientContext() {}
+
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+
+ private:
+ typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED;
+ };
virtual BitmapType asABitmap(SkBitmap* bitmap,
SkMatrix* matrix,
@@ -77,11 +85,12 @@ protected:
virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
private:
- typedef SkGradientShaderBase INHERITED;
const SkPoint fCenter1;
const SkPoint fCenter2;
const SkScalar fRadius1;
const SkScalar fRadius2;
+
+ typedef SkGradientShaderBase INHERITED;
};
#endif
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index e1359b12dd..a598c6e0e3 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -220,23 +220,60 @@ SkShader::GradientType SkTwoPointRadialGradient::asAGradient(
return kRadial2_GradientType;
}
-void SkTwoPointRadialGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
- int count) {
+size_t SkTwoPointRadialGradient::contextSize() const {
+ return sizeof(TwoPointRadialGradientContext);
+}
+
+bool SkTwoPointRadialGradient::validContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse) const {
+ // For now, we might have divided by zero, so detect that.
+ if (0 == fDiffRadius) {
+ return false;
+ }
+
+ return this->INHERITED::validContext(device, paint, matrix, totalInverse);
+}
+
+SkShader::Context* SkTwoPointRadialGradient::createContext(
+ const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, TwoPointRadialGradientContext,
+ (*this, device, paint, matrix));
+}
+
+SkTwoPointRadialGradient::TwoPointRadialGradientContext::TwoPointRadialGradientContext(
+ const SkTwoPointRadialGradient& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix)
+{
+ // we don't have a span16 proc
+ fFlags &= ~kHasSpan16_Flag;
+}
+
+void SkTwoPointRadialGradient::TwoPointRadialGradientContext::shadeSpan(
+ int x, int y, SkPMColor* dstCParam, int count) {
SkASSERT(count > 0);
+ const SkTwoPointRadialGradient& twoPointRadialGradient =
+ static_cast<const SkTwoPointRadialGradient&>(fShader);
+
SkPMColor* SK_RESTRICT dstC = dstCParam;
// Zero difference between radii: fill with transparent black.
- if (fDiffRadius == 0) {
+ if (twoPointRadialGradient.fDiffRadius == 0) {
sk_bzero(dstC, count * sizeof(*dstC));
return;
}
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- TileProc proc = fTileProc;
- const SkPMColor* SK_RESTRICT cache = this->getCache32();
+ TileProc proc = twoPointRadialGradient.fTileProc;
+ const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
- SkScalar foura = fA * 4;
- bool posRoot = fDiffRadius < 0;
+ SkScalar foura = twoPointRadialGradient.fA * 4;
+ bool posRoot = twoPointRadialGradient.fDiffRadius < 0;
if (fDstToIndexClass != kPerspective_MatrixClass) {
SkPoint srcPt;
dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
@@ -254,21 +291,23 @@ void SkTwoPointRadialGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
dx = fDstToIndex.getScaleX();
dy = fDstToIndex.getSkewY();
}
- SkScalar b = (SkScalarMul(fDiff.fX, fx) +
- SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
- SkScalar db = (SkScalarMul(fDiff.fX, dx) +
- SkScalarMul(fDiff.fY, dy)) * 2;
+ SkScalar b = (SkScalarMul(twoPointRadialGradient.fDiff.fX, fx) +
+ SkScalarMul(twoPointRadialGradient.fDiff.fY, fy) -
+ twoPointRadialGradient.fStartRadius) * 2;
+ SkScalar db = (SkScalarMul(twoPointRadialGradient.fDiff.fX, dx) +
+ SkScalarMul(twoPointRadialGradient.fDiff.fY, dy)) * 2;
TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
- if (SkShader::kClamp_TileMode == fTileMode) {
+ if (SkShader::kClamp_TileMode == twoPointRadialGradient.fTileMode) {
shadeProc = shadeSpan_twopoint_clamp;
- } else if (SkShader::kMirror_TileMode == fTileMode) {
+ } else if (SkShader::kMirror_TileMode == twoPointRadialGradient.fTileMode) {
shadeProc = shadeSpan_twopoint_mirror;
} else {
- SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
+ SkASSERT(SkShader::kRepeat_TileMode == twoPointRadialGradient.fTileMode);
}
(*shadeProc)(fx, dx, fy, dy, b, db,
- fSr2D2, foura, fOneOverTwoA, posRoot,
+ twoPointRadialGradient.fSr2D2, foura,
+ twoPointRadialGradient.fOneOverTwoA, posRoot,
dstC, cache, count);
} else { // perspective case
SkScalar dstX = SkIntToScalar(x);
@@ -278,10 +317,11 @@ void SkTwoPointRadialGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
dstProc(fDstToIndex, dstX, dstY, &srcPt);
SkScalar fx = srcPt.fX;
SkScalar fy = srcPt.fY;
- SkScalar b = (SkScalarMul(fDiff.fX, fx) +
- SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
- fOneOverTwoA, posRoot);
+ SkScalar b = (SkScalarMul(twoPointRadialGradient.fDiff.fX, fx) +
+ SkScalarMul(twoPointRadialGradient.fDiff.fY, fy) -
+ twoPointRadialGradient.fStartRadius) * 2;
+ SkFixed t = two_point_radial(b, fx, fy, twoPointRadialGradient.fSr2D2, foura,
+ twoPointRadialGradient.fOneOverTwoA, posRoot);
SkFixed index = proc(t);
SkASSERT(index <= 0xFFFF);
*dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
@@ -290,23 +330,6 @@ void SkTwoPointRadialGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
}
}
-bool SkTwoPointRadialGradient::setContext( const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix){
- // For now, we might have divided by zero, so detect that
- if (0 == fDiffRadius) {
- return false;
- }
-
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
- }
-
- // we don't have a span16 proc
- fFlags &= ~kHasSpan16_Flag;
- return true;
-}
-
#ifndef SK_IGNORE_TO_STRING
void SkTwoPointRadialGradient::toString(SkString* str) const {
str->append("SkTwoPointRadialGradient: (");
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.h b/src/effects/gradients/SkTwoPointRadialGradient.h
index ee1b49ee95..9ba89f2920 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.h
+++ b/src/effects/gradients/SkTwoPointRadialGradient.h
@@ -23,11 +23,26 @@ public:
virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE;
virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint&) const SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor* dstCParam,
- int count) SK_OVERRIDE;
- virtual bool setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) SK_OVERRIDE;
+
+ virtual size_t contextSize() const SK_OVERRIDE;
+ virtual bool validContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&,
+ void* storage) const SK_OVERRIDE;
+
+ class TwoPointRadialGradientContext : public SkGradientShaderBase::GradientShaderBaseContext {
+ public:
+ TwoPointRadialGradientContext(const SkTwoPointRadialGradient& shader,
+ const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix);
+ ~TwoPointRadialGradientContext() {}
+
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+
+ private:
+ typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED;
+ };
SkScalar getCenterX1() const { return fDiff.length(); }
SkScalar getStartRadius() const { return fStartRadius; }
@@ -41,7 +56,6 @@ protected:
virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
private:
- typedef SkGradientShaderBase INHERITED;
const SkPoint fCenter1;
const SkPoint fCenter2;
const SkScalar fRadius1;
@@ -50,6 +64,8 @@ private:
SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
void init();
+
+ typedef SkGradientShaderBase INHERITED;
};
#endif