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 "SkMatrix.h"
13#include "SkRect.h"
14
15class SkBitmap;
16class SkColorFilter;
17class SkBaseDevice;
18struct SkIPoint;
19class GrEffectRef;
20class GrTexture;
21
22/**
23 *  Base class for image filters. If one is installed in the paint, then
24 *  all drawing occurs as usual, but it is as if the drawing happened into an
25 *  offscreen (before the xfermode is applied). This offscreen bitmap will
26 *  then be handed to the imagefilter, who in turn creates a new bitmap which
27 *  is what will finally be drawn to the device (using the original xfermode).
28 */
29class SK_API SkImageFilter : public SkFlattenable {
30public:
31    SK_DECLARE_INST_COUNT(SkImageFilter)
32
33    class CropRect {
34    public:
35        enum CropEdge {
36            kHasLeft_CropEdge   = 0x01,
37            kHasTop_CropEdge    = 0x02,
38            kHasRight_CropEdge  = 0x04,
39            kHasBottom_CropEdge = 0x08,
40            kHasAll_CropEdge    = 0x0F,
41        };
42        CropRect() {}
43        explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge) : fRect(rect), fFlags(flags) {}
44        uint32_t flags() const { return fFlags; }
45        const SkRect& rect() const { return fRect; }
46    private:
47        SkRect fRect;
48        uint32_t fFlags;
49    };
50
51    class SK_API Cache : public SkRefCnt {
52    public:
53        // By default, we cache only image filters with 2 or more children.
54        static Cache* Create(int minChildren = 2);
55        virtual ~Cache() {}
56        virtual bool get(const SkImageFilter* key, SkBitmap* result, SkIPoint* offset) = 0;
57        virtual void set(const SkImageFilter* key,
58                         const SkBitmap& result, const SkIPoint& offset) = 0;
59        virtual void remove(const SkImageFilter* key) = 0;
60    };
61
62    class Context {
63    public:
64        Context(const SkMatrix& ctm, const SkIRect& clipBounds, Cache* cache) :
65            fCTM(ctm), fClipBounds(clipBounds), fCache(cache) {
66        }
67        const SkMatrix& ctm() const { return fCTM; }
68        const SkIRect& clipBounds() const { return fClipBounds; }
69        Cache* cache() const { return fCache; }
70    private:
71        SkMatrix fCTM;
72        SkIRect  fClipBounds;
73        Cache*   fCache;
74    };
75
76    class Proxy {
77    public:
78        virtual ~Proxy() {};
79
80        virtual SkBaseDevice* createDevice(int width, int height) = 0;
81        // returns true if the proxy can handle this filter natively
82        virtual bool canHandleImageFilter(const SkImageFilter*) = 0;
83        // returns true if the proxy handled the filter itself. if this returns
84        // false then the filter's code will be called.
85        virtual bool filterImage(const SkImageFilter*, const SkBitmap& src,
86                                 const Context&,
87                                 SkBitmap* result, SkIPoint* offset) = 0;
88    };
89
90    /**
91     *  Request a new (result) image to be created from the src image.
92     *  If the src has no pixels (isNull()) then the request just wants to
93     *  receive the config and width/height of the result.
94     *
95     *  The matrix is the current matrix on the canvas.
96     *
97     *  Offset is the amount to translate the resulting image relative to the
98     *  src when it is drawn. This is an out-param.
99     *
100     *  If the result image cannot be created, return false, in which case both
101     *  the result and offset parameters will be ignored by the caller.
102     */
103    bool filterImage(Proxy*, const SkBitmap& src, const Context&,
104                     SkBitmap* result, SkIPoint* offset) const;
105
106    /**
107     *  Given the src bounds of an image, this returns the bounds of the result
108     *  image after the filter has been applied.
109     */
110    bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const;
111
112    /**
113     *  Returns true if the filter can be processed on the GPU.  This is most
114     *  often used for multi-pass effects, where intermediate results must be
115     *  rendered to textures.  For single-pass effects, use asNewEffect().
116     *  The default implementation returns asNewEffect(NULL, NULL, SkMatrix::I(),
117     *  SkIRect()).
118     */
119    virtual bool canFilterImageGPU() const;
120
121    /**
122     *  Process this image filter on the GPU.  This is most often used for
123     *  multi-pass effects, where intermediate results must be rendered to
124     *  textures.  For single-pass effects, use asNewEffect().  src is the
125     *  source image for processing, as a texture-backed bitmap.  result is
126     *  the destination bitmap, which should contain a texture-backed pixelref
127     *  on success.  offset is the amount to translate the resulting image
128     *  relative to the src when it is drawn. The default implementation does
129     *  single-pass processing using asNewEffect().
130     */
131    virtual bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
132                                SkBitmap* result, SkIPoint* offset) const;
133
134    /**
135     *  Returns whether this image filter is a color filter and puts the color filter into the
136     *  "filterPtr" parameter if it can. Does nothing otherwise.
137     *  If this returns false, then the filterPtr is unchanged.
138     *  If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
139     *  (i.e. it may not be set to NULL).
140     */
141    virtual bool asColorFilter(SkColorFilter** filterPtr) const;
142
143    /**
144     *  Returns the number of inputs this filter will accept (some inputs can
145     *  be NULL).
146     */
147    int countInputs() const { return fInputCount; }
148
149    /**
150     *  Returns the input filter at a given index, or NULL if no input is
151     *  connected.  The indices used are filter-specific.
152     */
153    SkImageFilter* getInput(int i) const {
154        SkASSERT(i < fInputCount);
155        return fInputs[i];
156    }
157
158    /**
159     *  Returns whether any edges of the crop rect have been set. The crop
160     *  rect is set at construction time, and determines which pixels from the
161     *  input image will be processed. The size of the crop rect should be
162     *  used as the size of the destination image. The origin of this rect
163     *  should be used to offset access to the input images, and should also
164     *  be added to the "offset" parameter in onFilterImage and
165     *  filterImageGPU(). (The latter ensures that the resulting buffer is
166     *  drawn in the correct location.)
167     */
168    bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
169
170    // Default impl returns union of all input bounds.
171    virtual void computeFastBounds(const SkRect&, SkRect*) const;
172
173#ifdef SK_SUPPORT_GPU
174    /**
175     * Wrap the given texture in a texture-backed SkBitmap.
176     */
177    static void WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result);
178
179    /**
180     * Recursively evaluate this filter on the GPU. If the filter has no GPU
181     * implementation, it will be processed in software and uploaded to the GPU.
182     */
183    bool getInputResultGPU(SkImageFilter::Proxy* proxy, const SkBitmap& src, const Context&,
184                           SkBitmap* result, SkIPoint* offset) const;
185#endif
186
187    /**
188     *  Set an external cache to be used for all image filter processing. This
189     *  will replace the default intra-frame cache.
190     */
191    static void SetExternalCache(Cache* cache);
192
193    /**
194     *  Returns the currently-set external cache, or NULL if none is set.
195     */
196    static Cache* GetExternalCache();
197
198    SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter)
199
200protected:
201    SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect = NULL);
202
203    // Convenience constructor for 1-input filters.
204    explicit SkImageFilter(SkImageFilter* input, const CropRect* cropRect = NULL);
205
206    // Convenience constructor for 2-input filters.
207    SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect = NULL);
208
209    virtual ~SkImageFilter();
210
211    /**
212     *  Constructs a new SkImageFilter read from an SkReadBuffer object.
213     *
214     *  @param inputCount    The exact number of inputs expected for this SkImageFilter object.
215     *                       -1 can be used if the filter accepts any number of inputs.
216     *  @param rb            SkReadBuffer object from which the SkImageFilter is read.
217     */
218    explicit SkImageFilter(int inputCount, SkReadBuffer& rb);
219
220    virtual void flatten(SkWriteBuffer& wb) const SK_OVERRIDE;
221
222    /**
223     *  This is the virtual which should be overridden by the derived class
224     *  to perform image filtering.
225     *
226     *  src is the original primitive bitmap. If the filter has a connected
227     *  input, it should recurse on that input and use that in place of src.
228     *
229     *  The matrix is the current matrix on the canvas.
230     *
231     *  Offset is the amount to translate the resulting image relative to the
232     *  src when it is drawn. This is an out-param.
233     *
234     *  If the result image cannot be created, this should false, in which
235     *  case both the result and offset parameters will be ignored by the
236     *  caller.
237     */
238    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
239                               SkBitmap* result, SkIPoint* offset) const;
240    // Given the bounds of the destination rect to be filled in device
241    // coordinates (first parameter), and the CTM, compute (conservatively)
242    // which rect of the source image would be required (third parameter).
243    // Used for clipping and temp-buffer allocations, so the result need not
244    // be exact, but should never be smaller than the real answer. The default
245    // implementation recursively unions all input bounds, or returns false if
246    // no inputs.
247    virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const;
248
249    /** Computes source bounds as the src bitmap bounds offset by srcOffset.
250     *  Apply the transformed crop rect to the bounds if any of the
251     *  corresponding edge flags are set. Intersects the result against the
252     *  context's clipBounds, and returns the result in "bounds". If there is
253     *  no intersection, returns false and leaves "bounds" unchanged.
254     */
255    bool applyCropRect(const Context&, const SkBitmap& src, const SkIPoint& srcOffset,
256                       SkIRect* bounds) const;
257
258    /** Same as the above call, except that if the resulting crop rect is not
259     *  entirely contained by the source bitmap's bounds, it creates a new
260     *  bitmap in "result" and pads the edges with transparent black. In that
261     *  case, the srcOffset is modified to be the same as the bounds, since no
262     *  further adjustment is needed by the caller. This version should only
263     *  be used by filters which are not capable of processing a smaller
264     *  source bitmap into a larger destination.
265     */
266    bool applyCropRect(const Context&, Proxy* proxy, const SkBitmap& src, SkIPoint* srcOffset,
267                       SkIRect* bounds, SkBitmap* result) const;
268
269    /**
270     *  Returns true if the filter can be expressed a single-pass
271     *  GrEffect, used to process this filter on the GPU, or false if
272     *  not.
273     *
274     *  If effect is non-NULL, a new GrEffect instance is stored
275     *  in it.  The caller assumes ownership of the stage, and it is up to the
276     *  caller to unref it.
277     *
278     *  The effect can assume its vertexCoords space maps 1-to-1 with texels
279     *  in the texture.  "matrix" is a transformation to apply to filter
280     *  parameters before they are used in the effect. Note that this function
281     *  will be called with (NULL, NULL, SkMatrix::I()) to query for support,
282     *  so returning "true" indicates support for all possible matrices.
283     */
284    virtual bool asNewEffect(GrEffectRef** effect,
285                             GrTexture*,
286                             const SkMatrix& matrix,
287                             const SkIRect& bounds) const;
288
289private:
290    typedef SkFlattenable INHERITED;
291    int fInputCount;
292    SkImageFilter** fInputs;
293    CropRect fCropRect;
294};
295
296#endif
297