aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-17 13:28:06 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-17 13:28:06 +0000
commitcf41935735544a412ea66afd31470b418a586213 (patch)
treec5561514439d5c8c8a09512994b1b8706b197729
parent667b98d947892cec939669bccf204ab9ed565c4e (diff)
Add flipped gradient branch to two point conical gradient
BUG=skia: R=bsalomon@google.com, mtklein@google.com Author: egdaniel@google.com Review URL: https://codereview.chromium.org/227623004 git-svn-id: http://skia.googlecode.com/svn/trunk@14235 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--include/core/SkPicture.h3
-rw-r--r--src/effects/gradients/SkGradientShader.cpp49
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h5
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.cpp34
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.h16
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp35
6 files changed, 119 insertions, 23 deletions
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 441833db36..cd9ff546bf 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -322,13 +322,14 @@ protected:
// V21: add pushCull, popCull
// V22: SK_PICT_FACTORY_TAG's size is now the chunk size in bytes
// V23: SkPaint::FilterLevel became a real enum
+ // V24: SkTwoPointConicalGradient now has fFlipped flag for gradient flipping
// Note: If the picture version needs to be increased then please follow the
// steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw
// Only SKPs within the min/current picture version range (inclusive) can be read.
static const uint32_t MIN_PICTURE_VERSION = 19;
- static const uint32_t CURRENT_PICTURE_VERSION = 23;
+ static const uint32_t CURRENT_PICTURE_VERSION = 24;
mutable uint32_t fUniqueID;
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 3547fbec94..36d690ac09 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -203,6 +203,25 @@ void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
buffer.writeMatrix(fPtsToUnit);
}
+// V23_COMPATIBILITY_CODE
+void SkGradientShaderBase::flipGradientColors() {
+ SkAutoSTArray<8, SkColor> colorsTemp(fColorCount);
+ for (int i = 0; i < fColorCount; ++i) {
+ int offset = fColorCount - i - 1;
+ colorsTemp[i] = fOrigColors[offset];
+ }
+ if (fColorCount > 2) {
+ SkAutoSTArray<8, Rec> recsTemp(fColorCount);
+ for (int i = 0; i < fColorCount; ++i) {
+ int offset = fColorCount - i - 1;
+ recsTemp[i].fPos = 1 - fRecs[offset].fPos;
+ recsTemp[i].fScale = fRecs[offset].fScale;
+ }
+ memcpy(fRecs, recsTemp.get(), fColorCount * sizeof(Rec));
+ }
+ memcpy(fOrigColors, colorsTemp.get(), fColorCount * sizeof(SkColor));
+}
+
bool SkGradientShaderBase::isOpaque() const {
return fColorsAreOpaque;
}
@@ -793,12 +812,36 @@ SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start,
if (start == end && startRadius == endRadius) {
return SkNEW(SkEmptyShader);
}
+
EXPAND_1_COLOR(colorCount);
+ bool flipGradient = startRadius > endRadius;
+
SkGradientShaderBase::Descriptor desc;
- desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
- return SkNEW_ARGS(SkTwoPointConicalGradient,
- (start, startRadius, end, endRadius, desc));
+
+ if (!flipGradient) {
+ desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
+ return SkNEW_ARGS(SkTwoPointConicalGradient,
+ (start, startRadius, end, endRadius, flipGradient, desc));
+ } else {
+ SkAutoSTArray<8, SkColor> colorsNew(colorCount);
+ SkAutoSTArray<8, SkScalar> posNew(colorCount);
+ for (int i = 0; i < colorCount; ++i) {
+ colorsNew[i] = colors[colorCount - i - 1];
+ }
+
+ if (pos) {
+ for (int i = 0; i < colorCount; ++i) {
+ posNew[i] = 1 - pos[colorCount - i - 1];
+ }
+ desc_init(&desc, colorsNew.get(), posNew.get(), colorCount, mode, mapper, flags);
+ } else {
+ desc_init(&desc, colorsNew.get(), NULL, colorCount, mode, mapper, flags);
+ }
+
+ return SkNEW_ARGS(SkTwoPointConicalGradient,
+ (end, endRadius, start, startRadius, flipGradient, desc));
+ }
}
SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 1d0f008917..f4f53dee25 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -205,6 +205,11 @@ protected:
void commonAsAGradient(GradientInfo*) const;
+ // V23_COMPATIBILITY_CODE
+ // Used for 2-pt conical gradients since we sort start/end cirlces by radius
+ // Assumes space has already been allocated for fOrigColors
+ void flipGradientColors();
+
private:
enum {
kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index b0955a2583..59a135a642 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -32,7 +32,7 @@ static int valid_divide(float numer, float denom, float* ratio) {
// Return the number of distinct real roots, and write them into roots[] in
// ascending order
-static int find_quad_roots(float A, float B, float C, float roots[2]) {
+static int find_quad_roots(float A, float B, float C, float roots[2], bool descendingOrder = false) {
SkASSERT(roots);
if (A == 0) {
@@ -66,6 +66,9 @@ static int find_quad_roots(float A, float B, float C, float roots[2]) {
float r1 = C / Q;
roots[0] = r0 < r1 ? r0 : r1;
roots[1] = r0 > r1 ? r0 : r1;
+ if (descendingOrder) {
+ SkTSwap(roots[0], roots[1]);
+ }
return 2;
}
@@ -76,7 +79,8 @@ static float lerp(float x, float dx, float t) {
static float sqr(float x) { return x * x; }
void TwoPtRadial::init(const SkPoint& center0, SkScalar rad0,
- const SkPoint& center1, SkScalar rad1) {
+ const SkPoint& center1, SkScalar rad1,
+ bool flipped) {
fCenterX = SkScalarToFloat(center0.fX);
fCenterY = SkScalarToFloat(center0.fY);
fDCenterX = SkScalarToFloat(center1.fX) - fCenterX;
@@ -87,6 +91,8 @@ void TwoPtRadial::init(const SkPoint& center0, SkScalar rad0,
fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius);
fRadius2 = sqr(fRadius);
fRDR = fRadius * fDRadius;
+
+ fFlipped = flipped;
}
TwoPtRadialContext::TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy,
@@ -103,7 +109,7 @@ SkFixed TwoPtRadialContext::nextT() {
float roots[2];
float C = sqr(fRelX) + sqr(fRelY) - fRec.fRadius2;
- int countRoots = find_quad_roots(fRec.fA, fB, C, roots);
+ int countRoots = find_quad_roots(fRec.fA, fB, C, roots, fRec.fFlipped);
fRelX += fIncX;
fRelY += fIncY;
@@ -182,7 +188,7 @@ static void twopoint_mirror(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC
}
void SkTwoPointConicalGradient::init() {
- fRec.init(fCenter1, fRadius1, fCenter2, fRadius2);
+ fRec.init(fCenter1, fRadius1, fCenter2, fRadius2, fFlippedGrad);
fPtsToUnit.reset();
}
@@ -191,12 +197,13 @@ void SkTwoPointConicalGradient::init() {
SkTwoPointConicalGradient::SkTwoPointConicalGradient(
const SkPoint& start, SkScalar startRadius,
const SkPoint& end, SkScalar endRadius,
- const Descriptor& desc)
+ bool flippedGrad, const Descriptor& desc)
: SkGradientShaderBase(desc),
fCenter1(start),
fCenter2(end),
fRadius1(startRadius),
- fRadius2(endRadius) {
+ fRadius2(endRadius),
+ fFlippedGrad(flippedGrad) {
// this is degenerate, and should be caught by our caller
SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
this->init();
@@ -345,6 +352,20 @@ SkTwoPointConicalGradient::SkTwoPointConicalGradient(
fCenter2(buffer.readPoint()),
fRadius1(buffer.readScalar()),
fRadius2(buffer.readScalar()) {
+ if (buffer.pictureVersion() >= 24 || 0 == buffer.pictureVersion()) {
+ fFlippedGrad = buffer.readBool();
+ } else {
+ // V23_COMPATIBILITY_CODE
+ // Sort gradient by radius size for old pictures
+ if (fRadius2 < fRadius1) {
+ SkTSwap(fCenter1, fCenter2);
+ SkTSwap(fRadius1, fRadius2);
+ this->flipGradientColors();
+ fFlippedGrad = true;
+ } else {
+ fFlippedGrad = false;
+ }
+ }
this->init();
};
@@ -355,6 +376,7 @@ void SkTwoPointConicalGradient::flatten(
buffer.writePoint(fCenter2);
buffer.writeScalar(fRadius1);
buffer.writeScalar(fRadius2);
+ buffer.writeBool(fFlippedGrad);
}
#if SK_SUPPORT_GPU
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.h b/src/effects/gradients/SkTwoPointConicalGradient.h
index 4c049172d3..80aa6fa693 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.h
+++ b/src/effects/gradients/SkTwoPointConicalGradient.h
@@ -25,9 +25,11 @@ struct TwoPtRadial {
float fA;
float fRadius2;
float fRDR;
+ bool fFlipped;
void init(const SkPoint& center0, SkScalar rad0,
- const SkPoint& center1, SkScalar rad1);
+ const SkPoint& center1, SkScalar rad1,
+ bool flipped);
static bool DontDrawT(SkFixed t) {
return kDontDrawT == (uint32_t)t;
@@ -42,7 +44,7 @@ class SkTwoPointConicalGradient : public SkGradientShaderBase {
public:
SkTwoPointConicalGradient(const SkPoint& start, SkScalar startRadius,
const SkPoint& end, SkScalar endRadius,
- const Descriptor&);
+ bool flippedGrad, const Descriptor&);
virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&,
@@ -76,6 +78,7 @@ public:
const SkPoint& getStartCenter() const { return fCenter1; }
const SkPoint& getEndCenter() const { return fCenter2; }
SkScalar getEndRadius() const { return fRadius2; }
+ bool isFlippedGrad() const { return fFlippedGrad; }
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTwoPointConicalGradient)
@@ -85,10 +88,11 @@ protected:
virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
private:
- const SkPoint fCenter1;
- const SkPoint fCenter2;
- const SkScalar fRadius1;
- const SkScalar fRadius2;
+ SkPoint fCenter1;
+ SkPoint fCenter2;
+ SkScalar fRadius1;
+ SkScalar fRadius2;
+ bool fFlippedGrad;
typedef SkGradientShaderBase INHERITED;
};
diff --git a/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp b/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
index d7b0384017..7cdb62dc44 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
@@ -56,6 +56,7 @@ public:
// The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
bool isDegenerate() const { return SkScalarAbs(fDiffRadius) == SkScalarAbs(fCenterX1); }
+ bool isFlipped() const { return fIsFlipped; }
SkScalar center() const { return fCenterX1; }
SkScalar diffRadius() const { return fDiffRadius; }
SkScalar radius() const { return fRadius0; }
@@ -68,7 +69,8 @@ private:
return (INHERITED::onIsEqual(sBase) &&
this->fCenterX1 == s.fCenterX1 &&
this->fRadius0 == s.fRadius0 &&
- this->fDiffRadius == s.fDiffRadius);
+ this->fDiffRadius == s.fDiffRadius &&
+ this->fIsFlipped == s.fIsFlipped);
}
Default2PtConicalEffect(GrContext* ctx,
@@ -78,7 +80,8 @@ private:
: INHERITED(ctx, shader, matrix, tm),
fCenterX1(shader.getCenterX1()),
fRadius0(shader.getStartRadius()),
- fDiffRadius(shader.getDiffRadius()) {
+ fDiffRadius(shader.getDiffRadius()),
+ fIsFlipped(shader.isFlippedGrad()) {
// We pass the linear part of the quadratic as a varying.
// float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
fBTransform = this->getCoordTransform();
@@ -103,6 +106,7 @@ private:
SkScalar fCenterX1;
SkScalar fRadius0;
SkScalar fDiffRadius;
+ bool fIsFlipped;
// @}
@@ -132,6 +136,7 @@ protected:
const char* fFSVaryingName;
bool fIsDegenerate;
+ bool fIsFlipped;
// @{
/// Values last uploaded as uniforms
@@ -194,6 +199,7 @@ GLDefault2PtConicalEffect::GLDefault2PtConicalEffect(const GrBackendEffectFactor
const Default2PtConicalEffect& data = drawEffect.castEffect<Default2PtConicalEffect>();
fIsDegenerate = data.isDegenerate();
+ fIsFlipped = data.isFlipped();
}
void GLDefault2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
@@ -281,9 +287,14 @@ void GLDefault2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
// Note: If there are two roots that both generate radius(t) > 0, the
// Canvas spec says to choose the larger t.
- // so we'll look at the larger one first:
- builder->fsCodeAppendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(),
- r0Name.c_str(), r1Name.c_str());
+ // so we'll look at the larger one first (or smaller if flipped):
+ if (!fIsFlipped) {
+ builder->fsCodeAppendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(),
+ r0Name.c_str(), r1Name.c_str());
+ } else {
+ builder->fsCodeAppendf("\t\tfloat %s = min(%s, %s);\n", tName.c_str(),
+ r0Name.c_str(), r1Name.c_str());
+ }
// if r(t) > 0, then we're done; t will be our x coordinate
builder->fsCodeAppendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
@@ -294,8 +305,13 @@ void GLDefault2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
// otherwise, if r(t) for the larger root was <= 0, try the other root
builder->fsCodeAppend("\t\t} else {\n");
- builder->fsCodeAppendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(),
- r0Name.c_str(), r1Name.c_str());
+ if (!fIsFlipped) {
+ builder->fsCodeAppendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(),
+ r0Name.c_str(), r1Name.c_str());
+ } else {
+ builder->fsCodeAppendf("\t\t\t%s = max(%s, %s);\n", tName.c_str(),
+ r0Name.c_str(), r1Name.c_str());
+ }
// if r(t) > 0 for the smaller root, then t will be our x coordinate
builder->fsCodeAppendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
@@ -330,6 +346,7 @@ void GLDefault2PtConicalEffect::setData(const GrGLUniformManager& uman,
INHERITED::setData(uman, drawEffect);
const Default2PtConicalEffect& data = drawEffect.castEffect<Default2PtConicalEffect>();
SkASSERT(data.isDegenerate() == fIsDegenerate);
+ SkASSERT(data.isFlipped() == fIsFlipped);
SkScalar centerX1 = data.center();
SkScalar radius0 = data.radius();
SkScalar diffRadius = data.diffRadius();
@@ -365,12 +382,16 @@ GrGLEffect::EffectKey GLDefault2PtConicalEffect::GenKey(const GrDrawEffect& draw
const GrGLCaps&) {
enum {
kIsDegenerate = 1 << kBaseKeyBitCnt,
+ kIsFlipped = 1 << (kBaseKeyBitCnt + 1),
};
EffectKey key = GenBaseGradientKey(drawEffect);
if (drawEffect.castEffect<Default2PtConicalEffect>().isDegenerate()) {
key |= kIsDegenerate;
}
+ if (drawEffect.castEffect<Default2PtConicalEffect>().isFlipped()) {
+ key |= kIsFlipped;
+ }
return key;
}