1 2 /* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "GrStencilAndCoverPathRenderer.h" 11 #include "GrContext.h" 12 #include "GrGpu.h" 13 #include "GrPath.h" 14 #include "SkStrokeRec.h" 15 16 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) { 17 GrAssert(NULL != context); 18 GrAssert(NULL != context->getGpu()); 19 if (context->getGpu()->getCaps().pathStencilingSupport()) { 20 return SkNEW_ARGS(GrStencilAndCoverPathRenderer, (context->getGpu())); 21 } else { 22 return NULL; 23 } 24 } 25 26 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrGpu* gpu) { 27 GrAssert(gpu->getCaps().pathStencilingSupport()); 28 fGpu = gpu; 29 gpu->ref(); 30 } 31 32 GrStencilAndCoverPathRenderer::~GrStencilAndCoverPathRenderer() { 33 fGpu->unref(); 34 } 35 36 bool GrStencilAndCoverPathRenderer::canDrawPath(const SkPath& path, 37 const SkStrokeRec& stroke, 38 const GrDrawTarget* target, 39 bool antiAlias) const { 40 return stroke.isFillStyle() && 41 !antiAlias && // doesn't do per-path AA, relies on the target having MSAA 42 target->getDrawState().getStencil().isDisabled(); 43 } 44 45 GrPathRenderer::StencilSupport GrStencilAndCoverPathRenderer::onGetStencilSupport( 46 const SkPath&, 47 const SkStrokeRec& , 48 const GrDrawTarget*) const { 49 return GrPathRenderer::kStencilOnly_StencilSupport; 50 } 51 52 void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path, 53 const SkStrokeRec& stroke, 54 GrDrawTarget* target) { 55 GrAssert(!path.isInverseFillType()); 56 SkAutoTUnref<GrPath> p(fGpu->createPath(path)); 57 target->stencilPath(p, stroke, path.getFillType()); 58 } 59 60 bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path, 61 const SkStrokeRec& stroke, 62 GrDrawTarget* target, 63 bool antiAlias) { 64 GrAssert(!antiAlias); 65 GrAssert(!stroke.isHairlineStyle()); 66 67 GrDrawState* drawState = target->drawState(); 68 GrAssert(drawState->getStencil().isDisabled()); 69 70 SkAutoTUnref<GrPath> p(fGpu->createPath(path)); 71 72 SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(path.getFillType()); 73 target->stencilPath(p, stroke, nonInvertedFill); 74 75 // TODO: Use built in cover operation rather than a rect draw. This will require making our 76 // fragment shaders be able to eat varyings generated by a matrix. 77 78 // fill the path, zero out the stencil 79 GrRect bounds = p->getBounds(); 80 SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf; 81 GrDrawState::AutoDeviceCoordDraw adcd; 82 83 if (nonInvertedFill == path.getFillType()) { 84 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, 85 kZero_StencilOp, 86 kZero_StencilOp, 87 kNotEqual_StencilFunc, 88 0xffff, 89 0x0000, 90 0xffff); 91 *drawState->stencil() = kStencilPass; 92 } else { 93 GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass, 94 kZero_StencilOp, 95 kZero_StencilOp, 96 // We know our rect will hit pixels outside the clip and the user bits will be 0 97 // outside the clip. So we can't just fill where the user bits are 0. We also need to 98 // check that the clip bit is set. 99 kEqualIfInClip_StencilFunc, 100 0xffff, 101 0x0000, 102 0xffff); 103 SkMatrix vmi; 104 bounds.setLTRB(0, 0, 105 SkIntToScalar(drawState->getRenderTarget()->width()), 106 SkIntToScalar(drawState->getRenderTarget()->height())); 107 // mapRect through persp matrix may not be correct 108 if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) { 109 vmi.mapRect(&bounds); 110 // theoretically could set bloat = 0, instead leave it because of matrix inversion 111 // precision. 112 } else { 113 adcd.set(drawState); 114 bloat = 0; 115 } 116 *drawState->stencil() = kInvertedStencilPass; 117 } 118 bounds.outset(bloat, bloat); 119 target->drawSimpleRect(bounds, NULL); 120 target->drawState()->stencil()->setDisabled(); 121 return true; 122 } 123