diff options
author | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-04-17 13:28:06 +0000 |
---|---|---|
committer | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-04-17 13:28:06 +0000 |
commit | cf41935735544a412ea66afd31470b418a586213 (patch) | |
tree | c5561514439d5c8c8a09512994b1b8706b197729 | |
parent | 667b98d947892cec939669bccf204ab9ed565c4e (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.h | 3 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShader.cpp | 49 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShaderPriv.h | 5 | ||||
-rw-r--r-- | src/effects/gradients/SkTwoPointConicalGradient.cpp | 34 | ||||
-rw-r--r-- | src/effects/gradients/SkTwoPointConicalGradient.h | 16 | ||||
-rw-r--r-- | src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp | 35 |
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; } |