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 "GrDrawTargetCaps.h" 13#include "GrGpu.h" 14#include "GrPath.h" 15#include "SkStrokeRec.h" 16 17GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) { 18 SkASSERT(context); 19 SkASSERT(context->getGpu()); 20 if (context->getGpu()->caps()->pathRenderingSupport()) { 21 return SkNEW_ARGS(GrStencilAndCoverPathRenderer, (context->getGpu())); 22 } else { 23 return NULL; 24 } 25} 26 27GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrGpu* gpu) { 28 SkASSERT(gpu->caps()->pathRenderingSupport()); 29 fGpu = gpu; 30 gpu->ref(); 31} 32 33GrStencilAndCoverPathRenderer::~GrStencilAndCoverPathRenderer() { 34 fGpu->unref(); 35} 36 37bool GrStencilAndCoverPathRenderer::canDrawPath(const SkPath& path, 38 const SkStrokeRec& stroke, 39 const GrDrawTarget* target, 40 bool antiAlias) const { 41 return !stroke.isHairlineStyle() && 42 !antiAlias && // doesn't do per-path AA, relies on the target having MSAA 43 target->getDrawState().getRenderTarget()->getStencilBuffer() && 44 target->getDrawState().getStencil().isDisabled(); 45} 46 47GrPathRenderer::StencilSupport GrStencilAndCoverPathRenderer::onGetStencilSupport( 48 const SkPath&, 49 const SkStrokeRec& , 50 const GrDrawTarget*) const { 51 return GrPathRenderer::kStencilOnly_StencilSupport; 52} 53 54static GrPath* get_gr_path(GrGpu* gpu, const SkPath& skPath, const SkStrokeRec& stroke) { 55 GrContext* ctx = gpu->getContext(); 56 GrResourceKey resourceKey = GrPath::ComputeKey(skPath, stroke); 57 SkAutoTUnref<GrPath> path(static_cast<GrPath*>(ctx->findAndRefCachedResource(resourceKey))); 58 if (NULL == path || !path->isEqualTo(skPath, stroke)) { 59 path.reset(gpu->pathRendering()->createPath(skPath, stroke)); 60 ctx->addResourceToCache(resourceKey, path); 61 } 62 return path.detach(); 63} 64 65void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path, 66 const SkStrokeRec& stroke, 67 GrDrawTarget* target) { 68 SkASSERT(!path.isInverseFillType()); 69 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke)); 70 target->stencilPath(p, path.getFillType()); 71} 72 73bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path, 74 const SkStrokeRec& stroke, 75 GrDrawTarget* target, 76 bool antiAlias) { 77 SkASSERT(!antiAlias); 78 SkASSERT(!stroke.isHairlineStyle()); 79 80 GrDrawState* drawState = target->drawState(); 81 SkASSERT(drawState->getStencil().isDisabled()); 82 83 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke)); 84 85 if (path.isInverseFillType()) { 86 GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass, 87 kZero_StencilOp, 88 kZero_StencilOp, 89 // We know our rect will hit pixels outside the clip and the user bits will be 0 90 // outside the clip. So we can't just fill where the user bits are 0. We also need to 91 // check that the clip bit is set. 92 kEqualIfInClip_StencilFunc, 93 0xffff, 94 0x0000, 95 0xffff); 96 97 *drawState->stencil() = kInvertedStencilPass; 98 } else { 99 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, 100 kZero_StencilOp, 101 kZero_StencilOp, 102 kNotEqual_StencilFunc, 103 0xffff, 104 0x0000, 105 0xffff); 106 107 *drawState->stencil() = kStencilPass; 108 } 109 110 target->drawPath(p, path.getFillType()); 111 112 target->drawState()->stencil()->setDisabled(); 113 return true; 114} 115