aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkColorShader.h3
-rw-r--r--include/core/SkShader.h58
-rw-r--r--src/core/SkShader.cpp33
-rw-r--r--src/effects/SkGradientShader.cpp181
-rw-r--r--src/gpu/SkGpuDevice.cpp8
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