Fix fast blur for shadow rrects.
* Handles case where blur is greater than corner radius. * Speeds up shader by avoiding a divide. * Tweaks shadow sample to be more MD-ish. Bug: skia: Change-Id: I2990357b39784c22f02a8e51872391fd68e8226a Reviewed-on: https://skia-review.googlesource.com/14141 Commit-Queue: Jim Van Verth <jvanverth@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
713b8ef374
commit
b6069dfba7
@ -52,7 +52,7 @@ public:
|
||||
, fAnimAngle(0)
|
||||
, fShowAmbient(true)
|
||||
, fShowSpot(true)
|
||||
, fUseAlt(true)
|
||||
, fUseAlt(false)
|
||||
, fShowObject(true)
|
||||
, fIgnoreShadowAlpha(false) {}
|
||||
|
||||
@ -72,7 +72,7 @@ protected:
|
||||
fWideRectPath.addRect(SkRect::MakeXYWH(0, 0, 630, 70));
|
||||
fWideOvalPath.addOval(SkRect::MakeXYWH(0, 0, 630, 70));
|
||||
|
||||
fLightPos = SkPoint3::Make(-700, -700, 2800);
|
||||
fLightPos = SkPoint3::Make(350, 0, 600);
|
||||
}
|
||||
|
||||
// overrides from SkEventSink
|
||||
@ -465,38 +465,32 @@ protected:
|
||||
|
||||
void onDrawContent(SkCanvas* canvas) override {
|
||||
this->drawBG(canvas);
|
||||
const SkScalar kLightWidth = 2800;
|
||||
const SkScalar kAmbientAlpha = 0.25f;
|
||||
const SkScalar kLightWidth = 800;
|
||||
const SkScalar kAmbientAlpha = 0.1f;
|
||||
const SkScalar kSpotAlpha = 0.25f;
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
SkPoint3 lightPos = fLightPos;
|
||||
lightPos.fX = canvas->getBaseLayerSize().fWidth * 0.5f;
|
||||
|
||||
paint.setColor(SK_ColorWHITE);
|
||||
canvas->translate(200, 90);
|
||||
lightPos.fX += 200;
|
||||
lightPos.fY += 90;
|
||||
SkScalar zValue = SkTMax(1.0f, 2 + fZDelta);
|
||||
std::function<SkScalar(SkScalar, SkScalar)> zFunc =
|
||||
std::function<SkScalar(SkScalar, SkScalar)> zFunc =
|
||||
[zValue](SkScalar, SkScalar) { return zValue; };
|
||||
this->drawShadowedPath(canvas, fRRPath, zFunc, paint, kAmbientAlpha,
|
||||
lightPos, kLightWidth, kSpotAlpha);
|
||||
|
||||
paint.setColor(SK_ColorRED);
|
||||
canvas->translate(250, 0);
|
||||
lightPos.fX += 250;
|
||||
zValue = SkTMax(1.0f, 4 + fZDelta);
|
||||
zValue = SkTMax(1.0f, 8 + fZDelta);
|
||||
zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
|
||||
this->drawShadowedPath(canvas, fRectPath, zFunc, paint, kAmbientAlpha,
|
||||
lightPos, kLightWidth, kSpotAlpha);
|
||||
|
||||
paint.setColor(SK_ColorBLUE);
|
||||
canvas->translate(-250, 110);
|
||||
lightPos.fX -= 250;
|
||||
lightPos.fY += 110;
|
||||
zValue = SkTMax(1.0f, 12 + fZDelta);
|
||||
zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
|
||||
this->drawShadowedPath(canvas, fCirclePath, zFunc, paint, kAmbientAlpha,
|
||||
@ -504,7 +498,6 @@ protected:
|
||||
|
||||
paint.setColor(SK_ColorGREEN);
|
||||
canvas->translate(250, 0);
|
||||
lightPos.fX += 250;
|
||||
zValue = SkTMax(1.0f, 64 + fZDelta);
|
||||
zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
|
||||
this->drawShadowedPath(canvas, fRRPath, zFunc, paint, kAmbientAlpha,
|
||||
@ -512,8 +505,6 @@ protected:
|
||||
|
||||
paint.setColor(SK_ColorYELLOW);
|
||||
canvas->translate(-250, 110);
|
||||
lightPos.fX -= 250;
|
||||
lightPos.fY += 110;
|
||||
zValue = SkTMax(1.0f, 8 + fZDelta);
|
||||
zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
|
||||
this->drawShadowedPath(canvas, fFunkyRRPath, zFunc, paint, kAmbientAlpha,
|
||||
@ -521,7 +512,6 @@ protected:
|
||||
|
||||
paint.setColor(SK_ColorCYAN);
|
||||
canvas->translate(250, 0);
|
||||
lightPos.fX += 250;
|
||||
zValue = SkTMax(1.0f, 16 + fZDelta);
|
||||
zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
|
||||
this->drawShadowedPath(canvas, fCubicPath, zFunc, paint,
|
||||
@ -535,8 +525,6 @@ protected:
|
||||
|
||||
paint.setColor(SK_ColorMAGENTA);
|
||||
canvas->translate(-125, 60);
|
||||
lightPos.fX -= 125;
|
||||
lightPos.fY += 60;
|
||||
zValue = SkTMax(1.0f, 32 + fZDelta);
|
||||
zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
|
||||
this->drawShadowedPath(canvas, tmpPath, zFunc, paint, .1f,
|
||||
@ -555,9 +543,6 @@ protected:
|
||||
persp.preTranslate(-pivot.fX, -pivot.fY);
|
||||
persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
|
||||
canvas->setMatrix(persp);
|
||||
lightPos = fLightPos;
|
||||
lightPos.fX += pivot.fX + translate.fX;
|
||||
lightPos.fY += pivot.fY + translate.fY;
|
||||
zValue = SkTMax(1.0f, 16 + fZDelta);
|
||||
SkScalar radians = SkDegreesToRadians(fAnimAngle);
|
||||
zFunc = [zValue, pivot, radians](SkScalar x, SkScalar y) {
|
||||
@ -576,9 +561,6 @@ protected:
|
||||
persp.preTranslate(-pivot.fX, -pivot.fY);
|
||||
persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
|
||||
canvas->setMatrix(persp);
|
||||
lightPos = fLightPos;
|
||||
lightPos.fX += pivot.fX + translate.fX;
|
||||
lightPos.fY += pivot.fY + translate.fY;
|
||||
zValue = SkTMax(1.0f, 32 + fZDelta);
|
||||
zFunc = [zValue, pivot, radians](SkScalar x, SkScalar y) {
|
||||
return -SkScalarSin(radians)*x +
|
||||
|
@ -217,13 +217,13 @@ bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
|
||||
// TODO: take flags into account when generating shadow data
|
||||
|
||||
if (fAmbientAlpha > 0.0f) {
|
||||
SkScalar srcSpaceAmbientRadius = fOccluderHeight * kHeightFactor * kGeomFactor;
|
||||
SkScalar srcSpaceStrokeWidth = fOccluderHeight * kHeightFactor * kGeomFactor;
|
||||
const float umbraAlpha = (1.0f + SkTMax(fOccluderHeight * kHeightFactor, 0.0f));
|
||||
const SkScalar strokeWidth = srcSpaceAmbientRadius * umbraAlpha;
|
||||
const SkScalar blurWidth = srcSpaceStrokeWidth * umbraAlpha;
|
||||
|
||||
// For the ambient rrect, we outset the offset rect by srcSpaceAmbientRadius
|
||||
// minus half the strokeWidth to get our stroke shape.
|
||||
SkScalar ambientPathOutset = SkTMax(srcSpaceAmbientRadius - strokeWidth * 0.5f,
|
||||
SkScalar ambientPathOutset = SkTMax(srcSpaceStrokeWidth * 0.5f,
|
||||
minRadius);
|
||||
|
||||
SkRRect ambientRRect;
|
||||
@ -234,17 +234,18 @@ bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
|
||||
rrect.outset(ambientPathOutset, ambientPathOutset, &ambientRRect);
|
||||
}
|
||||
|
||||
const SkScalar devSpaceAmbientRadius = strokeWidth * scaleFactor;
|
||||
const SkScalar devSpaceAmbientBlur = blurWidth * scaleFactor;
|
||||
|
||||
GrPaint newPaint(paint);
|
||||
GrColor4f color = newPaint.getColor4f();
|
||||
color.fRGBA[3] *= fAmbientAlpha;
|
||||
newPaint.setColor4f(color);
|
||||
SkStrokeRec ambientStrokeRec(SkStrokeRec::kHairline_InitStyle);
|
||||
ambientStrokeRec.setStrokeStyle(strokeWidth, false);
|
||||
bool transparent = SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
|
||||
ambientStrokeRec.setStrokeStyle(srcSpaceStrokeWidth, transparent);
|
||||
|
||||
rtContext->drawShadowRRect(clip, std::move(newPaint), viewMatrix, ambientRRect,
|
||||
devSpaceAmbientRadius,
|
||||
devSpaceAmbientBlur,
|
||||
GrStyle(ambientStrokeRec, nullptr));
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
|
||||
// emit attributes
|
||||
varyingHandler->emitAttributes(rsgp);
|
||||
fragBuilder->codeAppend("vec4 shadowParams;");
|
||||
fragBuilder->codeAppend("vec3 shadowParams;");
|
||||
varyingHandler->addPassThroughAttribute(rsgp.inShadowParams(), "shadowParams");
|
||||
|
||||
// setup pass through color
|
||||
@ -47,9 +47,7 @@ public:
|
||||
fragBuilder->codeAppend("float d = length(shadowParams.xy);");
|
||||
fragBuilder->codeAppend("float distance = shadowParams.z * (1.0 - d);");
|
||||
|
||||
fragBuilder->codeAppend("float radius = shadowParams.w;");
|
||||
|
||||
fragBuilder->codeAppend("float factor = 1.0 - clamp(distance/radius, 0.0, 1.0);");
|
||||
fragBuilder->codeAppend("float factor = 1.0 - clamp(distance, 0.0, 1.0);");
|
||||
fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
|
||||
fragBuilder->codeAppendf("%s = vec4(factor);",
|
||||
args.fOutputCoverage);
|
||||
@ -83,7 +81,7 @@ GrRRectShadowGeoProc::GrRRectShadowGeoProc(const SkMatrix& localMatrix)
|
||||
fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
|
||||
kHigh_GrSLPrecision);
|
||||
fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
|
||||
fInShadowParams = &this->addVertexAttrib("inShadowParams", kVec4f_GrVertexAttribType);
|
||||
fInShadowParams = &this->addVertexAttrib("inShadowParams", kVec3f_GrVertexAttribType);
|
||||
}
|
||||
|
||||
void GrRRectShadowGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
|
||||
|
@ -168,8 +168,7 @@ private:
|
||||
SkPoint fPos;
|
||||
GrColor fColor;
|
||||
SkPoint fOffset;
|
||||
SkScalar fOuterRadius;
|
||||
SkScalar fBlurRadius;
|
||||
SkScalar fDistanceCorrection;
|
||||
};
|
||||
|
||||
int instanceCount = fCircles.count();
|
||||
@ -201,6 +200,7 @@ private:
|
||||
SkScalar outerRadius = circle.fOuterRadius;
|
||||
SkScalar innerRadius = circle.fInnerRadius;
|
||||
SkScalar blurRadius = circle.fBlurRadius;
|
||||
SkScalar distanceCorrection = outerRadius / blurRadius;
|
||||
|
||||
const SkRect& bounds = circle.fDevBounds;
|
||||
CircleVertex* ov0 = reinterpret_cast<CircleVertex*>(vertices + 0 * vertexStride);
|
||||
@ -222,50 +222,42 @@ private:
|
||||
ov0->fPos = center + SkPoint::Make(-octOffset * halfWidth, -halfWidth);
|
||||
ov0->fColor = color;
|
||||
ov0->fOffset = SkPoint::Make(-octOffset, -1);
|
||||
ov0->fOuterRadius = outerRadius;
|
||||
ov0->fBlurRadius = blurRadius;
|
||||
ov0->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
ov1->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth);
|
||||
ov1->fColor = color;
|
||||
ov1->fOffset = SkPoint::Make(octOffset, -1);
|
||||
ov1->fOuterRadius = outerRadius;
|
||||
ov1->fBlurRadius = blurRadius;
|
||||
ov1->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
ov2->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth);
|
||||
ov2->fColor = color;
|
||||
ov2->fOffset = SkPoint::Make(1, -octOffset);
|
||||
ov2->fOuterRadius = outerRadius;
|
||||
ov2->fBlurRadius = blurRadius;
|
||||
ov2->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
ov3->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth);
|
||||
ov3->fColor = color;
|
||||
ov3->fOffset = SkPoint::Make(1, octOffset);
|
||||
ov3->fOuterRadius = outerRadius;
|
||||
ov3->fBlurRadius = blurRadius;
|
||||
ov3->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
ov4->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth);
|
||||
ov4->fColor = color;
|
||||
ov4->fOffset = SkPoint::Make(octOffset, 1);
|
||||
ov4->fOuterRadius = outerRadius;
|
||||
ov4->fBlurRadius = blurRadius;
|
||||
ov4->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
ov5->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth);
|
||||
ov5->fColor = color;
|
||||
ov5->fOffset = SkPoint::Make(-octOffset, 1);
|
||||
ov5->fOuterRadius = outerRadius;
|
||||
ov5->fBlurRadius = blurRadius;
|
||||
ov5->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
ov6->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth);
|
||||
ov6->fColor = color;
|
||||
ov6->fOffset = SkPoint::Make(-1, octOffset);
|
||||
ov6->fOuterRadius = outerRadius;
|
||||
ov6->fBlurRadius = blurRadius;
|
||||
ov6->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
ov7->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth);
|
||||
ov7->fColor = color;
|
||||
ov7->fOffset = SkPoint::Make(-1, -octOffset);
|
||||
ov7->fOuterRadius = outerRadius;
|
||||
ov7->fBlurRadius = blurRadius;
|
||||
ov7->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
if (circle.fStroked) {
|
||||
// compute the inner ring
|
||||
@ -286,58 +278,49 @@ private:
|
||||
iv0->fPos = center + SkPoint::Make(-s * r, -c * r);
|
||||
iv0->fColor = color;
|
||||
iv0->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius);
|
||||
iv0->fOuterRadius = outerRadius;
|
||||
iv0->fBlurRadius = blurRadius;
|
||||
iv0->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
iv1->fPos = center + SkPoint::Make(s * r, -c * r);
|
||||
iv1->fColor = color;
|
||||
iv1->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius);
|
||||
iv1->fOuterRadius = outerRadius;
|
||||
iv1->fBlurRadius = blurRadius;
|
||||
iv1->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
iv2->fPos = center + SkPoint::Make(c * r, -s * r);
|
||||
iv2->fColor = color;
|
||||
iv2->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius);
|
||||
iv2->fOuterRadius = outerRadius;
|
||||
iv2->fBlurRadius = blurRadius;
|
||||
iv2->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
iv3->fPos = center + SkPoint::Make(c * r, s * r);
|
||||
iv3->fColor = color;
|
||||
iv3->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius);
|
||||
iv3->fOuterRadius = outerRadius;
|
||||
iv3->fBlurRadius = blurRadius;
|
||||
iv3->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
iv4->fPos = center + SkPoint::Make(s * r, c * r);
|
||||
iv4->fColor = color;
|
||||
iv4->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius);
|
||||
iv4->fOuterRadius = outerRadius;
|
||||
iv4->fBlurRadius = blurRadius;
|
||||
iv4->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
iv5->fPos = center + SkPoint::Make(-s * r, c * r);
|
||||
iv5->fColor = color;
|
||||
iv5->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius);
|
||||
iv5->fOuterRadius = outerRadius;
|
||||
iv5->fBlurRadius = blurRadius;
|
||||
iv5->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
iv6->fPos = center + SkPoint::Make(-c * r, s * r);
|
||||
iv6->fColor = color;
|
||||
iv6->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius);
|
||||
iv6->fOuterRadius = outerRadius;
|
||||
iv6->fBlurRadius = blurRadius;
|
||||
iv6->fDistanceCorrection = distanceCorrection;
|
||||
|
||||
iv7->fPos = center + SkPoint::Make(-c * r, -s * r);
|
||||
iv7->fColor = color;
|
||||
iv7->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius);
|
||||
iv7->fOuterRadius = outerRadius;
|
||||
iv7->fBlurRadius = blurRadius;
|
||||
iv7->fDistanceCorrection = distanceCorrection;
|
||||
} else {
|
||||
// filled
|
||||
CircleVertex* iv = reinterpret_cast<CircleVertex*>(vertices + 8 * vertexStride);
|
||||
iv->fPos = center;
|
||||
iv->fColor = color;
|
||||
iv->fOffset = SkPoint::Make(0, 0);
|
||||
iv->fOuterRadius = outerRadius;
|
||||
iv->fBlurRadius = blurRadius;
|
||||
iv->fDistanceCorrection = distanceCorrection;
|
||||
}
|
||||
|
||||
const uint16_t* primIndices = circle_type_to_indices(circle.fStroked);
|
||||
@ -392,10 +375,7 @@ private:
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// We have two possible cases for geometry for a shadow roundrect.
|
||||
//
|
||||
// In the case of a normal stroke, we draw the roundrect as a 9-patch without the center quad.
|
||||
// The geometry for a shadow roundrect is similar to a 9-patch:
|
||||
// ____________
|
||||
// |_|________|_|
|
||||
// | | | |
|
||||
@ -404,9 +384,23 @@ private:
|
||||
// |_|________|_|
|
||||
// |_|________|_|
|
||||
//
|
||||
// In the case where the stroke width is greater than twice the corner radius (overstroke),
|
||||
// we add additional geometry to mark out the rectangle in the center. The shared vertices
|
||||
// are duplicated so we can set a different outer radius for the fill calculation.
|
||||
// However, each corner is rendered as a fan rather than a simple quad, as below. (The diagram
|
||||
// shows the upper part of the upper left corner. The bottom triangle would similarly be split
|
||||
// into two triangles.)
|
||||
// ________
|
||||
// |\ \ |
|
||||
// | \ \ |
|
||||
// | \\ |
|
||||
// | \|
|
||||
// --------
|
||||
//
|
||||
// The center of the fan handles the curve of the corner. For roundrects where the stroke width
|
||||
// is greater than the corner radius, the outer triangles blend from the curve to the straight
|
||||
// sides. Otherwise these triangles will be degenerate.
|
||||
//
|
||||
// In the case where the stroke width is greater than the corner radius and the
|
||||
// blur radius (overstroke), we add additional geometry to mark out the rectangle in the center.
|
||||
// This rectangle extends the coverage values of the center edges of the 9-patch.
|
||||
// ____________
|
||||
// |_|________|_|
|
||||
// | |\ ____ /| |
|
||||
@ -415,40 +409,44 @@ private:
|
||||
// |_|/______\|_|
|
||||
// |_|________|_|
|
||||
//
|
||||
// For filled rrects we reuse the overstroke geometry but make the inner rect degenerate
|
||||
// (either a point or a horizontal or vertical line).
|
||||
// For filled rrects we reuse the stroke geometry but add an additional quad to the center.
|
||||
|
||||
static const uint16_t gOverstrokeRRectIndices[] = {
|
||||
// clang-format off
|
||||
// corners
|
||||
0, 1, 5, 0, 5, 4,
|
||||
2, 3, 7, 2, 7, 6,
|
||||
8, 9, 13, 8, 13, 12,
|
||||
10, 11, 15, 10, 15, 14,
|
||||
static const uint16_t gRRectIndices[] = {
|
||||
// clang-format off
|
||||
// overstroke quads
|
||||
// we place this at the beginning so that we can skip these indices when rendering as filled
|
||||
0, 6, 25, 0, 25, 24,
|
||||
6, 18, 27, 6, 27, 25,
|
||||
18, 12, 26, 18, 26, 27,
|
||||
12, 0, 24, 12, 24, 26,
|
||||
|
||||
// edges
|
||||
1, 2, 6, 1, 6, 5,
|
||||
4, 5, 9, 4, 9, 8,
|
||||
6, 7, 11, 6, 11, 10,
|
||||
9, 10, 14, 9, 14, 13,
|
||||
// corners
|
||||
0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5,
|
||||
6, 11, 10, 6, 10, 9, 6, 9, 8, 6, 8, 7,
|
||||
12, 17, 16, 12, 16, 15, 12, 15, 14, 12, 14, 13,
|
||||
18, 19, 20, 18, 20, 21, 18, 21, 22, 18, 22, 23,
|
||||
|
||||
// overstroke quads
|
||||
// we place this at the end so that we can skip these indices when rendering as stroked
|
||||
16, 17, 19, 16, 19, 18,
|
||||
19, 17, 23, 19, 23, 21,
|
||||
21, 23, 22, 21, 22, 20,
|
||||
22, 16, 18, 22, 18, 20,
|
||||
// clang-format on
|
||||
// edges
|
||||
0, 5, 11, 0, 11, 6,
|
||||
6, 7, 19, 6, 19, 18,
|
||||
18, 23, 17, 18, 17, 12,
|
||||
12, 13, 1, 12, 1, 0,
|
||||
|
||||
// fill quad
|
||||
// we place this at the end so that we can skip these indices when rendering as stroked
|
||||
0, 6, 18, 0, 18, 12,
|
||||
// clang-format on
|
||||
};
|
||||
// standard stroke indices start at the same place, but will skip the overstroke "ring"
|
||||
static const uint16_t* gStrokeRRectIndices = gOverstrokeRRectIndices;
|
||||
|
||||
// overstroke count
|
||||
static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gOverstrokeRRectIndices);
|
||||
static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
|
||||
// simple stroke count skips overstroke indices
|
||||
static const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6 * 4 + 6;
|
||||
static const int kVertsPerStrokeRRect = 16;
|
||||
static const int kVertsPerOverstrokeRRect = 24;
|
||||
static const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6*4;
|
||||
// fill count adds final quad to stroke count
|
||||
static const int kIndicesPerFillRRect = kIndicesPerStrokeRRect + 6;
|
||||
static const int kVertsPerStrokeRRect = 24;
|
||||
static const int kVertsPerOverstrokeRRect = 28;
|
||||
static const int kVertsPerFillRRect = 24;
|
||||
|
||||
enum RRectType {
|
||||
kFill_RRectType,
|
||||
@ -459,7 +457,7 @@ enum RRectType {
|
||||
static int rrect_type_to_vert_count(RRectType type) {
|
||||
switch (type) {
|
||||
case kFill_RRectType:
|
||||
return kVertsPerOverstrokeRRect;
|
||||
return kVertsPerFillRRect;
|
||||
case kStroke_RRectType:
|
||||
return kVertsPerStrokeRRect;
|
||||
case kOverstroke_RRectType:
|
||||
@ -472,7 +470,7 @@ static int rrect_type_to_vert_count(RRectType type) {
|
||||
static int rrect_type_to_index_count(RRectType type) {
|
||||
switch (type) {
|
||||
case kFill_RRectType:
|
||||
return kIndicesPerOverstrokeRRect;
|
||||
return kIndicesPerFillRRect;
|
||||
case kStroke_RRectType:
|
||||
return kIndicesPerStrokeRRect;
|
||||
case kOverstroke_RRectType:
|
||||
@ -485,25 +483,15 @@ static int rrect_type_to_index_count(RRectType type) {
|
||||
static const uint16_t* rrect_type_to_indices(RRectType type) {
|
||||
switch (type) {
|
||||
case kFill_RRectType:
|
||||
return gOverstrokeRRectIndices;
|
||||
case kStroke_RRectType:
|
||||
return gStrokeRRectIndices;
|
||||
return gRRectIndices + 6*4;
|
||||
case kOverstroke_RRectType:
|
||||
return gOverstrokeRRectIndices;
|
||||
return gRRectIndices;
|
||||
}
|
||||
SkFAIL("Invalid type");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// For distance computations in the interior of filled rrects we:
|
||||
//
|
||||
// add a interior degenerate (point or line) rect
|
||||
// each vertex of that rect gets -outerRad as its radius
|
||||
// this makes the computation of the distance to the outer edge be negative
|
||||
// negative values are caught and then handled differently in the GP's onEmitCode
|
||||
// each vertex is also given the normalized x & y distance from the interior rect's edge
|
||||
// the GP takes the min of those depths +1 to get the normalized distance to the outer edge
|
||||
|
||||
class ShadowCircularRRectOp final : public GrLegacyMeshDrawOp {
|
||||
public:
|
||||
DEFINE_OP_CLASS_ID
|
||||
@ -515,8 +503,9 @@ public:
|
||||
: INHERITED(ClassID()), fViewMatrixIfUsingLocalCoords(viewMatrix) {
|
||||
SkRect bounds = devRect;
|
||||
SkASSERT(!(devStrokeWidth <= 0 && strokeOnly));
|
||||
SkScalar innerRadius = 0.0f;
|
||||
SkScalar overStrokeRadius = 0.0f;
|
||||
SkScalar outerRadius = devRadius;
|
||||
SkScalar umbraInset = SkTMax(outerRadius, blurRadius);
|
||||
SkScalar halfWidth = 0;
|
||||
RRectType type = kFill_RRectType;
|
||||
if (devStrokeWidth > 0) {
|
||||
@ -525,22 +514,32 @@ public:
|
||||
} else {
|
||||
halfWidth = SkScalarHalf(devStrokeWidth);
|
||||
}
|
||||
|
||||
if (strokeOnly) {
|
||||
// If stroke is greater than width or height, this is still a fill
|
||||
// Otherwise we compute stroke params
|
||||
if (devStrokeWidth <= devRect.width() && devStrokeWidth <= devRect.height()) {
|
||||
innerRadius = devRadius - halfWidth;
|
||||
type = (innerRadius >= 0) ? kStroke_RRectType : kOverstroke_RRectType;
|
||||
}
|
||||
}
|
||||
outerRadius += halfWidth;
|
||||
bounds.outset(halfWidth, halfWidth);
|
||||
|
||||
// If the client has requested a stroke smaller than the outer radius,
|
||||
// we will assume they want no special umbra inset (this is for ambient shadows).
|
||||
if (devStrokeWidth <= outerRadius) {
|
||||
umbraInset = outerRadius;
|
||||
}
|
||||
|
||||
if (strokeOnly) {
|
||||
// If stroke is greater than width or height, this is still a fill,
|
||||
// otherwise we compute stroke params.
|
||||
if (devStrokeWidth <= devRect.width() && devStrokeWidth <= devRect.height()) {
|
||||
// We don't worry about an inner radius, we just need to know if we
|
||||
// need to create overstroke vertices.
|
||||
overStrokeRadius = SkTMax(devStrokeWidth - umbraInset,
|
||||
0.0f);
|
||||
type = overStrokeRadius > 0 ? kOverstroke_RRectType : kStroke_RRectType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
|
||||
|
||||
fGeoData.emplace_back(Geometry{color, outerRadius, innerRadius, blurRadius, bounds, type});
|
||||
fGeoData.emplace_back(Geometry{color, outerRadius, umbraInset, overStrokeRadius,
|
||||
blurRadius, bounds, type});
|
||||
fVertCount = rrect_type_to_vert_count(type);
|
||||
fIndexCount = rrect_type_to_index_count(type);
|
||||
}
|
||||
@ -552,10 +551,11 @@ public:
|
||||
for (int i = 0; i < fGeoData.count(); ++i) {
|
||||
string.appendf(
|
||||
"Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
|
||||
"OuterRad: %.2f, InnerRad: %.2f, BlurRad: %.2f\n",
|
||||
"OuterRad: %.2f, Umbra: %.2f, Overstroke: %.2f, BlurRad: %.2f\n",
|
||||
fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
|
||||
fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
|
||||
fGeoData[i].fOuterRadius, fGeoData[i].fInnerRadius, fGeoData[i].fBlurRadius);
|
||||
fGeoData[i].fOuterRadius, fGeoData[i].fUmbraInset,
|
||||
fGeoData[i].fOverstroke, fGeoData[i].fBlurRadius);
|
||||
}
|
||||
string.append(DumpPipelineInfo(*this->pipeline()));
|
||||
string.append(INHERITED::dumpInfo());
|
||||
@ -580,73 +580,37 @@ private:
|
||||
SkPoint fPos;
|
||||
GrColor fColor;
|
||||
SkPoint fOffset;
|
||||
SkScalar fOuterRadius;
|
||||
SkScalar fBlurRadius;
|
||||
SkScalar fDistanceCorrection;
|
||||
};
|
||||
|
||||
static void FillInOverstrokeVerts(CircleVertex** verts, const SkRect& bounds, SkScalar smInset,
|
||||
SkScalar bigInset, SkScalar xOffset, SkScalar outerRadius,
|
||||
GrColor color, SkScalar blurRadius) {
|
||||
SkASSERT(smInset < bigInset);
|
||||
|
||||
static void FillInOverstrokeVerts(CircleVertex** verts, const SkRect& bounds, SkScalar inset,
|
||||
GrColor color, SkScalar distanceCorrection) {
|
||||
// TL
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fTop + smInset);
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fTop + inset);
|
||||
(*verts)->fColor = color;
|
||||
(*verts)->fOffset = SkPoint::Make(xOffset, 0);
|
||||
(*verts)->fOuterRadius = outerRadius;
|
||||
(*verts)->fBlurRadius = blurRadius;
|
||||
(*verts)->fOffset = SkPoint::Make(0, 0);
|
||||
(*verts)->fDistanceCorrection = distanceCorrection;
|
||||
(*verts)++;
|
||||
|
||||
// TR
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fTop + smInset);
|
||||
(*verts)->fColor = color;
|
||||
(*verts)->fOffset = SkPoint::Make(xOffset, 0);
|
||||
(*verts)->fOuterRadius = outerRadius;
|
||||
(*verts)->fBlurRadius = blurRadius;
|
||||
(*verts)++;
|
||||
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fTop + bigInset);
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fTop + inset);
|
||||
(*verts)->fColor = color;
|
||||
(*verts)->fOffset = SkPoint::Make(0, 0);
|
||||
(*verts)->fOuterRadius = outerRadius;
|
||||
(*verts)->fBlurRadius = blurRadius;
|
||||
(*verts)++;
|
||||
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fTop + bigInset);
|
||||
(*verts)->fColor = color;
|
||||
(*verts)->fOffset = SkPoint::Make(0, 0);
|
||||
(*verts)->fOuterRadius = outerRadius;
|
||||
(*verts)->fBlurRadius = blurRadius;
|
||||
(*verts)++;
|
||||
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fBottom - bigInset);
|
||||
(*verts)->fColor = color;
|
||||
(*verts)->fOffset = SkPoint::Make(0, 0);
|
||||
(*verts)->fOuterRadius = outerRadius;
|
||||
(*verts)->fBlurRadius = blurRadius;
|
||||
(*verts)++;
|
||||
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fBottom - bigInset);
|
||||
(*verts)->fColor = color;
|
||||
(*verts)->fOffset = SkPoint::Make(0, 0);
|
||||
(*verts)->fOuterRadius = outerRadius;
|
||||
(*verts)->fBlurRadius = blurRadius;
|
||||
(*verts)->fDistanceCorrection = distanceCorrection;
|
||||
(*verts)++;
|
||||
|
||||
// BL
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fBottom - smInset);
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fBottom - inset);
|
||||
(*verts)->fColor = color;
|
||||
(*verts)->fOffset = SkPoint::Make(xOffset, 0);
|
||||
(*verts)->fOuterRadius = outerRadius;
|
||||
(*verts)->fBlurRadius = blurRadius;
|
||||
(*verts)->fOffset = SkPoint::Make(0, 0);
|
||||
(*verts)->fDistanceCorrection = distanceCorrection;
|
||||
(*verts)++;
|
||||
|
||||
// BR
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fBottom - smInset);
|
||||
(*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fBottom - inset);
|
||||
(*verts)->fColor = color;
|
||||
(*verts)->fOffset = SkPoint::Make(xOffset, 0);
|
||||
(*verts)->fOuterRadius = outerRadius;
|
||||
(*verts)->fBlurRadius = blurRadius;
|
||||
(*verts)->fOffset = SkPoint::Make(0, 0);
|
||||
(*verts)->fDistanceCorrection = distanceCorrection;
|
||||
(*verts)++;
|
||||
}
|
||||
|
||||
@ -691,69 +655,90 @@ private:
|
||||
|
||||
const SkRect& bounds = args.fDevBounds;
|
||||
|
||||
SkScalar yCoords[4] = {bounds.fTop, bounds.fTop + outerRadius,
|
||||
bounds.fBottom - outerRadius, bounds.fBottom};
|
||||
SkScalar umbraInset = args.fUmbraInset;
|
||||
|
||||
SkScalar minDim = 0.5f*SkTMin(bounds.width(), bounds.height());
|
||||
if (umbraInset > minDim) {
|
||||
umbraInset = minDim;
|
||||
}
|
||||
|
||||
SkScalar xInner[4] = { bounds.fLeft + umbraInset, bounds.fRight - umbraInset,
|
||||
bounds.fLeft + umbraInset, bounds.fRight - umbraInset };
|
||||
SkScalar xMid[4] = { bounds.fLeft + outerRadius, bounds.fRight - outerRadius,
|
||||
bounds.fLeft + outerRadius, bounds.fRight - outerRadius};
|
||||
SkScalar xOuter[4] = { bounds.fLeft, bounds.fRight,
|
||||
bounds.fLeft, bounds.fRight };
|
||||
SkScalar yInner[4] = { bounds.fTop + umbraInset, bounds.fTop + umbraInset,
|
||||
bounds.fBottom - umbraInset, bounds.fBottom - umbraInset };
|
||||
SkScalar yMid[4] = { bounds.fTop + outerRadius, bounds.fTop + outerRadius,
|
||||
bounds.fBottom - outerRadius, bounds.fBottom - outerRadius };
|
||||
SkScalar yOuter[4] = { bounds.fTop, bounds.fTop,
|
||||
bounds.fBottom, bounds.fBottom };
|
||||
|
||||
SkScalar yOuterRadii[4] = {-1, 0, 0, 1};
|
||||
// The inner radius in the vertex data must be specified in normalized space.
|
||||
// For fills, specifying -1/outerRadius guarantees an alpha of 1.0 at the inner radius.
|
||||
SkScalar blurRadius = args.fBlurRadius;
|
||||
|
||||
// In the case where we have to inset more for the umbra, our two triangles in the
|
||||
// corner get skewed to a diamond rather than a square. To correct for that,
|
||||
// we also skew the vectors we send to the shader that help define the circle.
|
||||
// By doing so, we end up with a quarter circle in the corner rather than the
|
||||
// elliptical curve.
|
||||
SkVector outerVec = SkVector::Make(0.5f*(outerRadius - umbraInset), -umbraInset);
|
||||
outerVec.normalize();
|
||||
SkVector diagVec = SkVector::Make(outerVec.fX + outerVec.fY,
|
||||
outerVec.fX + outerVec.fY);
|
||||
diagVec *= umbraInset / (2 * umbraInset - outerRadius);
|
||||
SkScalar distanceCorrection = umbraInset / blurRadius;
|
||||
|
||||
// build corner by corner
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
|
||||
// inner point
|
||||
verts->fPos = SkPoint::Make(xInner[i], yInner[i]);
|
||||
verts->fColor = color;
|
||||
verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
|
||||
verts->fOuterRadius = outerRadius;
|
||||
verts->fBlurRadius = blurRadius;
|
||||
verts->fOffset = SkVector::Make(0, 0);
|
||||
verts->fDistanceCorrection = distanceCorrection;
|
||||
verts++;
|
||||
|
||||
verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
|
||||
// outer points
|
||||
verts->fPos = SkPoint::Make(xOuter[i], yInner[i]);
|
||||
verts->fColor = color;
|
||||
verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
|
||||
verts->fOuterRadius = outerRadius;
|
||||
verts->fBlurRadius = blurRadius;
|
||||
verts->fOffset = SkVector::Make(0, -1);
|
||||
verts->fDistanceCorrection = distanceCorrection;
|
||||
verts++;
|
||||
|
||||
verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
|
||||
verts->fPos = SkPoint::Make(xOuter[i], yMid[i]);
|
||||
verts->fColor = color;
|
||||
verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
|
||||
verts->fOuterRadius = outerRadius;
|
||||
verts->fBlurRadius = blurRadius;
|
||||
verts->fOffset = outerVec;
|
||||
verts->fDistanceCorrection = distanceCorrection;
|
||||
verts++;
|
||||
|
||||
verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
|
||||
verts->fPos = SkPoint::Make(xOuter[i], yOuter[i]);
|
||||
verts->fColor = color;
|
||||
verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
|
||||
verts->fOuterRadius = outerRadius;
|
||||
verts->fBlurRadius = blurRadius;
|
||||
verts->fOffset = diagVec;
|
||||
verts->fDistanceCorrection = distanceCorrection;
|
||||
verts++;
|
||||
|
||||
verts->fPos = SkPoint::Make(xMid[i], yOuter[i]);
|
||||
verts->fColor = color;
|
||||
verts->fOffset = outerVec;
|
||||
verts->fDistanceCorrection = distanceCorrection;
|
||||
verts++;
|
||||
|
||||
verts->fPos = SkPoint::Make(xInner[i], yOuter[i]);
|
||||
verts->fColor = color;
|
||||
verts->fOffset = SkVector::Make(0, -1);
|
||||
verts->fDistanceCorrection = distanceCorrection;
|
||||
verts++;
|
||||
}
|
||||
|
||||
// Add the additional vertices for overstroked rrects.
|
||||
// Effectively this is an additional stroked rrect, with its
|
||||
// outer radius = outerRadius - innerRadius, and inner radius = 0.
|
||||
// This will give us correct AA in the center and the correct
|
||||
// distance to the outer edge.
|
||||
//
|
||||
// Also, the outer offset is a constant vector pointing to the right, which
|
||||
// guarantees that the distance value along the outer rectangle is constant.
|
||||
// parameters equal to those in the center of the 9-patch. This will
|
||||
// give constant values across this inner ring.
|
||||
if (kOverstroke_RRectType == args.fType) {
|
||||
SkASSERT(args.fInnerRadius <= 0.0f);
|
||||
SkASSERT(args.fOverstroke > 0.0f);
|
||||
|
||||
SkScalar overstrokeOuterRadius = outerRadius - args.fInnerRadius;
|
||||
// this is the normalized distance from the outer rectangle of this
|
||||
// geometry to the outer edge
|
||||
SkScalar maxOffset = -args.fInnerRadius / overstrokeOuterRadius;
|
||||
|
||||
FillInOverstrokeVerts(&verts, bounds, outerRadius, overstrokeOuterRadius, maxOffset,
|
||||
overstrokeOuterRadius, color, blurRadius);
|
||||
}
|
||||
|
||||
if (kFill_RRectType == args.fType) {
|
||||
SkScalar halfMinDim = 0.5f * SkTMin(bounds.width(), bounds.height());
|
||||
|
||||
SkScalar xOffset = 1.0f - outerRadius / halfMinDim;
|
||||
|
||||
FillInOverstrokeVerts(&verts, bounds, outerRadius, halfMinDim, xOffset, halfMinDim,
|
||||
color, blurRadius);
|
||||
FillInOverstrokeVerts(&verts, bounds, umbraInset + args.fOverstroke,
|
||||
color, distanceCorrection);
|
||||
}
|
||||
|
||||
const uint16_t* primIndices = rrect_type_to_indices(args.fType);
|
||||
@ -792,7 +777,8 @@ private:
|
||||
struct Geometry {
|
||||
GrColor fColor;
|
||||
SkScalar fOuterRadius;
|
||||
SkScalar fInnerRadius;
|
||||
SkScalar fUmbraInset;
|
||||
SkScalar fOverstroke;
|
||||
SkScalar fBlurRadius;
|
||||
SkRect fDevBounds;
|
||||
RRectType fType;
|
||||
@ -839,9 +825,9 @@ static std::unique_ptr<GrLegacyMeshDrawOp> make_shadow_rrect_op(GrColor color,
|
||||
|
||||
SkVector radii = rrect.getSimpleRadii();
|
||||
SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX] * radii.fX +
|
||||
viewMatrix[SkMatrix::kMSkewY] * radii.fY);
|
||||
SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX] * radii.fX +
|
||||
viewMatrix[SkMatrix::kMScaleY] * radii.fY);
|
||||
viewMatrix[SkMatrix::kMSkewX] * radii.fY);
|
||||
SkDEBUGCODE(SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewY] * radii.fX +
|
||||
viewMatrix[SkMatrix::kMScaleY] * radii.fY));
|
||||
SkASSERT(SkScalarNearlyEqual(xRadius, yRadius));
|
||||
|
||||
SkStrokeRec::Style style = stroke.getStyle();
|
||||
@ -859,9 +845,9 @@ static std::unique_ptr<GrLegacyMeshDrawOp> make_shadow_rrect_op(GrColor color,
|
||||
scaledStroke.set(1, 1);
|
||||
} else {
|
||||
scaledStroke.fX = SkScalarAbs(
|
||||
strokeWidth * (viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewY]));
|
||||
strokeWidth * (viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewY]));
|
||||
scaledStroke.fY = SkScalarAbs(
|
||||
strokeWidth * (viewMatrix[SkMatrix::kMSkewX] + viewMatrix[SkMatrix::kMScaleY]));
|
||||
strokeWidth * (viewMatrix[SkMatrix::kMSkewX] + viewMatrix[SkMatrix::kMScaleY]));
|
||||
}
|
||||
|
||||
// we don't handle anisotropic strokes
|
||||
@ -875,7 +861,7 @@ static std::unique_ptr<GrLegacyMeshDrawOp> make_shadow_rrect_op(GrColor color,
|
||||
// patch will have fractional coverage. This only matters when the interior is actually filled.
|
||||
// We could consider falling back to rect rendering here, since a tiny radius is
|
||||
// indistinguishable from a square corner.
|
||||
if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
|
||||
if (!isStrokeOnly && SK_ScalarHalf > xRadius) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -778,7 +778,7 @@ SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMat
|
||||
// if the umbra would collapse, we back off a bit on inner blur and adjust the alpha
|
||||
SkScalar newRadius = SkScalarSqrt(minDistSq) - kTolerance;
|
||||
fOffsetAdjust = newRadius - radius;
|
||||
SkScalar ratio = 256 * newRadius / radius;
|
||||
SkScalar ratio = 128 * (newRadius + radius) / radius;
|
||||
// they aren't PMColors, but the interpolation algorithm is the same
|
||||
fUmbraColor = SkPMLerp(fUmbraColor, fPenumbraColor, (unsigned)ratio);
|
||||
radius = newRadius;
|
||||
|
@ -454,33 +454,79 @@ void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, S
|
||||
}
|
||||
}
|
||||
|
||||
static bool draw_analytic_shadows(SkCanvas* canvas, const SkPath& path, SkScalar occluderZ,
|
||||
const SkPoint3& devLightPos, SkScalar lightRadius,
|
||||
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
|
||||
uint32_t flags) {
|
||||
SkRect rect;
|
||||
SkRRect rrect;
|
||||
if (canvas->getTotalMatrix().isSimilarity()) {
|
||||
if (path.isRect(&rect)) {
|
||||
SkPaint newPaint;
|
||||
newPaint.setColor(color);
|
||||
if (ambientAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
|
||||
ambientAlpha, flags));
|
||||
canvas->drawRect(rect, newPaint);
|
||||
}
|
||||
if (spotAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
|
||||
lightRadius, spotAlpha,
|
||||
flags));
|
||||
canvas->drawRect(rect, newPaint);
|
||||
}
|
||||
return true;
|
||||
} else if (path.isRRect(&rrect) && rrect.isSimpleCircular() &&
|
||||
rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero) {
|
||||
SkPaint newPaint;
|
||||
newPaint.setColor(color);
|
||||
if (ambientAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
|
||||
ambientAlpha, flags));
|
||||
canvas->drawRRect(rrect, newPaint);
|
||||
}
|
||||
if (spotAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
|
||||
lightRadius, spotAlpha,
|
||||
flags));
|
||||
canvas->drawRRect(rrect, newPaint);
|
||||
}
|
||||
return true;
|
||||
} else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
|
||||
rect.width() > SK_ScalarNearlyZero) {
|
||||
SkPaint newPaint;
|
||||
newPaint.setColor(color);
|
||||
if (ambientAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
|
||||
ambientAlpha, flags));
|
||||
canvas->drawOval(rect, newPaint);
|
||||
}
|
||||
if (spotAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
|
||||
lightRadius, spotAlpha,
|
||||
flags));
|
||||
canvas->drawOval(rect, newPaint);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Draw an offset spot shadow and outlining ambient shadow for the given path.
|
||||
void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight,
|
||||
const SkPoint3& devLightPos, SkScalar lightRadius,
|
||||
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
|
||||
uint32_t flags, SkResourceCache* cache) {
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
SkMatrix viewMatrix = canvas->getTotalMatrix();
|
||||
|
||||
// try circular fast path
|
||||
SkRect rect;
|
||||
if (viewMatrix.isSimilarity() &&
|
||||
path.isOval(&rect) && rect.width() == rect.height()) {
|
||||
SkPaint newPaint;
|
||||
newPaint.setColor(color);
|
||||
if (ambientAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderHeight, ambientAlpha,
|
||||
flags));
|
||||
canvas->drawOval(rect, newPaint);
|
||||
}
|
||||
if (spotAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderHeight, devLightPos,
|
||||
lightRadius, spotAlpha, flags));
|
||||
canvas->drawOval(rect, newPaint);
|
||||
}
|
||||
// try fast paths
|
||||
if (draw_analytic_shadows(canvas, path, occluderHeight, devLightPos, lightRadius,
|
||||
ambientAlpha, spotAlpha, color, flags)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
SkMatrix viewMatrix = canvas->getTotalMatrix();
|
||||
canvas->resetMatrix();
|
||||
|
||||
ShadowedPath shadowedPath(&path, &viewMatrix);
|
||||
@ -563,28 +609,14 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
|
||||
const SkPoint3& lightPos, SkScalar lightRadius,
|
||||
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
|
||||
uint32_t flags) {
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
SkMatrix viewMatrix = canvas->getTotalMatrix();
|
||||
|
||||
// try circular fast path
|
||||
SkRect rect;
|
||||
if (viewMatrix.isSimilarity() &&
|
||||
path.isOval(&rect) && rect.width() == rect.height()) {
|
||||
SkPaint newPaint;
|
||||
newPaint.setColor(color);
|
||||
if (ambientAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(heightFunc(0,0), ambientAlpha,
|
||||
flags));
|
||||
canvas->drawOval(rect, newPaint);
|
||||
}
|
||||
if (spotAlpha > 0) {
|
||||
newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(heightFunc(0,0), lightPos,
|
||||
lightRadius, spotAlpha, flags));
|
||||
canvas->drawOval(rect, newPaint);
|
||||
}
|
||||
// try fast paths
|
||||
if (draw_analytic_shadows(canvas, path, heightFunc(0, 0), lightPos, lightRadius,
|
||||
ambientAlpha, spotAlpha, color, flags)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
SkMatrix viewMatrix = canvas->getTotalMatrix();
|
||||
canvas->resetMatrix();
|
||||
|
||||
bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
|
||||
|
Loading…
Reference in New Issue
Block a user