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:
parent
40c0f249e6
commit
65f33fcbba
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user