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