Remove tonal color from DrawShadow internals

Bug: b/71719631
Change-Id: I676c34dfe5ea9b5e184ea53dd49a8b835d4e8cb6
Reviewed-on: https://skia-review.googlesource.com/95741
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2018-01-18 15:19:13 -05:00 committed by Skia Commit-Bot
parent 8bad7e01ba
commit b1b80f7de4
14 changed files with 143 additions and 145 deletions

View File

@ -65,9 +65,8 @@ protected:
fRec.fZPlaneParams = SkPoint3::Make(0, 0, kElevation);
fRec.fLightPos = SkPoint3::Make(270, 0, 600);
fRec.fLightRadius = 800;
fRec.fAmbientAlpha = 0.1f;
fRec.fSpotAlpha = 0.25f;
fRec.fColor = SK_ColorBLACK;
fRec.fAmbientColor = 0x19000000;
fRec.fSpotColor = 0x40000000;
fRec.fFlags = 0;
if (fTransparent) {
fRec.fFlags |= SkShadowFlags::kTransparentOccluder_ShadowFlag;

View File

@ -159,10 +159,11 @@ private:
// V58: No more 2pt conical flipping.
// V59: No more LocalSpace option on PictureImageFilter
// V60: Remove flags in picture header
// V61: Change SkDrawPictureRec to take two colors rather than two alphas
// Only SKPs within the min/current picture version range (inclusive) can be read.
static const uint32_t MIN_PICTURE_VERSION = 56; // august 2017
static const uint32_t CURRENT_PICTURE_VERSION = 60;
static const uint32_t CURRENT_PICTURE_VERSION = 61;
static bool IsValidPictInfo(const SkPictInfo& info);
static sk_sp<SkPicture> Forwardport(const SkPictInfo&,

View File

@ -16,7 +16,7 @@ enum SkShadowFlags {
kTransparentOccluder_ShadowFlag = 0x01,
/** Don't try to use analytic shadows. */
kGeometricOnly_ShadowFlag = 0x02,
/** Disable use of tonal values when applying color */
/** Disable use of tonal values when applying color (deprecated) */
kDisableTonalColor_ShadowFlag = 0x04,
/** mask for all shadow flags */
kAll_ShadowFlag = 0x07

View File

@ -20,6 +20,30 @@ class SkResourceCache;
class SK_API SkShadowUtils {
public:
/**
* Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
* light. The shadow may be cached, depending on the path type and canvas matrix. If the
* matrix is perspective or the path is volatile, it will not be cached.
*
* @param canvas The canvas on which to draw the shadows.
* @param path The occluder used to generate the shadows.
* @param zPlaneParams Values for the plane function which returns the Z offset of the
* occluder from the canvas based on local x and y values (the current matrix is not applied).
* @param lightPos The 3D position of the light relative to the canvas plane. This is
* independent of the canvas's current matrix.
* @param lightRadius The radius of the disc light.
* @param ambientColor The color of the ambient shadow.
* @param spotColor The color of the spot shadow.
* @param flags Options controlling opaque occluder optimizations and shadow appearance. See
* SkShadowFlags.
*/
static void DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams,
const SkPoint3& lightPos, SkScalar lightRadius,
SkColor ambientColor, SkColor spotColor,
uint32_t flags = SkShadowFlags::kNone_ShadowFlag);
/**
* Deprecated version that uses one color and two alphas, and supports tonal color.
*
* Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
* light. The shadow may be cached, depending on the path type and canvas matrix. If the
* matrix is perspective or the path is volatile, it will not be cached.
@ -37,17 +61,32 @@ public:
* @param flags Options controlling opaque occluder optimizations and shadow appearance. See
* SkShadowFlags.
*/
static void DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams,
static void DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlane,
const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha,
SkScalar spotAlpha, SkColor color,
uint32_t flags = SkShadowFlags::kNone_ShadowFlag);
uint32_t flags = SkShadowFlags::kNone_ShadowFlag) {
SkColor ambientColor;
SkColor spotColor;
if (flags & SkShadowFlags::kDisableTonalColor_ShadowFlag) {
ambientColor = SkColorSetARGB(ambientAlpha*SkColorGetA(color), SkColorGetR(color),
SkColorGetG(color), SkColorGetB(color));
spotColor = SkColorSetARGB(spotAlpha*SkColorGetA(color), SkColorGetR(color),
SkColorGetG(color), SkColorGetB(color));
} else {
SkColor inAmbient = SkColorSetA(color, ambientAlpha*SkColorGetA(color));
SkColor inSpot = SkColorSetA(color, spotAlpha*SkColorGetA(color));
ComputeTonalColors(inAmbient, inSpot, &ambientColor, &spotColor);
}
/**
DrawShadow(canvas, path, zPlane, lightPos, lightRadius, ambientColor, spotColor, flags);
}
/**
* Deprecated version with height value (to be removed when Flutter is updated).
*
* Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
* light.
*
* Deprecated version with height value (to be removed when Flutter is updated).
*
* @param canvas The canvas on which to draw the shadows.
* @param path The occluder used to generate the shadows.
* @param occluderHeight The vertical offset of the occluder from the canvas. This is
@ -70,56 +109,16 @@ public:
color, flags);
}
/**
* Helper routine to compute scale alpha values for one-pass tonal alpha.
*
* The final color we want to emulate is generated by rendering a color shadow (C_rgb) using an
* alpha computed from the color's luminance (C_a), and then a black shadow with alpha (S_a)
* which is an adjusted value of 'a'. Assuming SrcOver, a background color of B_rgb, and
* ignoring edge falloff, this becomes
*
* (C_a - S_a*C_a)*C_rgb + (1 - (S_a + C_a - S_a*C_a))*B_rgb
*
* Since we use premultiplied alpha, this means we can scale the color by (C_a - S_a*C_a) and
* set the alpha to (S_a + C_a - S_a*C_a).
*
* @param r Red value of color
* @param g Green value of color
* @param b Blue value of color
* @param a Alpha value of color
* @param colorScale Factor to scale color values by
* @param tonalAlpha Value to set alpha to
*/
static inline void ComputeTonalColorParams(SkScalar r, SkScalar g, SkScalar b, SkScalar a,
SkScalar* colorScale, SkScalar* tonalAlpha) {
SkScalar max = SkTMax(SkTMax(r, g), b);
SkScalar min = SkTMin(SkTMin(r, g), b);
SkScalar luminance = 0.5f*(max + min);
// We compute a color alpha value based on the luminance of the color, scaled by an
// adjusted alpha value. We want the following properties to match the UX examples
// (assuming a = 0.25) and to ensure that we have reasonable results when the color
// is black and/or the alpha is 0:
// f(0, a) = 0
// f(luminance, 0) = 0
// f(1, 0.25) = .5
// f(0.5, 0.25) = .4
// f(1, 1) = 1
// The following functions match this as closely as possible.
SkScalar alphaAdjust = (2.6f + (-2.66667f + 1.06667f*a)*a)*a;
SkScalar colorAlpha = (3.544762f + (-4.891428f + 2.3466f*luminance)*luminance)*luminance;
colorAlpha = SkTPin(alphaAdjust*colorAlpha, 0.0f, 1.0f);
// Similarly, we set the greyscale alpha based on luminance and alpha so that
// f(0, a) = a
// f(luminance, 0) = 0
// f(1, 0.25) = 0.15
SkScalar greyscaleAlpha = SkTPin(a*(1 - 0.4f*luminance), 0.0f, 1.0f);
*colorScale = colorAlpha*(SK_Scalar1 - greyscaleAlpha);
*tonalAlpha = *colorScale + greyscaleAlpha;
}
/**
* Helper routine to compute color values for one-pass tonal alpha.
*
* @param inAmbientColor Original ambient color
* @param inSpotColor Original spot color
* @param outAmbientColor Modified ambient color
* @param outSpotColor Modified spot color
*/
static void ComputeTonalColors(SkColor inAmbientColor, SkColor inSpotColor,
SkColor* outAmbientColor, SkColor* outSpotColor);
};
#endif

View File

@ -238,7 +238,8 @@ public:
}
void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override {
SkDrawShadowRec newRec(rec);
newRec.fColor = fXformer->apply(rec.fColor);
newRec.fAmbientColor = fXformer->apply(rec.fAmbientColor);
newRec.fSpotColor = fXformer->apply(rec.fSpotColor);
fTarget->private_draw_shadow_rec(path, newRec);
}
void onDrawPicture(const SkPicture* pic,

View File

@ -20,9 +20,8 @@ struct SkDrawShadowRec {
SkPoint3 fZPlaneParams;
SkPoint3 fLightPos;
SkScalar fLightRadius;
SkScalar fAmbientAlpha;
SkScalar fSpotAlpha;
SkColor fColor;
SkColor fAmbientColor;
SkColor fSpotColor;
uint32_t fFlags;
};

View File

@ -579,9 +579,16 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
reader->readPoint3(&rec.fZPlaneParams);
reader->readPoint3(&rec.fLightPos);
rec.fLightRadius = reader->readScalar();
rec.fAmbientAlpha = reader->readScalar();
rec.fSpotAlpha = reader->readScalar();
rec.fColor = reader->read32();
if (reader->isVersionLT(SkReadBuffer::kTwoColorDrawShadow_Version)) {
SkScalar ambientAlpha = reader->readScalar();
SkScalar spotAlpha = reader->readScalar();
SkColor color = reader->read32();
rec.fAmbientColor = SkColorSetA(color, SkColorGetA(color)*ambientAlpha);
rec.fSpotColor = SkColorSetA(color, SkColorGetA(color)*spotAlpha);
} else {
rec.fAmbientColor = reader->read32();
rec.fSpotColor = reader->read32();
}
rec.fFlags = reader->read32();
BREAK_ON_READ_ERROR(reader);

View File

@ -795,9 +795,8 @@ void SkPictureRecord::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec&
fWriter.writePoint3(rec.fZPlaneParams);
fWriter.writePoint3(rec.fLightPos);
fWriter.writeScalar(rec.fLightRadius);
fWriter.writeScalar(rec.fAmbientAlpha);
fWriter.writeScalar(rec.fSpotAlpha);
fWriter.write32(rec.fColor);
fWriter.write32(rec.fAmbientColor);
fWriter.write32(rec.fSpotColor);
fWriter.write32(rec.fFlags);
this->validate(initialOffset, size);

View File

@ -77,6 +77,7 @@ public:
k2PtConicalNoFlip_Version = 58,
kRemovePictureImageFilterLocalSpace = 59,
kRemoveHeaderFlags_Version = 60,
kTwoColorDrawShadow_Version = 61,
};
/**

View File

@ -943,7 +943,6 @@ static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
}
bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
GrColor color4ub,
const SkMatrix& viewMatrix,
const SkPath& path,
const SkDrawShadowRec& rec) {
@ -998,11 +997,9 @@ bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
SkScalar occluderHeight = rec.fZPlaneParams.fZ;
GrColor4f color = GrColor4f::FromGrColor(color4ub);
bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
bool tonalColor = !SkToBool(rec.fFlags & SkShadowFlags::kDisableTonalColor_ShadowFlag);
if (rec.fAmbientAlpha > 0) {
if (SkColorGetA(rec.fAmbientColor) > 0) {
SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
@ -1020,13 +1017,7 @@ bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
}
GrColor ambientColor;
if (tonalColor) {
// with tonal color, the color only applies to the spot shadow
ambientColor = GrColorPackRGBA(0, 0, 0, 255.999f*rec.fAmbientAlpha);
} else {
ambientColor = color.mulByScalar(rec.fAmbientAlpha).toGrColor();
}
GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
if (transparent) {
// set a large inset to force a fill
devSpaceInsetWidth = ambientRRect.width();
@ -1044,7 +1035,7 @@ bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
this->addDrawOp(clip, std::move(op));
}
if (rec.fSpotAlpha > 0) {
if (SkColorGetA(rec.fSpotColor) > 0) {
SkScalar devSpaceSpotBlur;
SkScalar spotScale;
SkVector spotOffset;
@ -1129,21 +1120,7 @@ bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
}
GrColor spotColor;
if (tonalColor) {
SkScalar colorScale;
SkScalar tonalAlpha;
SkShadowUtils::ComputeTonalColorParams(color.fRGBA[0], color.fRGBA[1],
color.fRGBA[2], color.fRGBA[3]*rec.fSpotAlpha,
&colorScale, &tonalAlpha);
color.fRGBA[0] *= colorScale;
color.fRGBA[1] *= colorScale;
color.fRGBA[2] *= colorScale;
color.fRGBA[3] = tonalAlpha;
spotColor = color.toGrColor();
} else {
spotColor = color.mulByScalar(rec.fSpotAlpha).toGrColor();
}
GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(spotColor, viewMatrix,
spotShadowRRect,

View File

@ -172,13 +172,11 @@ public:
* Use a fast method to render the ambient and spot shadows for a path.
* Will return false if not possible for the given path.
*
* @param color shadow color.
* @param viewMatrix transformation matrix
* @param path the path to shadow
* @param rec parameters for shadow rendering
*/
bool drawFastShadow(const GrClip&,
GrColor color,
const SkMatrix& viewMatrix,
const SkPath& path,
const SkDrawShadowRec& rec);

