blob: dd6ae9d02514f80e6c2708d0053e3972be8584b4 [file] [log] [blame]
bsalomon@google.com30085192011-08-19 15:42:31 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrDefaultPathRenderer.h"
9
10#include "GrContext.h"
tomhudson@google.com93813632011-10-27 20:21:16 +000011#include "GrDrawState.h"
bsalomon@google.com30085192011-08-19 15:42:31 +000012#include "GrPathUtils.h"
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000013#include "SkString.h"
sugoi@google.com5f74cf82012-12-17 21:16:45 +000014#include "SkStrokeRec.h"
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +000015#include "SkTLazy.h"
commit-bot@chromium.org933e65d2014-03-20 20:00:24 +000016#include "SkTraceEvent.h"
bsalomon@google.com30085192011-08-19 15:42:31 +000017
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.com5f74cf82012-12-17 21:16:45 +0000154static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000155#if STENCIL_OFF
156 return true;
157#else
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000158 if (!stroke.isHairlineStyle() && !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.com45a15f52012-12-10 19:10:17 +0000165GrPathRenderer::StencilSupport GrDefaultPathRenderer::onGetStencilSupport(
robertphillips@google.come79f3202014-02-11 16:30:21 +0000166 const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000167 const SkStrokeRec& stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000168 const GrDrawTarget*) const {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000169 if (single_pass_path(path, stroke)) {
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000170 return GrPathRenderer::kNoRestriction_StencilSupport;
171 } else {
172 return GrPathRenderer::kStencilOnly_StencilSupport;
173 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000174}
175
sugoi@google.com12b4e272012-12-06 20:13:11 +0000176static inline void append_countour_edge_indices(bool hairLine,
bsalomon@google.com30085192011-08-19 15:42:31 +0000177 uint16_t fanCenterIdx,
178 uint16_t edgeV0Idx,
179 uint16_t** indices) {
180 // when drawing lines we're appending line segments along
181 // the contour. When applying the other fill rules we're
182 // drawing triangle fans around fanCenterIdx.
sugoi@google.com12b4e272012-12-06 20:13:11 +0000183 if (!hairLine) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000184 *((*indices)++) = fanCenterIdx;
185 }
186 *((*indices)++) = edgeV0Idx;
187 *((*indices)++) = edgeV0Idx + 1;
188}
189
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000190bool GrDefaultPathRenderer::createGeom(const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000191 const SkStrokeRec& stroke,
bsalomon@google.com81712882012-11-01 17:12:34 +0000192 SkScalar srcSpaceTol,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000193 GrDrawTarget* target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000194 GrPrimitiveType* primType,
195 int* vertexCnt,
bsalomon@google.comb3729422012-03-07 19:13:28 +0000196 int* indexCnt,
197 GrDrawTarget::AutoReleaseGeometry* arg) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000198 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000199 SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000200 int contourCnt;
201 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
bsalomon@google.com30085192011-08-19 15:42:31 +0000202 srcSpaceTol);
203
204 if (maxPts <= 0) {
205 return false;
206 }
207 if (maxPts > ((int)SK_MaxU16 + 1)) {
208 GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
209 return false;
210 }
211
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000212 bool indexed = contourCnt > 1;
bsalomon@google.com30085192011-08-19 15:42:31 +0000213
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000214 const bool isHairline = stroke.isHairlineStyle();
sugoi@google.com12b4e272012-12-06 20:13:11 +0000215
bsalomon@google.com30085192011-08-19 15:42:31 +0000216 int maxIdxs = 0;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000217 if (isHairline) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000218 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000219 maxIdxs = 2 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000220 *primType = kLines_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000221 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000222 *primType = kLineStrip_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000223 }
224 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000225 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000226 maxIdxs = 3 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000227 *primType = kTriangles_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000228 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000229 *primType = kTriangleFan_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000230 }
231 }
232
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000233 target->drawState()->setDefaultVertexAttribs();
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000234 if (!arg->set(target, maxPts, maxIdxs)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000235 return false;
236 }
bsalomon@google.comb3729422012-03-07 19:13:28 +0000237
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000238 uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());
bsalomon@google.comb3729422012-03-07 19:13:28 +0000239 uint16_t* idx = idxBase;
240 uint16_t subpathIdxStart = 0;
241
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000242 SkPoint* base = reinterpret_cast<SkPoint*>(arg->vertices());
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000243 SkASSERT(NULL != base);
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000244 SkPoint* vert = base;
bsalomon@google.com30085192011-08-19 15:42:31 +0000245
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000246 SkPoint pts[4];
bsalomon@google.com30085192011-08-19 15:42:31 +0000247
248 bool first = true;
249 int subpath = 0;
250
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000251 SkPath::Iter iter(path, false);
bsalomon@google.com30085192011-08-19 15:42:31 +0000252
253 for (;;) {
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000254 SkPath::Verb verb = iter.next(pts);
255 switch (verb) {
reed@google.com277c3f82013-05-31 15:17:50 +0000256 case SkPath::kConic_Verb:
257 SkASSERT(0);
258 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000259 case SkPath::kMove_Verb:
bsalomon@google.com30085192011-08-19 15:42:31 +0000260 if (!first) {
261 uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000262 subpathIdxStart = currIdx;
263 ++subpath;
264 }
265 *vert = pts[0];
266 vert++;
267 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000268 case SkPath::kLine_Verb:
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000269 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000270 uint16_t prevIdx = (uint16_t)(vert - base) - 1;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000271 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000272 prevIdx, &idx);
273 }
274 *(vert++) = pts[1];
275 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000276 case SkPath::kQuad_Verb: {
bsalomon@google.com30085192011-08-19 15:42:31 +0000277 // first pt of quad is the pt we ended on in previous step
278 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000279 uint16_t numPts = (uint16_t)
bsalomon@google.com30085192011-08-19 15:42:31 +0000280 GrPathUtils::generateQuadraticPoints(
281 pts[0], pts[1], pts[2],
282 srcSpaceTolSqd, &vert,
283 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000284 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000285 for (uint16_t i = 0; i < numPts; ++i) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000286 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000287 firstQPtIdx + i, &idx);
288 }
289 }
290 break;
291 }
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000292 case SkPath::kCubic_Verb: {
bsalomon@google.com30085192011-08-19 15:42:31 +0000293 // first pt of cubic is the pt we ended on in previous step
294 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
295 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
296 pts[0], pts[1], pts[2], pts[3],
297 srcSpaceTolSqd, &vert,
298 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000299 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000300 for (uint16_t i = 0; i < numPts; ++i) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000301 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000302 firstCPtIdx + i, &idx);
303 }
304 }
305 break;
306 }
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000307 case SkPath::kClose_Verb:
bsalomon@google.com30085192011-08-19 15:42:31 +0000308 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000309 case SkPath::kDone_Verb:
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000310 // uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000311 goto FINISHED;
312 }
313 first = false;
314 }
315FINISHED:
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000316 SkASSERT((vert - base) <= maxPts);
317 SkASSERT((idx - idxBase) <= maxIdxs);
bsalomon@google.com30085192011-08-19 15:42:31 +0000318
robertphillips@google.comadacc702013-10-14 21:53:24 +0000319 *vertexCnt = static_cast<int>(vert - base);
320 *indexCnt = static_cast<int>(idx - idxBase);
bsalomon@google.com30085192011-08-19 15:42:31 +0000321
bsalomon@google.com30085192011-08-19 15:42:31 +0000322 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000323 return true;
324}
325
robertphillips@google.come79f3202014-02-11 16:30:21 +0000326bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
327 const SkStrokeRec& origStroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000328 GrDrawTarget* target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000329 bool stencilOnly) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000330
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000331 SkMatrix viewM = target->getDrawState().getViewMatrix();
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000332 SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
333
334 SkScalar hairlineCoverage;
335 if (IsStrokeHairlineOrEquivalent(*stroke, target->getDrawState().getViewMatrix(),
336 &hairlineCoverage)) {
337 uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage *
338 target->getDrawState().getCoverage());
339 target->drawState()->setCoverage(newCoverage);
340
341 if (!stroke->isHairlineStyle()) {
342 stroke.writable()->setHairlineStyle();
343 }
344 }
345
bsalomon@google.com81712882012-11-01 17:12:34 +0000346 SkScalar tol = SK_Scalar1;
robertphillips@google.come79f3202014-02-11 16:30:21 +0000347 tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
bsalomon@google.com30085192011-08-19 15:42:31 +0000348
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000349 int vertexCnt;
350 int indexCnt;
351 GrPrimitiveType primType;
bsalomon@google.comb3729422012-03-07 19:13:28 +0000352 GrDrawTarget::AutoReleaseGeometry arg;
robertphillips@google.come79f3202014-02-11 16:30:21 +0000353 if (!this->createGeom(path,
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000354 *stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000355 tol,
356 target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000357 &primType,
358 &vertexCnt,
bsalomon@google.comb3729422012-03-07 19:13:28 +0000359 &indexCnt,
360 &arg)) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000361 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000362 }
363
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000364 SkASSERT(NULL != target);
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000365 GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
366 GrDrawState* drawState = target->drawState();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000367 bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
bsalomon@google.com30085192011-08-19 15:42:31 +0000368 // face culling doesn't make sense here
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000369 SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
bsalomon@google.com30085192011-08-19 15:42:31 +0000370
371 int passCount = 0;
372 const GrStencilSettings* passes[3];
tomhudson@google.com93813632011-10-27 20:21:16 +0000373 GrDrawState::DrawFace drawFace[3];
bsalomon@google.com30085192011-08-19 15:42:31 +0000374 bool reverse = false;
375 bool lastPassIsBounds;
376
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000377 if (stroke->isHairlineStyle()) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000378 passCount = 1;
379 if (stencilOnly) {
380 passes[0] = &gDirectToStencil;
381 } else {
382 passes[0] = NULL;
383 }
384 lastPassIsBounds = false;
tomhudson@google.com93813632011-10-27 20:21:16 +0000385 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000386 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000387 if (single_pass_path(path, *stroke)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000388 passCount = 1;
389 if (stencilOnly) {
390 passes[0] = &gDirectToStencil;
391 } else {
392 passes[0] = NULL;
393 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000394 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000395 lastPassIsBounds = false;
396 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000397 switch (path.getFillType()) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000398 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000399 reverse = true;
400 // fallthrough
sugoi@google.com12b4e272012-12-06 20:13:11 +0000401 case SkPath::kEvenOdd_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000402 passes[0] = &gEOStencilPass;
403 if (stencilOnly) {
404 passCount = 1;
405 lastPassIsBounds = false;
406 } else {
407 passCount = 2;
408 lastPassIsBounds = true;
409 if (reverse) {
410 passes[1] = &gInvEOColorPass;
411 } else {
412 passes[1] = &gEOColorPass;
413 }
414 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000415 drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000416 break;
417
sugoi@google.com12b4e272012-12-06 20:13:11 +0000418 case SkPath::kInverseWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000419 reverse = true;
420 // fallthrough
sugoi@google.com12b4e272012-12-06 20:13:11 +0000421 case SkPath::kWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000422 if (fSeparateStencil) {
423 if (fStencilWrapOps) {
424 passes[0] = &gWindStencilSeparateWithWrap;
425 } else {
426 passes[0] = &gWindStencilSeparateNoWrap;
427 }
428 passCount = 2;
tomhudson@google.com93813632011-10-27 20:21:16 +0000429 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000430 } else {
431 if (fStencilWrapOps) {
432 passes[0] = &gWindSingleStencilWithWrapInc;
433 passes[1] = &gWindSingleStencilWithWrapDec;
434 } else {
435 passes[0] = &gWindSingleStencilNoWrapInc;
436 passes[1] = &gWindSingleStencilNoWrapDec;
437 }
438 // which is cw and which is ccw is arbitrary.
tomhudson@google.com93813632011-10-27 20:21:16 +0000439 drawFace[0] = GrDrawState::kCW_DrawFace;
440 drawFace[1] = GrDrawState::kCCW_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000441 passCount = 3;
442 }
443 if (stencilOnly) {
444 lastPassIsBounds = false;
445 --passCount;
446 } else {
447 lastPassIsBounds = true;
tomhudson@google.com93813632011-10-27 20:21:16 +0000448 drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000449 if (reverse) {
450 passes[passCount-1] = &gInvWindColorPass;
451 } else {
452 passes[passCount-1] = &gWindColorPass;
453 }
454 }
455 break;
456 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000457 SkDEBUGFAIL("Unknown path fFill!");
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000458 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000459 }
460 }
461 }
462
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000463 SkRect devBounds;
robertphillips@google.come79f3202014-02-11 16:30:21 +0000464 GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds);
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000465
bsalomon@google.com30085192011-08-19 15:42:31 +0000466 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000467 drawState->setDrawFace(drawFace[p]);
bsalomon@google.com30085192011-08-19 15:42:31 +0000468 if (NULL != passes[p]) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000469 *drawState->stencil() = *passes[p];
bsalomon@google.com30085192011-08-19 15:42:31 +0000470 }
471
472 if (lastPassIsBounds && (p == passCount-1)) {
473 if (!colorWritesWereDisabled) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000474 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
bsalomon@google.com30085192011-08-19 15:42:31 +0000475 }
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000476 SkRect bounds;
bsalomon@google.com137f1342013-05-29 21:27:53 +0000477 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com30085192011-08-19 15:42:31 +0000478 if (reverse) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000479 SkASSERT(NULL != drawState->getRenderTarget());
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000480 // draw over the dev bounds (which will be the whole dst surface for inv fill).
481 bounds = devBounds;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000482 SkMatrix vmi;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000483 // mapRect through persp matrix may not be correct
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000484 if (!drawState->getViewMatrix().hasPerspective() &&
485 drawState->getViewInverse(&vmi)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000486 vmi.mapRect(&bounds);
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000487 } else {
bsalomon@google.com137f1342013-05-29 21:27:53 +0000488 avmr.setIdentity(drawState);
bsalomon@google.com30085192011-08-19 15:42:31 +0000489 }
490 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000491 bounds = path.getBounds();
bsalomon@google.com30085192011-08-19 15:42:31 +0000492 }
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000493 GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit);
bsalomon01c8da12014-08-04 09:21:30 -0700494 target->drawSimpleRect(bounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000495 } else {
496 if (passCount > 1) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000497 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
bsalomon@google.com30085192011-08-19 15:42:31 +0000498 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000499 if (indexCnt) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000500 target->drawIndexed(primType, 0, 0,
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000501 vertexCnt, indexCnt, &devBounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000502 } else {
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000503 target->drawNonIndexed(primType, 0, vertexCnt, &devBounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000504 }
505 }
506 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000507 return true;
bsalomon@google.com30085192011-08-19 15:42:31 +0000508}
509
robertphillips@google.come79f3202014-02-11 16:30:21 +0000510bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
511 const SkStrokeRec& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000512 const GrDrawTarget* target,
513 bool antiAlias) const {
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000514 // this class can draw any path with any fill but doesn't do any anti-aliasing.
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000515
robertphillips730c0442014-07-25 05:52:38 -0700516 return !antiAlias && !(SkPath::kConic_SegmentMask & path.getSegmentMasks()) &&
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000517 (stroke.isFillStyle() ||
518 IsStrokeHairlineOrEquivalent(stroke, target->getDrawState().getViewMatrix(), NULL));
bsalomon@google.com30085192011-08-19 15:42:31 +0000519}
520
robertphillips@google.come79f3202014-02-11 16:30:21 +0000521bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
522 const SkStrokeRec& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000523 GrDrawTarget* target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000524 bool antiAlias) {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000525 return this->internalDrawPath(path,
526 stroke,
527 target,
528 false);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000529}
530
robertphillips@google.come79f3202014-02-11 16:30:21 +0000531void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
532 const SkStrokeRec& stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000533 GrDrawTarget* target) {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000534 SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
535 SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
536 this->internalDrawPath(path, stroke, target, true);
bsalomon@google.com30085192011-08-19 15:42:31 +0000537}