blob: d8f723eaefdc0fc33b0c1e5cef664fb5acacb14f [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"
joshualitt5478d422014-11-14 16:00:38 -080011#include "GrDefaultGeoProcFactory.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.com5f74cf82012-12-17 21:16:45 +000015#include "SkStrokeRec.h"
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +000016#include "SkTLazy.h"
commit-bot@chromium.org933e65d2014-03-20 20:00:24 +000017#include "SkTraceEvent.h"
bsalomon@google.com30085192011-08-19 15:42:31 +000018
19
20GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
21 bool stencilWrapOpsSupport)
22 : fSeparateStencil(separateStencilSupport)
bsalomon@google.comc2099d22012-03-02 21:26:50 +000023 , fStencilWrapOps(stencilWrapOpsSupport) {
bsalomon@google.com289533a2011-10-27 12:34:25 +000024}
25
26
bsalomon@google.com30085192011-08-19 15:42:31 +000027////////////////////////////////////////////////////////////////////////////////
28// Stencil rules for paths
29
30////// Even/Odd
31
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000032GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
33 kInvert_StencilOp,
34 kKeep_StencilOp,
35 kAlwaysIfInClip_StencilFunc,
36 0xffff,
37 0xffff,
38 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000039
40// ok not to check clip b/c stencil pass only wrote inside clip
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000041GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
42 kZero_StencilOp,
43 kZero_StencilOp,
44 kNotEqual_StencilFunc,
45 0xffff,
46 0x0000,
47 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000048
49// have to check clip b/c outside clip will always be zero.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000050GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
51 kZero_StencilOp,
52 kZero_StencilOp,
53 kEqualIfInClip_StencilFunc,
54 0xffff,
55 0x0000,
56 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000057
58////// Winding
59
60// when we have separate stencil we increment front faces / decrement back faces
61// when we don't have wrap incr and decr we use the stencil test to simulate
62// them.
63
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000064GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
bsalomon@google.com30085192011-08-19 15:42:31 +000065 kIncWrap_StencilOp, kDecWrap_StencilOp,
66 kKeep_StencilOp, kKeep_StencilOp,
67 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
tomhudson@google.com62b09682011-11-09 16:39:17 +000068 0xffff, 0xffff,
69 0xffff, 0xffff,
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000070 0xffff, 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000071
72// if inc'ing the max value, invert to make 0
73// if dec'ing zero invert to make all ones.
74// we can't avoid touching the stencil on both passing and
75// failing, so we can't resctrict ourselves to the clip.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000076GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
bsalomon@google.com30085192011-08-19 15:42:31 +000077 kInvert_StencilOp, kInvert_StencilOp,
78 kIncClamp_StencilOp, kDecClamp_StencilOp,
79 kEqual_StencilFunc, kEqual_StencilFunc,
tomhudson@google.com62b09682011-11-09 16:39:17 +000080 0xffff, 0xffff,
81 0xffff, 0x0000,
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000082 0xffff, 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000083
84// When there are no separate faces we do two passes to setup the winding rule
85// stencil. First we draw the front faces and inc, then we draw the back faces
86// and dec. These are same as the above two split into the incrementing and
87// decrementing passes.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000088GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
89 kIncWrap_StencilOp,
90 kKeep_StencilOp,
91 kAlwaysIfInClip_StencilFunc,
92 0xffff,
93 0xffff,
94 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000095
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000096GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
97 kDecWrap_StencilOp,
98 kKeep_StencilOp,
99 kAlwaysIfInClip_StencilFunc,
100 0xffff,
101 0xffff,
102 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +0000103
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000104GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
105 kInvert_StencilOp,
106 kIncClamp_StencilOp,
107 kEqual_StencilFunc,
108 0xffff,
109 0xffff,
110 0xffff);
111
112GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
113 kInvert_StencilOp,
114 kDecClamp_StencilOp,
115 kEqual_StencilFunc,
116 0xffff,
117 0x0000,
118 0xffff);
119
120// Color passes are the same whether we use the two-sided stencil or two passes
121
122GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
123 kZero_StencilOp,
124 kZero_StencilOp,
125 kNonZeroIfInClip_StencilFunc,
126 0xffff,
127 0x0000,
128 0xffff);
129
130GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
131 kZero_StencilOp,
132 kZero_StencilOp,
133 kEqualIfInClip_StencilFunc,
134 0xffff,
135 0x0000,
136 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +0000137
138////// Normal render to stencil
139
140// Sometimes the default path renderer can draw a path directly to the stencil
141// buffer without having to first resolve the interior / exterior.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000142GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
143 kZero_StencilOp,
144 kIncClamp_StencilOp,
145 kAlwaysIfInClip_StencilFunc,
146 0xffff,
147 0x0000,
148 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +0000149
150////////////////////////////////////////////////////////////////////////////////
151// Helpers for drawPath
152
bsalomon@google.com30085192011-08-19 15:42:31 +0000153#define STENCIL_OFF 0 // Always disable stencil (even when needed)
154
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000155static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000156#if STENCIL_OFF
157 return true;
158#else
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000159 if (!stroke.isHairlineStyle() && !path.isInverseFillType()) {
bsalomon@google.com7d72c452012-01-30 14:02:44 +0000160 return path.isConvex();
bsalomon@google.com30085192011-08-19 15:42:31 +0000161 }
162 return false;
163#endif
164}
165
joshualitt9853cce2014-11-17 14:22:48 -0800166GrPathRenderer::StencilSupport
167GrDefaultPathRenderer::onGetStencilSupport(const GrDrawTarget*,
168 const GrDrawState*,
169 const SkPath& path,
170 const SkStrokeRec& stroke) const {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000171 if (single_pass_path(path, stroke)) {
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000172 return GrPathRenderer::kNoRestriction_StencilSupport;
173 } else {
174 return GrPathRenderer::kStencilOnly_StencilSupport;
175 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000176}
177
sugoi@google.com12b4e272012-12-06 20:13:11 +0000178static inline void append_countour_edge_indices(bool hairLine,
bsalomon@google.com30085192011-08-19 15:42:31 +0000179 uint16_t fanCenterIdx,
180 uint16_t edgeV0Idx,
181 uint16_t** indices) {
182 // when drawing lines we're appending line segments along
183 // the contour. When applying the other fill rules we're
184 // drawing triangle fans around fanCenterIdx.
sugoi@google.com12b4e272012-12-06 20:13:11 +0000185 if (!hairLine) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000186 *((*indices)++) = fanCenterIdx;
187 }
188 *((*indices)++) = edgeV0Idx;
189 *((*indices)++) = edgeV0Idx + 1;
190}
191
joshualitt9853cce2014-11-17 14:22:48 -0800192bool GrDefaultPathRenderer::createGeom(GrDrawTarget* target,
193 GrDrawState* drawState,
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,
joshualitt9853cce2014-11-17 14:22:48 -0800197 GrDrawTarget::AutoReleaseGeometry* arg,
198 const SkPath& path,
199 const SkStrokeRec& stroke,
200 SkScalar srcSpaceTol) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000201 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000202 SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000203 int contourCnt;
204 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
bsalomon@google.com30085192011-08-19 15:42:31 +0000205 srcSpaceTol);
206
207 if (maxPts <= 0) {
208 return false;
209 }
210 if (maxPts > ((int)SK_MaxU16 + 1)) {
tfarina38406c82014-10-31 07:11:12 -0700211 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts);
bsalomon@google.com30085192011-08-19 15:42:31 +0000212 return false;
213 }
214
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000215 bool indexed = contourCnt > 1;
bsalomon@google.com30085192011-08-19 15:42:31 +0000216
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000217 const bool isHairline = stroke.isHairlineStyle();
sugoi@google.com12b4e272012-12-06 20:13:11 +0000218
bsalomon@google.com30085192011-08-19 15:42:31 +0000219 int maxIdxs = 0;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000220 if (isHairline) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000221 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000222 maxIdxs = 2 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000223 *primType = kLines_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000224 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000225 *primType = kLineStrip_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000226 }
227 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000228 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000229 maxIdxs = 3 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000230 *primType = kTriangles_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000231 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000232 *primType = kTriangleFan_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000233 }
234 }
235
joshualitt2e3b3e32014-12-09 13:31:14 -0800236 if (!arg->set(target, maxPts, GrDefaultGeoProcFactory::DefaultVertexStride(), maxIdxs)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000237 return false;
238 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800239 SkASSERT(GrDefaultGeoProcFactory::DefaultVertexStride() == sizeof(SkPoint));
bsalomon@google.comb3729422012-03-07 19:13:28 +0000240
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000241 uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());
bsalomon@google.comb3729422012-03-07 19:13:28 +0000242 uint16_t* idx = idxBase;
243 uint16_t subpathIdxStart = 0;
244
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000245 SkPoint* base = reinterpret_cast<SkPoint*>(arg->vertices());
bsalomon49f085d2014-09-05 13:34:00 -0700246 SkASSERT(base);
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000247 SkPoint* vert = base;
bsalomon@google.com30085192011-08-19 15:42:31 +0000248
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000249 SkPoint pts[4];
bsalomon@google.com30085192011-08-19 15:42:31 +0000250
251 bool first = true;
252 int subpath = 0;
253
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000254 SkPath::Iter iter(path, false);
bsalomon@google.com30085192011-08-19 15:42:31 +0000255
256 for (;;) {
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000257 SkPath::Verb verb = iter.next(pts);
258 switch (verb) {
reed@google.com277c3f82013-05-31 15:17:50 +0000259 case SkPath::kConic_Verb:
260 SkASSERT(0);
261 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000262 case SkPath::kMove_Verb:
bsalomon@google.com30085192011-08-19 15:42:31 +0000263 if (!first) {
264 uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000265 subpathIdxStart = currIdx;
266 ++subpath;
267 }
268 *vert = pts[0];
269 vert++;
270 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000271 case SkPath::kLine_Verb:
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000272 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000273 uint16_t prevIdx = (uint16_t)(vert - base) - 1;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000274 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000275 prevIdx, &idx);
276 }
277 *(vert++) = pts[1];
278 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000279 case SkPath::kQuad_Verb: {
bsalomon@google.com30085192011-08-19 15:42:31 +0000280 // first pt of quad is the pt we ended on in previous step
281 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000282 uint16_t numPts = (uint16_t)
bsalomon@google.com30085192011-08-19 15:42:31 +0000283 GrPathUtils::generateQuadraticPoints(
284 pts[0], pts[1], pts[2],
285 srcSpaceTolSqd, &vert,
286 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000287 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000288 for (uint16_t i = 0; i < numPts; ++i) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000289 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000290 firstQPtIdx + i, &idx);
291 }
292 }
293 break;
294 }
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000295 case SkPath::kCubic_Verb: {
bsalomon@google.com30085192011-08-19 15:42:31 +0000296 // first pt of cubic is the pt we ended on in previous step
297 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
298 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
299 pts[0], pts[1], pts[2], pts[3],
300 srcSpaceTolSqd, &vert,
301 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000302 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000303 for (uint16_t i = 0; i < numPts; ++i) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000304 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000305 firstCPtIdx + i, &idx);
306 }
307 }
308 break;
309 }
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000310 case SkPath::kClose_Verb:
bsalomon@google.com30085192011-08-19 15:42:31 +0000311 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000312 case SkPath::kDone_Verb:
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000313 // uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000314 goto FINISHED;
315 }
316 first = false;
317 }
318FINISHED:
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000319 SkASSERT((vert - base) <= maxPts);
320 SkASSERT((idx - idxBase) <= maxIdxs);
bsalomon@google.com30085192011-08-19 15:42:31 +0000321
robertphillips@google.comadacc702013-10-14 21:53:24 +0000322 *vertexCnt = static_cast<int>(vert - base);
323 *indexCnt = static_cast<int>(idx - idxBase);
bsalomon@google.com30085192011-08-19 15:42:31 +0000324
bsalomon@google.com30085192011-08-19 15:42:31 +0000325 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000326 return true;
327}
328
joshualitt9853cce2014-11-17 14:22:48 -0800329bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
330 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800331 GrColor color,
joshualitt9853cce2014-11-17 14:22:48 -0800332 const SkPath& path,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000333 const SkStrokeRec& origStroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000334 bool stencilOnly) {
joshualitt9853cce2014-11-17 14:22:48 -0800335 SkMatrix viewM = drawState->getViewMatrix();
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000336 SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
337
338 SkScalar hairlineCoverage;
joshualitt2e3b3e32014-12-09 13:31:14 -0800339 uint8_t newCoverage = 0xff;
joshualitt9853cce2014-11-17 14:22:48 -0800340 if (IsStrokeHairlineOrEquivalent(*stroke, drawState->getViewMatrix(),
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000341 &hairlineCoverage)) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800342 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000343
344 if (!stroke->isHairlineStyle()) {
345 stroke.writable()->setHairlineStyle();
346 }
347 }
348
bsalomon@google.com81712882012-11-01 17:12:34 +0000349 SkScalar tol = SK_Scalar1;
robertphillips@google.come79f3202014-02-11 16:30:21 +0000350 tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
bsalomon@google.com30085192011-08-19 15:42:31 +0000351
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000352 int vertexCnt;
353 int indexCnt;
354 GrPrimitiveType primType;
bsalomon@google.comb3729422012-03-07 19:13:28 +0000355 GrDrawTarget::AutoReleaseGeometry arg;
joshualitt9853cce2014-11-17 14:22:48 -0800356 if (!this->createGeom(target,
357 drawState,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000358 &primType,
359 &vertexCnt,
bsalomon@google.comb3729422012-03-07 19:13:28 +0000360 &indexCnt,
joshualitt9853cce2014-11-17 14:22:48 -0800361 &arg,
362 path,
363 *stroke,
364 tol)) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000365 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000366 }
367
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000368 bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
bsalomon@google.com30085192011-08-19 15:42:31 +0000369 // face culling doesn't make sense here
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000370 SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
bsalomon@google.com30085192011-08-19 15:42:31 +0000371
372 int passCount = 0;
373 const GrStencilSettings* passes[3];
tomhudson@google.com93813632011-10-27 20:21:16 +0000374 GrDrawState::DrawFace drawFace[3];
bsalomon@google.com30085192011-08-19 15:42:31 +0000375 bool reverse = false;
376 bool lastPassIsBounds;
377
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000378 if (stroke->isHairlineStyle()) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000379 passCount = 1;
380 if (stencilOnly) {
381 passes[0] = &gDirectToStencil;
382 } else {
383 passes[0] = NULL;
384 }
385 lastPassIsBounds = false;
tomhudson@google.com93813632011-10-27 20:21:16 +0000386 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000387 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000388 if (single_pass_path(path, *stroke)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000389 passCount = 1;
390 if (stencilOnly) {
391 passes[0] = &gDirectToStencil;
392 } else {
393 passes[0] = NULL;
394 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000395 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000396 lastPassIsBounds = false;
397 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000398 switch (path.getFillType()) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000399 case SkPath::kInverseEvenOdd_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::kEvenOdd_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000403 passes[0] = &gEOStencilPass;
404 if (stencilOnly) {
405 passCount = 1;
406 lastPassIsBounds = false;
407 } else {
408 passCount = 2;
409 lastPassIsBounds = true;
410 if (reverse) {
411 passes[1] = &gInvEOColorPass;
412 } else {
413 passes[1] = &gEOColorPass;
414 }
415 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000416 drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000417 break;
418
sugoi@google.com12b4e272012-12-06 20:13:11 +0000419 case SkPath::kInverseWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000420 reverse = true;
421 // fallthrough
sugoi@google.com12b4e272012-12-06 20:13:11 +0000422 case SkPath::kWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000423 if (fSeparateStencil) {
424 if (fStencilWrapOps) {
425 passes[0] = &gWindStencilSeparateWithWrap;
426 } else {
427 passes[0] = &gWindStencilSeparateNoWrap;
428 }
429 passCount = 2;
tomhudson@google.com93813632011-10-27 20:21:16 +0000430 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000431 } else {
432 if (fStencilWrapOps) {
433 passes[0] = &gWindSingleStencilWithWrapInc;
434 passes[1] = &gWindSingleStencilWithWrapDec;
435 } else {
436 passes[0] = &gWindSingleStencilNoWrapInc;
437 passes[1] = &gWindSingleStencilNoWrapDec;
438 }
439 // which is cw and which is ccw is arbitrary.
tomhudson@google.com93813632011-10-27 20:21:16 +0000440 drawFace[0] = GrDrawState::kCW_DrawFace;
441 drawFace[1] = GrDrawState::kCCW_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000442 passCount = 3;
443 }
444 if (stencilOnly) {
445 lastPassIsBounds = false;
446 --passCount;
447 } else {
448 lastPassIsBounds = true;
tomhudson@google.com93813632011-10-27 20:21:16 +0000449 drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000450 if (reverse) {
451 passes[passCount-1] = &gInvWindColorPass;
452 } else {
453 passes[passCount-1] = &gWindColorPass;
454 }
455 }
456 break;
457 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000458 SkDEBUGFAIL("Unknown path fFill!");
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000459 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000460 }
461 }
462 }
463
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000464 SkRect devBounds;
robertphillips@google.come79f3202014-02-11 16:30:21 +0000465 GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds);
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000466
bsalomon@google.com30085192011-08-19 15:42:31 +0000467 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000468 drawState->setDrawFace(drawFace[p]);
bsalomon49f085d2014-09-05 13:34:00 -0700469 if (passes[p]) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000470 *drawState->stencil() = *passes[p];
bsalomon@google.com30085192011-08-19 15:42:31 +0000471 }
472
473 if (lastPassIsBounds && (p == passCount-1)) {
474 if (!colorWritesWereDisabled) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000475 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
bsalomon@google.com30085192011-08-19 15:42:31 +0000476 }
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000477 SkRect bounds;
bsalomon@google.com137f1342013-05-29 21:27:53 +0000478 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com30085192011-08-19 15:42:31 +0000479 if (reverse) {
bsalomon49f085d2014-09-05 13:34:00 -0700480 SkASSERT(drawState->getRenderTarget());
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000481 // draw over the dev bounds (which will be the whole dst surface for inv fill).
482 bounds = devBounds;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000483 SkMatrix vmi;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000484 // mapRect through persp matrix may not be correct
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000485 if (!drawState->getViewMatrix().hasPerspective() &&
486 drawState->getViewInverse(&vmi)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000487 vmi.mapRect(&bounds);
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000488 } else {
bsalomon@google.com137f1342013-05-29 21:27:53 +0000489 avmr.setIdentity(drawState);
bsalomon@google.com30085192011-08-19 15:42:31 +0000490 }
491 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000492 bounds = path.getBounds();
bsalomon@google.com30085192011-08-19 15:42:31 +0000493 }
joshualitt9853cce2014-11-17 14:22:48 -0800494 GrDrawTarget::AutoGeometryPush agp(target);
joshualitt2e3b3e32014-12-09 13:31:14 -0800495 target->drawSimpleRect(drawState, color, bounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000496 } else {
497 if (passCount > 1) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000498 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
bsalomon@google.com30085192011-08-19 15:42:31 +0000499 }
joshualitt5478d422014-11-14 16:00:38 -0800500 GrDrawState::AutoRestoreEffects are(drawState);
joshualitt56995b52014-12-11 15:44:02 -0800501 SkAutoTUnref<const GrGeometryProcessor> gp(
joshualitt2e3b3e32014-12-09 13:31:14 -0800502 GrDefaultGeoProcFactory::Create(color,
503 GrDefaultGeoProcFactory::kPosition_GPType,
joshualitt56995b52014-12-11 15:44:02 -0800504 false,
505 newCoverage));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000506 if (indexCnt) {
joshualitt9853cce2014-11-17 14:22:48 -0800507 target->drawIndexed(drawState,
joshualitt56995b52014-12-11 15:44:02 -0800508 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800509 primType,
510 0,
511 0,
512 vertexCnt,
513 indexCnt,
514 &devBounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000515 } else {
joshualitt56995b52014-12-11 15:44:02 -0800516 target->drawNonIndexed(drawState, gp, primType, 0, vertexCnt, &devBounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000517 }
518 }
519 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000520 return true;
bsalomon@google.com30085192011-08-19 15:42:31 +0000521}
522
joshualitt9853cce2014-11-17 14:22:48 -0800523bool GrDefaultPathRenderer::canDrawPath(const GrDrawTarget* target,
524 const GrDrawState* drawState,
525 const SkPath& path,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000526 const SkStrokeRec& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000527 bool antiAlias) const {
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000528 // 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 +0000529
robertphillips730c0442014-07-25 05:52:38 -0700530 return !antiAlias && !(SkPath::kConic_SegmentMask & path.getSegmentMasks()) &&
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000531 (stroke.isFillStyle() ||
joshualitt9853cce2014-11-17 14:22:48 -0800532 IsStrokeHairlineOrEquivalent(stroke, drawState->getViewMatrix(), NULL));
bsalomon@google.com30085192011-08-19 15:42:31 +0000533}
534
joshualitt9853cce2014-11-17 14:22:48 -0800535bool GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
536 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800537 GrColor color,
joshualitt9853cce2014-11-17 14:22:48 -0800538 const SkPath& path,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000539 const SkStrokeRec& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000540 bool antiAlias) {
joshualitt9853cce2014-11-17 14:22:48 -0800541 return this->internalDrawPath(target,
542 drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800543 color,
joshualitt9853cce2014-11-17 14:22:48 -0800544 path,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000545 stroke,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000546 false);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000547}
548
joshualitt9853cce2014-11-17 14:22:48 -0800549void GrDefaultPathRenderer::onStencilPath(GrDrawTarget* target,
550 GrDrawState* drawState,
551 const SkPath& path,
552 const SkStrokeRec& stroke) {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000553 SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
554 SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
joshualitt2e3b3e32014-12-09 13:31:14 -0800555 this->internalDrawPath(target, drawState, GrColor_WHITE, path, stroke, true);
bsalomon@google.com30085192011-08-19 15:42:31 +0000556}