blob: af0404ae0efe97328530022e548de7f4d76592fa [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"
egdanielaf18a092015-01-05 10:22:28 -080014#include "SkGeometry.h"
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000015#include "SkString.h"
sugoi@google.com5f74cf82012-12-17 21:16:45 +000016#include "SkStrokeRec.h"
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +000017#include "SkTLazy.h"
commit-bot@chromium.org933e65d2014-03-20 20:00:24 +000018#include "SkTraceEvent.h"
bsalomon@google.com30085192011-08-19 15:42:31 +000019
bsalomon@google.com30085192011-08-19 15:42:31 +000020GrDefaultPathRenderer::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
egdanielaf18a092015-01-05 10:22:28 -0800192static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint pts[],
193 SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed,
194 bool isHairline, uint16_t subpathIdxStart, uint16_t** idx) {
195 // first pt of quad is the pt we ended on in previous step
196 uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1;
197 uint16_t numPts = (uint16_t)
198 GrPathUtils::generateQuadraticPoints(
199 pts[0], pts[1], pts[2],
200 srcSpaceTolSqd, vert,
201 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
202 if (indexed) {
203 for (uint16_t i = 0; i < numPts; ++i) {
204 append_countour_edge_indices(isHairline, subpathIdxStart,
205 firstQPtIdx + i, idx);
206 }
207 }
208}
209
joshualitt9853cce2014-11-17 14:22:48 -0800210bool GrDefaultPathRenderer::createGeom(GrDrawTarget* target,
211 GrDrawState* drawState,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000212 GrPrimitiveType* primType,
213 int* vertexCnt,
bsalomon@google.comb3729422012-03-07 19:13:28 +0000214 int* indexCnt,
joshualitt9853cce2014-11-17 14:22:48 -0800215 GrDrawTarget::AutoReleaseGeometry* arg,
216 const SkPath& path,
217 const SkStrokeRec& stroke,
218 SkScalar srcSpaceTol) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000219 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000220 SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000221 int contourCnt;
222 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
bsalomon@google.com30085192011-08-19 15:42:31 +0000223 srcSpaceTol);
224
225 if (maxPts <= 0) {
226 return false;
227 }
228 if (maxPts > ((int)SK_MaxU16 + 1)) {
tfarina38406c82014-10-31 07:11:12 -0700229 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts);
bsalomon@google.com30085192011-08-19 15:42:31 +0000230 return false;
231 }
232
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000233 bool indexed = contourCnt > 1;
bsalomon@google.com30085192011-08-19 15:42:31 +0000234
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000235 const bool isHairline = stroke.isHairlineStyle();
sugoi@google.com12b4e272012-12-06 20:13:11 +0000236
bsalomon@google.com30085192011-08-19 15:42:31 +0000237 int maxIdxs = 0;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000238 if (isHairline) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000239 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000240 maxIdxs = 2 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000241 *primType = kLines_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000242 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000243 *primType = kLineStrip_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000244 }
245 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000246 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000247 maxIdxs = 3 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000248 *primType = kTriangles_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000249 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000250 *primType = kTriangleFan_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000251 }
252 }
253
joshualitt2e3b3e32014-12-09 13:31:14 -0800254 if (!arg->set(target, maxPts, GrDefaultGeoProcFactory::DefaultVertexStride(), maxIdxs)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000255 return false;
256 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800257 SkASSERT(GrDefaultGeoProcFactory::DefaultVertexStride() == sizeof(SkPoint));
bsalomon@google.comb3729422012-03-07 19:13:28 +0000258
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000259 uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());
bsalomon@google.comb3729422012-03-07 19:13:28 +0000260 uint16_t* idx = idxBase;
261 uint16_t subpathIdxStart = 0;
262
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000263 SkPoint* base = reinterpret_cast<SkPoint*>(arg->vertices());
bsalomon49f085d2014-09-05 13:34:00 -0700264 SkASSERT(base);
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000265 SkPoint* vert = base;
bsalomon@google.com30085192011-08-19 15:42:31 +0000266
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000267 SkPoint pts[4];
bsalomon@google.com30085192011-08-19 15:42:31 +0000268
269 bool first = true;
270 int subpath = 0;
271
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000272 SkPath::Iter iter(path, false);
bsalomon@google.com30085192011-08-19 15:42:31 +0000273
274 for (;;) {
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000275 SkPath::Verb verb = iter.next(pts);
276 switch (verb) {
277 case SkPath::kMove_Verb:
bsalomon@google.com30085192011-08-19 15:42:31 +0000278 if (!first) {
279 uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000280 subpathIdxStart = currIdx;
281 ++subpath;
282 }
283 *vert = pts[0];
284 vert++;
285 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000286 case SkPath::kLine_Verb:
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000287 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000288 uint16_t prevIdx = (uint16_t)(vert - base) - 1;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000289 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000290 prevIdx, &idx);
291 }
292 *(vert++) = pts[1];
293 break;
egdanielaf18a092015-01-05 10:22:28 -0800294 case SkPath::kConic_Verb: {
295 SkScalar weight = iter.conicWeight();
296 SkAutoConicToQuads converter;
297 // Converting in src-space, hance the finer tolerance (0.25)
298 // TODO: find a way to do this in dev-space so the tolerance means something
299 const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
300 for (int i = 0; i < converter.countQuads(); ++i) {
301 add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol, indexed,
302 isHairline, subpathIdxStart, &idx);
bsalomon@google.com30085192011-08-19 15:42:31 +0000303 }
304 break;
305 }
egdanielaf18a092015-01-05 10:22:28 -0800306 case SkPath::kQuad_Verb:
307 add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, indexed,
308 isHairline, subpathIdxStart, &idx);
309 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000310 case SkPath::kCubic_Verb: {
bsalomon@google.com30085192011-08-19 15:42:31 +0000311 // first pt of cubic is the pt we ended on in previous step
312 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
313 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
314 pts[0], pts[1], pts[2], pts[3],
315 srcSpaceTolSqd, &vert,
316 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000317 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000318 for (uint16_t i = 0; i < numPts; ++i) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000319 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000320 firstCPtIdx + i, &idx);
321 }
322 }
323 break;
324 }
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000325 case SkPath::kClose_Verb:
bsalomon@google.com30085192011-08-19 15:42:31 +0000326 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000327 case SkPath::kDone_Verb:
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000328 // uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000329 goto FINISHED;
330 }
331 first = false;
332 }
333FINISHED:
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000334 SkASSERT((vert - base) <= maxPts);
335 SkASSERT((idx - idxBase) <= maxIdxs);
bsalomon@google.com30085192011-08-19 15:42:31 +0000336
robertphillips@google.comadacc702013-10-14 21:53:24 +0000337 *vertexCnt = static_cast<int>(vert - base);
338 *indexCnt = static_cast<int>(idx - idxBase);
bsalomon@google.com30085192011-08-19 15:42:31 +0000339
bsalomon@google.com30085192011-08-19 15:42:31 +0000340 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000341 return true;
342}
343
joshualitt9853cce2014-11-17 14:22:48 -0800344bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
345 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800346 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800347 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800348 const SkPath& path,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000349 const SkStrokeRec& origStroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000350 bool stencilOnly) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000351 SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
352
353 SkScalar hairlineCoverage;
joshualitt2e3b3e32014-12-09 13:31:14 -0800354 uint8_t newCoverage = 0xff;
joshualitt8059eb92014-12-29 15:10:07 -0800355 if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800356 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000357
358 if (!stroke->isHairlineStyle()) {
359 stroke.writable()->setHairlineStyle();
360 }
361 }
362
bsalomon@google.com81712882012-11-01 17:12:34 +0000363 SkScalar tol = SK_Scalar1;
joshualitt8059eb92014-12-29 15:10:07 -0800364 tol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
bsalomon@google.com30085192011-08-19 15:42:31 +0000365
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000366 int vertexCnt;
367 int indexCnt;
368 GrPrimitiveType primType;
bsalomon@google.comb3729422012-03-07 19:13:28 +0000369 GrDrawTarget::AutoReleaseGeometry arg;
joshualitt9853cce2014-11-17 14:22:48 -0800370 if (!this->createGeom(target,
371 drawState,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000372 &primType,
373 &vertexCnt,
bsalomon@google.comb3729422012-03-07 19:13:28 +0000374 &indexCnt,
joshualitt9853cce2014-11-17 14:22:48 -0800375 &arg,
376 path,
377 *stroke,
378 tol)) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000379 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000380 }
egdaniel080e6732014-12-22 07:35:52 -0800381 // Save the current xp on the draw state so we can reset it if needed
382 SkAutoTUnref<const GrXPFactory> backupXPFactory(SkRef(drawState->getXPFactory()));
bsalomon@google.com30085192011-08-19 15:42:31 +0000383 // face culling doesn't make sense here
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000384 SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
bsalomon@google.com30085192011-08-19 15:42:31 +0000385
386 int passCount = 0;
387 const GrStencilSettings* passes[3];
tomhudson@google.com93813632011-10-27 20:21:16 +0000388 GrDrawState::DrawFace drawFace[3];
bsalomon@google.com30085192011-08-19 15:42:31 +0000389 bool reverse = false;
390 bool lastPassIsBounds;
391
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000392 if (stroke->isHairlineStyle()) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000393 passCount = 1;
394 if (stencilOnly) {
395 passes[0] = &gDirectToStencil;
396 } else {
397 passes[0] = NULL;
398 }
399 lastPassIsBounds = false;
tomhudson@google.com93813632011-10-27 20:21:16 +0000400 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000401 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000402 if (single_pass_path(path, *stroke)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000403 passCount = 1;
404 if (stencilOnly) {
405 passes[0] = &gDirectToStencil;
406 } else {
407 passes[0] = NULL;
408 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000409 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000410 lastPassIsBounds = false;
411 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000412 switch (path.getFillType()) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000413 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000414 reverse = true;
415 // fallthrough
sugoi@google.com12b4e272012-12-06 20:13:11 +0000416 case SkPath::kEvenOdd_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000417 passes[0] = &gEOStencilPass;
418 if (stencilOnly) {
419 passCount = 1;
420 lastPassIsBounds = false;
421 } else {
422 passCount = 2;
423 lastPassIsBounds = true;
424 if (reverse) {
425 passes[1] = &gInvEOColorPass;
426 } else {
427 passes[1] = &gEOColorPass;
428 }
429 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000430 drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000431 break;
432
sugoi@google.com12b4e272012-12-06 20:13:11 +0000433 case SkPath::kInverseWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000434 reverse = true;
435 // fallthrough
sugoi@google.com12b4e272012-12-06 20:13:11 +0000436 case SkPath::kWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000437 if (fSeparateStencil) {
438 if (fStencilWrapOps) {
439 passes[0] = &gWindStencilSeparateWithWrap;
440 } else {
441 passes[0] = &gWindStencilSeparateNoWrap;
442 }
443 passCount = 2;
tomhudson@google.com93813632011-10-27 20:21:16 +0000444 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000445 } else {
446 if (fStencilWrapOps) {
447 passes[0] = &gWindSingleStencilWithWrapInc;
448 passes[1] = &gWindSingleStencilWithWrapDec;
449 } else {
450 passes[0] = &gWindSingleStencilNoWrapInc;
451 passes[1] = &gWindSingleStencilNoWrapDec;
452 }
453 // which is cw and which is ccw is arbitrary.
tomhudson@google.com93813632011-10-27 20:21:16 +0000454 drawFace[0] = GrDrawState::kCW_DrawFace;
455 drawFace[1] = GrDrawState::kCCW_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000456 passCount = 3;
457 }
458 if (stencilOnly) {
459 lastPassIsBounds = false;
460 --passCount;
461 } else {
462 lastPassIsBounds = true;
tomhudson@google.com93813632011-10-27 20:21:16 +0000463 drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000464 if (reverse) {
465 passes[passCount-1] = &gInvWindColorPass;
466 } else {
467 passes[passCount-1] = &gWindColorPass;
468 }
469 }
470 break;
471 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000472 SkDEBUGFAIL("Unknown path fFill!");
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000473 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000474 }
475 }
476 }
477
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000478 SkRect devBounds;
joshualitt8059eb92014-12-29 15:10:07 -0800479 GetPathDevBounds(path, drawState->getRenderTarget(), viewMatrix, &devBounds);
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000480
bsalomon@google.com30085192011-08-19 15:42:31 +0000481 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000482 drawState->setDrawFace(drawFace[p]);
bsalomon49f085d2014-09-05 13:34:00 -0700483 if (passes[p]) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000484 *drawState->stencil() = *passes[p];
bsalomon@google.com30085192011-08-19 15:42:31 +0000485 }
486
487 if (lastPassIsBounds && (p == passCount-1)) {
egdaniel080e6732014-12-22 07:35:52 -0800488 // Reset the XP Factory on drawState
489 drawState->setXPFactory(backupXPFactory);
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000490 SkRect bounds;
joshualittd27f73e2014-12-29 07:43:36 -0800491 SkMatrix localMatrix = SkMatrix::I();
bsalomon@google.com30085192011-08-19 15:42:31 +0000492 if (reverse) {
bsalomon49f085d2014-09-05 13:34:00 -0700493 SkASSERT(drawState->getRenderTarget());
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000494 // draw over the dev bounds (which will be the whole dst surface for inv fill).
495 bounds = devBounds;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000496 SkMatrix vmi;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000497 // mapRect through persp matrix may not be correct
joshualitt8059eb92014-12-29 15:10:07 -0800498 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000499 vmi.mapRect(&bounds);
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000500 } else {
joshualittd27f73e2014-12-29 07:43:36 -0800501 if (!viewMatrix.invert(&localMatrix)) {
502 return false;
503 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000504 }
505 } else {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000506 bounds = path.getBounds();
bsalomon@google.com30085192011-08-19 15:42:31 +0000507 }
joshualitt9853cce2014-11-17 14:22:48 -0800508 GrDrawTarget::AutoGeometryPush agp(target);
joshualitt8059eb92014-12-29 15:10:07 -0800509 const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
510 viewMatrix;
511 target->drawRect(drawState, color, viewM, bounds, NULL, &localMatrix);
bsalomon@google.com30085192011-08-19 15:42:31 +0000512 } else {
513 if (passCount > 1) {
egdaniel080e6732014-12-22 07:35:52 -0800514 drawState->setDisableColorXPFactory();
bsalomon@google.com30085192011-08-19 15:42:31 +0000515 }
joshualitt5478d422014-11-14 16:00:38 -0800516 GrDrawState::AutoRestoreEffects are(drawState);
joshualitt56995b52014-12-11 15:44:02 -0800517 SkAutoTUnref<const GrGeometryProcessor> gp(
joshualitt8059eb92014-12-29 15:10:07 -0800518 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
519 color,
520 viewMatrix,
521 SkMatrix::I(),
joshualitt56995b52014-12-11 15:44:02 -0800522 false,
523 newCoverage));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000524 if (indexCnt) {
joshualitt9853cce2014-11-17 14:22:48 -0800525 target->drawIndexed(drawState,
joshualitt56995b52014-12-11 15:44:02 -0800526 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800527 primType,
528 0,
529 0,
530 vertexCnt,
531 indexCnt,
532 &devBounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000533 } else {
joshualitt56995b52014-12-11 15:44:02 -0800534 target->drawNonIndexed(drawState, gp, primType, 0, vertexCnt, &devBounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000535 }
536 }
537 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000538 return true;
bsalomon@google.com30085192011-08-19 15:42:31 +0000539}
540
joshualitt9853cce2014-11-17 14:22:48 -0800541bool GrDefaultPathRenderer::canDrawPath(const GrDrawTarget* target,
542 const GrDrawState* drawState,
joshualitt8059eb92014-12-29 15:10:07 -0800543 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800544 const SkPath& path,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000545 const SkStrokeRec& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000546 bool antiAlias) const {
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000547 // this class can draw any path with any fill but doesn't do any anti-aliasing.
egdanielaf18a092015-01-05 10:22:28 -0800548 return !antiAlias && (stroke.isFillStyle() || IsStrokeHairlineOrEquivalent(stroke,
549 viewMatrix,
550 NULL));
bsalomon@google.com30085192011-08-19 15:42:31 +0000551}
552
joshualitt9853cce2014-11-17 14:22:48 -0800553bool GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
554 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800555 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800556 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800557 const SkPath& path,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000558 const SkStrokeRec& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000559 bool antiAlias) {
joshualitt9853cce2014-11-17 14:22:48 -0800560 return this->internalDrawPath(target,
561 drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800562 color,
joshualitt8059eb92014-12-29 15:10:07 -0800563 viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800564 path,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000565 stroke,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000566 false);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000567}
568
joshualitt9853cce2014-11-17 14:22:48 -0800569void GrDefaultPathRenderer::onStencilPath(GrDrawTarget* target,
570 GrDrawState* drawState,
joshualitt8059eb92014-12-29 15:10:07 -0800571 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800572 const SkPath& path,
573 const SkStrokeRec& stroke) {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000574 SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
575 SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
joshualitt8059eb92014-12-29 15:10:07 -0800576 this->internalDrawPath(target, drawState, GrColor_WHITE, viewMatrix, path, stroke, true);
bsalomon@google.com30085192011-08-19 15:42:31 +0000577}