Index: include/core/SkShader.h |
diff --git a/include/core/SkShader.h b/include/core/SkShader.h |
index 108c6b0829b22ddb764a1aba14417b52f0a4f781..6a25f53101ce5819ef0554f676965bf3401e4358 100644 |
--- a/include/core/SkShader.h |
+++ b/include/core/SkShader.h |
@@ -128,59 +128,130 @@ public: |
*/ |
virtual bool isOpaque() const { return false; } |
+ // Moved to public so it could on a Context object. May not be the right place for it. |
+ 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 |
+ }; |
+ |
/** |
- * Return the alpha associated with the data returned by shadeSpan16(). If |
- * kHasSpan16_Flag is not set, this value is meaningless. |
+ * Total number of bytes needed to store subclass specific Context information. |
+ * Each class will override this by including the macro DEFINE_CONTEXT_RETRIEVAL_FUNCTIONS() |
+ * in its private section, and defining getMySpaceNeededForContext(), which returns the |
+ * number of bytes required by that specific subclass (not including its parents). |
+ */ |
+ virtual size_t getTotalSpaceNeededForContext() const { return 0; } |
+ |
+ /** |
+ * Called to get a pointer to subclass-specific information. |
*/ |
- virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; } |
+ virtual void* getMyContext(Context* c) const = 0; |
+ |
+ class Context : public SkNoncopyable { |
+ public: |
+ Context(const SkMatrix& totalInverse, uint8_t paintAlpha, |
+ SkBitmap::Config deviceConfig); |
+ |
+ uint8_t getPaintAlpha() const { return fPaintAlpha; } |
+ SkBitmap::Config getDeviceConfig() const { return (SkBitmap::Config)fDeviceConfig; } |
+ const SkMatrix& getTotalInverse() const { return fTotalInverse; } |
+ MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; } |
+ |
+ /** |
+ * Should not be called directly. Instead, the subclass should call getMyContext. |
+ */ |
+ void* getExtraStorage() { |
+ SkAssert(fStorageAllocated); |
+ return fExtraStorage; |
+ } |
+ |
+ void reset(const SkShader& shader) { |
+ // This can only be called once |
+ SkAssert(!fStorageAllocated); |
+ fExtraStorage = fStorage.reset(shader.getTotalSpaceNeededForContext()); |
+ // What should we do if this fails? |
+ SkASSERT(fExtraStorage != NULL); |
+ fStorageAllocated = true; |
+ } |
+ |
+ private: |
+ SkMatrix fTotalInverse; |
+ uint8_t fPaintAlpha; |
+ uint8_t fDeviceConfig; |
+ uint8_t fTotalInverseClass; |
+ // This size is arbitrary, for now, but probably should be related to the size of the |
+ // subclasses needed. |
+ SkAutoSMalloc<1024> fStorage; |
+ // Should be debugcode |
+ bool fStorageAllocated; |
+ // Space for the subclasses' Context information. Will pint to fStorage. |
+ void* fExtraStorage; |
+ }; |
/** |
* 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 |
+ * Return a new Context object if your shader supports these parameters, |
+ * or NULL if not. If NULL is returned, nothing will be drawn. On success, |
* 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); |
+ Context* setContext(const SkBitmap& device, const SkPaint& paint, |
+ const SkMatrix& matrix); |
+ |
+ /** |
+ * Subclasses should be sure to call their INHERITED::onSetContext() if they |
+ * override this method. |
+ */ |
+ virtual bool onSetContext(Context* context, const SkBitmap& device, |
+ const SkPaint& paint, |
+ const SkMatrix& matrix) { return true; } |
/** |
* 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(). |
* |
+ * This method will delete the Context object. |
+ * |
* Subclasses should be sure to call their INHERITED::endContext() if they |
- * override this method. |
+ * override this method, after deleting their subclass-specific info. |
*/ |
- virtual void endContext(); |
+ virtual void endContext(Context*); |
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(Context* c) const { return c->getPaintAlpha(); } |
+ |
+ /** |
* 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; |
+ // FIXME: It may make more sense for Context to be a const ref? (Same for others) |
+ virtual void shadeSpan(Context* c, int x, int y, SkPMColor[], int count) = 0; |
+ // Used by SkBlitter_ARGB32.cpp |
typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count); |
+ // Will need to pass a Context to this as well. |
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); |
+ virtual void shadeSpan16(Context* c, 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); |
+ virtual void shadeSpanAlpha(Context* c, int x, int y, uint8_t alpha[], int count); |
/** |
* Helper function that returns true if this shader's shadeSpan16() method |
@@ -350,27 +421,13 @@ 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; } |
- SkBitmap::Config getDeviceConfig() const { return (SkBitmap::Config)fDeviceConfig; } |
- const SkMatrix& getTotalInverse() const { return fTotalInverse; } |
- MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; } |
- |
SkShader(SkReadBuffer& ); |
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; |
private: |
+ // FIXME: Move onto SkPaint. |
SkMatrix fLocalMatrix; |
- SkMatrix fTotalInverse; |
- uint8_t fPaintAlpha; |
- uint8_t fDeviceConfig; |
- uint8_t fTotalInverseClass; |
SkDEBUGCODE(SkBool8 fInSetContext;) |
static SkShader* CreateBitmapShader(const SkBitmap& src, |
@@ -380,4 +437,30 @@ private: |
typedef SkFlattenable INHERITED; |
}; |
+/** |
+ * Each SkShader subclass must include the following macro in its private |
+ * section (defined below): |
+ * |
+ * DEFINE_CONTEXT_RETRIEVAL_FUNCTIONS() |
+ * |
+ * It defines functions for accessing the particular subclass's specific |
+ * information from the Context. The subclass must also implement the |
+ * following function: |
+ * |
+ * size_t getMySpaceNeededForContext() const; |
+ * |
+ * This function will return the number of bytes required to store that |
+ * subclasses Context information. |
+ */ |
+ |
+#define DEFINE_CONTEXT_RETRIEVAL_FUNCTIONS() \ |
+ virtual size_t getTotalSpaceNeededForContext() const SK_OVERRIDE { \ |
+ return this->INHERITED::getTotalSpaceNeededForContext() \ |
+ + this->getMySpaceNeededForContext(); \ |
+ } \ |
+ virtual void* getMyContext(Context* c) const SK_OVERRIDE { \ |
+ return c->getExtraStorage() + this->INHERITED::getTotalSpaceNeededForContext(); \ |
+ } |
+ |
+ |
#endif |