Harden degenerate gradient context handling
Certain inputs produce degenerate values at context creation time only.
Detect such cases after context creation, and abort drawing by returning
a null shader context instead.
BUG=skia:5821
R=reed@google.com,brianosman@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2397473003
Review-Url: https://codereview.chromium.org/2397473003
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index 1910384..f565a53 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -736,6 +736,11 @@
this->setTypeMask(mask | kRectStaysRect_Mask);
}
+ /**
+ * Are all elements of the matrix finite?
+ */
+ bool isFinite() const { return SkScalarsAreFinite(fMat, 9); }
+
private:
enum {
/** Set if the matrix will map a rectangle to another rectangle. This
@@ -768,10 +773,6 @@
SkScalar fMat[9];
mutable uint32_t fTypeMask;
- /** Are all elements of the matrix finite?
- */
- bool isFinite() const { return SkScalarsAreFinite(fMat, 9); }
-
static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp);
uint8_t computeTypeMask() const;
diff --git a/src/effects/gradients/Sk4fGradientBase.cpp b/src/effects/gradients/Sk4fGradientBase.cpp
index a221368..8994db3 100644
--- a/src/effects/gradients/Sk4fGradientBase.cpp
+++ b/src/effects/gradients/Sk4fGradientBase.cpp
@@ -158,6 +158,11 @@
|| shader.fColorsAreOpaque;
}
+bool SkGradientShaderBase::
+GradientShaderBase4fContext::isValid() const {
+ return fDstToPos.isFinite();
+}
+
void SkGradientShaderBase::
GradientShaderBase4fContext::buildIntervals(const SkGradientShaderBase& shader,
const ContextRec& rec, bool reverse) {
diff --git a/src/effects/gradients/Sk4fGradientBase.h b/src/effects/gradients/Sk4fGradientBase.h
index 17f9563..fd6d656 100644
--- a/src/effects/gradients/Sk4fGradientBase.h
+++ b/src/effects/gradients/Sk4fGradientBase.h
@@ -28,6 +28,8 @@
void shadeSpan(int x, int y, SkPMColor dst[], int count) override;
void shadeSpan4f(int x, int y, SkPM4f dst[], int count) override;
+ bool isValid() const;
+
protected:
struct Interval {
Interval(const Sk4f& c0, SkScalar p0,
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 4ee8203..17302d9 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -397,6 +397,10 @@
}
}
+bool SkGradientShaderBase::GradientShaderBaseContext::isValid() const {
+ return fDstToIndex.isFinite();
+}
+
SkGradientShaderBase::GradientShaderCache::GradientShaderCache(
U8CPU alpha, bool dither, const SkGradientShaderBase& shader)
: fCacheAlpha(alpha)
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index f850994..61a4418 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -115,7 +115,6 @@
SkAutoMalloc fDynamicStorage;
};
-public:
SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
virtual ~SkGradientShaderBase();
@@ -159,6 +158,8 @@
uint32_t getFlags() const override { return fFlags; }
+ bool isValid() const;
+
protected:
SkMatrix fDstToIndex;
SkMatrix::MapXYProc fDstToIndexProc;
@@ -233,6 +234,16 @@
SkColor* colorSrc, Rec* recSrc,
int count);
+ template <typename T, typename... Args>
+ static Context* CheckedCreateContext(void* storage, Args&&... args) {
+ auto* ctx = new (storage) T(std::forward<Args>(args)...);
+ if (!ctx->isValid()) {
+ ctx->~T();
+ return nullptr;
+ }
+ return ctx;
+ }
+
private:
enum {
kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index be29540..a249ae4 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -82,8 +82,8 @@
SkShader::Context* SkLinearGradient::onCreateContext(const ContextRec& rec, void* storage) const {
return use_4f_context(rec, fGradFlags)
- ? static_cast<SkShader::Context*>(new (storage) LinearGradient4fContext(*this, rec))
- : static_cast<SkShader::Context*>(new (storage) LinearGradientContext(*this, rec));
+ ? CheckedCreateContext<LinearGradient4fContext>(storage, *this, rec)
+ : CheckedCreateContext< LinearGradientContext>(storage, *this, rec);
}
// This swizzles SkColor into the same component order as SkPMColor, but does not actually
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index b0ef205..18ef376 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -44,7 +44,7 @@
}
SkShader::Context* SkRadialGradient::onCreateContext(const ContextRec& rec, void* storage) const {
- return new (storage) RadialGradientContext(*this, rec);
+ return CheckedCreateContext<RadialGradientContext>(storage, *this, rec);
}
SkRadialGradient::RadialGradientContext::RadialGradientContext(
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index d99d979..d1fe269 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -50,7 +50,7 @@
}
SkShader::Context* SkSweepGradient::onCreateContext(const ContextRec& rec, void* storage) const {
- return new (storage) SweepGradientContext(*this, rec);
+ return CheckedCreateContext<SweepGradientContext>(storage, *this, rec);
}
SkSweepGradient::SweepGradientContext::SweepGradientContext(
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index fd48a62..599fd4c 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -216,7 +216,7 @@
SkShader::Context* SkTwoPointConicalGradient::onCreateContext(const ContextRec& rec,
void* storage) const {
- return new (storage) TwoPointConicalGradientContext(*this, rec);
+ return CheckedCreateContext<TwoPointConicalGradientContext>(storage, *this, rec);
}
SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradientContext(