diff options
-rw-r--r-- | include/core/SkRRect.h | 2 | ||||
-rw-r--r-- | samplecode/SampleAndroidShadows.cpp | 3 | ||||
-rw-r--r-- | src/core/SkRRect.cpp | 10 | ||||
-rw-r--r-- | src/effects/shadows/SkAmbientShadowMaskFilter.cpp | 5 | ||||
-rw-r--r-- | src/effects/shadows/SkSpotShadowMaskFilter.cpp | 42 | ||||
-rw-r--r-- | src/utils/SkShadowUtils.cpp | 24 |
6 files changed, 55 insertions, 31 deletions
diff --git a/include/core/SkRRect.h b/include/core/SkRRect.h index 3b691aab1b..4b7a33e43f 100644 --- a/include/core/SkRRect.h +++ b/include/core/SkRRect.h @@ -110,7 +110,7 @@ public: inline bool isNinePatch() const { return kNinePatch_Type == this->getType(); } inline bool isComplex() const { return kComplex_Type == this->getType(); } - bool allCornersCircular() const; + bool allCornersCircular(SkScalar tolerance = SK_ScalarNearlyZero) const; SkScalar width() const { return fRect.width(); } SkScalar height() const { return fRect.height(); } diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp index 0c0baaba10..55acd57f09 100644 --- a/samplecode/SampleAndroidShadows.cpp +++ b/samplecode/SampleAndroidShadows.cpp @@ -473,6 +473,7 @@ protected: paint.setAntiAlias(true); SkPoint3 lightPos = fLightPos; + lightPos.fX = canvas->getBaseLayerSize().fWidth * 0.5f; paint.setColor(SK_ColorWHITE); canvas->translate(200, 90); @@ -496,7 +497,7 @@ protected: canvas->translate(-250, 110); lightPos.fX -= 250; lightPos.fY += 110; - zValue = SkTMax(1.0f, 8 + fZDelta); + zValue = SkTMax(1.0f, 12 + fZDelta); zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; this->drawShadowedPath(canvas, fCirclePath, zFunc, paint, kAmbientAlpha, lightPos, kLightWidth, 0.5f); diff --git a/src/core/SkRRect.cpp b/src/core/SkRRect.cpp index 824ee62e60..8d69f4afc6 100644 --- a/src/core/SkRRect.cpp +++ b/src/core/SkRRect.cpp @@ -251,11 +251,11 @@ bool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const { return dist <= SkScalarSquare(fRadii[index].fX * fRadii[index].fY); } -bool SkRRect::allCornersCircular() const { - return fRadii[0].fX == fRadii[0].fY && - fRadii[1].fX == fRadii[1].fY && - fRadii[2].fX == fRadii[2].fY && - fRadii[3].fX == fRadii[3].fY; +bool SkRRect::allCornersCircular(SkScalar tolerance) const { + return SkScalarNearlyEqual(fRadii[0].fX, fRadii[0].fY, tolerance) && + SkScalarNearlyEqual(fRadii[1].fX, fRadii[1].fY, tolerance) && + SkScalarNearlyEqual(fRadii[2].fX, fRadii[2].fY, tolerance) && + SkScalarNearlyEqual(fRadii[3].fX, fRadii[3].fY, tolerance); } bool SkRRect::contains(const SkRect& rect) const { 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, diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp index 2e560b454e..8206bd3f54 100644 --- a/src/utils/SkShadowUtils.cpp +++ b/src/utils/SkShadowUtils.cpp @@ -471,12 +471,12 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc if (ambientAlpha > 0) { newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderHeight, ambientAlpha, flags)); - canvas->drawPath(path, newPaint); + canvas->drawOval(rect, newPaint); } if (spotAlpha > 0) { newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderHeight, devLightPos, lightRadius, spotAlpha, flags)); - canvas->drawPath(path, newPaint); + canvas->drawOval(rect, newPaint); } return; } @@ -565,6 +565,26 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path, uint32_t flags) { SkAutoCanvasRestore acr(canvas, true); SkMatrix viewMatrix = canvas->getTotalMatrix(); + + // try circular fast path + SkRect rect; + if (viewMatrix.isSimilarity() && + path.isOval(&rect) && rect.width() == rect.height()) { + SkPaint newPaint; + newPaint.setColor(color); + if (ambientAlpha > 0) { + newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(heightFunc(0,0), ambientAlpha, + flags)); + canvas->drawOval(rect, newPaint); + } + if (spotAlpha > 0) { + newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(heightFunc(0,0), lightPos, + lightRadius, spotAlpha, flags)); + canvas->drawOval(rect, newPaint); + } + return; + } + canvas->resetMatrix(); bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag); |