Add asAGradient shader extraction API.
authorvandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 24 Feb 2011 00:21:06 +0000 (00:21 +0000)
committervandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 24 Feb 2011 00:21:06 +0000 (00:21 +0000)
Store initial gradient parameters.
Add compile asserts in GPU code for BitmapType ordering.

Review URL: http://codereview.appspot.com/4178063

git-svn-id: http://skia.googlecode.com/svn/trunk@845 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkColorShader.h
include/core/SkShader.h
src/core/SkShader.cpp
src/effects/SkGradientShader.cpp
src/gpu/SkGpuDevice.cpp

index 44a6148c0f231f8116711ff6e47b583a346e2edf..1f833556f99da32664f4db8c867bfcee5bef3f69 100644 (file)
@@ -51,6 +51,9 @@ public:
                                  SkMatrix* outMatrix,
                                  TileMode xy[2], 
                                  SkScalar* twoPointRadialParams);
+
+    virtual GradientType asAGradient(GradientInfo* info) const;
+
 protected:
     SkColorShader(SkFlattenableReadBuffer& );
     virtual void flatten(SkFlattenableWriteBuffer& );
index 1cdbf17cf6351cb8a1f18200c8440917d5c78c67..faaa0afc4bf43e5a75b07801326206edbb405565 100644 (file)
@@ -163,7 +163,7 @@ public:
                             //   to (0,0) as bitmap x coord, where angle = 0 is
                             //   bitmap left edge of bitmap = 2pi is the 
                             //   right edge. Bitmap is 1 pixel tall. No extras
-        kTwoPointRadial_BitmapType
+        kTwoPointRadial_BitmapType,
                             //<! Matrix transforms to space where (0,0) is 
                             //   the center of the starting circle.  The second
                             //   circle will be centered (x, 0) where x  may be 
@@ -176,7 +176,8 @@ public:
                             //         space
                             //      2: the second radius minus the first radius
                             //         in pre-transformed space.        
-        
+
+       kLast_BitmapType = kTwoPointRadial_BitmapType
     };
     /** Optional methods for shaders that can pretend to be a bitmap/texture
         to play along with opengl. Default just returns kNone_BitmapType and 
@@ -196,6 +197,59 @@ public:
     virtual BitmapType asABitmap(SkBitmap* outTexture, SkMatrix* outMatrix,
                                  TileMode xy[2], SkScalar* twoPointRadialParams);
 
+    /**
+     *  If the shader subclass can be represented as a gradient, asAGradient
+     *  returns the matching GradientType enum (or kNone_GradientType if it
+     *  cannot). Also, if info is not null, asAGradient populates info with
+     *  the relevant (see below) parameters for the gradient.  fColorCount
+     *  is both an input and output parameter.  On input, it indicates how
+     *  many entries in fColors and fColorOffsets can be used, if they are
+     *  non-NULL.  After asAGradient has run, fColorCount indicates how
+     *  many color-offset pairs there are in the gradient.  If there is
+     *  insufficient space to store all of the color-offset pairs, fColors
+     *  and fColorOffsets will not be altered.  fColorOffsets specifies
+     *  where on the range of 0 to 1 to transition to the given color.
+     *  The meaning of fPoint and fRadius is dependant on the type of gradient.
+     *
+     *  None:
+     *      info is ignored.
+     *  Color:
+     *      fColorOffsets[0] is meaningless.
+     *  Linear:
+     *      fPoint[0] and fPoint[1] are the end-points of the gradient
+     *  Radial:
+     *      fPoint[0] and fRadius[0] are the center and radius
+     *  Radial2:
+     *      fPoint[0] and fRadius[0] are the center and radius of the 1st circle
+     *      fPoint[1] and fRadius[1] are the center and radius of the 2nd circle
+     *  Sweep:
+     *      fPoint[0] is the center of the sweep.
+     */
+
+    enum GradientType {
+        kNone_GradientType,
+        kColor_GradientType,
+        kLinear_GradientType,
+        kRadial_GradientType,
+        kRadial2_GradientType,
+        kSweep_GradientType,
+        kLast_GradientType = kSweep_GradientType
+    };
+
+    struct GradientInfo {
+        int         fColorCount;    //!< In-out parameter, specifies passed size
+                                    //   of fColors/fColorOffsets on input, and
+                                    //   actual number of colors/offsets on
+                                    //   output.
+        SkColor*    fColors;        //!< The colors in the gradient.
+        SkScalar*   fColorOffsets;  //!< The unit offset for color transitions.
+        SkPoint     fPoint[2];      //!< Type specific, see above.
+        SkScalar    fRadius[2];     //!< Type specific, see above.
+        TileMode    fTileMode;      //!< The tile mode used.
+    };
+
+    virtual GradientType asAGradient(GradientInfo* info) const;
+
     //////////////////////////////////////////////////////////////////////////
     //  Factory methods for stock shaders
 
