aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/effects
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2017-01-27 14:15:54 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-01-27 19:53:18 +0000
commit91af72703830f3946c538b47c6c7c96afc0adde2 (patch)
treef478faca5f38782c9178ca51068ff4fc827f35d3 /src/gpu/effects
parentfe8225802d2ab0dbc6f0d40f9666ebca1b4e2a4a (diff)
Add geometric version of spot shadow
BUG=skia:6119 Change-Id: Ib9770bd88f4eebd68f2d893c5788f966d89f193c Reviewed-on: https://skia-review.googlesource.com/7585 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
Diffstat (limited to 'src/gpu/effects')
-rwxr-xr-xsrc/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp72
-rwxr-xr-xsrc/gpu/effects/GrShadowTessellator.cpp365
-rwxr-xr-xsrc/gpu/effects/GrShadowTessellator.h73
3 files changed, 482 insertions, 28 deletions
diff --git a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
new file mode 100755
index 0000000000..1441a752c8
--- /dev/null
+++ b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "effects/GrBlurredEdgeFragmentProcessor.h"
+#include "GrInvariantOutput.h"
+
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+
+class GLSLBlurredEdgeFP : public GrGLSLFragmentProcessor {
+public:
+ GLSLBlurredEdgeFP() {}
+
+ void emitCode(EmitArgs& args) override {
+
+ GrBlurredEdgeFP::Mode mode = args.fFp.cast<GrBlurredEdgeFP>().mode();
+
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+
+ fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
+ if (!args.fGpImplementsDistanceVector) {
+ fragBuilder->codeAppendf("// assuming interpolant is set in vertex colors\n");
+ fragBuilder->codeAppendf("float factor = 1.0 - color.b;");
+ } else {
+ fragBuilder->codeAppendf("// using distance to edge to compute interpolant\n");
+ fragBuilder->codeAppend("float radius = color.r*256.0*64.0 + color.g*64.0;");
+ fragBuilder->codeAppend("float pad = color.b*64.0;");
+
+ fragBuilder->codeAppendf("float factor = 1.0 - clamp((%s.z - pad)/radius, 0.0, 1.0);",
+ fragBuilder->distanceVectorName());
+ }
+ switch (mode) {
+ case GrBlurredEdgeFP::kGaussian_Mode:
+ fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
+ break;
+ case GrBlurredEdgeFP::kSmoothstep_Mode:
+ fragBuilder->codeAppend("factor = smoothstep(factor, 0.0, 1.0);");
+ break;
+ }
+ fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.a);",
+ args.fOutputColor);
+ }
+
+protected:
+ void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {}
+
+ GrBlurredEdgeFP::Mode fMode;
+};
+
+GrGLSLFragmentProcessor* GrBlurredEdgeFP::onCreateGLSLInstance() const {
+ return new GLSLBlurredEdgeFP();
+}
+
+void GrBlurredEdgeFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+ GrProcessorKeyBuilder* b) const {
+ b->add32(fMode);
+}
+
+bool GrBlurredEdgeFP::onIsEqual(const GrFragmentProcessor& other) const {
+ const GrBlurredEdgeFP& that = other.cast<GrBlurredEdgeFP>();
+ return that.fMode == fMode;
+}
+
+void GrBlurredEdgeFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
+ inout->mulByUnknownFourComponents();
+}
+
+
diff --git a/src/gpu/effects/GrShadowTessellator.cpp b/src/gpu/effects/GrShadowTessellator.cpp
index 8aa91e2f40..a51a66addd 100755
--- a/src/gpu/effects/GrShadowTessellator.cpp
+++ b/src/gpu/effects/GrShadowTessellator.cpp
@@ -39,8 +39,7 @@ static void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScala
*n = SkScalarFloorToInt(steps);
}
-GrAmbientShadowTessellator::GrAmbientShadowTessellator(const SkMatrix& viewMatrix,
- const SkPath& path,
+GrAmbientShadowTessellator::GrAmbientShadowTessellator(const SkPath& path,
SkScalar radius,
GrColor umbraColor,
GrColor penumbraColor,
@@ -74,16 +73,16 @@ GrAmbientShadowTessellator::GrAmbientShadowTessellator(const SkMatrix& viewMatri
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
switch (verb) {
case SkPath::kLine_Verb:
- this->handleLine(viewMatrix, pts[1]);
+ this->handleLine(pts[1]);
break;
case SkPath::kQuad_Verb:
- this->handleQuad(viewMatrix, pts);
+ this->handleQuad(pts);
break;
case SkPath::kCubic_Verb:
- this->handleCubic(viewMatrix, pts);
+ this->handleCubic(pts);
break;
case SkPath::kConic_Verb:
- this->handleConic(viewMatrix, pts, iter.conicWeight());
+ this->handleConic(pts, iter.conicWeight());
break;
case SkPath::kMove_Verb:
case SkPath::kClose_Verb:
@@ -192,15 +191,10 @@ void GrAmbientShadowTessellator::handleLine(const SkPoint& p) {
SkVector normal;
if (compute_normal(fPositions[fPrevInnerIndex], p, fRadius, fDirection, &normal)) {
this->addArc(normal);
- this->addEdge(p, normal);
+ this->finishArcAndAddEdge(p, normal);
}
}
-void GrAmbientShadowTessellator::handleLine(const SkMatrix& m, SkPoint p) {
- m.mapPoints(&p, 1);
- this->handleLine(p);
-}
-
void GrAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) {
int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
fPointBuffer.setReserve(maxCount);
@@ -213,13 +207,7 @@ void GrAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) {
}
}
-void GrAmbientShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
- m.mapPoints(pts, 3);
- this->handleQuad(pts);
-}
-
-void GrAmbientShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
- m.mapPoints(pts, 4);
+void GrAmbientShadowTessellator::handleCubic(SkPoint pts[4]) {
int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
fPointBuffer.setReserve(maxCount);
SkPoint* target = fPointBuffer.begin();
@@ -231,8 +219,7 @@ void GrAmbientShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4])
}
}
-void GrAmbientShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
- m.mapPoints(pts, 3);
+void GrAmbientShadowTessellator::handleConic(SkPoint pts[3], SkScalar w) {
SkAutoConicToQuads quadder;
const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
SkPoint lastPoint = *(quads++);
@@ -268,7 +255,6 @@ void GrAmbientShadowTessellator::addArc(const SkVector& nextNormal) {
}
}
-
void GrAmbientShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
const SkVector& nextNormal) {
// close out previous arc
@@ -309,3 +295,338 @@ void GrAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVecto
fPrevInnerIndex = fPositions.count() - 2;
fPrevNormal = nextNormal;
}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+GrSpotShadowTessellator::GrSpotShadowTessellator(const SkPath& path,
+ SkScalar scale, const SkVector& translate,
+ SkScalar radius,
+ GrColor umbraColor, GrColor penumbraColor,
+ bool /* transparent */)
+ : fRadius(radius)
+ , fUmbraColor(umbraColor)
+ , fPenumbraColor(penumbraColor)
+ , fPrevInnerIndex(-1) {
+
+ // TODO: calculate these better
+ // Outer ring: 3*numPts
+ // Inner ring: numPts
+ fPositions.setReserve(4 * path.countPoints());
+ fColors.setReserve(4 * path.countPoints());
+ // Outer ring: 12*numPts
+ // Inner ring: 0
+ fIndices.setReserve(12 * path.countPoints());
+
+ fInitPoints.setReserve(3);
+
+ fClipPolygon.setReserve(path.countPoints());
+ this->computeClipBounds(path);
+ fCentroid *= scale;
+ fCentroid += translate;
+
+ // walk around the path, tessellate and generate inner and outer rings
+ SkPath::Iter iter(path, true);
+ SkPoint pts[4];
+ SkPath::Verb verb;
+ *fPositions.push() = fCentroid;
+ *fColors.push() = fUmbraColor;
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kLine_Verb:
+ this->handleLine(scale, translate, pts[1]);
+ break;
+ case SkPath::kQuad_Verb:
+ this->handleQuad(scale, translate, pts);
+ break;
+ case SkPath::kCubic_Verb:
+ this->handleCubic(scale, translate, pts);
+ break;
+ case SkPath::kConic_Verb:
+ this->handleConic(scale, translate, pts, iter.conicWeight());
+ break;
+ case SkPath::kMove_Verb:
+ case SkPath::kClose_Verb:
+ case SkPath::kDone_Verb:
+ break;
+ }
+ }
+
+ SkVector normal;
+ if (compute_normal(fPrevPoint, fFirstPoint, fRadius, fDirection,
+ &normal)) {
+ this->addArc(normal);
+
+ // close out previous arc
+ *fPositions.push() = fPrevPoint + normal;
+ *fColors.push() = fPenumbraColor;
+ *fIndices.push() = fPrevInnerIndex;
+ *fIndices.push() = fPositions.count() - 2;
+ *fIndices.push() = fPositions.count() - 1;
+
+ // add final edge
+ *fPositions.push() = fFirstPoint + normal;
+ *fColors.push() = fPenumbraColor;
+
+ *fIndices.push() = fPrevInnerIndex;
+ *fIndices.push() = fPositions.count() - 2;
+ *fIndices.push() = fFirstVertex;
+
+ *fIndices.push() = fPositions.count() - 2;
+ *fIndices.push() = fPositions.count() - 1;
+ *fIndices.push() = fFirstVertex;
+
+ // add to center fan
+ *fIndices.push() = 0;
+ *fIndices.push() = fPrevInnerIndex;
+ *fIndices.push() = fFirstVertex;
+ }
+
+ // final fan
+ if (fPositions.count() >= 3) {
+ fPrevInnerIndex = fFirstVertex;
+ fPrevPoint = fFirstPoint;
+ fPrevNormal = normal;
+ this->addArc(fFirstNormal);
+
+ *fIndices.push() = fFirstVertex;
+ *fIndices.push() = fPositions.count() - 1;
+ *fIndices.push() = fFirstVertex + 1;
+ }
+}
+
+void GrSpotShadowTessellator::computeClipBounds(const SkPath& path) {
+ // walk around the path and compute clip polygon
+ // if original path is transparent, will accumulate sum of points for centroid
+ SkPath::Iter iter(path, true);
+ SkPoint pts[4];
+ SkPath::Verb verb;
+
+ fCentroid = SkPoint::Make(0, 0);
+ int centroidCount = 0;
+ fClipPolygon.reset();
+
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ break;
+ case SkPath::kLine_Verb:
+ fCentroid += pts[1];
+ centroidCount++;
+ *fClipPolygon.push() = pts[1];
+ break;
+ case SkPath::kQuad_Verb:
+ fCentroid += pts[1];
+ fCentroid += pts[2];
+ centroidCount += 2;
+ *fClipPolygon.push() = pts[2];
+ break;
+ case SkPath::kConic_Verb:
+ fCentroid += pts[1];
+ fCentroid += pts[2];
+ centroidCount += 2;
+ *fClipPolygon.push() = pts[2];
+ break;
+ case SkPath::kCubic_Verb:
+ fCentroid += pts[1];
+ fCentroid += pts[2];
+ fCentroid += pts[3];
+ centroidCount += 3;
+ *fClipPolygon.push() = pts[3];
+ break;
+ case SkPath::kClose_Verb:
+ break;
+ default:
+ SkDEBUGFAIL("unknown verb");
+ }
+ }
+
+ fCentroid *= SkScalarInvert(centroidCount);
+}
+
+void GrSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate,
+ SkPoint* pts, int count) {
+ // TODO: vectorize
+ for (int i = 0; i < count; ++i) {
+ pts[i] *= scale;
+ pts[i] += xlate;
+ }
+}
+
+void GrSpotShadowTessellator::handleLine(const SkPoint& p) {
+ if (fInitPoints.count() < 2) {
+ *fInitPoints.push() = p;
+ return;
+ }
+
+ if (fInitPoints.count() == 2) {
+ // determine if cw or ccw
+ SkVector v0 = fInitPoints[1] - fInitPoints[0];
+ SkVector v1 = p - fInitPoints[0];
+ SkScalar perpDot = v0.fX*v1.fY - v0.fY*v1.fX;
+ if (SkScalarNearlyZero(perpDot)) {
+ // nearly parallel, just treat as straight line and continue
+ fInitPoints[1] = p;
+ return;
+ }
+
+ // if perpDot > 0, winding is ccw
+ fDirection = (perpDot > 0) ? -1 : 1;
+
+ // add first quad
+ if (!compute_normal(fInitPoints[0], fInitPoints[1], fRadius, fDirection,
+ &fFirstNormal)) {
+ // first two points are incident, make the third point the second and continue
+ fInitPoints[1] = p;
+ return;
+ }
+
+ fFirstPoint = fInitPoints[0];
+ fFirstVertex = fPositions.count();
+ fPrevNormal = fFirstNormal;
+ fPrevPoint = fFirstPoint;
+ fPrevInnerIndex = fFirstVertex;
+
+ this->addInnerPoint(fFirstPoint, fUmbraColor, fRadius);
+ SkPoint newPoint = fFirstPoint + fFirstNormal;
+ *fPositions.push() = newPoint;
+ *fColors.push() = fPenumbraColor;
+ this->addEdge(fInitPoints[1], fFirstNormal);
+
+ // to ensure we skip this block next time
+ *fInitPoints.push() = p;
+ }
+
+ SkVector normal;
+ if (compute_normal(fPrevPoint, p, fRadius, fDirection, &normal)) {
+ this->addArc(normal);
+ this->finishArcAndAddEdge(p, normal);
+ }
+}
+
+void GrSpotShadowTessellator::handleLine(SkScalar scale, const SkVector& xlate, SkPoint p) {
+ this->mapPoints(scale, xlate, &p, 1);
+ this->handleLine(p);
+}
+
+void GrSpotShadowTessellator::handleQuad(const SkPoint pts[3]) {
+ int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
+ fPointBuffer.setReserve(maxCount);
+ SkPoint* target = fPointBuffer.begin();
+ int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
+ kQuadTolerance, &target, maxCount);
+ fPointBuffer.setCount(count);
+ for (int i = 0; i < count; i++) {
+ this->handleLine(fPointBuffer[i]);
+ }
+}
+
+void GrSpotShadowTessellator::handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]) {
+ this->mapPoints(scale, xlate, pts, 3);
+ this->handleQuad(pts);
+}
+
+void GrSpotShadowTessellator::handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]) {
+ this->mapPoints(scale, xlate, pts, 4);
+ int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
+ fPointBuffer.setReserve(maxCount);
+ SkPoint* target = fPointBuffer.begin();
+ int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
+ kCubicTolerance, &target, maxCount);
+ fPointBuffer.setCount(count);
+ for (int i = 0; i < count; i++) {
+ this->handleLine(fPointBuffer[i]);
+ }
+}
+
+void GrSpotShadowTessellator::handleConic(SkScalar scale, const SkVector& xlate,
+ SkPoint pts[3], SkScalar w) {
+ this->mapPoints(scale, xlate, pts, 3);
+ SkAutoConicToQuads quadder;
+ const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
+ SkPoint lastPoint = *(quads++);
+ int count = quadder.countQuads();
+ for (int i = 0; i < count; ++i) {
+ SkPoint quadPts[3];
+ quadPts[0] = lastPoint;
+ quadPts[1] = quads[0];
+ quadPts[2] = i == count - 1 ? pts[2] : quads[1];
+ this->handleQuad(quadPts);
+ lastPoint = quadPts[2];
+ quads += 2;
+ }
+}
+
+void GrSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint, GrColor umbraColor,
+ SkScalar radius) {
+ SkVector v = fCentroid - pathPoint;
+ SkScalar distance = v.length();
+ if (distance < radius) {
+ *fPositions.push() = fCentroid;
+ *fColors.push() = umbraColor; // fix this
+ // TODO: deal with fanning from centroid
+ } else {
+ SkScalar t = radius / distance;
+ v *= t;
+ SkPoint innerPoint = pathPoint + v;
+ *fPositions.push() = innerPoint;
+ *fColors.push() = umbraColor;
+ }
+ fPrevPoint = pathPoint;
+}
+
+void GrSpotShadowTessellator::addArc(const SkVector& nextNormal) {
+ // fill in fan from previous quad
+ SkScalar rotSin, rotCos;
+ int numSteps;
+ compute_radial_steps(fPrevNormal, nextNormal, fRadius, &rotSin, &rotCos, &numSteps);
+ SkVector prevNormal = fPrevNormal;
+ for (int i = 0; i < numSteps; ++i) {
+ SkVector nextNormal;
+ nextNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin;
+ nextNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin;
+ *fPositions.push() = fPrevPoint + nextNormal;
+ *fColors.push() = fPenumbraColor;
+ *fIndices.push() = fPrevInnerIndex;
+ *fIndices.push() = fPositions.count() - 2;
+ *fIndices.push() = fPositions.count() - 1;
+
+ prevNormal = nextNormal;
+ }
+}
+
+void GrSpotShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
+ const SkVector& nextNormal) {
+ // close out previous arc
+ SkPoint newPoint = fPrevPoint + nextNormal;
+ *fPositions.push() = newPoint;
+ *fColors.push() = fPenumbraColor;
+ *fIndices.push() = fPrevInnerIndex;
+ *fIndices.push() = fPositions.count() - 2;
+ *fIndices.push() = fPositions.count() - 1;
+
+ this->addEdge(nextPoint, nextNormal);
+}
+
+void GrSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
+ // add next quad
+ this->addInnerPoint(nextPoint, fUmbraColor, fRadius);
+ SkPoint newPoint = nextPoint + nextNormal;
+ *fPositions.push() = newPoint;
+ *fColors.push() = fPenumbraColor;
+
+ *fIndices.push() = fPrevInnerIndex;
+ *fIndices.push() = fPositions.count() - 3;
+ *fIndices.push() = fPositions.count() - 2;
+
+ *fIndices.push() = fPositions.count() - 3;
+ *fIndices.push() = fPositions.count() - 1;
+ *fIndices.push() = fPositions.count() - 2;
+
+ // add to center fan
+ *fIndices.push() = 0;
+ *fIndices.push() = fPrevInnerIndex;
+ *fIndices.push() = fPositions.count() - 2;
+
+ fPrevInnerIndex = fPositions.count() - 2;
+ fPrevNormal = nextNormal;
+}
diff --git a/src/gpu/effects/GrShadowTessellator.h b/src/gpu/effects/GrShadowTessellator.h
index 6d42f496f7..c2acde72f4 100755
--- a/src/gpu/effects/GrShadowTessellator.h
+++ b/src/gpu/effects/GrShadowTessellator.h
@@ -16,6 +16,8 @@
class SkMatrix;
class SkPath;
+// TODO: derive these two classes from a base class containing common elements
+
/**
* This class generates an ambient shadow for a path by walking the path, outsetting by the
* radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively.
@@ -23,8 +25,8 @@ class SkPath;
*/
class GrAmbientShadowTessellator {
public:
- GrAmbientShadowTessellator(const SkMatrix& viewMatrix, const SkPath& path, SkScalar radius,
- GrColor umbraColor, GrColor penumbraColor, bool transparent);
+ GrAmbientShadowTessellator(const SkPath& path, SkScalar radius, GrColor umbraColor,
+ GrColor penumbraColor, bool transparent);
int vertexCount() { return fPositions.count(); }
SkPoint* positions() { return fPositions.begin(); }
@@ -34,14 +36,12 @@ public:
private:
void handleLine(const SkPoint& p);
- void handleLine(const SkMatrix& m, SkPoint p);
void handleQuad(const SkPoint pts[3]);
- void handleQuad(const SkMatrix& m, SkPoint pts[3]);
- void handleCubic(const SkMatrix& m, SkPoint pts[4]);
+ void handleCubic(SkPoint pts[4]);
- void handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w);
+ void handleConic(SkPoint pts[3], SkScalar w);
void addArc(const SkVector& nextNormal);
void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
@@ -69,4 +69,65 @@ private:
SkTDArray<SkPoint> fPointBuffer;
};
+/**
+ * This class generates an spot shadow for a path by walking the transformed path, further
+ * transforming by the scale and translation, and outsetting and insetting by a radius.
+ * The center will be clipped against the original path unless transparent is true.
+ */
+class GrSpotShadowTessellator {
+public:
+ GrSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate,
+ SkScalar radius, GrColor umbraColor, GrColor penumbraColor,
+ bool transparent);
+
+ int vertexCount() { return fPositions.count(); }
+ SkPoint* positions() { return fPositions.begin(); }
+ GrColor* colors() { return fColors.begin(); }
+ int indexCount() { return fIndices.count(); }
+ uint16_t* indices() { return fIndices.begin(); }
+
+private:
+ void computeClipBounds(const SkPath& path);
+
+ void handleLine(const SkPoint& p);
+ void handleLine(SkScalar scale, const SkVector& xlate, SkPoint p);
+
+ void handleQuad(const SkPoint pts[3]);
+ void handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]);
+
+ void handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]);
+
+ void handleConic(SkScalar scale, const SkVector& xlate, SkPoint pts[3], SkScalar w);
+
+ void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count);
+ void addInnerPoint(const SkPoint& pathPoint, GrColor umbraColor, SkScalar radiusSqd);
+ void addArc(const SkVector& nextNormal);
+ void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
+ void addEdge(const SkVector& nextPoint, const SkVector& nextNormal);
+
+ SkScalar fRadius;
+ GrColor fUmbraColor;
+ GrColor fPenumbraColor;
+
+ SkTDArray<SkPoint> fPositions;
+ SkTDArray<GrColor> fColors;
+ SkTDArray<uint16_t> fIndices;
+
+ int fPrevInnerIndex;
+ SkPoint fPrevPoint;
+ SkVector fPrevNormal;
+ int fFirstVertex;
+ SkPoint fFirstPoint;
+ SkVector fFirstNormal;
+ SkScalar fDirection;
+
+ SkPoint fCentroid;
+ SkTDArray<SkPoint> fClipPolygon;
+
+ // first three points
+ SkTDArray<SkPoint> fInitPoints;
+ // temporary buffer
+ SkTDArray<SkPoint> fPointBuffer;
+};
+
#endif