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>
This commit is contained in:
Michael Ludwig 2021-08-12 10:41:53 -04:00 committed by SkCQ
parent 06273bcb8a
commit c7829eb316
3 changed files with 19 additions and 14 deletions

View File

@ -657,10 +657,10 @@ static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
// 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 @@ static bool compute_decomposition_center(const SkMatrix& dstToLocal,
dstToLocal.mapPoints(&center, 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 @@ static std::pair<skif::Mapping, skif::LayerSpace<SkIRect>> get_layer_mapping_and
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, &center)) {
!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 @@ static std::pair<skif::Mapping, skif::LayerSpace<SkIRect>> get_layer_mapping_and
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;

View File

@ -50,12 +50,13 @@ Mapping Mapping::DecomposeCTM(const SkMatrix& ctm, const SkImageFilter* filter,
// 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 @@ Mapping Mapping::DecomposeCTM(const SkMatrix& ctm, const SkImageFilter* filter,
remainder.preScale(SkScalarInvert(scale), SkScalarInvert(scale));
layer = SkMatrix::Scale(scale, scale);
}
return Mapping(remainder, layer);
}

View File

@ -1864,8 +1864,7 @@ SkScalar SkMatrixPriv::DifferentialAreaScale(const SkMatrix& m, const SkPoint& p
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));
}