index 7b3a024c4f0b92567c6af29d3398c0cb53fd9467..6798bec888249e1ae03d4349b79b291a3954514b 100644 (file)
@@ -15,6 +15,7 @@
 ** limitations under the License.
 */
 
+#include "SkScalar.h"
 #include "SkShader.h"
 #include "SkPaint.h"
 #include "SkMallocPixelRef.h"
@@ -196,11 +197,15 @@ SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
 
 //////////////////////////////////////////////////////////////////////////////
 
-SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, 
+SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*,
                                          TileMode*, SkScalar*) {
     return kNone_BitmapType;
 }
 
+SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
+    return kNone_GradientType;
+}
+
 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
                                        TileMode tmx, TileMode tmy) {
     return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0);
@@ -258,20 +263,18 @@ bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
         return false;
     }
 
-    SkColor c;
     unsigned a;
-    
+
     if (fInheritColor) {
-        c = paint.getColor();
-        a = SkColorGetA(c);
+        fColor = paint.getColor();
+        a = SkColorGetA(fColor);
     } else {
-        c = fColor;
-        a = SkAlphaMul(SkColorGetA(c), SkAlpha255To256(paint.getAlpha()));
+        a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha()));
     }
 
-    unsigned r = SkColorGetR(c);
-    unsigned g = SkColorGetG(c);
-    unsigned b = SkColorGetB(c);
+    unsigned r = SkColorGetR(fColor);
+    unsigned g = SkColorGetG(fColor);
+    unsigned b = SkColorGetB(fColor);
 
     // we want this before we apply any alpha
     fColor16 = SkPack888ToRGB16(r, g, b);
@@ -331,3 +334,13 @@ SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix
     return kDefault_BitmapType;
 }
 
+SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
+    if (info) {
+        if (info->fColors && info->fColorCount >= 1) {
+            info->fColors[0] = fColor;
+        }
+        info->fColorCount = 1;
+        info->fTileMode = SkShader::kRepeat_TileMode;
+    }
+    return kColor_GradientType;
+}
index 64a78c7f0e32a82e3c75149f744a852c3306c260..41b97cc4c3d7a8f58e925c372ea5f6709ebf9664 100644 (file)
@@ -129,6 +129,7 @@ protected:
     SkMallocPixelRef* fCache32PixelRef;
 
     void commonAsABitmap(SkBitmap*);
+    void commonAsAGradient(GradientInfo*) const;
 
 private:
     enum {
@@ -687,6 +688,28 @@ void Gradient_Shader::commonAsABitmap(SkBitmap* bitmap) {
     }
 }
 
+void Gradient_Shader::commonAsAGradient(GradientInfo* info) const {
+    if (info) {
+        if (info->fColorCount >= fColorCount) {
+            if (info->fColors) {
+                memcpy(info->fColors, fOrigColors,
+                       fColorCount * sizeof(SkColor));
+            }
+            if (info->fColorOffsets) {
+                if (fColorCount == 2) {
+                    info->fColorOffsets[0] = 0;
+                    info->fColorOffsets[1] = SK_Scalar1;
+                } else if (fColorCount > 2) {
+                    for (int i = 0; i < fColorCount; i++)
+                        info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos);
+                }
+            }
+        }
+        info->fColorCount = fColorCount;
+        info->fTileMode = fTileMode;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 
 static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
@@ -707,7 +730,9 @@ public:
     Linear_Gradient(const SkPoint pts[2],
                     const SkColor colors[], const SkScalar pos[], int colorCount,
                     SkShader::TileMode mode, SkUnitMapper* mapper)
-        : Gradient_Shader(colors, pos, colorCount, mode, mapper)
+        : Gradient_Shader(colors, pos, colorCount, mode, mapper),
+          fStart(pts[0]),
+          fEnd(pts[1])
     {
         pts_to_unit_matrix(pts, &fPtsToUnit);
     }
@@ -717,17 +742,32 @@ public:
     virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
     virtual BitmapType asABitmap(SkBitmap*, SkMatrix*,
                                  TileMode*, SkScalar* twoPointRadialParams);
+    virtual GradientType asAGradient(GradientInfo* info) const;
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(Linear_Gradient, (buffer));
     }
 
+    virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+        this->INHERITED::flatten(buffer);
+        buffer.writeScalar(fStart.fX);
+        buffer.writeScalar(fStart.fY);
+        buffer.writeScalar(fEnd.fX);
+        buffer.writeScalar(fEnd.fY);
+    }
+
 protected:
