SkImageFilter.h revision 8b0e8ac5f582de80356019406e2975079bf0829d
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkImageFilter_DEFINED
9#define SkImageFilter_DEFINED
10
11#include "SkFlattenable.h"
12#include "SkRect.h"
13
14class SkBitmap;
15class SkColorFilter;
16class SkBaseDevice;
17class SkMatrix;
18struct SkIPoint;
19class SkShader;
20class GrEffectRef;
21class GrTexture;
22
23/**
24 *  Base class for image filters. If one is installed in the paint, then
25 *  all drawing occurs as usual, but it is as if the drawing happened into an
26 *  offscreen (before the xfermode is applied). This offscreen bitmap will
27 *  then be handed to the imagefilter, who in turn creates a new bitmap which
28 *  is what will finally be drawn to the device (using the original xfermode).
29 */
30class SK_API SkImageFilter : public SkFlattenable {
31public:
32    SK_DECLARE_INST_COUNT(SkImageFilter)
33
34    class CropRect {
35    public:
36        enum CropEdge {
37            kHasLeft_CropEdge   = 0x01,
38            kHasTop_CropEdge    = 0x02,
39            kHasRight_CropEdge  = 0x04,
40            kHasBottom_CropEdge = 0x08,
41            kHasAll_CropEdge    = 0x0F,
42        };
43        CropRect() {}
44        explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge) : fRect(rect), fFlags(flags) {}
45        uint32_t flags() const { return fFlags; }
46        const SkRect& rect() const { return fRect; }
47    private:
48        SkRect fRect;
49        uint32_t fFlags;
50    };
51
52    class Proxy {
53    public:
54        virtual ~Proxy() {};
55
56        virtual SkBaseDevice* createDevice(int width, int height) = 0;
57        // returns true if the proxy can handle this filter natively
58        virtual bool canHandleImageFilter(SkImageFilter*) = 0;
59        // returns true if the proxy handled the filter itself. if this returns
60        // false then the filter's code will be called.
61        virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
62                                 const SkMatrix& ctm,
63                                 SkBitmap* result, SkIPoint* offset) = 0;
64    };
65
66    /**
67     *  Request a new (result) image to be created from the src image.
68     *  If the src has no pixels (isNull()) then the request just wants to
69     *  receive the config and width/height of the result.
70     *
71     *  The matrix is the current matrix on the canvas.
72     *
73     *  Offset is the amount to translate the resulting image relative to the
74     *  src when it is drawn. This is an out-param.
75     *
76     *  If the result image cannot be created, return false, in which case both
77     *  the result and offset parameters will be ignored by the caller.
78     */
79    bool filterImage(Proxy*, const SkBitmap& src, const SkMatrix& ctm,
80                     SkBitmap* result, SkIPoint* offset);
81
82    /**
83     *  Given the src bounds of an image, this returns the bounds of the result
84     *  image after the filter has been applied.
85     */
86    bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst);
87
88    /**
89     *  Returns true if the filter can be processed on the GPU.  This is most
90     *  often used for multi-pass effects, where intermediate results must be
91     *  rendered to textures.  For single-pass effects, use asNewEffect().
92     *  The default implementation returns asNewEffect(NULL, NULL, SkMatrix::I(),
93     *  SkIRect()).
94     */
95    virtual bool canFilterImageGPU() const;
96
97    /**
98     *  Process this image filter on the GPU.  This is most often used for
99     *  multi-pass effects, where intermediate results must be rendered to
100     *  textures.  For single-pass effects, use asNewEffect().  src is the
101     *  source image for processing, as a texture-backed bitmap.  result is
102     *  the destination bitmap, which should contain a texture-backed pixelref
103     *  on success.  offset is the amount to translate the resulting image
104     *  relative to the src when it is drawn. The default implementation does
105     *  single-pass processing using asNewEffect().
106     */
107    virtual bool filterImageGPU(Proxy*, const SkBitmap& src, const SkMatrix& ctm,
108                                SkBitmap* result, SkIPoint* offset);
109
110    /**
111     *  Returns whether this image filter is a color filter and puts the color filter into the
112     *  "filterPtr" parameter if it can. Does nothing otherwise.
113     *  If this returns false, then the filterPtr is unchanged.
114     *  If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
115     *  (i.e. it may not be set to NULL).
116     */
117    virtual bool asColorFilter(SkColorFilter** filterPtr) const;
118
119    /**
120     *  Returns the number of inputs this filter will accept (some inputs can
121     *  be NULL).
122     */
123    int countInputs() const { return fInputCount; }
124
125    /**
126     *  Returns the input filter at a given index, or NULL if no input is
127     *  connected.  The indices used are filter-specific.
128     */
129    SkImageFilter* getInput(int i) const {
130        SkASSERT(i < fInputCount);
131        return fInputs[i];
132    }
133
134    /**
135     *  Returns whether any edges of the crop rect have been set. The crop
136     *  rect is set at construction time, and determines which pixels from the
137     *  input image will be processed. The size of the crop rect should be
138     *  used as the size of the destination image. The origin of this rect
139     *  should be used to offset access to the input images, and should also
140     *  be added to the "offset" parameter in onFilterImage and
141     *  filterImageGPU(). (The latter ensures that the resulting buffer is
142     *  drawn in the correct location.)
143     */
144    bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
145
146    // Default impl returns union of all input bounds.
147    virtual void computeFastBounds(const SkRect&, SkRect*) const;
148
149    SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter)
150
151protected:
152    SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect = NULL);
153
154    // Convenience constructor for 1-input filters.
155    explicit SkImageFilter(SkImageFilter* input, const CropRect* cropRect = NULL);
156
157    // Convenience constructor for 2-input filters.
158    SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect = NULL);
159
160    virtual ~SkImageFilter();
161
162    /**
163     *  Constructs a new SkImageFilter read from an SkReadBuffer object.
164     *
165     *  @param inputCount    The exact number of inputs expected for this SkImageFilter object.
166     *                       -1 can be used if the filter accepts any number of inputs.
167     *  @param rb            SkReadBuffer object from which the SkImageFilter is read.
168     */
169    explicit SkImageFilter(int inputCount, SkReadBuffer& rb);
170
171    virtual void flatten(SkWriteBuffer& wb) const SK_OVERRIDE;
172
173    /**
174     *  This is the virtual which should be overridden by the derived class
175     *  to perform image filtering.
176     *
177     *  src is the original primitive bitmap. If the filter has a connected
178     *  input, it should recurse on that input and use that in place of src.
179     *
180     *  The matrix is the current matrix on the canvas.
181     *
182     *  Offset is the amount to translate the resulting image relative to the
183     *  src when it is drawn. This is an out-param.
184     *
185     *  If the result image cannot be created, this should false, in which
186     *  case both the result and offset parameters will be ignored by the
187     *  caller.
188     */
189    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
190                               SkBitmap* result, SkIPoint* offset);
191    // Default impl copies src into dst and returns true
192    virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*);
193
194    // Applies "matrix" to the crop rect, and sets "rect" to the intersection of
195    // "rect" and the transformed crop rect. If there is no overlap, returns
196    // false and leaves "rect" unchanged.
197    bool applyCropRect(SkIRect* rect, const SkMatrix& matrix) const;
198
199    /**
200     *  Returns true if the filter can be expressed a single-pass
201     *  GrEffect, used to process this filter on the GPU, or false if
202     *  not.
203     *
204     *  If effect is non-NULL, a new GrEffect instance is stored
205     *  in it.  The caller assumes ownership of the stage, and it is up to the
206     *  caller to unref it.
207     *
208     *  The effect can assume its vertexCoords space maps 1-to-1 with texels
209     *  in the texture.  "matrix" is a transformation to apply to filter
210     *  parameters before they are used in the effect. Note that this function
211     *  will be called with (NULL, NULL, SkMatrix::I()) to query for support,
212     *  so returning "true" indicates support for all possible matrices.
213     */
214    virtual bool asNewEffect(GrEffectRef** effect,
215                             GrTexture*,
216                             const SkMatrix& matrix,
217                             const SkIRect& bounds) const;
218
219private:
220    typedef SkFlattenable INHERITED;
221    int fInputCount;
222    SkImageFilter** fInputs;
223    CropRect fCropRect;
224};
225
226#endif
227