Loading libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp +8 −516 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <SkGaussianEdgeShader.h> #include <SkPathOps.h> #include <SkRRectsGaussianEdgeMaskFilter.h> #include <SkShadowUtils.h> namespace android { namespace uirenderer { Loading Loading @@ -115,498 +116,6 @@ void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) { } } /** * @param canvas the destination for the shadow draws * @param shape the shape casting the shadow * @param casterZValue the Z value of the caster RRect * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow * @param draw the function used to draw 'shape' */ template <typename Shape, typename F> static void DrawAmbientShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue, float ambientAlpha, F&& draw) { if (ambientAlpha <= 0) { return; } const float kHeightFactor = 1.f/128.f; const float kGeomFactor = 64; float umbraAlpha = 1 / (1 + SkMaxScalar(casterZValue*kHeightFactor, 0)); float radius = casterZValue*kHeightFactor*kGeomFactor; sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, SkBlurMask::ConvertRadiusToSigma(radius), SkBlurMaskFilter::kNone_BlurFlag); SkPaint paint; paint.setAntiAlias(true); paint.setMaskFilter(std::move(mf)); paint.setARGB(ambientAlpha*umbraAlpha, 0, 0, 0); draw(shape, paint); } /** * @param canvas the destination for the shadow draws * @param shape the shape casting the shadow * @param casterZValue the Z value of the caster RRect * @param lightPos the position of the light casting the shadow * @param lightWidth * @param spotAlpha the maximum alpha value to use when drawing the spot shadow * @param draw the function used to draw 'shape' */ template <typename Shape, typename F> static void DrawSpotShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue, float spotAlpha, F&& draw) { if (spotAlpha <= 0) { return; } const Vector3 lightPos = SkiaPipeline::getLightCenter(); float zRatio = casterZValue / (lightPos.z - casterZValue); // clamp if (zRatio < 0.0f) { zRatio = 0.0f; } else if (zRatio > 0.95f) { zRatio = 0.95f; } float blurRadius = SkiaPipeline::getLightRadius()*zRatio; SkAutoCanvasRestore acr(canvas, true); sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, SkBlurMask::ConvertRadiusToSigma(blurRadius), SkBlurMaskFilter::kNone_BlurFlag); SkPaint paint; paint.setAntiAlias(true); paint.setMaskFilter(std::move(mf)); paint.setARGB(spotAlpha, 0, 0, 0); // approximate projection by translating and scaling projected offset of bounds center // TODO: compute the actual 2D projection SkScalar scale = lightPos.z / (lightPos.z - casterZValue); canvas->scale(scale, scale); SkPoint center = SkPoint::Make(shape.getBounds().centerX(), shape.getBounds().centerY()); SkMatrix ctmInverse; if (!canvas->getTotalMatrix().invert(&ctmInverse)) { ALOGW("Matrix is degenerate. Will not render shadow!"); return; } SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y); ctmInverse.mapPoints(&lightPos2D, 1); canvas->translate(zRatio*(center.fX - lightPos2D.fX), zRatio*(center.fY - lightPos2D.fY)); draw(shape, paint); } #define MAX_BLUR_RADIUS 16383.75f #define MAX_PAD 64 /** * @param casterRect the rectangle bounds of the RRect casting the shadow * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow * @param spotAlpha the maximum alpha value to use when drawing the spot shadow * @param casterAlpha the alpha value of the RRect casting the shadow (0.0-1.0 range) * @param casterZValue the Z value of the caster RRect * @param scaleFactor the scale needed to map from src-space to device-space * @param canvas the destination for the shadow draws */ static void DrawRRectShadows(const SkRect& casterRect, SkScalar casterCornerRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue, SkScalar scaleFactor, SkCanvas* canvas) { SkASSERT(casterCornerRadius >= 0.0f); // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space const SkScalar minRadius = 0.5f / scaleFactor; const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()), SkScalarHalf(casterRect.height())); const bool isRect = casterCornerRadius <= minRadius; sk_sp<SkShader> edgeShader(SkGaussianEdgeShader::Make()); if (ambientAlpha > 0.0f) { static const float kHeightFactor = 1.0f / 128.0f; static const float kGeomFactor = 64.0f; SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor; // the device-space radius sent to the blur shader must fit in 14.2 fixed point if (srcSpaceAmbientRadius*scaleFactor > MAX_BLUR_RADIUS) { srcSpaceAmbientRadius = MAX_BLUR_RADIUS/scaleFactor; } const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f)); const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha; // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius // to get our stroke shape. SkScalar ambientPathOutset = std::max(ambientOffset - srcSpaceAmbientRadius * 0.5f, minRadius); SkRRect ambientRRect; const SkRect temp = casterRect.makeOutset(ambientPathOutset, ambientPathOutset); if (isOval) { ambientRRect = SkRRect::MakeOval(temp); } else if (isRect) { ambientRRect = SkRRect::MakeRectXY(temp, ambientPathOutset, ambientPathOutset); } else { ambientRRect = SkRRect::MakeRectXY(temp, casterCornerRadius + ambientPathOutset, casterCornerRadius + ambientPathOutset); } SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); // we outset the stroke a little to cover up AA on the interior edge float pad = 0.5f; paint.setStrokeWidth(srcSpaceAmbientRadius + 2.0f * pad); // handle scale of radius and pad due to CTM pad *= scaleFactor; const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor; SkASSERT(devSpaceAmbientRadius <= MAX_BLUR_RADIUS); SkASSERT(pad < MAX_PAD); // convert devSpaceAmbientRadius to 14.2 fixed point and place in the R & G components // convert pad to 6.2 fixed point and place in the B component uint16_t iDevSpaceAmbientRadius = (uint16_t)(4.0f * devSpaceAmbientRadius); paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, iDevSpaceAmbientRadius >> 8, iDevSpaceAmbientRadius & 0xff, (unsigned char)(4.0f * pad))); paint.setShader(edgeShader); canvas->drawRRect(ambientRRect, paint); } if (spotAlpha > 0.0f) { const Vector3 lightPos = SkiaPipeline::getLightCenter(); float zRatio = casterZValue / (lightPos.z - casterZValue); // clamp if (zRatio < 0.0f) { zRatio = 0.0f; } else if (zRatio > 0.95f) { zRatio = 0.95f; } const SkScalar lightWidth = SkiaPipeline::getLightRadius(); SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio; // the device-space radius sent to the blur shader must fit in 14.2 fixed point if (srcSpaceSpotRadius*scaleFactor > MAX_BLUR_RADIUS) { srcSpaceSpotRadius = MAX_BLUR_RADIUS/scaleFactor; } SkRRect spotRRect; if (isOval) { spotRRect = SkRRect::MakeOval(casterRect); } else if (isRect) { spotRRect = SkRRect::MakeRectXY(casterRect, minRadius, minRadius); } else { spotRRect = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius); } SkRRect spotShadowRRect; // Compute the scale and translation for the spot shadow. const SkScalar scale = lightPos.z / (lightPos.z - casterZValue); spotRRect.transform(SkMatrix::MakeScale(scale, scale), &spotShadowRRect); SkPoint center = SkPoint::Make(spotShadowRRect.rect().centerX(), spotShadowRRect.rect().centerY()); SkMatrix ctmInverse; if (!canvas->getTotalMatrix().invert(&ctmInverse)) { ALOGW("Matrix is degenerate. Will not render spot shadow!"); return; } SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y); ctmInverse.mapPoints(&lightPos2D, 1); const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX), zRatio*(center.fY - lightPos2D.fY)); SkAutoCanvasRestore acr(canvas, true); // 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. // We also add 1/2 to cover up AA on the interior edge. SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(casterRect.fLeft), SkTAbs(casterRect.fRight)), SkTMax(SkTAbs(casterRect.fTop), SkTAbs(casterRect.fBottom))); SkScalar insetAmount = spotOffset.length() - (0.5f * srcSpaceSpotRadius) + scaleOffset + 0.5f; // Compute area SkScalar strokeWidth = srcSpaceSpotRadius + insetAmount; SkScalar strokedArea = 2.0f*strokeWidth * (spotShadowRRect.width() + spotShadowRRect.height()); SkScalar filledArea = (spotShadowRRect.height() + srcSpaceSpotRadius) * (spotShadowRRect.width() + srcSpaceSpotRadius); SkPaint paint; paint.setAntiAlias(true); // If the area of the stroked geometry is larger than the fill geometry, just fill it. if (strokedArea > filledArea || casterAlpha < 1.0f || insetAmount < 0.0f) { paint.setStyle(SkPaint::kStrokeAndFill_Style); paint.setStrokeWidth(srcSpaceSpotRadius); } 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); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(strokeWidth); } // handle scale of radius and pad due to CTM const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor; SkASSERT(devSpaceSpotRadius <= MAX_BLUR_RADIUS); const SkScalar devSpaceSpotPad = 0; SkASSERT(devSpaceSpotPad < MAX_PAD); // convert devSpaceSpotRadius to 14.2 fixed point and place in the R & G // components convert devSpaceSpotPad to 6.2 fixed point and place in the B component uint16_t iDevSpaceSpotRadius = (uint16_t)(4.0f * devSpaceSpotRadius); paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, iDevSpaceSpotRadius >> 8, iDevSpaceSpotRadius & 0xff, (unsigned char)(4.0f * devSpaceSpotPad))); paint.setShader(edgeShader); canvas->translate(spotOffset.fX, spotOffset.fY); canvas->drawRRect(spotShadowRRect, paint); } } /** * @param casterRect the rectangle bounds of the RRect casting the shadow * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow * @param spotAlpha the maximum alpha value to use when drawing the spot shadow * @param casterZValue the Z value of the caster RRect * @param scaleFactor the scale needed to map from src-space to device-space * @param clipRR the oval or rect with which the drawn roundrect must be intersected * @param canvas the destination for the shadow draws */ static void DrawRRectShadowsWithClip(const SkRect& casterRect, SkScalar casterCornerRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterZValue, SkScalar scaleFactor, const SkRRect& clipRR, SkCanvas* canvas) { SkASSERT(casterCornerRadius >= 0.0f); const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()), SkScalarHalf(casterRect.height())); if (ambientAlpha > 0.0f) { static const float kHeightFactor = 1.0f / 128.0f; static const float kGeomFactor = 64.0f; const SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor; const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor; const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f)); const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha; const SkRect srcSpaceAmbientRect = casterRect.makeOutset(ambientOffset, ambientOffset); SkRect devSpaceAmbientRect; canvas->getTotalMatrix().mapRect(&devSpaceAmbientRect, srcSpaceAmbientRect); SkRRect devSpaceAmbientRRect; if (isOval) { devSpaceAmbientRRect = SkRRect::MakeOval(devSpaceAmbientRect); } else { const SkScalar devSpaceCornerRadius = scaleFactor * (casterCornerRadius + ambientOffset); devSpaceAmbientRRect = SkRRect::MakeRectXY(devSpaceAmbientRect, devSpaceCornerRadius, devSpaceCornerRadius); } const SkRect srcSpaceAmbClipRect = clipRR.rect().makeOutset(ambientOffset, ambientOffset); SkRect devSpaceAmbClipRect; canvas->getTotalMatrix().mapRect(&devSpaceAmbClipRect, srcSpaceAmbClipRect); SkRRect devSpaceAmbientClipRR; if (clipRR.isOval()) { devSpaceAmbientClipRR = SkRRect::MakeOval(devSpaceAmbClipRect); } else { SkASSERT(clipRR.isRect()); devSpaceAmbientClipRR = SkRRect::MakeRect(devSpaceAmbClipRect); } SkRect cover = srcSpaceAmbClipRect; if (!cover.intersect(srcSpaceAmbientRect)) { return; } SkPaint paint; paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, 0, 0, 0)); paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceAmbientRRect, devSpaceAmbientClipRR, devSpaceAmbientRadius)); canvas->drawRect(cover, paint); } if (spotAlpha > 0.0f) { const Vector3 lightPos = SkiaPipeline::getLightCenter(); float zRatio = casterZValue / (lightPos.z - casterZValue); // clamp if (zRatio < 0.0f) { zRatio = 0.0f; } else if (zRatio > 0.95f) { zRatio = 0.95f; } const SkScalar lightWidth = SkiaPipeline::getLightRadius(); const SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio; const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor; // Compute the scale and translation for the spot shadow. const SkScalar scale = lightPos.z / (lightPos.z - casterZValue); const SkMatrix spotMatrix = SkMatrix::MakeScale(scale, scale); SkRect srcSpaceScaledRect = casterRect; spotMatrix.mapRect(&srcSpaceScaledRect); srcSpaceScaledRect.outset(SkScalarHalf(srcSpaceSpotRadius), SkScalarHalf(srcSpaceSpotRadius)); SkRRect srcSpaceSpotRRect; if (isOval) { srcSpaceSpotRRect = SkRRect::MakeOval(srcSpaceScaledRect); } else { srcSpaceSpotRRect = SkRRect::MakeRectXY(srcSpaceScaledRect, casterCornerRadius * scale, casterCornerRadius * scale); } SkPoint center = SkPoint::Make(srcSpaceSpotRRect.rect().centerX(), srcSpaceSpotRRect.rect().centerY()); SkMatrix ctmInverse; if (!canvas->getTotalMatrix().invert(&ctmInverse)) { ALOGW("Matrix is degenerate. Will not render spot shadow!"); return; } SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y); ctmInverse.mapPoints(&lightPos2D, 1); const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX), zRatio*(center.fY - lightPos2D.fY)); SkAutoCanvasRestore acr(canvas, true); canvas->translate(spotOffset.fX, spotOffset.fY); SkRect devSpaceScaledRect; canvas->getTotalMatrix().mapRect(&devSpaceScaledRect, srcSpaceScaledRect); SkRRect devSpaceSpotRRect; if (isOval) { devSpaceSpotRRect = SkRRect::MakeOval(devSpaceScaledRect); } else { const SkScalar devSpaceScaledCornerRadius = casterCornerRadius * scale * scaleFactor; devSpaceSpotRRect = SkRRect::MakeRectXY(devSpaceScaledRect, devSpaceScaledCornerRadius, devSpaceScaledCornerRadius); } SkPaint paint; paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, 0, 0, 0)); SkRect srcSpaceScaledClipRect = clipRR.rect(); spotMatrix.mapRect(&srcSpaceScaledClipRect); srcSpaceScaledClipRect.outset(SkScalarHalf(srcSpaceSpotRadius), SkScalarHalf(srcSpaceSpotRadius)); SkRect devSpaceScaledClipRect; canvas->getTotalMatrix().mapRect(&devSpaceScaledClipRect, srcSpaceScaledClipRect); SkRRect devSpaceSpotClipRR; if (clipRR.isOval()) { devSpaceSpotClipRR = SkRRect::MakeOval(devSpaceScaledClipRect); } else { SkASSERT(clipRR.isRect()); devSpaceSpotClipRR = SkRRect::MakeRect(devSpaceScaledClipRect); } paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceSpotRRect, devSpaceSpotClipRR, devSpaceSpotRadius)); SkRect cover = srcSpaceScaledClipRect; if (!cover.intersect(srcSpaceSpotRRect.rect())) { return; } canvas->drawRect(cover, paint); } } /** * @param casterRect the rectangle bounds of the RRect casting the shadow * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow * @param casterClipRect a rectangular clip that must be intersected with the * shadow-casting RRect prior to casting the shadow * @param revealClip a circular clip that must be interested with the castClipRect * and the shadow-casting rect prior to casting the shadow * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow * @param spotAlpha the maximum alpha value to use when drawing the spot shadow * @param casterAlpha the alpha value of the RRect casting the shadow (0.0-1.0 range) * @param casterZValue the Z value of the caster RRect * @param canvas the destination for the shadow draws * * We have special cases for 4 round rect shadow draws: * 1) a RRect clipped by a reveal animation * 2) a RRect clipped by a rectangle * 3) an unclipped RRect with non-uniform scale * 4) an unclipped RRect with uniform scale * 1,2 and 4 require that the scale is uniform. * 1 and 2 require that rects stay rects. */ static bool DrawShadowsAsRRects(const SkRect& casterRect, SkScalar casterCornerRadius, const SkRect& casterClipRect, const RevealClip& revealClip, SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue, SkCanvas* canvas) { SkScalar scaleFactors[2]; if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) { ALOGW("Matrix is degenerate. Will not render shadow!"); return false; } // The casterClipRect will be empty when bounds clipping is disabled bool casterIsClippedByRect = !casterClipRect.isEmpty(); bool uniformScale = scaleFactors[0] == scaleFactors[1]; if (revealClip.willClip()) { if (casterIsClippedByRect || !uniformScale || !canvas->getTotalMatrix().rectStaysRect()) { return false; // Fall back to the slow path since PathOps are required } const float revealRadius = revealClip.getRadius(); SkRect revealClipRect = SkRect::MakeLTRB(revealClip.getX()-revealRadius, revealClip.getY()-revealRadius, revealClip.getX()+revealRadius, revealClip.getY()+revealRadius); SkRRect revealClipRR = SkRRect::MakeOval(revealClipRect); DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, casterZValue, scaleFactors[0], revealClipRR, canvas); return true; } if (casterIsClippedByRect) { if (!uniformScale || !canvas->getTotalMatrix().rectStaysRect()) { return false; // Fall back to the slow path since PathOps are required } SkRRect casterClipRR = SkRRect::MakeRect(casterClipRect); DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, casterZValue, scaleFactors[0], casterClipRR, canvas); return true; } // The fast path needs uniform scale if (!uniformScale) { SkRRect casterRR = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius); DrawAmbientShadowGeneral(canvas, casterRR, casterZValue, ambientAlpha, [&](const SkRRect& rrect, const SkPaint& paint) { canvas->drawRRect(rrect, paint); }); DrawSpotShadowGeneral(canvas, casterRR, casterZValue, spotAlpha, [&](const SkRRect& rrect, const SkPaint& paint) { canvas->drawRRect(rrect, paint); }); return true; } DrawRRectShadows(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, casterAlpha, casterZValue, scaleFactors[0], canvas); return true; } // copied from FrameBuilder::deferShadow void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) { const RenderProperties& casterProperties = caster->getNodeProperties(); Loading @@ -626,8 +135,8 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* return; } float ambientAlpha = SkiaPipeline::getAmbientShadowAlpha()*casterAlpha; float spotAlpha = SkiaPipeline::getSpotShadowAlpha()*casterAlpha; float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha; float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha; const float casterZValue = casterProperties.getZ(); const RevealClip& revealClip = casterProperties.getRevealClip(); Loading Loading @@ -659,19 +168,7 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* hwuiMatrix.copyTo(shadowMatrix); canvas->concat(shadowMatrix); const Outline& casterOutline = casterProperties.getOutline(); Rect possibleRect; float radius; if (casterOutline.getAsRoundRect(&possibleRect, &radius)) { if (DrawShadowsAsRRects(possibleRect.toSkRect(), radius, casterClipRect, revealClip, ambientAlpha, spotAlpha, casterAlpha, casterZValue, canvas)) { return; } } // Hard cases and calls to general shadow code const SkPath* casterOutlinePath = casterProperties.getOutline().getPath(); // holds temporary SkPath to store the result of intersections SkPath tmpPath; const SkPath* casterPath = casterOutlinePath; Loading @@ -691,16 +188,11 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath); casterPath = &tmpPath; } DrawAmbientShadowGeneral(canvas, *casterPath, casterZValue, ambientAlpha, [&](const SkPath& path, const SkPaint& paint) { canvas->drawPath(path, paint); }); DrawSpotShadowGeneral(canvas, *casterPath, casterZValue, spotAlpha, [&](const SkPath& path, const SkPaint& paint) { canvas->drawPath(path, paint); }); const Vector3 lightPos = SkiaPipeline::getLightCenter(); SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z); SkShadowUtils::DrawShadow(canvas, *casterPath, casterZValue, skiaLightPos, SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK, casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0); } }; // namespace skiapipeline Loading Loading
libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp +8 −516 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <SkGaussianEdgeShader.h> #include <SkPathOps.h> #include <SkRRectsGaussianEdgeMaskFilter.h> #include <SkShadowUtils.h> namespace android { namespace uirenderer { Loading Loading @@ -115,498 +116,6 @@ void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) { } } /** * @param canvas the destination for the shadow draws * @param shape the shape casting the shadow * @param casterZValue the Z value of the caster RRect * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow * @param draw the function used to draw 'shape' */ template <typename Shape, typename F> static void DrawAmbientShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue, float ambientAlpha, F&& draw) { if (ambientAlpha <= 0) { return; } const float kHeightFactor = 1.f/128.f; const float kGeomFactor = 64; float umbraAlpha = 1 / (1 + SkMaxScalar(casterZValue*kHeightFactor, 0)); float radius = casterZValue*kHeightFactor*kGeomFactor; sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, SkBlurMask::ConvertRadiusToSigma(radius), SkBlurMaskFilter::kNone_BlurFlag); SkPaint paint; paint.setAntiAlias(true); paint.setMaskFilter(std::move(mf)); paint.setARGB(ambientAlpha*umbraAlpha, 0, 0, 0); draw(shape, paint); } /** * @param canvas the destination for the shadow draws * @param shape the shape casting the shadow * @param casterZValue the Z value of the caster RRect * @param lightPos the position of the light casting the shadow * @param lightWidth * @param spotAlpha the maximum alpha value to use when drawing the spot shadow * @param draw the function used to draw 'shape' */ template <typename Shape, typename F> static void DrawSpotShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue, float spotAlpha, F&& draw) { if (spotAlpha <= 0) { return; } const Vector3 lightPos = SkiaPipeline::getLightCenter(); float zRatio = casterZValue / (lightPos.z - casterZValue); // clamp if (zRatio < 0.0f) { zRatio = 0.0f; } else if (zRatio > 0.95f) { zRatio = 0.95f; } float blurRadius = SkiaPipeline::getLightRadius()*zRatio; SkAutoCanvasRestore acr(canvas, true); sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, SkBlurMask::ConvertRadiusToSigma(blurRadius), SkBlurMaskFilter::kNone_BlurFlag); SkPaint paint; paint.setAntiAlias(true); paint.setMaskFilter(std::move(mf)); paint.setARGB(spotAlpha, 0, 0, 0); // approximate projection by translating and scaling projected offset of bounds center // TODO: compute the actual 2D projection SkScalar scale = lightPos.z / (lightPos.z - casterZValue); canvas->scale(scale, scale); SkPoint center = SkPoint::Make(shape.getBounds().centerX(), shape.getBounds().centerY()); SkMatrix ctmInverse; if (!canvas->getTotalMatrix().invert(&ctmInverse)) { ALOGW("Matrix is degenerate. Will not render shadow!"); return; } SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y); ctmInverse.mapPoints(&lightPos2D, 1); canvas->translate(zRatio*(center.fX - lightPos2D.fX), zRatio*(center.fY - lightPos2D.fY)); draw(shape, paint); } #define MAX_BLUR_RADIUS 16383.75f #define MAX_PAD 64 /** * @param casterRect the rectangle bounds of the RRect casting the shadow * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow * @param spotAlpha the maximum alpha value to use when drawing the spot shadow * @param casterAlpha the alpha value of the RRect casting the shadow (0.0-1.0 range) * @param casterZValue the Z value of the caster RRect * @param scaleFactor the scale needed to map from src-space to device-space * @param canvas the destination for the shadow draws */ static void DrawRRectShadows(const SkRect& casterRect, SkScalar casterCornerRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue, SkScalar scaleFactor, SkCanvas* canvas) { SkASSERT(casterCornerRadius >= 0.0f); // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space const SkScalar minRadius = 0.5f / scaleFactor; const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()), SkScalarHalf(casterRect.height())); const bool isRect = casterCornerRadius <= minRadius; sk_sp<SkShader> edgeShader(SkGaussianEdgeShader::Make()); if (ambientAlpha > 0.0f) { static const float kHeightFactor = 1.0f / 128.0f; static const float kGeomFactor = 64.0f; SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor; // the device-space radius sent to the blur shader must fit in 14.2 fixed point if (srcSpaceAmbientRadius*scaleFactor > MAX_BLUR_RADIUS) { srcSpaceAmbientRadius = MAX_BLUR_RADIUS/scaleFactor; } const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f)); const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha; // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius // to get our stroke shape. SkScalar ambientPathOutset = std::max(ambientOffset - srcSpaceAmbientRadius * 0.5f, minRadius); SkRRect ambientRRect; const SkRect temp = casterRect.makeOutset(ambientPathOutset, ambientPathOutset); if (isOval) { ambientRRect = SkRRect::MakeOval(temp); } else if (isRect) { ambientRRect = SkRRect::MakeRectXY(temp, ambientPathOutset, ambientPathOutset); } else { ambientRRect = SkRRect::MakeRectXY(temp, casterCornerRadius + ambientPathOutset, casterCornerRadius + ambientPathOutset); } SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); // we outset the stroke a little to cover up AA on the interior edge float pad = 0.5f; paint.setStrokeWidth(srcSpaceAmbientRadius + 2.0f * pad); // handle scale of radius and pad due to CTM pad *= scaleFactor; const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor; SkASSERT(devSpaceAmbientRadius <= MAX_BLUR_RADIUS); SkASSERT(pad < MAX_PAD); // convert devSpaceAmbientRadius to 14.2 fixed point and place in the R & G components // convert pad to 6.2 fixed point and place in the B component uint16_t iDevSpaceAmbientRadius = (uint16_t)(4.0f * devSpaceAmbientRadius); paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, iDevSpaceAmbientRadius >> 8, iDevSpaceAmbientRadius & 0xff, (unsigned char)(4.0f * pad))); paint.setShader(edgeShader); canvas->drawRRect(ambientRRect, paint); } if (spotAlpha > 0.0f) { const Vector3 lightPos = SkiaPipeline::getLightCenter(); float zRatio = casterZValue / (lightPos.z - casterZValue); // clamp if (zRatio < 0.0f) { zRatio = 0.0f; } else if (zRatio > 0.95f) { zRatio = 0.95f; } const SkScalar lightWidth = SkiaPipeline::getLightRadius(); SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio; // the device-space radius sent to the blur shader must fit in 14.2 fixed point if (srcSpaceSpotRadius*scaleFactor > MAX_BLUR_RADIUS) { srcSpaceSpotRadius = MAX_BLUR_RADIUS/scaleFactor; } SkRRect spotRRect; if (isOval) { spotRRect = SkRRect::MakeOval(casterRect); } else if (isRect) { spotRRect = SkRRect::MakeRectXY(casterRect, minRadius, minRadius); } else { spotRRect = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius); } SkRRect spotShadowRRect; // Compute the scale and translation for the spot shadow. const SkScalar scale = lightPos.z / (lightPos.z - casterZValue); spotRRect.transform(SkMatrix::MakeScale(scale, scale), &spotShadowRRect); SkPoint center = SkPoint::Make(spotShadowRRect.rect().centerX(), spotShadowRRect.rect().centerY()); SkMatrix ctmInverse; if (!canvas->getTotalMatrix().invert(&ctmInverse)) { ALOGW("Matrix is degenerate. Will not render spot shadow!"); return; } SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y); ctmInverse.mapPoints(&lightPos2D, 1); const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX), zRatio*(center.fY - lightPos2D.fY)); SkAutoCanvasRestore acr(canvas, true); // 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. // We also add 1/2 to cover up AA on the interior edge. SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(casterRect.fLeft), SkTAbs(casterRect.fRight)), SkTMax(SkTAbs(casterRect.fTop), SkTAbs(casterRect.fBottom))); SkScalar insetAmount = spotOffset.length() - (0.5f * srcSpaceSpotRadius) + scaleOffset + 0.5f; // Compute area SkScalar strokeWidth = srcSpaceSpotRadius + insetAmount; SkScalar strokedArea = 2.0f*strokeWidth * (spotShadowRRect.width() + spotShadowRRect.height()); SkScalar filledArea = (spotShadowRRect.height() + srcSpaceSpotRadius) * (spotShadowRRect.width() + srcSpaceSpotRadius); SkPaint paint; paint.setAntiAlias(true); // If the area of the stroked geometry is larger than the fill geometry, just fill it. if (strokedArea > filledArea || casterAlpha < 1.0f || insetAmount < 0.0f) { paint.setStyle(SkPaint::kStrokeAndFill_Style); paint.setStrokeWidth(srcSpaceSpotRadius); } 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); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(strokeWidth); } // handle scale of radius and pad due to CTM const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor; SkASSERT(devSpaceSpotRadius <= MAX_BLUR_RADIUS); const SkScalar devSpaceSpotPad = 0; SkASSERT(devSpaceSpotPad < MAX_PAD); // convert devSpaceSpotRadius to 14.2 fixed point and place in the R & G // components convert devSpaceSpotPad to 6.2 fixed point and place in the B component uint16_t iDevSpaceSpotRadius = (uint16_t)(4.0f * devSpaceSpotRadius); paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, iDevSpaceSpotRadius >> 8, iDevSpaceSpotRadius & 0xff, (unsigned char)(4.0f * devSpaceSpotPad))); paint.setShader(edgeShader); canvas->translate(spotOffset.fX, spotOffset.fY); canvas->drawRRect(spotShadowRRect, paint); } } /** * @param casterRect the rectangle bounds of the RRect casting the shadow * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow * @param spotAlpha the maximum alpha value to use when drawing the spot shadow * @param casterZValue the Z value of the caster RRect * @param scaleFactor the scale needed to map from src-space to device-space * @param clipRR the oval or rect with which the drawn roundrect must be intersected * @param canvas the destination for the shadow draws */ static void DrawRRectShadowsWithClip(const SkRect& casterRect, SkScalar casterCornerRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterZValue, SkScalar scaleFactor, const SkRRect& clipRR, SkCanvas* canvas) { SkASSERT(casterCornerRadius >= 0.0f); const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()), SkScalarHalf(casterRect.height())); if (ambientAlpha > 0.0f) { static const float kHeightFactor = 1.0f / 128.0f; static const float kGeomFactor = 64.0f; const SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor; const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor; const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f)); const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha; const SkRect srcSpaceAmbientRect = casterRect.makeOutset(ambientOffset, ambientOffset); SkRect devSpaceAmbientRect; canvas->getTotalMatrix().mapRect(&devSpaceAmbientRect, srcSpaceAmbientRect); SkRRect devSpaceAmbientRRect; if (isOval) { devSpaceAmbientRRect = SkRRect::MakeOval(devSpaceAmbientRect); } else { const SkScalar devSpaceCornerRadius = scaleFactor * (casterCornerRadius + ambientOffset); devSpaceAmbientRRect = SkRRect::MakeRectXY(devSpaceAmbientRect, devSpaceCornerRadius, devSpaceCornerRadius); } const SkRect srcSpaceAmbClipRect = clipRR.rect().makeOutset(ambientOffset, ambientOffset); SkRect devSpaceAmbClipRect; canvas->getTotalMatrix().mapRect(&devSpaceAmbClipRect, srcSpaceAmbClipRect); SkRRect devSpaceAmbientClipRR; if (clipRR.isOval()) { devSpaceAmbientClipRR = SkRRect::MakeOval(devSpaceAmbClipRect); } else { SkASSERT(clipRR.isRect()); devSpaceAmbientClipRR = SkRRect::MakeRect(devSpaceAmbClipRect); } SkRect cover = srcSpaceAmbClipRect; if (!cover.intersect(srcSpaceAmbientRect)) { return; } SkPaint paint; paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, 0, 0, 0)); paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceAmbientRRect, devSpaceAmbientClipRR, devSpaceAmbientRadius)); canvas->drawRect(cover, paint); } if (spotAlpha > 0.0f) { const Vector3 lightPos = SkiaPipeline::getLightCenter(); float zRatio = casterZValue / (lightPos.z - casterZValue); // clamp if (zRatio < 0.0f) { zRatio = 0.0f; } else if (zRatio > 0.95f) { zRatio = 0.95f; } const SkScalar lightWidth = SkiaPipeline::getLightRadius(); const SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio; const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor; // Compute the scale and translation for the spot shadow. const SkScalar scale = lightPos.z / (lightPos.z - casterZValue); const SkMatrix spotMatrix = SkMatrix::MakeScale(scale, scale); SkRect srcSpaceScaledRect = casterRect; spotMatrix.mapRect(&srcSpaceScaledRect); srcSpaceScaledRect.outset(SkScalarHalf(srcSpaceSpotRadius), SkScalarHalf(srcSpaceSpotRadius)); SkRRect srcSpaceSpotRRect; if (isOval) { srcSpaceSpotRRect = SkRRect::MakeOval(srcSpaceScaledRect); } else { srcSpaceSpotRRect = SkRRect::MakeRectXY(srcSpaceScaledRect, casterCornerRadius * scale, casterCornerRadius * scale); } SkPoint center = SkPoint::Make(srcSpaceSpotRRect.rect().centerX(), srcSpaceSpotRRect.rect().centerY()); SkMatrix ctmInverse; if (!canvas->getTotalMatrix().invert(&ctmInverse)) { ALOGW("Matrix is degenerate. Will not render spot shadow!"); return; } SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y); ctmInverse.mapPoints(&lightPos2D, 1); const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX), zRatio*(center.fY - lightPos2D.fY)); SkAutoCanvasRestore acr(canvas, true); canvas->translate(spotOffset.fX, spotOffset.fY); SkRect devSpaceScaledRect; canvas->getTotalMatrix().mapRect(&devSpaceScaledRect, srcSpaceScaledRect); SkRRect devSpaceSpotRRect; if (isOval) { devSpaceSpotRRect = SkRRect::MakeOval(devSpaceScaledRect); } else { const SkScalar devSpaceScaledCornerRadius = casterCornerRadius * scale * scaleFactor; devSpaceSpotRRect = SkRRect::MakeRectXY(devSpaceScaledRect, devSpaceScaledCornerRadius, devSpaceScaledCornerRadius); } SkPaint paint; paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, 0, 0, 0)); SkRect srcSpaceScaledClipRect = clipRR.rect(); spotMatrix.mapRect(&srcSpaceScaledClipRect); srcSpaceScaledClipRect.outset(SkScalarHalf(srcSpaceSpotRadius), SkScalarHalf(srcSpaceSpotRadius)); SkRect devSpaceScaledClipRect; canvas->getTotalMatrix().mapRect(&devSpaceScaledClipRect, srcSpaceScaledClipRect); SkRRect devSpaceSpotClipRR; if (clipRR.isOval()) { devSpaceSpotClipRR = SkRRect::MakeOval(devSpaceScaledClipRect); } else { SkASSERT(clipRR.isRect()); devSpaceSpotClipRR = SkRRect::MakeRect(devSpaceScaledClipRect); } paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceSpotRRect, devSpaceSpotClipRR, devSpaceSpotRadius)); SkRect cover = srcSpaceScaledClipRect; if (!cover.intersect(srcSpaceSpotRRect.rect())) { return; } canvas->drawRect(cover, paint); } } /** * @param casterRect the rectangle bounds of the RRect casting the shadow * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow * @param casterClipRect a rectangular clip that must be intersected with the * shadow-casting RRect prior to casting the shadow * @param revealClip a circular clip that must be interested with the castClipRect * and the shadow-casting rect prior to casting the shadow * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow * @param spotAlpha the maximum alpha value to use when drawing the spot shadow * @param casterAlpha the alpha value of the RRect casting the shadow (0.0-1.0 range) * @param casterZValue the Z value of the caster RRect * @param canvas the destination for the shadow draws * * We have special cases for 4 round rect shadow draws: * 1) a RRect clipped by a reveal animation * 2) a RRect clipped by a rectangle * 3) an unclipped RRect with non-uniform scale * 4) an unclipped RRect with uniform scale * 1,2 and 4 require that the scale is uniform. * 1 and 2 require that rects stay rects. */ static bool DrawShadowsAsRRects(const SkRect& casterRect, SkScalar casterCornerRadius, const SkRect& casterClipRect, const RevealClip& revealClip, SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue, SkCanvas* canvas) { SkScalar scaleFactors[2]; if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) { ALOGW("Matrix is degenerate. Will not render shadow!"); return false; } // The casterClipRect will be empty when bounds clipping is disabled bool casterIsClippedByRect = !casterClipRect.isEmpty(); bool uniformScale = scaleFactors[0] == scaleFactors[1]; if (revealClip.willClip()) { if (casterIsClippedByRect || !uniformScale || !canvas->getTotalMatrix().rectStaysRect()) { return false; // Fall back to the slow path since PathOps are required } const float revealRadius = revealClip.getRadius(); SkRect revealClipRect = SkRect::MakeLTRB(revealClip.getX()-revealRadius, revealClip.getY()-revealRadius, revealClip.getX()+revealRadius, revealClip.getY()+revealRadius); SkRRect revealClipRR = SkRRect::MakeOval(revealClipRect); DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, casterZValue, scaleFactors[0], revealClipRR, canvas); return true; } if (casterIsClippedByRect) { if (!uniformScale || !canvas->getTotalMatrix().rectStaysRect()) { return false; // Fall back to the slow path since PathOps are required } SkRRect casterClipRR = SkRRect::MakeRect(casterClipRect); DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, casterZValue, scaleFactors[0], casterClipRR, canvas); return true; } // The fast path needs uniform scale if (!uniformScale) { SkRRect casterRR = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius); DrawAmbientShadowGeneral(canvas, casterRR, casterZValue, ambientAlpha, [&](const SkRRect& rrect, const SkPaint& paint) { canvas->drawRRect(rrect, paint); }); DrawSpotShadowGeneral(canvas, casterRR, casterZValue, spotAlpha, [&](const SkRRect& rrect, const SkPaint& paint) { canvas->drawRRect(rrect, paint); }); return true; } DrawRRectShadows(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, casterAlpha, casterZValue, scaleFactors[0], canvas); return true; } // copied from FrameBuilder::deferShadow void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) { const RenderProperties& casterProperties = caster->getNodeProperties(); Loading @@ -626,8 +135,8 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* return; } float ambientAlpha = SkiaPipeline::getAmbientShadowAlpha()*casterAlpha; float spotAlpha = SkiaPipeline::getSpotShadowAlpha()*casterAlpha; float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha; float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha; const float casterZValue = casterProperties.getZ(); const RevealClip& revealClip = casterProperties.getRevealClip(); Loading Loading @@ -659,19 +168,7 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* hwuiMatrix.copyTo(shadowMatrix); canvas->concat(shadowMatrix); const Outline& casterOutline = casterProperties.getOutline(); Rect possibleRect; float radius; if (casterOutline.getAsRoundRect(&possibleRect, &radius)) { if (DrawShadowsAsRRects(possibleRect.toSkRect(), radius, casterClipRect, revealClip, ambientAlpha, spotAlpha, casterAlpha, casterZValue, canvas)) { return; } } // Hard cases and calls to general shadow code const SkPath* casterOutlinePath = casterProperties.getOutline().getPath(); // holds temporary SkPath to store the result of intersections SkPath tmpPath; const SkPath* casterPath = casterOutlinePath; Loading @@ -691,16 +188,11 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath); casterPath = &tmpPath; } DrawAmbientShadowGeneral(canvas, *casterPath, casterZValue, ambientAlpha, [&](const SkPath& path, const SkPaint& paint) { canvas->drawPath(path, paint); }); DrawSpotShadowGeneral(canvas, *casterPath, casterZValue, spotAlpha, [&](const SkPath& path, const SkPaint& paint) { canvas->drawPath(path, paint); }); const Vector3 lightPos = SkiaPipeline::getLightCenter(); SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z); SkShadowUtils::DrawShadow(canvas, *casterPath, casterZValue, skiaLightPos, SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK, casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0); } }; // namespace skiapipeline Loading