Merge "Use new Skia DrawShadow API"
This commit is contained in:
committed by
Android (Google) Code Review
commit
41fed8cc15
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user