diff options
author | 2017-04-20 15:48:37 -0400 | |
---|---|---|
committer | 2017-04-21 15:23:53 +0000 | |
commit | 8f7dc9f6caabe798723d9f17aff371121369b846 (patch) | |
tree | 5062e5b6d635476d519ff6e4dd3dfef39de0ae79 /src/effects | |
parent | 5e958e9291f53b81045f776a2af3a871381dd5fb (diff) |
Circular shadow fixes for Flutter.
* Fix spot shadow placement for SkSpotShadowMaskFilter.
* Make sure we don't try to render an oval as a plain RRect
due to floating point error.
* Use fast path for uncached circles.
* Make sure ShadowMaskFilters can handle near-circles.
Change-Id: Ia9967a00a6e1c980a1c0a7ba8248f09fde61a3b7
Reviewed-on: https://skia-review.googlesource.com/13969
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Diffstat (limited to 'src/effects')
-rw-r--r-- | src/effects/shadows/SkAmbientShadowMaskFilter.cpp | 5 | ||||
-rw-r--r-- | src/effects/shadows/SkSpotShadowMaskFilter.cpp | 42 |
2 files changed, 25 insertions, 22 deletions
diff --git a/src/effects/shadows/SkAmbientShadowMaskFilter.cpp b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp index e6a8de4141..84f9836b52 100644 --- a/src/effects/shadows/SkAmbientShadowMaskFilter.cpp +++ b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp @@ -163,9 +163,8 @@ bool SkAmbientShadowMaskFilterImpl::directFilterMaskGPU(GrContext* context, } // if circle - // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we - // have our own GeometryProc. - if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) { + if (path.isOval(nullptr) && SkScalarNearlyEqual(path.getBounds().width(), + path.getBounds().height())) { SkRRect rrect = SkRRect::MakeOval(path.getBounds()); return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip, SkMatrix::I(), strokeRec, rrect, rrect); diff --git a/src/effects/shadows/SkSpotShadowMaskFilter.cpp b/src/effects/shadows/SkSpotShadowMaskFilter.cpp index ee82342ecc..93c7e9c0fa 100644 --- a/src/effects/shadows/SkSpotShadowMaskFilter.cpp +++ b/src/effects/shadows/SkSpotShadowMaskFilter.cpp @@ -180,9 +180,8 @@ bool SkSpotShadowMaskFilterImpl::directFilterMaskGPU(GrContext* context, } // if circle - // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we - // have our own GeometryProc. - if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) { + if (path.isOval(nullptr) && SkScalarNearlyEqual(path.getBounds().width(), + path.getBounds().height())) { SkRRect rrect = SkRRect::MakeOval(path.getBounds()); return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip, SkMatrix::I(), strokeRec, rrect, rrect); @@ -211,7 +210,7 @@ bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*, if (SkStrokeRec::kFill_Style != strokeRec.getStyle()) { return false; } - // Fast path only supports simple rrects with circular corners. + // Fast path only supports simple rrects with near-circular corners. SkASSERT(devRRect.allCornersCircular()); if (!rrect.isRect() && !rrect.isOval() && !rrect.isSimple()) { return false; @@ -236,7 +235,9 @@ bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*, if (fSpotAlpha > 0.0f) { float zRatio = SkTPin(fOccluderHeight / (fLightPos.fZ - fOccluderHeight), 0.0f, 0.95f); - SkScalar srcSpaceSpotRadius = 2.0f * fLightRadius * zRatio; + SkScalar devSpaceSpotRadius = 2.0f * fLightRadius * zRatio; + // handle scale of radius and pad due to CTM + const SkScalar srcSpaceSpotRadius = devSpaceSpotRadius / scaleFactor; SkRRect spotRRect; if (isRect) { @@ -250,18 +251,18 @@ bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*, const SkScalar scale = fLightPos.fZ / (fLightPos.fZ - fOccluderHeight); spotRRect.transform(SkMatrix::MakeScale(scale, scale), &spotShadowRRect); - SkPoint center = SkPoint::Make(spotShadowRRect.rect().centerX(), - spotShadowRRect.rect().centerY()); + SkPoint spotOffset = SkPoint::Make(zRatio*(-fLightPos.fX), zRatio*(-fLightPos.fY)); + // Adjust for the effect of the scale. + spotOffset.fX += scale*viewMatrix[SkMatrix::kMTransX]; + spotOffset.fY += scale*viewMatrix[SkMatrix::kMTransY]; + // This offset is in dev space, need to transform it into source space. SkMatrix ctmInverse; if (!viewMatrix.invert(&ctmInverse)) { SkDebugf("Matrix is degenerate. Will not render spot shadow!\n"); //**** TODO: this is not good return true; } - SkPoint lightPos2D = SkPoint::Make(fLightPos.fX, fLightPos.fY); - ctmInverse.mapPoints(&lightPos2D, 1); - const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX), - zRatio*(center.fY - lightPos2D.fY)); + ctmInverse.mapPoints(&spotOffset, 1); // 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 @@ -292,17 +293,20 @@ bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*, } else { // Since we can't have unequal strokes, inset the shadow rect so the inner // and outer edges of the stroke will land where we want. - SkRect insetRect = spotShadowRRect.rect().makeInset(insetAmount / 2.0f, - insetAmount / 2.0f); - SkScalar insetRad = SkTMax(spotShadowRRect.getSimpleRadii().fX - insetAmount / 2.0f, - minRadius); - spotShadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad); + insetAmount *= 0.5f; + SkRect insetRect = spotShadowRRect.rect().makeInset(insetAmount, insetAmount); + // If the shadowRRect was an oval then its inset will also be one. + // We set it explicitly to avoid errors. + if (spotShadowRRect.isOval()) { + spotShadowRRect = SkRRect::MakeOval(insetRect); + } else { + SkScalar insetRad = SkTMax(spotShadowRRect.getSimpleRadii().fX - insetAmount, + minRadius); + spotShadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad); + } spotStrokeRec.setStrokeStyle(strokeWidth, false); } - // handle scale of radius and pad due to CTM - const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor; - spotShadowRRect.offset(spotOffset.fX, spotOffset.fY); rtContext->drawShadowRRect(clip, std::move(paint), viewMatrix, spotShadowRRect, |