|
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 */ |
|
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 */ |
|
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 */ |
|
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). |
|
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 */ |
|
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 */ |
|
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. |
|
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 |