-    Linear_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {}
+    Linear_Gradient(SkFlattenableReadBuffer& buffer)
+        : Gradient_Shader(buffer),
+          fStart(SkPoint::Make(buffer.readScalar(), buffer.readScalar())),
+          fEnd(SkPoint::Make(buffer.readScalar(), buffer.readScalar())) {
+    }
     virtual Factory getFactory() { return CreateProc; }
 
 private:
     typedef Gradient_Shader INHERITED;
+    const SkPoint fStart;
+    const SkPoint fEnd;
 };
 
 bool Linear_Gradient::setContext(const SkBitmap& device, const SkPaint& paint,
@@ -850,6 +890,15 @@ SkShader::BitmapType Linear_Gradient::asABitmap(SkBitmap* bitmap,
     return kDefault_BitmapType;
 }
 
+SkShader::GradientType Linear_Gradient::asAGradient(GradientInfo* info) const {
+    if (info) {
+        commonAsAGradient(info);
+        info->fPoint[0] = fStart;
+        info->fPoint[1] = fEnd;
+    }
+    return kLinear_GradientType;
+}
+
 static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
                             int count) {
     if (reinterpret_cast<uintptr_t>(dst) & 2) {
@@ -989,7 +1038,9 @@ public:
     Radial_Gradient(const SkPoint& center, SkScalar radius,
                     const SkColor colors[], const SkScalar pos[], int colorCount,
                     SkShader::TileMode mode, SkUnitMapper* mapper)
-        : Gradient_Shader(colors, pos, colorCount, mode, mapper)
+        : Gradient_Shader(colors, pos, colorCount, mode, mapper),
+          fCenter(center),
+          fRadius(radius)
     {
         // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
         SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
@@ -1199,17 +1250,38 @@ public:
         }
         return kRadial_BitmapType;
     }
+    virtual GradientType asAGradient(GradientInfo* info) const {
+        if (info) {
+            commonAsAGradient(info);
+            info->fPoint[0] = fCenter;
+            info->fRadius[0] = fRadius;
+        }
+        return kRadial_GradientType;
+    }
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(Radial_Gradient, (buffer));
     }
 
+    virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+        this->INHERITED::flatten(buffer);
+        buffer.writeScalar(fCenter.fX);
+        buffer.writeScalar(fCenter.fY);
+        buffer.writeScalar(fRadius);
+    }
+
 protected:
-    Radial_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {};
+    Radial_Gradient(SkFlattenableReadBuffer& buffer)
+        : Gradient_Shader(buffer),
+          fCenter(SkPoint::Make(buffer.readScalar(), buffer.readScalar())),
+          fRadius(buffer.readScalar()) {
+    }
     virtual Factory getFactory() { return CreateProc; }
 
 private:
     typedef Gradient_Shader INHERITED;
