GrDefaultPathRenderer.cpp revision 99c7c07e0f1f7b78980eb21d84bebda8b45a7178
1/*
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 "GrBatch.h"
11#include "GrBatchTarget.h"
12#include "GrBufferAllocPool.h"
13#include "GrContext.h"
14#include "GrDefaultGeoProcFactory.h"
15#include "GrPathUtils.h"
16#include "GrPipelineBuilder.h"
17#include "GrVertexBuffer.h"
18#include "SkGeometry.h"
19#include "SkString.h"
20#include "SkStrokeRec.h"
21#include "SkTLazy.h"
22#include "SkTraceEvent.h"
23
24GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
25                                             bool stencilWrapOpsSupport)
26    : fSeparateStencil(separateStencilSupport)
27    , fStencilWrapOps(stencilWrapOpsSupport) {
28}
29
30
31////////////////////////////////////////////////////////////////////////////////
32// Stencil rules for paths
33
34////// Even/Odd
35
36GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
37    kInvert_StencilOp,
38    kKeep_StencilOp,
39    kAlwaysIfInClip_StencilFunc,
40    0xffff,
41    0xffff,
42    0xffff);
43
44// ok not to check clip b/c stencil pass only wrote inside clip
45GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
46    kZero_StencilOp,
47    kZero_StencilOp,
48    kNotEqual_StencilFunc,
49    0xffff,
50    0x0000,
51    0xffff);
52
53// have to check clip b/c outside clip will always be zero.
54GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
55    kZero_StencilOp,
56    kZero_StencilOp,
57    kEqualIfInClip_StencilFunc,
58    0xffff,
59    0x0000,
60    0xffff);
61
62////// Winding
63
64// when we have separate stencil we increment front faces / decrement back faces
65// when we don't have wrap incr and decr we use the stencil test to simulate
66// them.
67
68GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
69    kIncWrap_StencilOp,             kDecWrap_StencilOp,
70    kKeep_StencilOp,                kKeep_StencilOp,
71    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
72    0xffff,                         0xffff,
73    0xffff,                         0xffff,
74    0xffff,                         0xffff);
75
76// if inc'ing the max value, invert to make 0
77// if dec'ing zero invert to make all ones.
78// we can't avoid touching the stencil on both passing and
79// failing, so we can't resctrict ourselves to the clip.
80GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
81    kInvert_StencilOp,              kInvert_StencilOp,
82    kIncClamp_StencilOp,            kDecClamp_StencilOp,
83    kEqual_StencilFunc,             kEqual_StencilFunc,
84    0xffff,                         0xffff,
85    0xffff,                         0x0000,
86    0xffff,                         0xffff);
87
88// When there are no separate faces we do two passes to setup the winding rule
89// stencil. First we draw the front faces and inc, then we draw the back faces
90// and dec. These are same as the above two split into the incrementing and
91// decrementing passes.
92GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
93    kIncWrap_StencilOp,
94    kKeep_StencilOp,
95    kAlwaysIfInClip_StencilFunc,
96    0xffff,
97    0xffff,
98    0xffff);
99
100GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
101    kDecWrap_StencilOp,
102    kKeep_StencilOp,
103    kAlwaysIfInClip_StencilFunc,
104    0xffff,
105    0xffff,
106    0xffff);
107
108GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
109    kInvert_StencilOp,
110    kIncClamp_StencilOp,
111    kEqual_StencilFunc,
112    0xffff,
113    0xffff,
114    0xffff);
115
116GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
117    kInvert_StencilOp,
118    kDecClamp_StencilOp,
119    kEqual_StencilFunc,
120    0xffff,
121    0x0000,
122    0xffff);
123
124// Color passes are the same whether we use the two-sided stencil or two passes
125
126GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
127    kZero_StencilOp,
128    kZero_StencilOp,
129    kNonZeroIfInClip_StencilFunc,
130    0xffff,
131    0x0000,
132    0xffff);
133
134GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
135    kZero_StencilOp,
136    kZero_StencilOp,
137    kEqualIfInClip_StencilFunc,
138    0xffff,
139    0x0000,
140    0xffff);
141
142////// Normal render to stencil
143
144// Sometimes the default path renderer can draw a path directly to the stencil
145// buffer without having to first resolve the interior / exterior.
146GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
147    kZero_StencilOp,
148    kIncClamp_StencilOp,
149    kAlwaysIfInClip_StencilFunc,
150    0xffff,
151    0x0000,
152    0xffff);
153
154////////////////////////////////////////////////////////////////////////////////
155// Helpers for drawPath
156
157#define STENCIL_OFF     0   // Always disable stencil (even when needed)
158
159static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
160#if STENCIL_OFF
161    return true;
162#else
163    if (!stroke.isHairlineStyle() && !path.isInverseFillType()) {
164        return path.isConvex();
165    }
166    return false;
167#endif
168}
169
170GrPathRenderer::StencilSupport
171GrDefaultPathRenderer::onGetStencilSupport(const GrDrawTarget*,
172                                           const GrPipelineBuilder*,
173                                           const SkPath& path,
174                                           const GrStrokeInfo& stroke) const {
175    if (single_pass_path(path, stroke.getStrokeRec())) {
176        return GrPathRenderer::kNoRestriction_StencilSupport;
177    } else {
178        return GrPathRenderer::kStencilOnly_StencilSupport;
179    }
180}
181
182static inline void append_countour_edge_indices(bool hairLine,
183                                                uint16_t fanCenterIdx,
184                                                uint16_t edgeV0Idx,
185                                                uint16_t** indices) {
186    // when drawing lines we're appending line segments along
187    // the contour. When applying the other fill rules we're
188    // drawing triangle fans around fanCenterIdx.
189    if (!hairLine) {
190        *((*indices)++) = fanCenterIdx;
191    }
192    *((*indices)++) = edgeV0Idx;
193    *((*indices)++) = edgeV0Idx + 1;
194}
195
196static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint pts[],
197                            SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed,
198                            bool isHairline, uint16_t subpathIdxStart, int offset, uint16_t** idx) {
199    // first pt of quad is the pt we ended on in previous step
200    uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1 + offset;
201    uint16_t numPts =  (uint16_t)
202        GrPathUtils::generateQuadraticPoints(
203            pts[0], pts[1], pts[2],
204            srcSpaceTolSqd, vert,
205            GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
206    if (indexed) {
207        for (uint16_t i = 0; i < numPts; ++i) {
208            append_countour_edge_indices(isHairline, subpathIdxStart,
209                                         firstQPtIdx + i, idx);
210        }
211    }
212}
213
214class DefaultPathBatch : public GrBatch {
215public:
216    struct Geometry {
217        GrColor fColor;
218        SkPath fPath;
219        SkScalar fTolerance;
220    };
221
222    static GrBatch* Create(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix,
223                           bool isHairline, const SkRect& devBounds) {
224        return SkNEW_ARGS(DefaultPathBatch, (geometry, coverage, viewMatrix, isHairline,
225                                             devBounds));
226    }
227
228    const char* name() const override { return "DefaultPathBatch"; }
229
230    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
231        // When this is called on a batch, there is only one geometry bundle
232        out->setKnownFourComponents(fGeoData[0].fColor);
233    }
234    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
235        out->setKnownSingleComponent(this->coverage());
236    }
237
238    void initBatchTracker(const GrPipelineInfo& init) override {
239        // Handle any color overrides
240        if (init.fColorIgnored) {
241            fGeoData[0].fColor = GrColor_ILLEGAL;
242        } else if (GrColor_ILLEGAL != init.fOverrideColor) {
243            fGeoData[0].fColor = init.fOverrideColor;
244        }
245
246        // setup batch properties
247        fBatch.fColorIgnored = init.fColorIgnored;
248        fBatch.fColor = fGeoData[0].fColor;
249        fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
250        fBatch.fCoverageIgnored = init.fCoverageIgnored;
251    }
252
253    void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
254        SkAutoTUnref<const GrGeometryProcessor> gp(
255                GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
256                                                this->color(),
257                                                this->viewMatrix(),
258                                                SkMatrix::I(),
259                                                false,
260                                                this->coverage()));
261
262        size_t vertexStride = gp->getVertexStride();
263        SkASSERT(vertexStride == sizeof(SkPoint));
264
265        batchTarget->initDraw(gp, pipeline);
266
267        // TODO this is hacky, but the only way we have to initialize the GP is to use the
268        // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
269        // everywhere we can remove this nastiness
270        GrPipelineInfo init;
271        init.fColorIgnored = fBatch.fColorIgnored;
272        init.fOverrideColor = GrColor_ILLEGAL;
273        init.fCoverageIgnored = fBatch.fCoverageIgnored;
274        init.fUsesLocalCoords = this->usesLocalCoords();
275        gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
276
277        int instanceCount = fGeoData.count();
278
279        // compute number of vertices
280        int maxVertices = 0;
281
282        // We will use index buffers if we have multiple paths or one path with multiple contours
283        bool isIndexed = instanceCount > 1;
284        for (int i = 0; i < instanceCount; i++) {
285            Geometry& args = fGeoData[i];
286
287            int contourCount;
288            maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount,
289                                                            args.fTolerance);
290
291            isIndexed = isIndexed || contourCount > 1;
292        }
293
294        if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) {
295            SkDebugf("Cannot render path (%d)\n", maxVertices);
296            return;
297        }
298
299        // determine primitiveType
300        int maxIndices = 0;
301        GrPrimitiveType primitiveType;
302        if (this->isHairline()) {
303            if (isIndexed) {
304                maxIndices = 2 * maxVertices;
305                primitiveType = kLines_GrPrimitiveType;
306            } else {
307                primitiveType = kLineStrip_GrPrimitiveType;
308            }
309        } else {
310            if (isIndexed) {
311                maxIndices = 3 * maxVertices;
312                primitiveType = kTriangles_GrPrimitiveType;
313            } else {
314                primitiveType = kTriangleFan_GrPrimitiveType;
315            }
316        }
317
318        // allocate vertex / index buffers
319        const GrVertexBuffer* vertexBuffer;
320        int firstVertex;
321
322        void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
323                                                              maxVertices,
324                                                              &vertexBuffer,
325                                                              &firstVertex);
326
327        if (!vertices) {
328            SkDebugf("Could not allocate vertices\n");
329            return;
330        }
331
332        const GrIndexBuffer* indexBuffer;
333        int firstIndex;
334
335        void* indices = NULL;
336        if (isIndexed) {
337            indices = batchTarget->indexPool()->makeSpace(maxIndices,
338                                                          &indexBuffer,
339                                                          &firstIndex);
340
341            if (!indices) {
342                SkDebugf("Could not allocate indices\n");
343                return;
344            }
345        }
346
347        // fill buffers
348        int vertexOffset = 0;
349        int indexOffset = 0;
350        for (int i = 0; i < instanceCount; i++) {
351            Geometry& args = fGeoData[i];
352
353            int vertexCnt = 0;
354            int indexCnt = 0;
355            if (!this->createGeom(vertices,
356                                  vertexOffset,
357                                  indices,
358                                  indexOffset,
359                                  &vertexCnt,
360                                  &indexCnt,
361                                  args.fPath,
362                                  args.fTolerance,
363                                  isIndexed)) {
364                return;
365            }
366
367            vertexOffset += vertexCnt;
368            indexOffset += indexCnt;
369            SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices);
370        }
371
372        GrDrawTarget::DrawInfo drawInfo;
373        drawInfo.setPrimitiveType(primitiveType);
374        drawInfo.setVertexBuffer(vertexBuffer);
375        drawInfo.setStartVertex(firstVertex);
376        drawInfo.setVertexCount(vertexOffset);
377        if (isIndexed) {
378            drawInfo.setIndexBuffer(indexBuffer);
379            drawInfo.setStartIndex(firstIndex);
380            drawInfo.setIndexCount(indexOffset);
381        } else {
382            drawInfo.setStartIndex(0);
383            drawInfo.setIndexCount(0);
384        }
385        batchTarget->draw(drawInfo);
386
387        // put back reserves
388        batchTarget->putBackIndices((size_t)(maxIndices - indexOffset));
389        batchTarget->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride);
390    }
391
392    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
393
394private:
395    DefaultPathBatch(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix,
396                     bool isHairline, const SkRect& devBounds) {
397        this->initClassID<DefaultPathBatch>();
398        fBatch.fCoverage = coverage;
399        fBatch.fIsHairline = isHairline;
400        fBatch.fViewMatrix = viewMatrix;
401        fGeoData.push_back(geometry);
402
403        this->setBounds(devBounds);
404    }
405
406    bool onCombineIfPossible(GrBatch* t) override {
407        DefaultPathBatch* that = t->cast<DefaultPathBatch>();
408
409        if (this->color() != that->color()) {
410            return false;
411        }
412
413        if (this->coverage() != that->coverage()) {
414            return false;
415        }
416
417        if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
418            return false;
419        }
420
421        if (this->isHairline() != that->isHairline()) {
422            return false;
423        }
424
425        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
426        this->joinBounds(that->bounds());
427        return true;
428    }
429
430    bool createGeom(void* vertices,
431                    size_t vertexOffset,
432                    void* indices,
433                    size_t indexOffset,
434                    int* vertexCnt,
435                    int* indexCnt,
436                    const SkPath& path,
437                    SkScalar srcSpaceTol,
438                    bool isIndexed)  {
439        {
440            SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
441
442            uint16_t indexOffsetU16 = (uint16_t)indexOffset;
443            uint16_t vertexOffsetU16 = (uint16_t)vertexOffset;
444
445            uint16_t* idxBase = reinterpret_cast<uint16_t*>(indices) + indexOffsetU16;
446            uint16_t* idx = idxBase;
447            uint16_t subpathIdxStart = vertexOffsetU16;
448
449            SkPoint* base = reinterpret_cast<SkPoint*>(vertices) + vertexOffset;
450            SkPoint* vert = base;
451
452            SkPoint pts[4];
453
454            bool first = true;
455            int subpath = 0;
456
457            SkPath::Iter iter(path, false);
458
459            bool done = false;
460            while (!done) {
461                SkPath::Verb verb = iter.next(pts);
462                switch (verb) {
463                    case SkPath::kMove_Verb:
464                        if (!first) {
465                            uint16_t currIdx = (uint16_t) (vert - base) + vertexOffsetU16;
466                            subpathIdxStart = currIdx;
467                            ++subpath;
468                        }
469                        *vert = pts[0];
470                        vert++;
471                        break;
472                    case SkPath::kLine_Verb:
473                        if (isIndexed) {
474                            uint16_t prevIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
475                            append_countour_edge_indices(this->isHairline(), subpathIdxStart,
476                                                         prevIdx, &idx);
477                        }
478                        *(vert++) = pts[1];
479                        break;
480                    case SkPath::kConic_Verb: {
481                        SkScalar weight = iter.conicWeight();
482                        SkAutoConicToQuads converter;
483                        // Converting in src-space, hance the finer tolerance (0.25)
484                        // TODO: find a way to do this in dev-space so the tolerance means something
485                        const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
486                        for (int i = 0; i < converter.countQuads(); ++i) {
487                            add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol,
488                                     isIndexed, this->isHairline(), subpathIdxStart,
489                                     (int)vertexOffset, &idx);
490                        }
491                        break;
492                    }
493                    case SkPath::kQuad_Verb:
494                        add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, isIndexed,
495                                 this->isHairline(), subpathIdxStart, (int)vertexOffset, &idx);
496                        break;
497                    case SkPath::kCubic_Verb: {
498                        // first pt of cubic is the pt we ended on in previous step
499                        uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
500                        uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
501                                        pts[0], pts[1], pts[2], pts[3],
502                                        srcSpaceTolSqd, &vert,
503                                        GrPathUtils::cubicPointCount(pts, srcSpaceTol));
504                        if (isIndexed) {
505                            for (uint16_t i = 0; i < numPts; ++i) {
506                                append_countour_edge_indices(this->isHairline(), subpathIdxStart,
507                                                             firstCPtIdx + i, &idx);
508                            }
509                        }
510                        break;
511                    }
512                    case SkPath::kClose_Verb:
513                        break;
514                    case SkPath::kDone_Verb:
515                        done = true;
516                }
517                first = false;
518            }
519
520            *vertexCnt = static_cast<int>(vert - base);
521            *indexCnt = static_cast<int>(idx - idxBase);
522
523        }
524        return true;
525    }
526
527    GrColor color() const { return fBatch.fColor; }
528    uint8_t coverage() const { return fBatch.fCoverage; }
529    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
530    const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
531    bool isHairline() const { return fBatch.fIsHairline; }
532
533    struct BatchTracker {
534        GrColor fColor;
535        uint8_t fCoverage;
536        SkMatrix fViewMatrix;
537        bool fUsesLocalCoords;
538        bool fColorIgnored;
539        bool fCoverageIgnored;
540        bool fIsHairline;
541    };
542
543    BatchTracker fBatch;
544    SkSTArray<1, Geometry, true> fGeoData;
545};
546
547bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
548                                             GrPipelineBuilder* pipelineBuilder,
549                                             GrColor color,
550                                             const SkMatrix& viewMatrix,
551                                             const SkPath& path,
552                                             const GrStrokeInfo& origStroke,
553                                             bool stencilOnly) {
554    SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
555
556    SkScalar hairlineCoverage;
557    uint8_t newCoverage = 0xff;
558    if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) {
559        newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
560
561        if (!stroke->getStrokeRec().isHairlineStyle()) {
562            stroke.writable()->getStrokeRecPtr()->setHairlineStyle();
563        }
564    }
565
566    const bool isHairline = stroke->getStrokeRec().isHairlineStyle();
567
568    // Save the current xp on the draw state so we can reset it if needed
569    SkAutoTUnref<const GrXPFactory> backupXPFactory(SkRef(pipelineBuilder->getXPFactory()));
570    // face culling doesn't make sense here
571    SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
572
573    int                         passCount = 0;
574    const GrStencilSettings*    passes[3];
575    GrPipelineBuilder::DrawFace drawFace[3];
576    bool                        reverse = false;
577    bool                        lastPassIsBounds;
578
579    if (isHairline) {
580        passCount = 1;
581        if (stencilOnly) {
582            passes[0] = &gDirectToStencil;
583        } else {
584            passes[0] = NULL;
585        }
586        lastPassIsBounds = false;
587        drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
588    } else {
589        if (single_pass_path(path, stroke->getStrokeRec())) {
590            passCount = 1;
591            if (stencilOnly) {
592                passes[0] = &gDirectToStencil;
593            } else {
594                passes[0] = NULL;
595            }
596            drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
597            lastPassIsBounds = false;
598        } else {
599            switch (path.getFillType()) {
600                case SkPath::kInverseEvenOdd_FillType:
601                    reverse = true;
602                    // fallthrough
603                case SkPath::kEvenOdd_FillType:
604                    passes[0] = &gEOStencilPass;
605                    if (stencilOnly) {
606                        passCount = 1;
607                        lastPassIsBounds = false;
608                    } else {
609                        passCount = 2;
610                        lastPassIsBounds = true;
611                        if (reverse) {
612                            passes[1] = &gInvEOColorPass;
613                        } else {
614                            passes[1] = &gEOColorPass;
615                        }
616                    }
617                    drawFace[0] = drawFace[1] = GrPipelineBuilder::kBoth_DrawFace;
618                    break;
619
620                case SkPath::kInverseWinding_FillType:
621                    reverse = true;
622                    // fallthrough
623                case SkPath::kWinding_FillType:
624                    if (fSeparateStencil) {
625                        if (fStencilWrapOps) {
626                            passes[0] = &gWindStencilSeparateWithWrap;
627                        } else {
628                            passes[0] = &gWindStencilSeparateNoWrap;
629                        }
630                        passCount = 2;
631                        drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
632                    } else {
633                        if (fStencilWrapOps) {
634                            passes[0] = &gWindSingleStencilWithWrapInc;
635                            passes[1] = &gWindSingleStencilWithWrapDec;
636                        } else {
637                            passes[0] = &gWindSingleStencilNoWrapInc;
638                            passes[1] = &gWindSingleStencilNoWrapDec;
639                        }
640                        // which is cw and which is ccw is arbitrary.
641                        drawFace[0] = GrPipelineBuilder::kCW_DrawFace;
642                        drawFace[1] = GrPipelineBuilder::kCCW_DrawFace;
643                        passCount = 3;
644                    }
645                    if (stencilOnly) {
646                        lastPassIsBounds = false;
647                        --passCount;
648                    } else {
649                        lastPassIsBounds = true;
650                        drawFace[passCount-1] = GrPipelineBuilder::kBoth_DrawFace;
651                        if (reverse) {
652                            passes[passCount-1] = &gInvWindColorPass;
653                        } else {
654                            passes[passCount-1] = &gWindColorPass;
655                        }
656                    }
657                    break;
658                default:
659                    SkDEBUGFAIL("Unknown path fFill!");
660                    return false;
661            }
662        }
663    }
664
665    SkScalar tol = GrPathUtils::kDefaultTolerance;
666    SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
667
668    SkRect devBounds;
669    GetPathDevBounds(path, pipelineBuilder->getRenderTarget(), viewMatrix, &devBounds);
670
671    for (int p = 0; p < passCount; ++p) {
672        pipelineBuilder->setDrawFace(drawFace[p]);
673        if (passes[p]) {
674            *pipelineBuilder->stencil() = *passes[p];
675        }
676
677        if (lastPassIsBounds && (p == passCount-1)) {
678            // Reset the XP Factory on pipelineBuilder
679            pipelineBuilder->setXPFactory(backupXPFactory);
680            SkRect bounds;
681            SkMatrix localMatrix = SkMatrix::I();
682            if (reverse) {
683                SkASSERT(pipelineBuilder->getRenderTarget());
684                // draw over the dev bounds (which will be the whole dst surface for inv fill).
685                bounds = devBounds;
686                SkMatrix vmi;
687                // mapRect through persp matrix may not be correct
688                if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
689                    vmi.mapRect(&bounds);
690                } else {
691                    if (!viewMatrix.invert(&localMatrix)) {
692                        return false;
693                    }
694                }
695            } else {
696                bounds = path.getBounds();
697            }
698            const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
699                                                                               viewMatrix;
700            target->drawRect(pipelineBuilder, color, viewM, bounds, NULL, &localMatrix);
701        } else {
702            if (passCount > 1) {
703                pipelineBuilder->setDisableColorXPFactory();
704            }
705
706            DefaultPathBatch::Geometry geometry;
707            geometry.fColor = color;
708            geometry.fPath = path;
709            geometry.fTolerance = srcSpaceTol;
710
711            SkAutoTUnref<GrBatch> batch(DefaultPathBatch::Create(geometry, newCoverage, viewMatrix,
712                                                                 isHairline, devBounds));
713
714            target->drawBatch(pipelineBuilder, batch);
715        }
716    }
717    return true;
718}
719
720bool GrDefaultPathRenderer::canDrawPath(const GrDrawTarget* target,
721                                        const GrPipelineBuilder* pipelineBuilder,
722                                        const SkMatrix& viewMatrix,
723                                        const SkPath& path,
724                                        const GrStrokeInfo& stroke,
725                                        bool antiAlias) const {
726    // this class can draw any path with any fill but doesn't do any anti-aliasing.
727    return !antiAlias && (stroke.isFillStyle() || IsStrokeHairlineOrEquivalent(stroke,
728                                                                               viewMatrix,
729                                                                               NULL));
730}
731
732bool GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
733                                       GrPipelineBuilder* pipelineBuilder,
734                                       GrColor color,
735                                       const SkMatrix& viewMatrix,
736                                       const SkPath& path,
737                                       const GrStrokeInfo& stroke,
738                                       bool antiAlias) {
739    return this->internalDrawPath(target,
740                                  pipelineBuilder,
741                                  color,
742                                  viewMatrix,
743                                  path,
744                                  stroke,
745                                  false);
746}
747
748void GrDefaultPathRenderer::onStencilPath(GrDrawTarget* target,
749                                          GrPipelineBuilder* pipelineBuilder,
750                                          const SkMatrix& viewMatrix,
751                                          const SkPath& path,
752                                          const GrStrokeInfo& stroke) {
753    SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
754    SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
755    this->internalDrawPath(target, pipelineBuilder, GrColor_WHITE, viewMatrix, path, stroke, true);
756}
757