aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2017-05-04 09:51:29 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-05-04 14:21:08 +0000
commit65f33fcbbadde807667a0c7ce451ad95c31c52ea (patch)
tree1e93bd95f21f1086379fdf04d46ac8313b8f0bac
parent40c0f249e60dbca7686952de5a459a8dd415a3be (diff)
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>
-rw-r--r--src/effects/shadows/SkAmbientShadowMaskFilter.cpp11
-rw-r--r--src/effects/shadows/SkSpotShadowMaskFilter.cpp50
2 files changed, 38 insertions, 23 deletions
diff --git a/src/effects/shadows/SkAmbientShadowMaskFilter.cpp b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp
index 4d5bc7cbd0..584dc747ae 100644
--- a/src/effects/shadows/SkAmbientShadowMaskFilter.cpp
+++ b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp
@@ -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);
diff --git a/src/effects/shadows/SkSpotShadowMaskFilter.cpp b/src/effects/shadows/SkSpotShadowMaskFilter.cpp
index 847150865f..fc73afc9c1 100644
--- a/src/effects/shadows/SkSpotShadowMaskFilter.cpp
+++ b/src/effects/shadows/SkSpotShadowMaskFilter.cpp
@@ -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;
-
- // Compute area
+ // 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.
+
+ // 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));
}