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
20class SkPath;
21
22struct 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 */
31class SK_API GrPathRenderer : public SkRefCnt {
32public:
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     */
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     */
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     */
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).
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
173protected:
174    /**
175     * Subclass overrides if it has any limitations of stenciling support.
176     */
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     */
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.
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
232private:
233
234    typedef SkRefCnt INHERITED;
235};
236
237#endif
238