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 <fmalita@chromium.org>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Florin Malita 2017-07-29 18:23:10 -04:00 committed by Skia Commit-Bot
parent 28a586966d
commit 9c2212fa79
3 changed files with 58 additions and 28 deletions

View File

@ -1202,8 +1202,8 @@ sk_sp<SkShader> 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<SkTwoPointConicalGradient>(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<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
flags, localMatrix);
}
return sk_make_sp<SkTwoPointConicalGradient>(end, endRadius, start, startRadius,
flipGradient, desc);
return SkTwoPointConicalGradient::Create(end, endRadius, start, startRadius, flipGradient,
desc);
}
}

View File

@ -10,16 +10,47 @@
#include "SkRasterPipeline.h"
#include "../../jumper/SkJumper.h"
sk_sp<SkShader> 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<SkShader>(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).

View File

@ -13,7 +13,7 @@
class SkTwoPointConicalGradient final : public SkGradientShaderBase {
public:
SkTwoPointConicalGradient(const SkPoint& start, SkScalar startRadius,
static sk_sp<SkShader> Create(const SkPoint& start, SkScalar startRadius,
const SkPoint& end, SkScalar endRadius,
bool flippedGrad, const Descriptor&);
@ -35,7 +35,6 @@ public:
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTwoPointConicalGradient)
protected:
SkTwoPointConicalGradient(SkReadBuffer& buffer);
void flatten(SkWriteBuffer& buffer) const override;
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
@ -47,11 +46,22 @@ protected:
bool onIsRasterPipelineOnly() const override { return true; }
private:
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;
Type fType;
friend class SkGradientShader;
typedef SkGradientShaderBase INHERITED;