View File

@ -1586,8 +1586,7 @@ void SkGpuDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
ASSERT_SINGLE_OWNER
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawShadow", fContext.get());
GrColor color = SkColorToPremulGrColor(rec.fColor);
if (!fRenderTargetContext->drawFastShadow(this->clip(), color, this->ctm(), path, rec)) {
if (!fRenderTargetContext->drawFastShadow(this->clip(), this->ctm(), path, rec)) {
// failed to find an accelerated case
this->INHERITED::drawShadow(path, rec);
}

View File

@ -458,32 +458,65 @@ static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
return result;
}
static SkColor compute_render_color(SkColor color, float alpha, bool useTonalColor) {
if (useTonalColor) {
SkScalar colorScale;
SkScalar tonalAlpha;
SkColor4f color4f = SkColor4f::FromColor(color);
SkShadowUtils::ComputeTonalColorParams(color4f.fR,
color4f.fG,
color4f.fB,
color4f.fA*alpha,
&colorScale, &tonalAlpha);
// After pre-multiplying, we want the alpha to be scaled by tonalAlpha, and
// the color scaled by colorScale. This scale factor gives that.
SkScalar unPremulScale = colorScale / tonalAlpha;
void SkShadowUtils::ComputeTonalColors(SkColor inAmbientColor, SkColor inSpotColor,
SkColor* outAmbientColor, SkColor* outSpotColor) {
// For tonal color we only compute color values for the spot shadow.
// The ambient shadow is greyscale only.
return SkColorSetARGB(tonalAlpha*255.999f, unPremulScale*SkColorGetR(color),
unPremulScale*SkColorGetG(color), unPremulScale*SkColorGetB(color));
}
// Ambient
*outAmbientColor = SkColorSetARGB(SkColorGetA(inAmbientColor), 0, 0, 0);
return SkColorSetARGB(alpha*SkColorGetA(color), SkColorGetR(color),
SkColorGetG(color), SkColorGetB(color));
// Spot
int spotR = SkColorGetR(inSpotColor);
int spotG = SkColorGetG(inSpotColor);
int spotB = SkColorGetB(inSpotColor);
int max = SkTMax(SkTMax(spotR, spotG), spotB);
int min = SkTMin(SkTMin(spotR, spotG), spotB);
SkScalar luminance = 0.5f*(max + min)/255.f;
SkScalar origA = SkColorGetA(inSpotColor)/255.f;
// We compute a color alpha value based on the luminance of the color, scaled by an
// adjusted alpha value. We want the following properties to match the UX examples
// (assuming a = 0.25) and to ensure that we have reasonable results when the color
// is black and/or the alpha is 0:
// f(0, a) = 0
// f(luminance, 0) = 0
// f(1, 0.25) = .5
// f(0.5, 0.25) = .4
// f(1, 1) = 1
// The following functions match this as closely as possible.
SkScalar alphaAdjust = (2.6f + (-2.66667f + 1.06667f*origA)*origA)*origA;
SkScalar colorAlpha = (3.544762f + (-4.891428f + 2.3466f*luminance)*luminance)*luminance;
colorAlpha = SkTPin(alphaAdjust*colorAlpha, 0.0f, 1.0f);
// Similarly, we set the greyscale alpha based on luminance and alpha so that
// f(0, a) = a
// f(luminance, 0) = 0
// f(1, 0.25) = 0.15
SkScalar greyscaleAlpha = SkTPin(origA*(1 - 0.4f*luminance), 0.0f, 1.0f);
// The final color we want to emulate is generated by rendering a color shadow (C_rgb) using an
// alpha computed from the color's luminance (C_a), and then a black shadow with alpha (S_a)
// which is an adjusted value of 'a'. Assuming SrcOver, a background color of B_rgb, and
// ignoring edge falloff, this becomes
//
// (C_a - S_a*C_a)*C_rgb + (1 - (S_a + C_a - S_a*C_a))*B_rgb
//
// Assuming premultiplied alpha, this means we scale the color by (C_a - S_a*C_a) and
// set the alpha to (S_a + C_a - S_a*C_a).
SkScalar colorScale = colorAlpha*(SK_Scalar1 - greyscaleAlpha);
SkScalar tonalAlpha = colorScale + greyscaleAlpha;
SkScalar unPremulScale = colorScale / tonalAlpha;
*outSpotColor = SkColorSetARGB(tonalAlpha*255.999f,
unPremulScale*spotR,
unPremulScale*spotG,
unPremulScale*spotB);
}
// Draw an offset spot shadow and outlining ambient shadow for the given path.
void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams,
const SkPoint3& devLightPos, SkScalar lightRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
SkColor ambientColor, SkColor spotColor,
uint32_t flags) {
SkMatrix inverse;
if (!canvas->getTotalMatrix().invert(&inverse)) {
@ -495,9 +528,8 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
rec.fZPlaneParams = zPlaneParams;
rec.fLightPos = { pt.fX, pt.fY, devLightPos.fZ };
rec.fLightRadius = lightRadius;
rec.fAmbientAlpha = SkScalarToFloat(ambientAlpha);
rec.fSpotAlpha = SkScalarToFloat(spotAlpha);
rec.fColor = color;
rec.fAmbientColor = ambientColor;
rec.fSpotColor = spotColor;
rec.fFlags = flags;
canvas->private_draw_shadow_rec(path, rec);
@ -519,22 +551,12 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
bool tiltZPlane = tilted(rec.fZPlaneParams);
bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
bool uncached = tiltZPlane || path.isVolatile();
bool useTonalColor = !SkToBool(rec.fFlags & kDisableTonalColor_ShadowFlag);
SkColor color = rec.fColor;
SkPoint3 zPlaneParams = rec.fZPlaneParams;
SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
float lightRadius = rec.fLightRadius;
float ambientAlpha = rec.fAmbientAlpha;
if (ambientAlpha > 0) {
ambientAlpha = SkTMin(ambientAlpha, 1.f);
SkColor renderColor;
if (useTonalColor) {
renderColor = compute_render_color(SK_ColorBLACK, ambientAlpha, false);
} else {
renderColor = compute_render_color(color, ambientAlpha, false);
}
if (SkColorGetA(rec.fAmbientColor) > 0) {
if (uncached) {
sk_sp<SkVertices> vertices = SkShadowTessellator::MakeAmbient(path, viewMatrix,
zPlaneParams,
@ -544,7 +566,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
// Run the vertex color through a GaussianColorFilter and then modulate the
// grayscale result of that against our 'color' param.
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkColorFilter::MakeModeFilter(rec.fAmbientColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
}
@ -559,14 +581,11 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
factory.fOffset.fY = viewMatrix.getTranslateY();
}
draw_shadow(factory, drawVertsProc, shadowedPath, renderColor);
draw_shadow(factory, drawVertsProc, shadowedPath, rec.fAmbientColor);
}
}
float spotAlpha = rec.fSpotAlpha;
if (spotAlpha > 0) {
spotAlpha = SkTMin(spotAlpha, 1.f);
SkColor renderColor = compute_render_color(color, spotAlpha, useTonalColor);
if (SkColorGetA(rec.fSpotColor) > 0) {
if (uncached) {
sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix,
zPlaneParams,
@ -577,7 +596,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
// Run the vertex color through a GaussianColorFilter and then modulate the
// grayscale result of that against our 'color' param.
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkColorFilter::MakeModeFilter(rec.fSpotColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
}
@ -627,7 +646,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
break;
}
#endif
draw_shadow(factory, drawVertsProc, shadowedPath, renderColor);
draw_shadow(factory, drawVertsProc, shadowedPath, rec.fSpotColor);
}
}
}

View File

@ -65,9 +65,8 @@ void check_xformed_bounds(skiatest::Reporter* reporter, const SkPath& path, cons
SkPoint3::Make(0, 0, 4),
SkPoint3::Make(100, 0, 600),
800.f,
0.035f,
0.25f,
SK_ColorBLACK,
0x08000000,
0x40000000,
0
};
SkRect bounds;