From 9c2212fa79e03ea7f3527bf4c30b3e6bbd560932 Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Sat, 29 Jul 2017 18:23:10 -0400 Subject: [PATCH] Don't instantiate degenerate 2pt gradients We can catch the condition at construction time, no need to defer. Change-Id: I973b9e1b79998e2b334e3a91694c793882dfd65a Reviewed-on: https://skia-review.googlesource.com/26564 Commit-Queue: Florin Malita Reviewed-by: Mike Klein --- src/shaders/gradients/SkGradientShader.cpp | 8 +-- .../gradients/SkTwoPointConicalGradient.cpp | 54 +++++++++++++------ .../gradients/SkTwoPointConicalGradient.h | 24 ++++++--- 3 files changed, 58 insertions(+), 28 deletions(-) diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp index 56a8fe317b..c9a69e2a55 100644 --- a/src/shaders/gradients/SkGradientShader.cpp +++ b/src/shaders/gradients/SkGradientShader.cpp @@ -1202,8 +1202,8 @@ sk_sp SkGradientShader::MakeTwoPointConical(const SkPoint& start, if (!flipGradient) { desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags, localMatrix); - return sk_make_sp(start, startRadius, end, endRadius, - flipGradient, desc); + return SkTwoPointConicalGradient::Create(start, startRadius, end, endRadius, flipGradient, + desc); } else { SkAutoSTArray<8, SkColor4f> colorsNew(opt.fCount); SkAutoSTArray<8, SkScalar> posNew(opt.fCount); @@ -1222,8 +1222,8 @@ sk_sp SkGradientShader::MakeTwoPointConical(const SkPoint& start, flags, localMatrix); } - return sk_make_sp(end, endRadius, start, startRadius, - flipGradient, desc); + return SkTwoPointConicalGradient::Create(end, endRadius, start, startRadius, flipGradient, + desc); } } diff --git a/src/shaders/gradients/SkTwoPointConicalGradient.cpp b/src/shaders/gradients/SkTwoPointConicalGradient.cpp index 22ae177559..479d85ffd8 100644 --- a/src/shaders/gradients/SkTwoPointConicalGradient.cpp +++ b/src/shaders/gradients/SkTwoPointConicalGradient.cpp @@ -10,16 +10,47 @@ #include "SkRasterPipeline.h" #include "../../jumper/SkJumper.h" +sk_sp SkTwoPointConicalGradient::Create(const SkPoint& c0, SkScalar r0, + const SkPoint& c1, SkScalar r1, + bool flipped, const Descriptor& desc) { + SkMatrix gradientMatrix; + Type gradientType; + + if (SkScalarNearlyZero((c0 - c1).length())) { + // Concentric case: we can pretend we're radial (with a tiny twist). + gradientMatrix = SkMatrix::MakeTrans(-c1.x(), -c1.y()); + gradientMatrix.postScale(1 / r1, 1 / r1); + + gradientType = Type::kRadial; + } else { + const SkPoint centers[2] = { c0 , c1 }; + const SkPoint unitvec[2] = { {0, 0}, {1, 0} }; + + if (!gradientMatrix.setPolyToPoly(centers, unitvec, 2)) { + // Degenerate case. + return nullptr; + } + + // General two-point case. + gradientType = Type::kTwoPoint; + } + + return sk_sp(new SkTwoPointConicalGradient(c0, r0, c1, r1, flipped, desc, + gradientType, gradientMatrix)); +} + SkTwoPointConicalGradient::SkTwoPointConicalGradient( const SkPoint& start, SkScalar startRadius, const SkPoint& end, SkScalar endRadius, - bool flippedGrad, const Descriptor& desc) - : SkGradientShaderBase(desc, SkMatrix::I()) + bool flippedGrad, const Descriptor& desc, + Type type, const SkMatrix& gradientMatrix) + : SkGradientShaderBase(desc, gradientMatrix) , fCenter1(start) , fCenter2(end) , fRadius1(startRadius) , fRadius2(endRadius) , fFlippedGrad(flippedGrad) + , fType(type) { // this is degenerate, and should be caught by our caller SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2); @@ -176,15 +207,12 @@ bool SkTwoPointConicalGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc, SkMatrix* matrix, SkRasterPipeline* p, SkRasterPipeline* postPipeline) const { - const auto dCenter = (fCenter1 - fCenter2).length(); + matrix->postConcat(fPtsToUnit); + const auto dRadius = fRadius2 - fRadius1; SkASSERT(dRadius >= 0); - // When the two circles are concentric, we can pretend we're radial (with a tiny *twist). - if (SkScalarNearlyZero(dCenter)) { - const SkMatrix tmp = SkMatrix::Concat(SkMatrix::MakeScale(1 / fRadius2, 1 / fRadius2), - SkMatrix::MakeTrans(-fCenter1.fX, -fCenter1.fY)); - matrix->postConcat(tmp); + if (fType == Type::kRadial) { p->append(SkRasterPipeline::xy_to_radius); // Tiny twist: radial computes a t for [0, r2], but we want a t for [r1, r2]. @@ -197,15 +225,7 @@ bool SkTwoPointConicalGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc, return true; } - // To simplify the stage math, we transform the universe (translate/scale/rotate) - // such that fCenter1 -> (0, 0) and fCenter2 -> (1, 0). - SkMatrix map_to_unit_vector; - const SkPoint centers[2] = { fCenter1, fCenter2 }; - const SkPoint unitvec[2] = { {0, 0}, {1, 0} }; - if (!map_to_unit_vector.setPolyToPoly(centers, unitvec, 2)) { - return false; - } - matrix->postConcat(map_to_unit_vector); + const auto dCenter = (fCenter1 - fCenter2).length(); // Since we've squashed the centers into a unit vector, we must also scale // all the coefficient variables by (1 / dCenter). diff --git a/src/shaders/gradients/SkTwoPointConicalGradient.h b/src/shaders/gradients/SkTwoPointConicalGradient.h index 41909c900d..8b11963802 100644 --- a/src/shaders/gradients/SkTwoPointConicalGradient.h +++ b/src/shaders/gradients/SkTwoPointConicalGradient.h @@ -13,9 +13,9 @@ class SkTwoPointConicalGradient final : public SkGradientShaderBase { public: - SkTwoPointConicalGradient(const SkPoint& start, SkScalar startRadius, - const SkPoint& end, SkScalar endRadius, - bool flippedGrad, const Descriptor&); + static sk_sp Create(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + bool flippedGrad, const Descriptor&); SkShader::GradientType asAGradient(GradientInfo* info) const override; #if SK_SUPPORT_GPU @@ -35,7 +35,6 @@ public: SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTwoPointConicalGradient) protected: - SkTwoPointConicalGradient(SkReadBuffer& buffer); void flatten(SkWriteBuffer& buffer) const override; sk_sp onMakeColorSpace(SkColorSpaceXformer* xformer) const override; @@ -47,11 +46,22 @@ protected: bool onIsRasterPipelineOnly() const override { return true; } private: - SkPoint fCenter1; - SkPoint fCenter2; + enum class Type { + kRadial, + kTwoPoint, + }; + + SkTwoPointConicalGradient(const SkPoint& c0, SkScalar r0, + const SkPoint& c1, SkScalar r1, + bool flippedGrad, const Descriptor&, + Type, const SkMatrix&); + + SkPoint fCenter1; + SkPoint fCenter2; SkScalar fRadius1; SkScalar fRadius2; - bool fFlippedGrad; + bool fFlippedGrad; + Type fType; friend class SkGradientShader; typedef SkGradientShaderBase INHERITED;