• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "GrStrokeInfo.h"
16 
17 #include "SkDrawProcs.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 GrPipelineBuilder::kNumStages-1.
28  *  The 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 GrProcessor coverage stage that sets coverage to zero to eliminate pixels that are
53      * covered by bounding geometry but outside the path. These exterior pixels would still be
54      * rendered into 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 GrPipelineBuilder 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 GrDrawTarget * target,const GrPipelineBuilder * pipelineBuilder,const SkPath & path,const GrStrokeInfo & stroke)84     StencilSupport getStencilSupport(const GrDrawTarget* target,
85                                      const GrPipelineBuilder* pipelineBuilder,
86                                      const SkPath& path,
87                                      const GrStrokeInfo& stroke) const {
88         SkASSERT(!path.isInverseFillType());
89         return this->onGetStencilSupport(target, pipelineBuilder, path, stroke);
90     }
91 
92     /**
93      * Returns true if this path renderer is able to render the path. Returning false allows the
94      * caller to fallback to another path renderer This function is called when searching for a path
95      * renderer capable of rendering a path.
96      *
97      * @param target           The target that the path will be rendered to
98      * @param pipelineBuilder  The pipelineBuilder
99      * @param viewMatrix       The viewMatrix
100      * @param path             The path to draw
101      * @param stroke           The stroke information (width, join, cap)
102      * @param antiAlias        True if anti-aliasing is required.
103      *
104      * @return  true if the path can be drawn by this object, false otherwise.
105      */
106     virtual bool canDrawPath(const GrDrawTarget* target,
107                              const GrPipelineBuilder* pipelineBuilder,
108                              const SkMatrix& viewMatrix,
109                              const SkPath& path,
110                              const GrStrokeInfo& rec,
111                              bool antiAlias) const = 0;
112     /**
113      * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
114      * the subclass must respect the stencil settings of the target's draw state.
115      *
116      * @param target                The target that the path will be rendered to
117      * @param pipelineBuilder       The pipelineBuilder
118      * @param viewMatrix            The viewMatrix
119      * @param path                  the path to draw.
120      * @param stroke                the stroke information (width, join, cap)
121      * @param antiAlias             true if anti-aliasing is required.
122      */
drawPath(GrDrawTarget * target,GrPipelineBuilder * ds,GrColor color,const SkMatrix & viewMatrix,const SkPath & path,const GrStrokeInfo & stroke,bool antiAlias)123     bool drawPath(GrDrawTarget* target,
124                   GrPipelineBuilder* ds,
125                   GrColor color,
126                   const SkMatrix& viewMatrix,
127                   const SkPath& path,
128                   const GrStrokeInfo& stroke,
129                   bool antiAlias) {
130         SkASSERT(!path.isEmpty());
131         SkASSERT(this->canDrawPath(target, ds, viewMatrix, path, stroke, antiAlias));
132         SkASSERT(ds->getStencil().isDisabled() ||
133                  kNoRestriction_StencilSupport == this->getStencilSupport(target, ds, path,
134                                                                           stroke));
135         return this->onDrawPath(target, ds, color, viewMatrix, path, stroke, antiAlias);
136     }
137 
138     /**
139      * Draws the path to the stencil buffer. Assume the writable stencil bits are already
140      * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
141      *
142      * @param path                  the path to draw.
143      * @param stroke                the stroke information (width, join, cap)
144      * @param target                target that the path will be rendered to
145      */
stencilPath(GrDrawTarget * target,GrPipelineBuilder * ds,const SkMatrix & viewMatrix,const SkPath & path,const GrStrokeInfo & stroke)146     void stencilPath(GrDrawTarget* target,
147                      GrPipelineBuilder* ds,
148                      const SkMatrix& viewMatrix,
149                      const SkPath& path,
150                      const GrStrokeInfo& stroke) {
151         SkASSERT(!path.isEmpty());
152         SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(target, ds, path, stroke));
153         this->onStencilPath(target, ds, viewMatrix, path, stroke);
154     }
155 
156     // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
157     // If we can, we draw lots faster (raster device does this same test).
IsStrokeHairlineOrEquivalent(const GrStrokeInfo & stroke,const SkMatrix & matrix,SkScalar * outCoverage)158     static bool IsStrokeHairlineOrEquivalent(const GrStrokeInfo& stroke, const SkMatrix& matrix,
159                                              SkScalar* outCoverage) {
160         if (stroke.isDashed()) {
161             return false;
162         }
163         if (stroke.getStrokeRec().isHairlineStyle()) {
164             if (outCoverage) {
165                 *outCoverage = SK_Scalar1;
166             }
167             return true;
168         }
169         return stroke.getStrokeRec().getStyle() == SkStrokeRec::kStroke_Style &&
170             SkDrawTreatAAStrokeAsHairline(stroke.getStrokeRec().getWidth(), matrix, outCoverage);
171     }
172 
173 protected:
174     /**
175      * Subclass overrides if it has any limitations of stenciling support.
176      */
onGetStencilSupport(const GrDrawTarget *,const GrPipelineBuilder *,const SkPath &,const GrStrokeInfo &)177     virtual StencilSupport onGetStencilSupport(const GrDrawTarget*,
178                                                const GrPipelineBuilder*,
179                                                const SkPath&,
180                                                const GrStrokeInfo&) const {
181         return kNoRestriction_StencilSupport;
182     }
183 
184     /**
185      * Subclass implementation of drawPath()
186      */
187     virtual bool onDrawPath(GrDrawTarget*,
188                             GrPipelineBuilder*,
189                             GrColor,
190                             const SkMatrix& viewMatrix,
191                             const SkPath&,
192                             const GrStrokeInfo&,
193                             bool antiAlias) = 0;
194 
195     /**
196      * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
197      * kStencilOnly in onGetStencilSupport().
198      */
onStencilPath(GrDrawTarget * target,GrPipelineBuilder * pipelineBuilder,const SkMatrix & viewMatrix,const SkPath & path,const GrStrokeInfo & stroke)199     virtual void onStencilPath(GrDrawTarget* target,
200                                GrPipelineBuilder* pipelineBuilder,
201                                const SkMatrix& viewMatrix,
202                                const SkPath& path,
203                                const GrStrokeInfo& stroke) {
204         GR_STATIC_CONST_SAME_STENCIL(kIncrementStencil,
205                                      kReplace_StencilOp,
206                                      kReplace_StencilOp,
207                                      kAlways_StencilFunc,
208                                      0xffff,
209                                      0xffff,
210                                      0xffff);
211         pipelineBuilder->setStencil(kIncrementStencil);
212         pipelineBuilder->setDisableColorXPFactory();
213         this->drawPath(target, pipelineBuilder, GrColor_WHITE, viewMatrix, path, stroke, false);
214     }
215 
216     // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
217     // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
218     static void GetPathDevBounds(const SkPath& path,
219                                  int devW,
220                                  int devH,
221                                  const SkMatrix& matrix,
222                                  SkRect* bounds);
223 
224     // Helper version that gets the dev width and height from a GrSurface.
GetPathDevBounds(const SkPath & path,const GrSurface * device,const SkMatrix & matrix,SkRect * bounds)225     static void GetPathDevBounds(const SkPath& path,
226                                  const GrSurface* device,
227                                  const SkMatrix& matrix,
228                                  SkRect* bounds) {
229         GetPathDevBounds(path, device->width(), device->height(), matrix, bounds);
230     }
231 
232 private:
233 
234     typedef SkRefCnt INHERITED;
235 };
236 
237 #endif
238