diff options
author | fmalita <fmalita@chromium.org> | 2016-10-05 09:28:42 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-10-05 09:28:42 -0700 |
commit | 088e21ba652ceaa4abb4ba8cdd2ec1bc8afc32ed (patch) | |
tree | d85e228092824a9e721d5831947209842f2bdf1c | |
parent | c6618dd1dadeac8b47b81fbee108c42cca8ab166 (diff) |
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
-rw-r--r-- | include/core/SkMatrix.h | 9 | ||||
-rw-r--r-- | src/effects/gradients/Sk4fGradientBase.cpp | 5 | ||||
-rw-r--r-- | src/effects/gradients/Sk4fGradientBase.h | 2 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShader.cpp | 4 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShaderPriv.h | 13 | ||||
-rw-r--r-- | src/effects/gradients/SkLinearGradient.cpp | 4 | ||||
-rw-r--r-- | src/effects/gradients/SkRadialGradient.cpp | 2 | ||||
-rw-r--r-- | src/effects/gradients/SkSweepGradient.cpp | 2 | ||||
-rw-r--r-- | src/effects/gradients/SkTwoPointConicalGradient.cpp | 2 |
9 files changed, 33 insertions, 10 deletions
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h index 19103843bf..f565a537ba 100644 --- a/include/core/SkMatrix.h +++ b/include/core/SkMatrix.h @@ -736,6 +736,11 @@ public: 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 @@ private: 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 a22136831d..8994db3a91 100644 --- a/src/effects/gradients/Sk4fGradientBase.cpp +++ b/src/effects/gradients/Sk4fGradientBase.cpp @@ -158,6 +158,11 @@ GradientShaderBase4fContext::GradientShaderBase4fContext(const SkGradientShaderB || 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 17f9563957..fd6d6563a7 100644 --- a/src/effects/gradients/Sk4fGradientBase.h +++ b/src/effects/gradients/Sk4fGradientBase.h @@ -28,6 +28,8 @@ public: 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 4ee82037d1..17302d9d4f 100644 --- a/src/effects/gradients/SkGradientShader.cpp +++ b/src/effects/gradients/SkGradientShader.cpp @@ -397,6 +397,10 @@ SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext( } } +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 f850994761..61a44184ff 100644 --- a/src/effects/gradients/SkGradientShaderPriv.h +++ b/src/effects/gradients/SkGradientShaderPriv.h @@ -115,7 +115,6 @@ public: SkAutoMalloc fDynamicStorage; }; -public: SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit); virtual ~SkGradientShaderBase(); @@ -159,6 +158,8 @@ public: uint32_t getFlags() const override { return fFlags; } + bool isValid() const; + protected: SkMatrix fDstToIndex; SkMatrix::MapXYProc fDstToIndexProc; @@ -233,6 +234,16 @@ protected: 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 be29540add..a249ae4ac8 100644 --- a/src/effects/gradients/SkLinearGradient.cpp +++ b/src/effects/gradients/SkLinearGradient.cpp @@ -82,8 +82,8 @@ size_t SkLinearGradient::onContextSize(const ContextRec& rec) const { 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 b0ef205f44..18ef376862 100644 --- a/src/effects/gradients/SkRadialGradient.cpp +++ b/src/effects/gradients/SkRadialGradient.cpp @@ -44,7 +44,7 @@ size_t SkRadialGradient::onContextSize(const ContextRec&) const { } 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 d99d979f68..d1fe269b9c 100644 --- a/src/effects/gradients/SkSweepGradient.cpp +++ b/src/effects/gradients/SkSweepGradient.cpp @@ -50,7 +50,7 @@ size_t SkSweepGradient::onContextSize(const ContextRec&) const { } 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 fd48a62679..599fd4c9fd 100644 --- a/src/effects/gradients/SkTwoPointConicalGradient.cpp +++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp @@ -216,7 +216,7 @@ size_t SkTwoPointConicalGradient::onContextSize(const ContextRec&) const { 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( |