blob: b103880d21fb02cb54916366db480cc8eb821fe5 [file] [log] [blame]
bsalomon@google.comffca4002011-02-22 20:34:01 +00001#include "GrPathRenderer.h"
2
3#include "GrPoint.h"
4#include "GrDrawTarget.h"
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +00005#include "GrPathUtils.h"
bsalomon@google.comffca4002011-02-22 20:34:01 +00006#include "GrTexture.h"
7
tomhudson@google.com278cbb42011-06-30 19:37:01 +00008#include "SkString.h"
bsalomon@google.com3582bf92011-06-30 21:32:31 +00009#include "SkTemplates.h"
10
tomhudson@google.com278cbb42011-06-30 19:37:01 +000011#include SK_USER_TRACE_INCLUDE_FILE
12
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000013GrPathRenderer::GrPathRenderer()
bsalomon@google.comee435122011-07-01 14:57:55 +000014 : fCurveTolerance (GR_Scalar1)
15 , fPath(NULL)
16 , fTarget(NULL) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017}
bsalomon@google.comee435122011-07-01 14:57:55 +000018
19
20void GrPathRenderer::setPath(GrDrawTarget* target,
21 const SkPath* path,
22 GrPathFill fill,
23 const GrPoint* translate) {
24 GrAssert(NULL == fPath);
25 GrAssert(NULL == fTarget);
26 GrAssert(NULL != target);
27
28 fTarget = target;
29 fPath = path;
30 fFill = fill;
31 if (NULL != translate) {
32 fTranslate = *translate;
33 } else {
34 fTranslate.fX = fTranslate.fY = 0;
35 }
36 this->pathWasSet();
37}
38
39void GrPathRenderer::clearPath() {
40 this->pathWillClear();
41 fTarget->resetVertexSource();
42 fTarget = NULL;
43 fPath = NULL;
44}
45
46////////////////////////////////////////////////////////////////////////////////
47
bsalomon@google.comd302f142011-03-03 13:54:13 +000048GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
49 bool stencilWrapOpsSupport)
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000050 : fSeparateStencil(separateStencilSupport)
bsalomon@google.comee435122011-07-01 14:57:55 +000051 , fStencilWrapOps(stencilWrapOpsSupport)
52 , fSubpathCount(0)
53 , fSubpathVertCount(0)
54 , fPreviousSrcTol(-GR_Scalar1)
55 , fPreviousStages(-1) {
56 fTarget = NULL;
bsalomon@google.comffca4002011-02-22 20:34:01 +000057}
58
59////////////////////////////////////////////////////////////////////////////////
bsalomon@google.comd302f142011-03-03 13:54:13 +000060// Stencil rules for paths
61
62////// Even/Odd
63
64static const GrStencilSettings gEOStencilPass = {
65 kInvert_StencilOp, kInvert_StencilOp,
66 kKeep_StencilOp, kKeep_StencilOp,
67 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
68 0xffffffff, 0xffffffff,
69 0xffffffff, 0xffffffff,
70 0xffffffff, 0xffffffff
71};
72
73// ok not to check clip b/c stencil pass only wrote inside clip
74static const GrStencilSettings gEOColorPass = {
75 kZero_StencilOp, kZero_StencilOp,
76 kZero_StencilOp, kZero_StencilOp,
77 kNotEqual_StencilFunc, kNotEqual_StencilFunc,
78 0xffffffff, 0xffffffff,
79 0x0, 0x0,
80 0xffffffff, 0xffffffff
81};
82
83// have to check clip b/c outside clip will always be zero.
84static const GrStencilSettings gInvEOColorPass = {
85 kZero_StencilOp, kZero_StencilOp,
86 kZero_StencilOp, kZero_StencilOp,
87 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
88 0xffffffff, 0xffffffff,
89 0x0, 0x0,
90 0xffffffff, 0xffffffff
91};
92
93////// Winding
94
95// when we have separate stencil we increment front faces / decrement back faces
96// when we don't have wrap incr and decr we use the stencil test to simulate
97// them.
98
99static const GrStencilSettings gWindStencilSeparateWithWrap = {
100 kIncWrap_StencilOp, kDecWrap_StencilOp,
101 kKeep_StencilOp, kKeep_StencilOp,
102 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
103 0xffffffff, 0xffffffff,
104 0xffffffff, 0xffffffff,
105 0xffffffff, 0xffffffff
106};
107
108// if inc'ing the max value, invert to make 0
109// if dec'ing zero invert to make all ones.
110// we can't avoid touching the stencil on both passing and
111// failing, so we can't resctrict ourselves to the clip.
112static const GrStencilSettings gWindStencilSeparateNoWrap = {
113 kInvert_StencilOp, kInvert_StencilOp,
114 kIncClamp_StencilOp, kDecClamp_StencilOp,
115 kEqual_StencilFunc, kEqual_StencilFunc,
116 0xffffffff, 0xffffffff,
117 0xffffffff, 0x0,
118 0xffffffff, 0xffffffff
119};
120
121// When there are no separate faces we do two passes to setup the winding rule
122// stencil. First we draw the front faces and inc, then we draw the back faces
123// and dec. These are same as the above two split into the incrementing and
124// decrementing passes.
125static const GrStencilSettings gWindSingleStencilWithWrapInc = {
126 kIncWrap_StencilOp, kIncWrap_StencilOp,
127 kKeep_StencilOp, kKeep_StencilOp,
128 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
129 0xffffffff, 0xffffffff,
130 0xffffffff, 0xffffffff,
131 0xffffffff, 0xffffffff
132};
133static const GrStencilSettings gWindSingleStencilWithWrapDec = {
134 kDecWrap_StencilOp, kDecWrap_StencilOp,
135 kKeep_StencilOp, kKeep_StencilOp,
136 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
137 0xffffffff, 0xffffffff,
138 0xffffffff, 0xffffffff,
139 0xffffffff, 0xffffffff
140};
141static const GrStencilSettings gWindSingleStencilNoWrapInc = {
142 kInvert_StencilOp, kInvert_StencilOp,
143 kIncClamp_StencilOp, kIncClamp_StencilOp,
144 kEqual_StencilFunc, kEqual_StencilFunc,
145 0xffffffff, 0xffffffff,
146 0xffffffff, 0xffffffff,
147 0xffffffff, 0xffffffff
148};
149static const GrStencilSettings gWindSingleStencilNoWrapDec = {
150 kInvert_StencilOp, kInvert_StencilOp,
151 kDecClamp_StencilOp, kDecClamp_StencilOp,
152 kEqual_StencilFunc, kEqual_StencilFunc,
153 0xffffffff, 0xffffffff,
154 0x0, 0x0,
155 0xffffffff, 0xffffffff
156};
157
158static const GrStencilSettings gWindColorPass = {
159 kZero_StencilOp, kZero_StencilOp,
160 kZero_StencilOp, kZero_StencilOp,
161 kNonZeroIfInClip_StencilFunc, kNonZeroIfInClip_StencilFunc,
162 0xffffffff, 0xffffffff,
163 0x0, 0x0,
164 0xffffffff, 0xffffffff
165};
166
167static const GrStencilSettings gInvWindColorPass = {
168 kZero_StencilOp, kZero_StencilOp,
169 kZero_StencilOp, kZero_StencilOp,
170 kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
171 0xffffffff, 0xffffffff,
172 0x0, 0x0,
173 0xffffffff, 0xffffffff
174};
175
176////// Normal render to stencil
177
178// Sometimes the default path renderer can draw a path directly to the stencil
179// buffer without having to first resolve the interior / exterior.
180static const GrStencilSettings gDirectToStencil = {
181 kZero_StencilOp, kZero_StencilOp,
182 kIncClamp_StencilOp, kIncClamp_StencilOp,
183 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
184 0xffffffff, 0xffffffff,
185 0x0, 0x0,
186 0xffffffff, 0xffffffff
187};
188
189////////////////////////////////////////////////////////////////////////////////
190// Helpers for drawPath
bsalomon@google.comffca4002011-02-22 20:34:01 +0000191
reed@google.com07f3ee12011-05-16 17:21:57 +0000192static GrConvexHint getConvexHint(const SkPath& path) {
193 return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
194}
195
bsalomon@google.comffca4002011-02-22 20:34:01 +0000196#define STENCIL_OFF 0 // Always disable stencil (even when needed)
bsalomon@google.comffca4002011-02-22 20:34:01 +0000197
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000198static inline bool single_pass_path(const GrDrawTarget& target,
reed@google.com07f3ee12011-05-16 17:21:57 +0000199 const GrPath& path,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000200 GrPathFill fill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000201#if STENCIL_OFF
202 return true;
203#else
204 if (kEvenOdd_PathFill == fill) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000205 GrConvexHint hint = getConvexHint(path);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000206 return hint == kConvex_ConvexHint ||
207 hint == kNonOverlappingConvexPieces_ConvexHint;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000208 } else if (kWinding_PathFill == fill) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000209 GrConvexHint hint = getConvexHint(path);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000210 return hint == kConvex_ConvexHint ||
211 hint == kNonOverlappingConvexPieces_ConvexHint ||
212 (hint == kSameWindingConvexPieces_ConvexHint &&
bsalomon@google.comffca4002011-02-22 20:34:01 +0000213 target.canDisableBlend() && !target.isDitherState());
214
215 }
216 return false;
217#endif
218}
219
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000220bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +0000221 const GrPath& path,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000222 GrPathFill fill) const {
reed@google.com07f3ee12011-05-16 17:21:57 +0000223 return !single_pass_path(*target, path, fill);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000224}
225
bsalomon@google.comee435122011-07-01 14:57:55 +0000226void GrDefaultPathRenderer::pathWillClear() {
227 fSubpathVertCount.realloc(0);
228 fTarget->resetVertexSource();
229 fPreviousSrcTol = -GR_Scalar1;
230 fPreviousStages = -1;
231}
232
233void GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
234 GrDrawTarget::StageBitfield stages) {
235 {
236 SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
237
238 fPreviousSrcTol = srcSpaceTol;
239 fPreviousStages = stages;
240
241 GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
242 int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
243 srcSpaceTol);
244
245 GrVertexLayout layout = 0;
246 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
247 if ((1 << s) & stages) {
248 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
249 }
250 }
251
252 // add 4 to hold the bounding rect
253 GrPoint* base;
254 fTarget->reserveVertexSpace(layout, maxPts + 4, (void**)&base);
255
256 GrPoint* vert = base;
257 GrPoint* subpathBase = base;
258
259 fSubpathVertCount.realloc(fSubpathCount);
260
261 GrPoint pts[4];
262
263 bool first = true;
264 int subpath = 0;
265
266 SkPath::Iter iter(*fPath, false);
267
268 for (;;) {
269 GrPathCmd cmd = (GrPathCmd)iter.next(pts);
270 switch (cmd) {
271 case kMove_PathCmd:
272 if (!first) {
273 fSubpathVertCount[subpath] = vert-subpathBase;
274 subpathBase = vert;
275 ++subpath;
276 }
277 *vert = pts[0];
278 vert++;
279 break;
280 case kLine_PathCmd:
281 *vert = pts[1];
282 vert++;
283 break;
284 case kQuadratic_PathCmd: {
285 GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
286 srcSpaceTolSqd, &vert,
287 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
288 break;
289 }
290 case kCubic_PathCmd: {
291 GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
292 srcSpaceTolSqd, &vert,
293 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
294 break;
295 }
296 case kClose_PathCmd:
297 break;
298 case kEnd_PathCmd:
299 fSubpathVertCount[subpath] = vert-subpathBase;
300 ++subpath; // this could be only in debug
301 goto FINISHED;
302 }
303 first = false;
304 }
305FINISHED:
306 GrAssert(subpath == fSubpathCount);
307 GrAssert((vert - base) <= maxPts);
308
309 if (fTranslate.fX || fTranslate.fY) {
310 int count = vert - base;
311 for (int i = 0; i < count; i++) {
312 base[i].offset(fTranslate.fX, fTranslate.fY);
313 }
314 }
315 }
316}
317
318void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000319 bool stencilOnly) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000320
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000321 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
322 "points", SkStringPrintf("%i", path.countPoints()).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000323
bsalomon@google.comee435122011-07-01 14:57:55 +0000324 GrMatrix viewM = fTarget->getViewMatrix();
bsalomon@google.comffca4002011-02-22 20:34:01 +0000325 // In order to tesselate the path we get a bound on how much the matrix can
326 // stretch when mapping to screen coordinates.
327 GrScalar stretch = viewM.getMaxStretch();
328 bool useStretch = stretch > 0;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000329 GrScalar tol = fCurveTolerance;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000330
331 if (!useStretch) {
332 // TODO: deal with perspective in some better way.
333 tol /= 10;
334 } else {
bungeman@google.com8c5753e2011-05-20 19:11:50 +0000335 tol = GrScalarDiv(tol, stretch);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000336 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000337 // FIXME: It's really dumb that we recreate the verts for a new vertex
338 // layout. We only do that because the GrDrawTarget API doesn't allow
339 // us to change the vertex layout after reserveVertexSpace(). We won't
340 // actually change the vertex data when the layout changes since all the
341 // stages reference the positions (rather than having separate tex coords)
342 // and we don't ever have per-vert colors. In practice our call sites
343 // won't change the stages in use inside a setPath / removePath pair. But
344 // it is a silly limitation of the GrDrawTarget design that should be fixed.
345 if (tol != fPreviousSrcTol ||
346 stages != fPreviousStages) {
347 this->createGeom(tol, stages);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000348 }
349
bsalomon@google.comee435122011-07-01 14:57:55 +0000350 GrAssert(NULL != fTarget);
351 GrDrawTarget::AutoStateRestore asr(fTarget);
352 bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
353 // face culling doesn't make sense here
354 GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000355
bsalomon@google.comffca4002011-02-22 20:34:01 +0000356 GrPrimitiveType type;
357 int passCount = 0;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000358 const GrStencilSettings* passes[3];
359 GrDrawTarget::DrawFace drawFace[3];
bsalomon@google.comffca4002011-02-22 20:34:01 +0000360 bool reverse = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000361 bool lastPassIsBounds;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000362
bsalomon@google.comee435122011-07-01 14:57:55 +0000363 if (kHairLine_PathFill == fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000364 type = kLineStrip_PrimitiveType;
365 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000366 if (stencilOnly) {
367 passes[0] = &gDirectToStencil;
368 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000369 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000370 }
371 lastPassIsBounds = false;
372 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000373 } else {
374 type = kTriangleFan_PrimitiveType;
bsalomon@google.comee435122011-07-01 14:57:55 +0000375 if (single_pass_path(*fTarget, *fPath, fFill)) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000376 passCount = 1;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000377 if (stencilOnly) {
378 passes[0] = &gDirectToStencil;
379 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000380 passes[0] = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000381 }
382 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
383 lastPassIsBounds = false;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000384 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000385 switch (fFill) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000386 case kInverseEvenOdd_PathFill:
387 reverse = true;
388 // fallthrough
389 case kEvenOdd_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000390 passes[0] = &gEOStencilPass;
391 if (stencilOnly) {
392 passCount = 1;
393 lastPassIsBounds = false;
394 } else {
395 passCount = 2;
396 lastPassIsBounds = true;
397 if (reverse) {
398 passes[1] = &gInvEOColorPass;
399 } else {
400 passes[1] = &gEOColorPass;
401 }
402 }
403 drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000404 break;
405
406 case kInverseWinding_PathFill:
407 reverse = true;
408 // fallthrough
409 case kWinding_PathFill:
bsalomon@google.comd302f142011-03-03 13:54:13 +0000410 if (fSeparateStencil) {
411 if (fStencilWrapOps) {
412 passes[0] = &gWindStencilSeparateWithWrap;
413 } else {
414 passes[0] = &gWindStencilSeparateNoWrap;
415 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000416 passCount = 2;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000417 drawFace[0] = GrDrawTarget::kBoth_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000418 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000419 if (fStencilWrapOps) {
420 passes[0] = &gWindSingleStencilWithWrapInc;
421 passes[1] = &gWindSingleStencilWithWrapDec;
422 } else {
423 passes[0] = &gWindSingleStencilNoWrapInc;
424 passes[1] = &gWindSingleStencilNoWrapDec;
425 }
426 // which is cw and which is ccw is arbitrary.
427 drawFace[0] = GrDrawTarget::kCW_DrawFace;
428 drawFace[1] = GrDrawTarget::kCCW_DrawFace;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000429 passCount = 3;
430 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000431 if (stencilOnly) {
432 lastPassIsBounds = false;
433 --passCount;
434 } else {
435 lastPassIsBounds = true;
436 drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
437 if (reverse) {
438 passes[passCount-1] = &gInvWindColorPass;
439 } else {
440 passes[passCount-1] = &gWindColorPass;
441 }
442 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000443 break;
444 default:
bsalomon@google.comee435122011-07-01 14:57:55 +0000445 GrAssert(!"Unknown path fFill!");
bsalomon@google.comffca4002011-02-22 20:34:01 +0000446 return;
447 }
448 }
449 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000450
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000451 {
452 SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
453 "verts", SkStringPrintf("%i", vert - base).c_str());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000454 for (int p = 0; p < passCount; ++p) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000455 fTarget->setDrawFace(drawFace[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000456 if (NULL != passes[p]) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000457 fTarget->setStencil(*passes[p]);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000458 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000459
460 if (lastPassIsBounds && (p == passCount-1)) {
461 if (!colorWritesWereDisabled) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000462 fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000463 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000464 GrRect bounds;
465 if (reverse) {
466 GrAssert(NULL != fTarget->getRenderTarget());
467 // draw over the whole world.
468 bounds.setLTRB(0, 0,
469 GrIntToScalar(fTarget->getRenderTarget()->width()),
470 GrIntToScalar(fTarget->getRenderTarget()->height()));
471 GrMatrix vmi;
472 if (fTarget->getViewInverse(&vmi)) {
473 vmi.mapRect(&bounds);
474 }
475 } else {
476 bounds = fPath->getBounds();
477 }
478 GrDrawTarget::AutoGeometryPush agp(fTarget);
479 fTarget->drawSimpleRect(bounds, NULL, stages);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000480 } else {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000481 if (passCount > 1) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000482 fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000483 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000484 int baseVertex = 0;
bsalomon@google.comee435122011-07-01 14:57:55 +0000485 for (int sp = 0; sp < fSubpathCount; ++sp) {
486 fTarget->drawNonIndexed(type, baseVertex,
487 fSubpathVertCount[sp]);
488 baseVertex += fSubpathVertCount[sp];
bsalomon@google.comffca4002011-02-22 20:34:01 +0000489 }
490 }
491 }
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000492 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000493}
bsalomon@google.comd302f142011-03-03 13:54:13 +0000494
bsalomon@google.comee435122011-07-01 14:57:55 +0000495void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
496 this->onDrawPath(stages, false);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000497}
498
bsalomon@google.comee435122011-07-01 14:57:55 +0000499void GrDefaultPathRenderer::drawPathToStencil() {
500 GrAssert(kInverseEvenOdd_PathFill != fFill);
501 GrAssert(kInverseWinding_PathFill != fFill);
502 this->onDrawPath(0, true);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000503}