Fix spot shadow inset.

This handles negative values in the spot translation, and produces
a tight fit for rrects and circles.

Change-Id: Id2536347dca98f06f57b31518390037b86fd8a9e
Reviewed-on: https://skia-review.googlesource.com/15248
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Jim Van Verth 2017-05-04 09:51:29 -04:00 committed by Skia Commit-Bot
parent 40c0f249e6
commit 65f33fcbba
2 changed files with 37 additions and 22 deletions

View File

@ -219,11 +219,14 @@ bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
SkScalar ambientPathOutset = 0.5f*srcSpaceStrokeWidth;
SkRRect ambientRRect;
if (rrect.isRect()) {
const SkRect temp = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
ambientRRect = SkRRect::MakeRectXY(temp, ambientPathOutset, ambientPathOutset);
SkRect insetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
// If the rrect was an oval then its outset will also be one.
// We set it explicitly to avoid errors.
if (rrect.isOval()) {
ambientRRect = SkRRect::MakeOval(insetRect);
} else {
rrect.outset(ambientPathOutset, ambientPathOutset, &ambientRRect);
SkScalar insetRad = rrect.getSimpleRadii().fX + ambientPathOutset;
ambientRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
}
GrPaint newPaint(paint);

View File

@ -251,29 +251,38 @@ bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
// We want to extend the stroked area in so that it meets up with the caster
// geometry. The stroked geometry will, by definition already be inset half the
// stroke width but we also have to account for the scaling.
SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(rrect.rect().fLeft),
SkTAbs(rrect.rect().fRight)),
SkTMax(SkTAbs(rrect.rect().fTop),
SkTAbs(rrect.rect().fBottom)));
SkScalar insetAmount = spotOffset.length() - (0.5f * srcSpaceSpotRadius) + scaleOffset;
// stroke width but we also have to account for the scaling and translation when
// computing a new stroke shape.
//
// We begin by transforming the min and max corners -- inset by the radius -- by the scale
// and translation. The distance from that to the original inset point plus the difference
// between the scaled radius and the original radius gives the distance from the
// transformed shadow shape to the original shape. If the max of the two distances is
// greater than the strokeWidth then we need to inset and increase the strokeWidth to cover
// the hole. If less, then we can outset and decrease the strokeWidth to reduce our
// coverage.
// Compute area
// This factor handles both the transform scale and subtracting the original value.
SkScalar comboScale = scale - 1;
SkScalar r = rrect.getSimpleRadii().fX;
SkPoint upperLeftOffset = SkPoint::Make(comboScale*(rrect.rect().fLeft + r),
comboScale*(rrect.rect().fTop + r));
upperLeftOffset += spotOffset;
SkPoint lowerRightOffset = SkPoint::Make(comboScale*(rrect.rect().fRight - r),
comboScale*(rrect.rect().fBottom - r));
lowerRightOffset += spotOffset;
SkScalar maxOffset = SkTMax(upperLeftOffset.length(), lowerRightOffset.length());
maxOffset += comboScale*r;
SkScalar insetAmount = maxOffset - (0.5f * srcSpaceSpotRadius);
SkScalar strokeWidth = srcSpaceSpotRadius + insetAmount;
SkScalar strokedArea = 2.0f*strokeWidth *
(spotShadowRRect.width() + spotShadowRRect.height());
SkScalar filledArea = (spotShadowRRect.height() + srcSpaceSpotRadius) *
(spotShadowRRect.width() + srcSpaceSpotRadius);
GrColor4f color = paint.getColor4f();
color.fRGBA[3] *= fSpotAlpha;
paint.setColor4f(color);
SkScalar strokedDiff = SkTMin(spotShadowRRect.width(), spotShadowRRect.height())
- (insetAmount + strokeWidth);
SkStrokeRec spotStrokeRec(SkStrokeRec::kFill_InitStyle);
// If the area of the stroked geometry is larger than the fill geometry,
// or if the caster is transparent, just fill it.
if (strokedArea > filledArea ||
fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag) {
// If the caster has too large a stroke or is transparent, just fill it.
if (strokedDiff < 0 || fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag) {
spotStrokeRec.setStrokeStyle(srcSpaceSpotRadius, true);
} else {
// Since we can't have unequal strokes, inset the shadow rect so the inner
@ -293,6 +302,9 @@ bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
spotShadowRRect.offset(spotOffset.fX, spotOffset.fY);
GrColor4f color = paint.getColor4f();
color.fRGBA[3] *= fSpotAlpha;
paint.setColor4f(color);
rtContext->drawShadowRRect(clip, std::move(paint), viewMatrix, spotShadowRRect,
devSpaceSpotRadius, GrStyle(spotStrokeRec, nullptr));
}