+    const SkPoint fCenter;
+    const SkScalar fRadius;
 };
 
 /* Two-point radial gradients are specified by two circles, each with a center
@@ -1305,20 +1377,12 @@ public:
                               const SkColor colors[], const SkScalar pos[],
                               int colorCount, SkShader::TileMode mode,
                               SkUnitMapper* mapper)
-        : Gradient_Shader(colors, pos, colorCount, mode, mapper)
-    {
-        fDiff = start - end;
-        fDiffRadius = endRadius - startRadius;
-        SkScalar inv = SkScalarInvert(fDiffRadius);
-        fDiff.fX = SkScalarMul(fDiff.fX, inv);
-        fDiff.fY = SkScalarMul(fDiff.fY, inv);
-        fStartRadius = SkScalarMul(startRadius, inv);
-        fSr2D2 = SkScalarSquare(fStartRadius);
-        fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
-        fOneOverTwoA = SkScalarInvert(fA * 2);
-
-        fPtsToUnit.setTranslate(-start.fX, -start.fY);
-        fPtsToUnit.postScale(inv, inv);
+            : Gradient_Shader(colors, pos, colorCount, mode, mapper),
+              fCenter1(start),
+              fCenter2(end),
+              fRadius1(startRadius),
+              fRadius2(endRadius) {
+        init();
     }
 
     virtual BitmapType asABitmap(SkBitmap* bitmap,
@@ -1351,6 +1415,17 @@ public:
         return kTwoPointRadial_BitmapType;
     }
 
+    virtual GradientType asAGradient(GradientInfo* info) const {
+        if (info) {
+            commonAsAGradient(info);
+            info->fPoint[0] = fCenter1;
+            info->fPoint[1] = fCenter2;
+            info->fRadius[0] = fRadius1;
+            info->fRadius[1] = fRadius2;
+        }
+        return kRadial2_GradientType;
+    }
+
     virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
     {
         SkASSERT(count > 0);
@@ -1468,32 +1543,48 @@ public:
 
     virtual void flatten(SkFlattenableWriteBuffer& buffer) {
         this->INHERITED::flatten(buffer);
-        buffer.writeScalar(fDiff.fX);
-        buffer.writeScalar(fDiff.fY);
-        buffer.writeScalar(fStartRadius);
-        buffer.writeScalar(fDiffRadius);
-        buffer.writeScalar(fSr2D2);
-        buffer.writeScalar(fA);
-        buffer.writeScalar(fOneOverTwoA);
+        buffer.writeScalar(fCenter1.fX);
+        buffer.writeScalar(fCenter1.fY);
+        buffer.writeScalar(fCenter2.fX);
+        buffer.writeScalar(fCenter2.fY);
+        buffer.writeScalar(fRadius1);
+        buffer.writeScalar(fRadius2);
     }
 
 protected:
     Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer)
-            : Gradient_Shader(buffer) {
-        fDiff.fX = buffer.readScalar();
-        fDiff.fY = buffer.readScalar();
-        fStartRadius = buffer.readScalar();
-        fDiffRadius = buffer.readScalar();
-        fSr2D2 = buffer.readScalar();
-        fA = buffer.readScalar();
-        fOneOverTwoA = buffer.readScalar();
+            : Gradient_Shader(buffer),
+              fCenter1(SkPoint::Make(buffer.readScalar(), buffer.readScalar())),
+              fCenter2(SkPoint::Make(buffer.readScalar(), buffer.readScalar())),
+              fRadius1(buffer.readScalar()),
+              fRadius2(buffer.readScalar()) {
+        init();
     };
     virtual Factory getFactory() { return CreateProc; }
 
 private:
     typedef Gradient_Shader INHERITED;
+    const SkPoint fCenter1;
+    const SkPoint fCenter2;
+    const SkScalar fRadius1;
+    const SkScalar fRadius2;
     SkPoint fDiff;
     SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
+
+    void init() {
+        fDiff = fCenter1 - fCenter2;
+        fDiffRadius = fRadius2 - fRadius1;
+        SkScalar inv = SkScalarInvert(fDiffRadius);
+        fDiff.fX = SkScalarMul(fDiff.fX, inv);
+        fDiff.fY = SkScalarMul(fDiff.fY, inv);
+        fStartRadius = SkScalarMul(fRadius1, inv);
+        fSr2D2 = SkScalarSquare(fStartRadius);
+        fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
+        fOneOverTwoA = SkScalarInvert(fA * 2);
+
+        fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
+        fPtsToUnit.postScale(inv, inv);
+    }
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1502,7 +1593,8 @@ class Sweep_Gradient : public Gradient_Shader {
 public:
     Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
                    const SkScalar pos[], int count, SkUnitMapper* mapper)
-    : Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper)
+    : Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper),
+      fCenter(SkPoint::Make(cx, cy))
     {
         fPtsToUnit.setTranslate(-cx, -cy);
     }
@@ -1526,16 +1618,35 @@ public:
         return kSweep_BitmapType;
     }
 
+    virtual GradientType asAGradient(GradientInfo* info) const {
+        if (info) {
+            commonAsAGradient(info);
+            info->fPoint[0] = fCenter;
+        }
+        return kSweep_GradientType;
+    }
+
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(Sweep_Gradient, (buffer));
     }
 
+    virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+        this->INHERITED::flatten(buffer);
+        buffer.writeScalar(fCenter.fX);
+        buffer.writeScalar(fCenter.fY);
+    }
+
 protected:
-    Sweep_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {}
+    Sweep_Gradient(SkFlattenableReadBuffer& buffer)
+        : Gradient_Shader(buffer),
+          fCenter(SkPoint::Make(buffer.readScalar(), buffer.readScalar())) {
+    }
+
     virtual Factory getFactory() { return CreateProc; }
 
 private:
     typedef Gradient_Shader INHERITED;
+    const SkPoint fCenter;
 };
 
 #ifdef COMPUTE_SWEEP_TABLE
index 71c0c48e71783f8df7d4d67158f9033e6352efc6..3dfe02aa1409e5ff04fbfbfbd4b56b7434706a65 100644 (file)
@@ -325,7 +325,13 @@ bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
 
 ///////////////////////////////////////////////////////////////////////////////
 
-// must be in SkShader::BitmapTypeOrder
+SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
+SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
+SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
+SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
+SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
+                  shader_type_mismatch);
+SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
 
 static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
     (GrSamplerState::SampleMode) -1,                    // kNone_BitmapType