Guard against large content bounds for layer mapping calculations
Bug: chromium:1232744, chromium:1226344
Change-Id: I1fda9fb01f8c501bb5b410a8c7cd292f53b13142
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/438577
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index f04a1c5..39fd744 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -657,10 +657,10 @@
// Helper function to compute the center reference point used for scale decomposition under
// non-linear transformations.
-static bool compute_decomposition_center(const SkMatrix& dstToLocal,
- const skif::ParameterSpace<SkRect>* contentBounds,
- const skif::DeviceSpace<SkIRect>& targetOutput,
- skif::ParameterSpace<SkPoint>* out) {
+static skif::ParameterSpace<SkPoint> compute_decomposition_center(
+ const SkMatrix& dstToLocal,
+ const skif::ParameterSpace<SkRect>* contentBounds,
+ const skif::DeviceSpace<SkIRect>& targetOutput) {
// Will use the inverse and center of the device bounds if the content bounds aren't provided.
SkRect rect = contentBounds ? SkRect(*contentBounds) : SkRect::Make(SkIRect(targetOutput));
SkPoint center = {rect.centerX(), rect.centerY()};
@@ -670,8 +670,7 @@
dstToLocal.mapPoints(¢er, 1);
}
- *out = skif::ParameterSpace<SkPoint>(center);
- return true;
+ return skif::ParameterSpace<SkPoint>(center);
}
// Compute suitable transformations and layer bounds for a new layer that will be used as the source
@@ -686,13 +685,14 @@
const skif::DeviceSpace<SkIRect>& targetOutput,
const skif::ParameterSpace<SkRect>* contentBounds = nullptr,
bool mustCoverDst = true) {
- skif::ParameterSpace<SkPoint> center;
SkMatrix dstToLocal;
if (!localToDst.isFinite() ||
- !localToDst.invert(&dstToLocal) ||
- !compute_decomposition_center(dstToLocal, contentBounds, targetOutput, ¢er)) {
+ !localToDst.invert(&dstToLocal)) {
return {{}, skif::LayerSpace<SkIRect>(SkIRect::MakeEmpty())};
}
+
+ skif::ParameterSpace<SkPoint> center =
+ compute_decomposition_center(dstToLocal, contentBounds, targetOutput);
// *after* possibly getting a representative point from the provided content bounds, it might
// be necessary to discard the bounds for subsequent layer calculations.
if (mustCoverDst) {
@@ -743,7 +743,11 @@
SkMatrix adjust = SkMatrix::MakeRectToRect(SkRect::Make(SkIRect(layerBounds)),
SkRect::Make(SkIRect(newLayerBounds)),
SkMatrix::kFill_ScaleToFit);
- if (!mapping.adjustLayerSpace(adjust)) {
+ // If the adjust matrix isn't invertible, or if multiplying it into the device transform
+ // causes overflows, then subsequent SkDevice coordinate spaces would be invalid, so
+ // just return the empty bounds and skip the layer.
+ if (!mapping.adjustLayerSpace(adjust) ||
+ !mapping.deviceMatrix().isFinite()) {
layerBounds = skif::LayerSpace<SkIRect>(SkIRect::MakeEmpty());
} else {
layerBounds = newLayerBounds;
diff --git a/src/core/SkImageFilterTypes.cpp b/src/core/SkImageFilterTypes.cpp
index 0ec20a6..88077b8 100644
--- a/src/core/SkImageFilterTypes.cpp
+++ b/src/core/SkImageFilterTypes.cpp
@@ -50,12 +50,13 @@
// Perspective, which has a non-uniform scaling effect on the filter. Pick a single scale
// factor that best matches where the filter will be evaluated.
SkScalar scale = SkMatrixPriv::DifferentialAreaScale(ctm, SkPoint(representativePoint));
- if (SkScalarIsFinite(scale)) {
+ if (SkScalarIsFinite(scale) && !SkScalarNearlyZero(scale)) {
// Now take the sqrt to go from an area scale factor to a scaling per X and Y
// FIXME: It would be nice to be able to choose a non-uniform scale.
scale = SkScalarSqrt(scale);
} else {
// The representative point was behind the W = 0 plane, so don't factor out any scale.
+ // NOTE: This makes remainder and layer the same as the MatrixCapability::Translate case
scale = 1.f;
}
@@ -63,6 +64,7 @@
remainder.preScale(SkScalarInvert(scale), SkScalarInvert(scale));
layer = SkMatrix::Scale(scale, scale);
}
+
return Mapping(remainder, layer);
}
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index 80c282c..9a57187 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -1864,8 +1864,7 @@
m.getScaleX(), m.getSkewY(), m.getPerspX(),
m.getSkewX(), m.getScaleY(), m.getPerspY());
- SkScalar denom = 1.f / xyw.fZ; // 1/w
+ double denom = 1.0 / xyw.fZ; // 1/w
denom = denom * denom * denom; // 1/w^3
-
- return SkScalarAbs(SkDoubleToScalar(sk_determinant(jacobian.fMat, true)) * denom);
+ return SkScalarAbs(SkDoubleToScalar(sk_determinant(jacobian.fMat, true) * denom));
}