blob: 85485c86a3da0f1ce2091ebabe1c8141e0ab5123 [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"
bsalomon@google.com30085192011-08-19 15:42:31 +000015#include "SkTrace.h"
16
17
18GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
19 bool stencilWrapOpsSupport)
20 : fSeparateStencil(separateStencilSupport)
bsalomon@google.comc2099d22012-03-02 21:26:50 +000021 , fStencilWrapOps(stencilWrapOpsSupport) {
bsalomon@google.com289533a2011-10-27 12:34:25 +000022}
23
24
bsalomon@google.com30085192011-08-19 15:42:31 +000025////////////////////////////////////////////////////////////////////////////////
26// Stencil rules for paths
27
28////// Even/Odd
29
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000030GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
31 kInvert_StencilOp,
32 kKeep_StencilOp,
33 kAlwaysIfInClip_StencilFunc,
34 0xffff,
35 0xffff,
36 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000037
38// ok not to check clip b/c stencil pass only wrote inside clip
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000039GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
40 kZero_StencilOp,
41 kZero_StencilOp,
42 kNotEqual_StencilFunc,
43 0xffff,
44 0x0000,
45 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000046
47// have to check clip b/c outside clip will always be zero.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000048GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
49 kZero_StencilOp,
50 kZero_StencilOp,
51 kEqualIfInClip_StencilFunc,
52 0xffff,
53 0x0000,
54 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000055
56////// Winding
57
58// when we have separate stencil we increment front faces / decrement back faces
59// when we don't have wrap incr and decr we use the stencil test to simulate
60// them.
61
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000062GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
bsalomon@google.com30085192011-08-19 15:42:31 +000063 kIncWrap_StencilOp, kDecWrap_StencilOp,
64 kKeep_StencilOp, kKeep_StencilOp,
65 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
tomhudson@google.com62b09682011-11-09 16:39:17 +000066 0xffff, 0xffff,
67 0xffff, 0xffff,
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000068 0xffff, 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000069
70// if inc'ing the max value, invert to make 0
71// if dec'ing zero invert to make all ones.
72// we can't avoid touching the stencil on both passing and
73// failing, so we can't resctrict ourselves to the clip.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000074GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
bsalomon@google.com30085192011-08-19 15:42:31 +000075 kInvert_StencilOp, kInvert_StencilOp,
76 kIncClamp_StencilOp, kDecClamp_StencilOp,
77 kEqual_StencilFunc, kEqual_StencilFunc,
tomhudson@google.com62b09682011-11-09 16:39:17 +000078 0xffff, 0xffff,
79 0xffff, 0x0000,
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000080 0xffff, 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000081
82// When there are no separate faces we do two passes to setup the winding rule
83// stencil. First we draw the front faces and inc, then we draw the back faces
84// and dec. These are same as the above two split into the incrementing and
85// decrementing passes.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000086GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
87 kIncWrap_StencilOp,
88 kKeep_StencilOp,
89 kAlwaysIfInClip_StencilFunc,
90 0xffff,
91 0xffff,
92 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +000093
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000094GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
95 kDecWrap_StencilOp,
96 kKeep_StencilOp,
97 kAlwaysIfInClip_StencilFunc,
98 0xffff,
99 0xffff,
100 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +0000101
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000102GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
103 kInvert_StencilOp,
104 kIncClamp_StencilOp,
105 kEqual_StencilFunc,
106 0xffff,
107 0xffff,
108 0xffff);
109
110GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
111 kInvert_StencilOp,
112 kDecClamp_StencilOp,
113 kEqual_StencilFunc,
114 0xffff,
115 0x0000,
116 0xffff);
117
118// Color passes are the same whether we use the two-sided stencil or two passes
119
120GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
121 kZero_StencilOp,
122 kZero_StencilOp,
123 kNonZeroIfInClip_StencilFunc,
124 0xffff,
125 0x0000,
126 0xffff);
127
128GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
129 kZero_StencilOp,
130 kZero_StencilOp,
131 kEqualIfInClip_StencilFunc,
132 0xffff,
133 0x0000,
134 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +0000135
136////// Normal render to stencil
137
138// Sometimes the default path renderer can draw a path directly to the stencil
139// buffer without having to first resolve the interior / exterior.
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000140GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
141 kZero_StencilOp,
142 kIncClamp_StencilOp,
143 kAlwaysIfInClip_StencilFunc,
144 0xffff,
145 0x0000,
146 0xffff);
bsalomon@google.com30085192011-08-19 15:42:31 +0000147
148////////////////////////////////////////////////////////////////////////////////
149// Helpers for drawPath
150
bsalomon@google.com30085192011-08-19 15:42:31 +0000151#define STENCIL_OFF 0 // Always disable stencil (even when needed)
152
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000153static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000154#if STENCIL_OFF
155 return true;
156#else
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000157 if (!stroke.isHairlineStyle() && !path.isInverseFillType()) {
bsalomon@google.com7d72c452012-01-30 14:02:44 +0000158 return path.isConvex();
bsalomon@google.com30085192011-08-19 15:42:31 +0000159 }
160 return false;
161#endif
162}
163
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000164GrPathRenderer::StencilSupport GrDefaultPathRenderer::onGetStencilSupport(
165 const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000166 const SkStrokeRec& stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000167 const GrDrawTarget*) const {
168 if (single_pass_path(path, stroke)) {
169 return GrPathRenderer::kNoRestriction_StencilSupport;
170 } else {
171 return GrPathRenderer::kStencilOnly_StencilSupport;
172 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000173}
174
sugoi@google.com12b4e272012-12-06 20:13:11 +0000175static inline void append_countour_edge_indices(bool hairLine,
bsalomon@google.com30085192011-08-19 15:42:31 +0000176 uint16_t fanCenterIdx,
177 uint16_t edgeV0Idx,
178 uint16_t** indices) {
179 // when drawing lines we're appending line segments along
180 // the contour. When applying the other fill rules we're
181 // drawing triangle fans around fanCenterIdx.
sugoi@google.com12b4e272012-12-06 20:13:11 +0000182 if (!hairLine) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000183 *((*indices)++) = fanCenterIdx;
184 }
185 *((*indices)++) = edgeV0Idx;
186 *((*indices)++) = edgeV0Idx + 1;
187}
188
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000189bool GrDefaultPathRenderer::createGeom(const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000190 const SkStrokeRec& stroke,
bsalomon@google.com81712882012-11-01 17:12:34 +0000191 SkScalar srcSpaceTol,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000192 GrDrawTarget* target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000193 GrPrimitiveType* primType,
194 int* vertexCnt,
bsalomon@google.comb3729422012-03-07 19:13:28 +0000195 int* indexCnt,
196 GrDrawTarget::AutoReleaseGeometry* arg) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000197 {
198 SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
199
bsalomon@google.com81712882012-11-01 17:12:34 +0000200 SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000201 int contourCnt;
202 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
bsalomon@google.com30085192011-08-19 15:42:31 +0000203 srcSpaceTol);
204
205 if (maxPts <= 0) {
206 return false;
207 }
208 if (maxPts > ((int)SK_MaxU16 + 1)) {
209 GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
210 return false;
211 }
212
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000213 bool indexed = contourCnt > 1;
bsalomon@google.com30085192011-08-19 15:42:31 +0000214
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000215 const bool isHairline = stroke.isHairlineStyle();
sugoi@google.com12b4e272012-12-06 20:13:11 +0000216
bsalomon@google.com30085192011-08-19 15:42:31 +0000217 int maxIdxs = 0;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000218 if (isHairline) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000219 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000220 maxIdxs = 2 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000221 *primType = kLines_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000222 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000223 *primType = kLineStrip_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000224 }
225 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000226 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000227 maxIdxs = 3 * maxPts;
bsalomon@google.com47059542012-06-06 20:51:20 +0000228 *primType = kTriangles_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000229 } else {
bsalomon@google.com47059542012-06-06 20:51:20 +0000230 *primType = kTriangleFan_GrPrimitiveType;
bsalomon@google.com30085192011-08-19 15:42:31 +0000231 }
232 }
233
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000234 target->drawState()->setDefaultVertexAttribs();
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000235 if (!arg->set(target, maxPts, maxIdxs)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000236 return false;
237 }
bsalomon@google.comb3729422012-03-07 19:13:28 +0000238
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000239 uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());
bsalomon@google.comb3729422012-03-07 19:13:28 +0000240 uint16_t* idx = idxBase;
241 uint16_t subpathIdxStart = 0;
242
243 GrPoint* base = reinterpret_cast<GrPoint*>(arg->vertices());
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000244 SkASSERT(NULL != base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000245 GrPoint* vert = base;
246
bsalomon@google.com30085192011-08-19 15:42:31 +0000247 GrPoint pts[4];
248
249 bool first = true;
250 int subpath = 0;
251
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000252 SkPath::Iter iter(path, false);
bsalomon@google.com30085192011-08-19 15:42:31 +0000253
254 for (;;) {
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000255 SkPath::Verb verb = iter.next(pts);
256 switch (verb) {
reed@google.com277c3f82013-05-31 15:17:50 +0000257 case SkPath::kConic_Verb:
258 SkASSERT(0);
259 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000260 case SkPath::kMove_Verb:
bsalomon@google.com30085192011-08-19 15:42:31 +0000261 if (!first) {
262 uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000263 subpathIdxStart = currIdx;
264 ++subpath;
265 }
266 *vert = pts[0];
267 vert++;
268 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000269 case SkPath::kLine_Verb:
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000270 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000271 uint16_t prevIdx = (uint16_t)(vert - base) - 1;
sugoi@google.com12b4e272012-12-06 20:13:11 +0000272 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000273 prevIdx, &idx);
274 }
275 *(vert++) = pts[1];
276 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000277 case SkPath::kQuad_Verb: {
bsalomon@google.com30085192011-08-19 15:42:31 +0000278 // first pt of quad is the pt we ended on in previous step
279 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000280 uint16_t numPts = (uint16_t)
bsalomon@google.com30085192011-08-19 15:42:31 +0000281 GrPathUtils::generateQuadraticPoints(
282 pts[0], pts[1], pts[2],
283 srcSpaceTolSqd, &vert,
284 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000285 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000286 for (uint16_t i = 0; i < numPts; ++i) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000287 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000288 firstQPtIdx + i, &idx);
289 }
290 }
291 break;
292 }
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000293 case SkPath::kCubic_Verb: {
bsalomon@google.com30085192011-08-19 15:42:31 +0000294 // first pt of cubic is the pt we ended on in previous step
295 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
296 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
297 pts[0], pts[1], pts[2], pts[3],
298 srcSpaceTolSqd, &vert,
299 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000300 if (indexed) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000301 for (uint16_t i = 0; i < numPts; ++i) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000302 append_countour_edge_indices(isHairline, subpathIdxStart,
bsalomon@google.com30085192011-08-19 15:42:31 +0000303 firstCPtIdx + i, &idx);
304 }
305 }
306 break;
307 }
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000308 case SkPath::kClose_Verb:
bsalomon@google.com30085192011-08-19 15:42:31 +0000309 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000310 case SkPath::kDone_Verb:
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000311 // uint16_t currIdx = (uint16_t) (vert - base);
bsalomon@google.com30085192011-08-19 15:42:31 +0000312 goto FINISHED;
313 }
314 first = false;
315 }
316FINISHED:
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000317 SkASSERT((vert - base) <= maxPts);
318 SkASSERT((idx - idxBase) <= maxIdxs);
bsalomon@google.com30085192011-08-19 15:42:31 +0000319
robertphillips@google.comadacc702013-10-14 21:53:24 +0000320 *vertexCnt = static_cast<int>(vert - base);
321 *indexCnt = static_cast<int>(idx - idxBase);
bsalomon@google.com30085192011-08-19 15:42:31 +0000322
bsalomon@google.com30085192011-08-19 15:42:31 +0000323 }
bsalomon@google.com30085192011-08-19 15:42:31 +0000324 return true;
325}
326
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000327bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000328 const SkStrokeRec& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000329 GrDrawTarget* target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000330 bool stencilOnly) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000331
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000332 SkMatrix viewM = target->getDrawState().getViewMatrix();
bsalomon@google.com81712882012-11-01 17:12:34 +0000333 SkScalar tol = SK_Scalar1;
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000334 tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
bsalomon@google.com30085192011-08-19 15:42:31 +0000335
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000336 int vertexCnt;
337 int indexCnt;
338 GrPrimitiveType primType;
bsalomon@google.comb3729422012-03-07 19:13:28 +0000339 GrDrawTarget::AutoReleaseGeometry arg;
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000340 if (!this->createGeom(path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000341 stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000342 tol,
343 target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000344 &primType,
345 &vertexCnt,
bsalomon@google.comb3729422012-03-07 19:13:28 +0000346 &indexCnt,
347 &arg)) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000348 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000349 }
350
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000351 SkASSERT(NULL != target);
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000352 GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
353 GrDrawState* drawState = target->drawState();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000354 bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
bsalomon@google.com30085192011-08-19 15:42:31 +0000355 // face culling doesn't make sense here
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000356 SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
bsalomon@google.com30085192011-08-19 15:42:31 +0000357
358 int passCount = 0;
359 const GrStencilSettings* passes[3];
tomhudson@google.com93813632011-10-27 20:21:16 +0000360 GrDrawState::DrawFace drawFace[3];
bsalomon@google.com30085192011-08-19 15:42:31 +0000361 bool reverse = false;
362 bool lastPassIsBounds;
363
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000364 if (stroke.isHairlineStyle()) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000365 passCount = 1;
366 if (stencilOnly) {
367 passes[0] = &gDirectToStencil;
368 } else {
369 passes[0] = NULL;
370 }
371 lastPassIsBounds = false;
tomhudson@google.com93813632011-10-27 20:21:16 +0000372 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000373 } else {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000374 if (single_pass_path(path, stroke)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000375 passCount = 1;
376 if (stencilOnly) {
377 passes[0] = &gDirectToStencil;
378 } else {
379 passes[0] = NULL;
380 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000381 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000382 lastPassIsBounds = false;
383 } else {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000384 switch (path.getFillType()) {
385 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000386 reverse = true;
387 // fallthrough
sugoi@google.com12b4e272012-12-06 20:13:11 +0000388 case SkPath::kEvenOdd_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000389 passes[0] = &gEOStencilPass;
390 if (stencilOnly) {
391 passCount = 1;
392 lastPassIsBounds = false;
393 } else {
394 passCount = 2;
395 lastPassIsBounds = true;
396 if (reverse) {
397 passes[1] = &gInvEOColorPass;
398 } else {
399 passes[1] = &gEOColorPass;
400 }
401 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000402 drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000403 break;
404
sugoi@google.com12b4e272012-12-06 20:13:11 +0000405 case SkPath::kInverseWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000406 reverse = true;
407 // fallthrough
sugoi@google.com12b4e272012-12-06 20:13:11 +0000408 case SkPath::kWinding_FillType:
bsalomon@google.com30085192011-08-19 15:42:31 +0000409 if (fSeparateStencil) {
410 if (fStencilWrapOps) {
411 passes[0] = &gWindStencilSeparateWithWrap;
412 } else {
413 passes[0] = &gWindStencilSeparateNoWrap;
414 }
415 passCount = 2;
tomhudson@google.com93813632011-10-27 20:21:16 +0000416 drawFace[0] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000417 } else {
418 if (fStencilWrapOps) {
419 passes[0] = &gWindSingleStencilWithWrapInc;
420 passes[1] = &gWindSingleStencilWithWrapDec;
421 } else {
422 passes[0] = &gWindSingleStencilNoWrapInc;
423 passes[1] = &gWindSingleStencilNoWrapDec;
424 }
425 // which is cw and which is ccw is arbitrary.
tomhudson@google.com93813632011-10-27 20:21:16 +0000426 drawFace[0] = GrDrawState::kCW_DrawFace;
427 drawFace[1] = GrDrawState::kCCW_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000428 passCount = 3;
429 }
430 if (stencilOnly) {
431 lastPassIsBounds = false;
432 --passCount;
433 } else {
434 lastPassIsBounds = true;
tomhudson@google.com93813632011-10-27 20:21:16 +0000435 drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
bsalomon@google.com30085192011-08-19 15:42:31 +0000436 if (reverse) {
437 passes[passCount-1] = &gInvWindColorPass;
438 } else {
439 passes[passCount-1] = &gWindColorPass;
440 }
441 }
442 break;
443 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000444 SkDEBUGFAIL("Unknown path fFill!");
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000445 return false;
bsalomon@google.com30085192011-08-19 15:42:31 +0000446 }
447 }
448 }
449
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000450 SkRect devBounds;
451 GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds);
452
bsalomon@google.com30085192011-08-19 15:42:31 +0000453 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000454 drawState->setDrawFace(drawFace[p]);
bsalomon@google.com30085192011-08-19 15:42:31 +0000455 if (NULL != passes[p]) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000456 *drawState->stencil() = *passes[p];
bsalomon@google.com30085192011-08-19 15:42:31 +0000457 }
458
459 if (lastPassIsBounds && (p == passCount-1)) {
460 if (!colorWritesWereDisabled) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000461 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
bsalomon@google.com30085192011-08-19 15:42:31 +0000462 }
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000463 SkRect bounds;
bsalomon@google.com137f1342013-05-29 21:27:53 +0000464 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com30085192011-08-19 15:42:31 +0000465 if (reverse) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000466 SkASSERT(NULL != drawState->getRenderTarget());
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000467 // draw over the dev bounds (which will be the whole dst surface for inv fill).
468 bounds = devBounds;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000469 SkMatrix vmi;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000470 // mapRect through persp matrix may not be correct
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000471 if (!drawState->getViewMatrix().hasPerspective() &&
472 drawState->getViewInverse(&vmi)) {
bsalomon@google.com30085192011-08-19 15:42:31 +0000473 vmi.mapRect(&bounds);
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000474 } else {
bsalomon@google.com137f1342013-05-29 21:27:53 +0000475 avmr.setIdentity(drawState);
bsalomon@google.com30085192011-08-19 15:42:31 +0000476 }
477 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000478 bounds = path.getBounds();
bsalomon@google.com30085192011-08-19 15:42:31 +0000479 }
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000480 GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000481 target->drawSimpleRect(bounds, NULL);
bsalomon@google.com30085192011-08-19 15:42:31 +0000482 } else {
483 if (passCount > 1) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000484 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
bsalomon@google.com30085192011-08-19 15:42:31 +0000485 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000486 if (indexCnt) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000487 target->drawIndexed(primType, 0, 0,
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000488 vertexCnt, indexCnt, &devBounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000489 } else {
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000490 target->drawNonIndexed(primType, 0, vertexCnt, &devBounds);
bsalomon@google.com30085192011-08-19 15:42:31 +0000491 }
492 }
493 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000494 return true;
bsalomon@google.com30085192011-08-19 15:42:31 +0000495}
496
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000497bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000498 const SkStrokeRec& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000499 const GrDrawTarget* target,
500 bool antiAlias) const {
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000501 // this class can draw any path with any fill but doesn't do any anti-aliasing.
502 return (stroke.isFillStyle() || stroke.isHairlineStyle()) && !antiAlias;
bsalomon@google.com30085192011-08-19 15:42:31 +0000503}
504
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000505bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000506 const SkStrokeRec& stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000507 GrDrawTarget* target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000508 bool antiAlias) {
509 return this->internalDrawPath(path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000510 stroke,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000511 target,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000512 false);
513}
514
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000515void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000516 const SkStrokeRec& stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000517 GrDrawTarget* target) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000518 SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
519 SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
sugoi@google.com12b4e272012-12-06 20:13:11 +0000520 this->internalDrawPath(path, stroke, target, true);
bsalomon@google.com30085192011-08-19 15:42:31 +0000521}