1 2 /* 3 * Copyright 2011 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 #ifndef GrPathRenderer_DEFINED 10 #define GrPathRenderer_DEFINED 11 12 #include "GrDrawTarget.h" 13 #include "GrPathRendererChain.h" 14 #include "GrStencil.h" 15 16 #include "SkDrawProcs.h" 17 #include "SkStrokeRec.h" 18 #include "SkTArray.h" 19 20 class SkPath; 21 22 struct GrPoint; 23 24 /** 25 * Base class for drawing paths into a GrDrawTarget. 26 * 27 * Derived classes can use stages GrPaint::kTotalStages through GrDrawState::kNumStages-1. The 28 * stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and 29 * filter masks). 30 */ 31 class SK_API GrPathRenderer : public SkRefCnt { 32 public: 33 SK_DECLARE_INST_COUNT(GrPathRenderer) 34 35 /** 36 * This is called to install custom path renderers in every GrContext at create time. The 37 * default implementation in GrCreatePathRenderer_none.cpp does not add any additional 38 * renderers. Link against another implementation to install your own. The first added is the 39 * most preferred path renderer, second is second most preferred, etc. 40 * 41 * @param context the context that will use the path renderer 42 * @param prChain the chain to add path renderers to. 43 */ 44 static void AddPathRenderers(GrContext* context, GrPathRendererChain* prChain); 45 46 47 GrPathRenderer(); 48 49 /** 50 * A caller may wish to use a path renderer to draw a path into the stencil buffer. However, 51 * the path renderer itself may require use of the stencil buffer. Also a path renderer may 52 * use a GrEffect coverage stage that sets coverage to zero to eliminate pixels that are covered 53 * by bounding geometry but outside the path. These exterior pixels would still be rendered into 54 * the stencil. 55 * 56 * A GrPathRenderer can provide three levels of support for stenciling paths: 57 * 1) kNoRestriction: This is the most general. The caller sets up the GrDrawState on the target 58 * and calls drawPath(). The path is rendered exactly as the draw state 59 * indicates including support for simultaneous color and stenciling with 60 * arbitrary stenciling rules. Pixels partially covered by AA paths are 61 * affected by the stencil settings. 62 * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil 63 * simultaneously. The path renderer does support the stencilPath() function 64 * which performs no color writes and writes a non-zero stencil value to pixels 65 * covered by the path. 66 * 3) kNoSupport: This path renderer cannot be used to stencil the path. 67 */ 68 typedef GrPathRendererChain::StencilSupport StencilSupport; 69 static const StencilSupport kNoSupport_StencilSupport = 70 GrPathRendererChain::kNoSupport_StencilSupport; 71 static const StencilSupport kStencilOnly_StencilSupport = 72 GrPathRendererChain::kStencilOnly_StencilSupport; 73 static const StencilSupport kNoRestriction_StencilSupport = 74 GrPathRendererChain::kNoRestriction_StencilSupport; 75 76 /** 77 * This function is to get the stencil support for a particular path. The path's fill must 78 * not be an inverse type. 79 * 80 * @param target target that the path will be rendered to 81 * @param path the path that will be drawn 82 * @param stroke the stroke information (width, join, cap). 83 */ getStencilSupport(const SkPath & path,const SkStrokeRec & stroke,const GrDrawTarget * target)84 StencilSupport getStencilSupport(const SkPath& path, 85 const SkStrokeRec& stroke, 86 const GrDrawTarget* target) const { 87 SkASSERT(!path.isInverseFillType()); 88 return this->onGetStencilSupport(path, stroke, target); 89 } 90 91 /** 92 * Returns true if this path renderer is able to render the path. Returning false allows the 93 * caller to fallback to another path renderer This function is called when searching for a path 94 * renderer capable of rendering a path. 95 * 96 * @param path The path to draw 97 * @param stroke The stroke information (width, join, cap) 98 * @param target The target that the path will be rendered to 99 * @param antiAlias True if anti-aliasing is required. 100 * 101 * @return true if the path can be drawn by this object, false otherwise. 102 */ 103 virtual bool canDrawPath(const SkPath& path, 104 const SkStrokeRec& rec, 105 const GrDrawTarget* target, 106 bool antiAlias) const = 0; 107 /** 108 * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then 109 * the subclass must respect the stencil settings of the target's draw state. 110 * 111 * @param path the path to draw. 112 * @param stroke the stroke information (width, join, cap) 113 * @param target target that the path will be rendered to 114 * @param antiAlias true if anti-aliasing is required. 115 */ drawPath(const SkPath & path,const SkStrokeRec & stroke,GrDrawTarget * target,bool antiAlias)116 bool drawPath(const SkPath& path, 117 const SkStrokeRec& stroke, 118 GrDrawTarget* target, 119 bool antiAlias) { 120 SkASSERT(!path.isEmpty()); 121 SkASSERT(this->canDrawPath(path, stroke, target, antiAlias)); 122 SkASSERT(target->drawState()->getStencil().isDisabled() || 123 kNoRestriction_StencilSupport == this->getStencilSupport(path, stroke, target)); 124 return this->onDrawPath(path, stroke, target, antiAlias); 125 } 126 127 /** 128 * Draws the path to the stencil buffer. Assume the writable stencil bits are already 129 * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards. 130 * 131 * @param path the path to draw. 132 * @param stroke the stroke information (width, join, cap) 133 * @param target target that the path will be rendered to 134 */ stencilPath(const SkPath & path,const SkStrokeRec & stroke,GrDrawTarget * target)135 void stencilPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target) { 136 SkASSERT(!path.isEmpty()); 137 SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(path, stroke, target)); 138 this->onStencilPath(path, stroke, target); 139 } 140 141 // Helper for determining if we can treat a thin stroke as a hairline w/ coverage. 142 // If we can, we draw lots faster (raster device does this same test). IsStrokeHairlineOrEquivalent(const SkStrokeRec & stroke,const SkMatrix & matrix,SkScalar * outCoverage)143 static bool IsStrokeHairlineOrEquivalent(const SkStrokeRec& stroke, const SkMatrix& matrix, 144 SkScalar* outCoverage) { 145 if (stroke.isHairlineStyle()) { 146 if (NULL != outCoverage) { 147 *outCoverage = SK_Scalar1; 148 } 149 return true; 150 } 151 return stroke.getStyle() == SkStrokeRec::kStroke_Style && 152 SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage); 153 } 154 155 protected: 156 /** 157 * Subclass overrides if it has any limitations of stenciling support. 158 */ onGetStencilSupport(const SkPath &,const SkStrokeRec &,const GrDrawTarget *)159 virtual StencilSupport onGetStencilSupport(const SkPath&, 160 const SkStrokeRec&, 161 const GrDrawTarget*) const { 162 return kNoRestriction_StencilSupport; 163 } 164 165 /** 166 * Subclass implementation of drawPath() 167 */ 168 virtual bool onDrawPath(const SkPath& path, 169 const SkStrokeRec& stroke, 170 GrDrawTarget* target, 171 bool antiAlias) = 0; 172 173 /** 174 * Subclass implementation of stencilPath(). Subclass must override iff it ever returns 175 * kStencilOnly in onGetStencilSupport(). 176 */ onStencilPath(const SkPath & path,const SkStrokeRec & stroke,GrDrawTarget * target)177 virtual void onStencilPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target) { 178 GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); 179 GrDrawState* drawState = target->drawState(); 180 GR_STATIC_CONST_SAME_STENCIL(kIncrementStencil, 181 kReplace_StencilOp, 182 kReplace_StencilOp, 183 kAlways_StencilFunc, 184 0xffff, 185 0xffff, 186 0xffff); 187 drawState->setStencil(kIncrementStencil); 188 drawState->enableState(GrDrawState::kNoColorWrites_StateBit); 189 this->drawPath(path, stroke, target, false); 190 } 191 192 // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set 193 // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize. 194 static void GetPathDevBounds(const SkPath& path, 195 int devW, 196 int devH, 197 const SkMatrix& matrix, 198 SkRect* bounds); 199 200 // Helper version that gets the dev width and height from a GrSurface. GetPathDevBounds(const SkPath & path,const GrSurface * device,const SkMatrix & matrix,SkRect * bounds)201 static void GetPathDevBounds(const SkPath& path, 202 const GrSurface* device, 203 const SkMatrix& matrix, 204 SkRect* bounds) { 205 GetPathDevBounds(path, device->width(), device->height(), matrix, bounds); 206 } 207 208 private: 209 210 typedef SkRefCnt INHERITED; 211 }; 212 213 #endif 214