3 * Copyright 2012 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "GrStencilAndCoverPathRenderer.h"
11 #include "GrContext.h"
12 #include "GrDrawTargetCaps.h"
15 #include "SkStrokeRec.h"
18 * For now paths only natively support winding and even odd fill types
20 static GrPathRendering::FillType convert_skpath_filltype(SkPath::FillType fill) {
23 SkFAIL("Incomplete Switch\n");
24 case SkPath::kWinding_FillType:
25 case SkPath::kInverseWinding_FillType:
26 return GrPathRendering::kWinding_FillType;
27 case SkPath::kEvenOdd_FillType:
28 case SkPath::kInverseEvenOdd_FillType:
29 return GrPathRendering::kEvenOdd_FillType;
33 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) {
35 SkASSERT(context->getGpu());
36 if (context->getGpu()->caps()->pathRenderingSupport()) {
37 return SkNEW_ARGS(GrStencilAndCoverPathRenderer, (context->getGpu()));
43 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrGpu* gpu) {
44 SkASSERT(gpu->caps()->pathRenderingSupport());
49 GrStencilAndCoverPathRenderer::~GrStencilAndCoverPathRenderer() {
53 bool GrStencilAndCoverPathRenderer::canDrawPath(const SkPath& path,
54 const SkStrokeRec& stroke,
55 const GrDrawTarget* target,
56 bool antiAlias) const {
57 return !stroke.isHairlineStyle() &&
58 !antiAlias && // doesn't do per-path AA, relies on the target having MSAA
59 target->getDrawState().getRenderTarget()->getStencilBuffer() &&
60 target->getDrawState().getStencil().isDisabled();
63 GrPathRenderer::StencilSupport
64 GrStencilAndCoverPathRenderer::onGetStencilSupport(const SkPath&,
66 const GrDrawTarget*) const {
67 return GrPathRenderer::kStencilOnly_StencilSupport;
70 static GrPath* get_gr_path(GrGpu* gpu, const SkPath& skPath, const SkStrokeRec& stroke) {
71 GrContext* ctx = gpu->getContext();
72 GrResourceKey resourceKey = GrPath::ComputeKey(skPath, stroke);
73 SkAutoTUnref<GrPath> path(static_cast<GrPath*>(ctx->findAndRefCachedResource(resourceKey)));
74 if (NULL == path || !path->isEqualTo(skPath, stroke)) {
75 path.reset(gpu->pathRendering()->createPath(skPath, stroke));
76 ctx->addResourceToCache(resourceKey, path);
81 void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path,
82 const SkStrokeRec& stroke,
83 GrDrawTarget* target) {
84 SkASSERT(!path.isInverseFillType());
85 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke));
86 target->stencilPath(p, convert_skpath_filltype(path.getFillType()));
89 bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path,
90 const SkStrokeRec& stroke,
94 SkASSERT(!stroke.isHairlineStyle());
96 GrDrawState* drawState = target->drawState();
97 SkASSERT(drawState->getStencil().isDisabled());
99 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke));
101 if (path.isInverseFillType()) {
102 GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
105 // We know our rect will hit pixels outside the clip and the user bits will be 0
106 // outside the clip. So we can't just fill where the user bits are 0. We also need to
107 // check that the clip bit is set.
108 kEqualIfInClip_StencilFunc,
113 drawState->setStencil(kInvertedStencilPass);
115 // fake inverse with a stencil and cover
116 target->stencilPath(p, convert_skpath_filltype(path.getFillType()));
118 GrDrawState::AutoViewMatrixRestore avmr;
119 SkRect bounds = SkRect::MakeLTRB(0, 0,
120 SkIntToScalar(drawState->getRenderTarget()->width()),
121 SkIntToScalar(drawState->getRenderTarget()->height()));
123 // mapRect through persp matrix may not be correct
124 if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
125 vmi.mapRect(&bounds);
126 // theoretically could set bloat = 0, instead leave it because of matrix inversion
128 SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
129 bounds.outset(bloat, bloat);
131 avmr.setIdentity(drawState);
133 target->drawSimpleRect(bounds);
135 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
138 kNotEqual_StencilFunc,
143 drawState->setStencil(kStencilPass);
144 target->drawPath(p, convert_skpath_filltype(path.getFillType()));
147 target->drawState()->stencil()->setDisabled();