blob: f80b4d793ff21218f42e75402352af70eefc1e02 [file] [log] [blame]
bsalomon@google.com30085192011-08-19 15:42:31 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "GrDefaultPathRenderer.h"
10
11#include "GrContext.h"
tomhudson@google.com93813632011-10-27 20:21:16 +000012#include "GrDrawState.h"
bsalomon@google.com30085192011-08-19 15:42:31 +000013#include "GrPathUtils.h"
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000014#include "SkString.h"
sugoi@google.com12b4e272012-12-06 20:13:11 +000015#include "SkStroke.h"
bsalomon@google.com30085192011-08-19 15:42:31 +000016#include "SkTrace.h"
17
18
19GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
20 bool stencilWrapOpsSupport)
21 : fSeparateStencil(separateStencilSupport)
bsalomon@google.comc2099d22012-03-02 21:26:50 +000022 , fStencilWrapOps(stencilWrapOpsSupport) {
bsalomon@google.com289533a2011-10-27 12:34:25 +000023}
24
25
bsalomon@google.com30085192011-08-19 15:42:31 +000026////////////////////////////////////////////////////////////////////////////////
27// Stencil rules for paths
28
29////// Even/Odd
30
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000031GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
32 kInvert_StencilOp,
33 kKeep_StencilOp,
34 kAlwaysIfInClip_StencilFunc,
35 0xffff,
36 0xffff,
37 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000038
39// ok not to check clip b/c stencil pass only wrote inside clip
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000040GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
41 kZero_StencilOp,
42 kZero_StencilOp,
43 kNotEqual_StencilFunc,
44 0xffff,
45 0x0000,
46 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000047
48// have to check clip b/c outside clip will always be zero.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000049GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
50 kZero_StencilOp,
51 kZero_StencilOp,
52 kEqualIfInClip_StencilFunc,
53 0xffff,
54 0x0000,
55 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000056
57////// Winding
58
59// when we have separate stencil we increment front faces / decrement back faces
60// when we don't have wrap incr and decr we use the stencil test to simulate
61// them.
62
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000063GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
bsalomon@google.com30085192011-08-19 15:42:31 +000064 kIncWrap_StencilOp, kDecWrap_StencilOp,
65 kKeep_StencilOp, kKeep_StencilOp,
66 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
tomhudson@google.com62b09682011-11-09 16:39:17 +000067 0xffff, 0xffff,
68 0xffff, 0xffff,
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000069 0xffff, 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000070
71// if inc'ing the max value, invert to make 0
72// if dec'ing zero invert to make all ones.
73// we can't avoid touching the stencil on both passing and
74// failing, so we can't resctrict ourselves to the clip.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000075GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
bsalomon@google.com30085192011-08-19 15:42:31 +000076 kInvert_StencilOp, kInvert_StencilOp,
77 kIncClamp_StencilOp, kDecClamp_StencilOp,
78 kEqual_StencilFunc, kEqual_StencilFunc,
tomhudson@google.com62b09682011-11-09 16:39:17 +000079 0xffff, 0xffff,
80 0xffff, 0x0000,
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000081 0xffff, 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000082
83// When there are no separate faces we do two passes to setup the winding rule
84// stencil. First we draw the front faces and inc, then we draw the back faces
85// and dec. These are same as the above two split into the incrementing and
86// decrementing passes.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000087GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
88 kIncWrap_StencilOp,
89 kKeep_StencilOp,
90 kAlwaysIfInClip_StencilFunc,
91 0xffff,
92 0xffff,
93 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000094
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000095GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
96 kDecWrap_StencilOp,
97 kKeep_StencilOp,
98 kAlwaysIfInClip_StencilFunc,
99 0xffff,
100 0xffff,
101 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +0000102
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000103GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
104 kInvert_StencilOp,
105 kIncClamp_StencilOp,
106 kEqual_StencilFunc,
107 0xffff,
108 0xffff,
109 0xffff);
110
111GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
112 kInvert_StencilOp,
113 kDecClamp_StencilOp,
114 kEqual_StencilFunc,
115 0xffff,
116 0x0000,
117 0xffff);
118
119// Color passes are the same whether we use the two-sided stencil or two passes
120
121GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
122 kZero_StencilOp,
123 kZero_StencilOp,
124 kNonZeroIfInClip_StencilFunc,
125 0xffff,
126 0x0000,
127 0xffff);
128
129GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
130 kZero_StencilOp,
131 kZero_StencilOp,
132 kEqualIfInClip_StencilFunc,
133 0xffff,
134 0x0000,
135 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +0000136
137////// Normal render to stencil
138
139// Sometimes the default path renderer can draw a path directly to the stencil
140// buffer without having to first resolve the interior / exterior.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000141GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
142 kZero_StencilOp,
143 kIncClamp_StencilOp,
144 kAlwaysIfInClip_StencilFunc,
145 0xffff,
146 0x0000,
147 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +0000148
149////////////////////////////////////////////////////////////////////////////////
150// Helpers for drawPath
151
bsalomon@google.com30085192011-08-19 15:42:31 +0000152#define STENCIL_OFF 0 // Always disable stencil (even when needed)
153
sugoi@google.com12b4e272012-12-06 20:13:11 +0000154static inline bool single_pass_path(const SkPath& path, const SkStroke& stroke) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000155#if STENCIL_OFF
156 return true;
157#else
sugoi@google.com12b4e272012-12-06 20:13:11 +0000158 if ((0 != stroke.getWidthIfStroked()) && !path.isInverseFillType()) {
bsalomon@google.com7d72c452012-01-30 14:02:44 +0000159 return path.isConvex();
bsalomon@google.com30085192011-08-19 15:42:31 +0000160 }
161 return false;
162#endif
163}
164
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000165bool GrDefaultPathRenderer::requiresStencilPass(const SkPath& path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000166 const SkStroke& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000167 const GrDrawTarget* target) const {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000168 return !single_pass_path(path, stroke);
bsalomon@google.com30085192011-08-19 15:42:31 +0000169}
170
sugoi@google.com12b4e272012-12-06 20:13:11 +0000171static inline void append_countour_edge_indices(bool hairLine,
bsalomon@google.com30085192011-08-19 15:42:31 +0000172 uint16_t fanCenterIdx,
173 uint16_t edgeV0Idx,
174 uint16_t** indices) {
175 // when drawing lines we're appending line segments along
176 // the contour. When applying the other fill rules we're
177 // drawing triangle fans around fanCenterIdx.
sugoi@google.com12b4e272012-12-06 20:13:11 +0000178 if (!hairLine) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000179 *((*indices)++) = fanCenterIdx;
180 }
181 *((*indices)++) = edgeV0Idx;
182 *((*indices)++) = edgeV0Idx + 1;
183}
184
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000185bool GrDefaultPathRenderer::createGeom(const SkPath& path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000186 const SkStroke& stroke,
bsalomon@google.com81712882012-11-01 17:12:34 +0000187 SkScalar srcSpaceTol,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000188 GrDrawTarget* target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000189 GrPrimitiveType* primType,
190 int* vertexCnt,
bsalomon@google.comb3729422012-03-07 19:13:28 +0000191 int* indexCnt,
192 GrDrawTarget::AutoReleaseGeometry* arg) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000193 {
194 SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
195
bsalomon@google.com81712882012-11-01 17:12:34 +0000196 SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000197 int contourCnt;
198 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
bsalomon@google.com30085192011-08-19 15:42:31 +0000199 srcSpaceTol);
200
201 if (maxPts <= 0) {
202 return false;
203 }
204 if (maxPts > ((int)SK_MaxU16 + 1)) {
205 GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
206 return false;
207 }
208
209 GrVertexLayout layout = 0;
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000210 bool indexed = contourCnt > 1;
bsalomon@google.com30085192011-08-19 15:42:31 +0000211
sugoi@google.com12b4e272012-12-06 20:13:11 +0000212 const bool isHairline = 0 == stroke.getWidthIfStroked();
213
bsalomon@google.com30085192011-08-19 15:42:31 +0000214 int maxIdxs = 0;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000215 if (isHairline) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000216 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000217 maxIdxs = 2 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000218 *primType = kLines_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000219 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000220 *primType = kLineStrip_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000221 }
222 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000223 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000224 maxIdxs = 3 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000225 *primType = kTriangles_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000226 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000227 *primType = kTriangleFan_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000228 }
229 }
230
bsalomon@google.comb3729422012-03-07 19:13:28 +0000231
232 if (!arg->set(target, layout, maxPts, maxIdxs)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000233 return false;
234 }
bsalomon@google.comb3729422012-03-07 19:13:28 +0000235
236 uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());;
237 uint16_t* idx = idxBase;
238 uint16_t subpathIdxStart = 0;
239
240 GrPoint* base = reinterpret_cast<GrPoint*>(arg->vertices());
bsalomon@google.com30085192011-08-19 15:42:31 +0000241 GrAssert(NULL != base);
242 GrPoint* vert = base;
243
bsalomon@google.com30085192011-08-19 15:42:31 +0000244 GrPoint pts[4];
245
246 bool first = true;
247 int subpath = 0;
248
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000249 SkPath::Iter iter(path, false);
bsalomon@google.com30085192011-08-19 15:42:31 +0000250
251 for (;;) {
252 GrPathCmd cmd = (GrPathCmd)iter.next(pts);
253 switch (cmd) {
254 case kMove_PathCmd:
255 if (!first) {
256 uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000257 subpathIdxStart = currIdx;
258 ++subpath;
259 }
260 *vert = pts[0];
261 vert++;
262 break;
263 case kLine_PathCmd:
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000264 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000265 uint16_t prevIdx = (uint16_t)(vert - base) - 1;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000266 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000267 prevIdx, &idx);
268 }
269 *(vert++) = pts[1];
270 break;
271 case kQuadratic_PathCmd: {
272 // first pt of quad is the pt we ended on in previous step
273 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000274 uint16_t numPts = (uint16_t)
bsalomon@google.com30085192011-08-19 15:42:31 +0000275 GrPathUtils::generateQuadraticPoints(
276 pts[0], pts[1], pts[2],
277 srcSpaceTolSqd, &vert,
278 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000279 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000280 for (uint16_t i = 0; i < numPts; ++i) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000281 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000282 firstQPtIdx + i, &idx);
283 }
284 }
285 break;
286 }
287 case kCubic_PathCmd: {
288 // first pt of cubic is the pt we ended on in previous step
289 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
290 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
291 pts[0], pts[1], pts[2], pts[3],
292 srcSpaceTolSqd, &vert,
293 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000294 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000295 for (uint16_t i = 0; i < numPts; ++i) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000296 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000297 firstCPtIdx + i, &idx);
298 }
299 }
300 break;
301 }
302 case kClose_PathCmd:
303 break;
304 case kEnd_PathCmd:
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000305 // uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000306 goto FINISHED;
307 }
308 first = false;
309 }
310FINISHED:
311 GrAssert((vert - base) <= maxPts);
312 GrAssert((idx - idxBase) <= maxIdxs);
313
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000314 *vertexCnt = vert - base;
315 *indexCnt = idx - idxBase;
bsalomon@google.com30085192011-08-19 15:42:31 +0000316
bsalomon@google.com30085192011-08-19 15:42:31 +0000317 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000318 return true;
319}
320
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000321bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000322 const SkStroke& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000323 GrDrawTarget* target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000324 bool stencilOnly) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000325
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000326 SkMatrix viewM = target->getDrawState().getViewMatrix();
bsalomon@google.com81712882012-11-01 17:12:34 +0000327 SkScalar tol = SK_Scalar1;
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000328 tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
bsalomon@google.com30085192011-08-19 15:42:31 +0000329
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000330 int vertexCnt;
331 int indexCnt;
332 GrPrimitiveType primType;
bsalomon@google.comb3729422012-03-07 19:13:28 +0000333 GrDrawTarget::AutoReleaseGeometry arg;
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000334 if (!this->createGeom(path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000335 stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000336 tol,
337 target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000338 &primType,
339 &vertexCnt,
bsalomon@google.comb3729422012-03-07 19:13:28 +0000340 &indexCnt,
341 &arg)) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000342 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000343 }
344
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000345 GrAssert(NULL != target);
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000346 GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
347 GrDrawState* drawState = target->drawState();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000348 bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
bsalomon@google.com30085192011-08-19 15:42:31 +0000349 // face culling doesn't make sense here
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000350 GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
bsalomon@google.com30085192011-08-19 15:42:31 +0000351
352 int passCount = 0;
353 const GrStencilSettings* passes[3];
tomhudson@google.com93813632011-10-27 20:21:16 +0000354 GrDrawState::DrawFace drawFace[3];
bsalomon@google.com30085192011-08-19 15:42:31 +0000355 bool reverse = false;
356 bool lastPassIsBounds;
357
sugoi@google.com12b4e272012-12-06 20:13:11 +0000358 if (0 == stroke.getWidthIfStroked()) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000359 passCount = 1;
360 if (stencilOnly) {
361 passes[0] = &gDirectToStencil;
362 } else {
363 passes[0] = NULL;
364 }
365 lastPassIsBounds = false;
tomhudson@google.com93813632011-10-27 20:21:16 +0000366 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000367 } else {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000368 if (single_pass_path(path, stroke)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000369 passCount = 1;
370 if (stencilOnly) {
371 passes[0] = &gDirectToStencil;
372 } else {
373 passes[0] = NULL;
374 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000375 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000376 lastPassIsBounds = false;
377 } else {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000378 switch (path.getFillType()) {
379 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000380 reverse = true;
381 // fallthrough
sugoi@google.com12b4e272012-12-06 20:13:11 +0000382 case SkPath::kEvenOdd_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000383 passes[0] = &gEOStencilPass;
384 if (stencilOnly) {
385 passCount = 1;
386 lastPassIsBounds = false;
387 } else {
388 passCount = 2;
389 lastPassIsBounds = true;
390 if (reverse) {
391 passes[1] = &gInvEOColorPass;
392 } else {
393 passes[1] = &gEOColorPass;
394 }
395 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000396 drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000397 break;
398
sugoi@google.com12b4e272012-12-06 20:13:11 +0000399 case SkPath::kInverseWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000400 reverse = true;
401 // fallthrough
sugoi@google.com12b4e272012-12-06 20:13:11 +0000402 case SkPath::kWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000403 if (fSeparateStencil) {
404 if (fStencilWrapOps) {
405 passes[0] = &gWindStencilSeparateWithWrap;
406 } else {
407 passes[0] = &gWindStencilSeparateNoWrap;
408 }
409 passCount = 2;
tomhudson@google.com93813632011-10-27 20:21:16 +0000410 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000411 } else {
412 if (fStencilWrapOps) {
413 passes[0] = &gWindSingleStencilWithWrapInc;
414 passes[1] = &gWindSingleStencilWithWrapDec;
415 } else {
416 passes[0] = &gWindSingleStencilNoWrapInc;
417 passes[1] = &gWindSingleStencilNoWrapDec;
418 }
419 // which is cw and which is ccw is arbitrary.
tomhudson@google.com93813632011-10-27 20:21:16 +0000420 drawFace[0] = GrDrawState::kCW_DrawFace;
421 drawFace[1] = GrDrawState::kCCW_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000422 passCount = 3;
423 }
424 if (stencilOnly) {
425 lastPassIsBounds = false;
426 --passCount;
427 } else {
428 lastPassIsBounds = true;
tomhudson@google.com93813632011-10-27 20:21:16 +0000429 drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000430 if (reverse) {
431 passes[passCount-1] = &gInvWindColorPass;
432 } else {
433 passes[passCount-1] = &gWindColorPass;
434 }
435 }
436 break;
437 default:
438 GrAssert(!"Unknown path fFill!");
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000439 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000440 }
441 }
442 }
443
444 {
bsalomon@google.com30085192011-08-19 15:42:31 +0000445 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000446 drawState->setDrawFace(drawFace[p]);
bsalomon@google.com30085192011-08-19 15:42:31 +0000447 if (NULL != passes[p]) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000448 *drawState->stencil() = *passes[p];
bsalomon@google.com30085192011-08-19 15:42:31 +0000449 }
450
451 if (lastPassIsBounds && (p == passCount-1)) {
452 if (!colorWritesWereDisabled) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000453 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
bsalomon@google.com30085192011-08-19 15:42:31 +0000454 }
455 GrRect bounds;
bsalomon@google.com288d9542012-10-17 12:53:54 +0000456 GrDrawState::AutoDeviceCoordDraw adcd;
bsalomon@google.com30085192011-08-19 15:42:31 +0000457 if (reverse) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000458 GrAssert(NULL != drawState->getRenderTarget());
bsalomon@google.com30085192011-08-19 15:42:31 +0000459 // draw over the whole world.
460 bounds.setLTRB(0, 0,
bsalomon@google.com81712882012-11-01 17:12:34 +0000461 SkIntToScalar(drawState->getRenderTarget()->width()),
462 SkIntToScalar(drawState->getRenderTarget()->height()));
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000463 SkMatrix vmi;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000464 // mapRect through persp matrix may not be correct
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000465 if (!drawState->getViewMatrix().hasPerspective() &&
466 drawState->getViewInverse(&vmi)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000467 vmi.mapRect(&bounds);
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000468 } else {
bsalomon@google.com288d9542012-10-17 12:53:54 +0000469 adcd.set(drawState);
bsalomon@google.com30085192011-08-19 15:42:31 +0000470 }
471 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000472 bounds = path.getBounds();
bsalomon@google.com30085192011-08-19 15:42:31 +0000473 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000474 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000475 target->drawSimpleRect(bounds, NULL);
bsalomon@google.com30085192011-08-19 15:42:31 +0000476 } else {
477 if (passCount > 1) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000478 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
bsalomon@google.com30085192011-08-19 15:42:31 +0000479 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000480 if (indexCnt) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000481 target->drawIndexed(primType, 0, 0,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000482 vertexCnt, indexCnt);
bsalomon@google.com30085192011-08-19 15:42:31 +0000483 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000484 target->drawNonIndexed(primType, 0, vertexCnt);
bsalomon@google.com30085192011-08-19 15:42:31 +0000485 }
486 }
487 }
488 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000489 return true;
bsalomon@google.com30085192011-08-19 15:42:31 +0000490}
491
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000492bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000493 const SkStroke& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000494 const GrDrawTarget* target,
495 bool antiAlias) const {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000496 // this class can draw any path with any fill but doesn't do any
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000497 // anti-aliasing.
sugoi@google.com12b4e272012-12-06 20:13:11 +0000498 return (stroke.getWidthIfStroked() <= 0) && !antiAlias;
bsalomon@google.com30085192011-08-19 15:42:31 +0000499}
500
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000501bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000502 const SkStroke& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000503 GrDrawTarget* target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000504 bool antiAlias) {
505 return this->internalDrawPath(path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000506 stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000507 target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000508 false);
509}
510
511void GrDefaultPathRenderer::drawPathToStencil(const SkPath& path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000512 const SkStroke& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000513 GrDrawTarget* target) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000514 GrAssert(SkPath::kInverseEvenOdd_FillType != path.getFillType());
515 GrAssert(SkPath::kInverseWinding_FillType != path.getFillType());
516 this->internalDrawPath(path, stroke, target, true);
bsalomon@google.com30085192011-08-19 15:42:31 +0000517}