diff options
-rw-r--r-- | include/core/SkColorShader.h | 3 | ||||
-rw-r--r-- | include/core/SkShader.h | 58 | ||||
-rw-r--r-- | src/core/SkShader.cpp | 33 | ||||
-rw-r--r-- | src/effects/SkGradientShader.cpp | 181 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 8 |
5 files changed, 235 insertions, 48 deletions
diff --git a/include/core/SkColorShader.h b/include/core/SkColorShader.h index 44a6148c0f..1f833556f9 100644 --- a/include/core/SkColorShader.h +++ b/include/core/SkColorShader.h @@ -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& ); diff --git a/include/core/SkShader.h b/include/core/SkShader.h index 1cdbf17cf6..faaa0afc4b 100644 --- a/include/core/SkShader.h +++ b/include/core/SkShader.h @@ -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 diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp index 7b3a024c4f..6798bec888 100644 --- a/src/core/SkShader.cpp +++ b/src/core/SkShader.cpp @@ -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; +} diff --git a/src/effects/SkGradientShader.cpp b/src/effects/SkGradientShader.cpp index 64a78c7f0e..41b97cc4c3 100644 --- a/src/effects/SkGradientShader.cpp +++ b/src/effects/SkGradientShader.cpp @@ -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 diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 71c0c48e71..3dfe02aa14 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -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 |