Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41fed8cc authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Use new Skia DrawShadow API"

parents 915b594d 30a75deb
Loading
Loading
Loading
Loading
+8 −516
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <SkGaussianEdgeShader.h>
#include <SkPathOps.h>
#include <SkRRectsGaussianEdgeMaskFilter.h>
#include <SkShadowUtils.h>

namespace android {
namespace uirenderer {
@@ -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();
@@ -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();
@@ -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;
@@ -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