2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef SkImageFilter_DEFINED
9 #define SkImageFilter_DEFINED
11 #include "SkFlattenable.h"
14 #include "SkTemplates.h"
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).
30 class SK_API SkImageFilter : public SkFlattenable {
32 SK_DECLARE_INST_COUNT(SkImageFilter)
37 kHasLeft_CropEdge = 0x01,
38 kHasTop_CropEdge = 0x02,
39 kHasRight_CropEdge = 0x04,
40 kHasBottom_CropEdge = 0x08,
41 kHasAll_CropEdge = 0x0F,
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; }
52 // This cache maps from (filter's unique ID + CTM + clipBounds + src bitmap generation ID) to
54 class Cache : public SkRefCnt {
58 static Cache* Create(size_t maxBytes);
60 virtual bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const = 0;
61 virtual void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) = 0;
66 Context(const SkMatrix& ctm, const SkIRect& clipBounds, Cache* cache) :
67 fCTM(ctm), fClipBounds(clipBounds), fCache(cache) {
69 const SkMatrix& ctm() const { return fCTM; }
70 const SkIRect& clipBounds() const { return fClipBounds; }
71 Cache* cache() const { return fCache; }
82 virtual SkBaseDevice* createDevice(int width, int height) = 0;
83 // returns true if the proxy can handle this filter natively
84 virtual bool canHandleImageFilter(const SkImageFilter*) = 0;
85 // returns true if the proxy handled the filter itself. if this returns
86 // false then the filter's code will be called.
87 virtual bool filterImage(const SkImageFilter*, const SkBitmap& src,
89 SkBitmap* result, SkIPoint* offset) = 0;
93 * Request a new (result) image to be created from the src image.
94 * If the src has no pixels (isNull()) then the request just wants to
95 * receive the config and width/height of the result.
97 * The matrix is the current matrix on the canvas.
99 * Offset is the amount to translate the resulting image relative to the
100 * src when it is drawn. This is an out-param.
102 * If the result image cannot be created, return false, in which case both
103 * the result and offset parameters will be ignored by the caller.
105 bool filterImage(Proxy*, const SkBitmap& src, const Context&,
106 SkBitmap* result, SkIPoint* offset) const;
109 * Given the src bounds of an image, this returns the bounds of the result
110 * image after the filter has been applied.
112 bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const;
115 * Returns true if the filter can be processed on the GPU. This is most
116 * often used for multi-pass effects, where intermediate results must be
117 * rendered to textures. For single-pass effects, use asNewEffect().
118 * The default implementation returns asNewEffect(NULL, NULL, SkMatrix::I(),
121 virtual bool canFilterImageGPU() const;
124 * Process this image filter on the GPU. This is most often used for
125 * multi-pass effects, where intermediate results must be rendered to
126 * textures. For single-pass effects, use asNewEffect(). src is the
127 * source image for processing, as a texture-backed bitmap. result is
128 * the destination bitmap, which should contain a texture-backed pixelref
129 * on success. offset is the amount to translate the resulting image
130 * relative to the src when it is drawn. The default implementation does
131 * single-pass processing using asNewEffect().
133 virtual bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
134 SkBitmap* result, SkIPoint* offset) const;
137 * Returns whether this image filter is a color filter and puts the color filter into the
138 * "filterPtr" parameter if it can. Does nothing otherwise.
139 * If this returns false, then the filterPtr is unchanged.
140 * If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
141 * (i.e. it may not be set to NULL).
143 virtual bool asColorFilter(SkColorFilter** filterPtr) const;
146 * Returns the number of inputs this filter will accept (some inputs can
149 int countInputs() const { return fInputCount; }
152 * Returns the input filter at a given index, or NULL if no input is
153 * connected. The indices used are filter-specific.
155 SkImageFilter* getInput(int i) const {
156 SkASSERT(i < fInputCount);
161 * Returns whether any edges of the crop rect have been set. The crop
162 * rect is set at construction time, and determines which pixels from the
163 * input image will be processed. The size of the crop rect should be
164 * used as the size of the destination image. The origin of this rect
165 * should be used to offset access to the input images, and should also
166 * be added to the "offset" parameter in onFilterImage and
167 * filterImageGPU(). (The latter ensures that the resulting buffer is
168 * drawn in the correct location.)
170 bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
172 // Default impl returns union of all input bounds.
173 virtual void computeFastBounds(const SkRect&, SkRect*) const;
177 * Wrap the given texture in a texture-backed SkBitmap.
179 static void WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result);
182 * Recursively evaluate this filter on the GPU. If the filter has no GPU
183 * implementation, it will be processed in software and uploaded to the GPU.
185 bool getInputResultGPU(SkImageFilter::Proxy* proxy, const SkBitmap& src, const Context&,
186 SkBitmap* result, SkIPoint* offset) const;
190 * Set an external cache to be used for all image filter processing. This
191 * will replace the default intra-frame cache.
193 static void SetExternalCache(Cache* cache);
196 * Returns the currently-set external cache, or NULL if none is set.
198 static Cache* GetExternalCache();
200 SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter)
208 bool unflatten(SkReadBuffer&, int expectedInputs = -1);
210 CropRect cropRect() const { return fCropRect; }
211 int inputCount() const { return fInputs.count(); }
212 SkImageFilter** inputs() const { return fInputs.get(); }
213 uint32_t uniqueID() const { return fUniqueID; }
215 // If the caller wants a copy of the inputs, call this and it will transfer ownership
216 // of the unflattened input filters to the caller. This is just a short-cut for copying
217 // the inputs, calling ref() on each, and then waiting for Common's destructor to call
219 void detachInputs(SkImageFilter** inputs);
223 // most filters accept at most 2 input-filters
224 SkAutoSTArray<2, SkImageFilter*> fInputs;
227 void allocInputs(int count);
230 SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect = NULL);
232 virtual ~SkImageFilter();
235 * Constructs a new SkImageFilter read from an SkReadBuffer object.
237 * @param inputCount The exact number of inputs expected for this SkImageFilter object.
238 * -1 can be used if the filter accepts any number of inputs.
239 * @param rb SkReadBuffer object from which the SkImageFilter is read.
241 explicit SkImageFilter(int inputCount, SkReadBuffer& rb);
243 virtual void flatten(SkWriteBuffer& wb) const SK_OVERRIDE;
246 * This is the virtual which should be overridden by the derived class
247 * to perform image filtering.
249 * src is the original primitive bitmap. If the filter has a connected
250 * input, it should recurse on that input and use that in place of src.
252 * The matrix is the current matrix on the canvas.
254 * Offset is the amount to translate the resulting image relative to the
255 * src when it is drawn. This is an out-param.
257 * If the result image cannot be created, this should false, in which
258 * case both the result and offset parameters will be ignored by the
261 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
262 SkBitmap* result, SkIPoint* offset) const;
263 // Given the bounds of the destination rect to be filled in device
264 // coordinates (first parameter), and the CTM, compute (conservatively)
265 // which rect of the source image would be required (third parameter).
266 // Used for clipping and temp-buffer allocations, so the result need not
267 // be exact, but should never be smaller than the real answer. The default
268 // implementation recursively unions all input bounds, or returns false if
270 virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const;
272 /** Computes source bounds as the src bitmap bounds offset by srcOffset.
273 * Apply the transformed crop rect to the bounds if any of the
274 * corresponding edge flags are set. Intersects the result against the
275 * context's clipBounds, and returns the result in "bounds". If there is
276 * no intersection, returns false and leaves "bounds" unchanged.
278 bool applyCropRect(const Context&, const SkBitmap& src, const SkIPoint& srcOffset,
279 SkIRect* bounds) const;
281 /** Same as the above call, except that if the resulting crop rect is not
282 * entirely contained by the source bitmap's bounds, it creates a new
283 * bitmap in "result" and pads the edges with transparent black. In that
284 * case, the srcOffset is modified to be the same as the bounds, since no
285 * further adjustment is needed by the caller. This version should only
286 * be used by filters which are not capable of processing a smaller
287 * source bitmap into a larger destination.
289 bool applyCropRect(const Context&, Proxy* proxy, const SkBitmap& src, SkIPoint* srcOffset,
290 SkIRect* bounds, SkBitmap* result) const;
293 * Returns true if the filter can be expressed a single-pass
294 * GrEffect, used to process this filter on the GPU, or false if
297 * If effect is non-NULL, a new GrEffect instance is stored
298 * in it. The caller assumes ownership of the stage, and it is up to the
299 * caller to unref it.
301 * The effect can assume its vertexCoords space maps 1-to-1 with texels
302 * in the texture. "matrix" is a transformation to apply to filter
303 * parameters before they are used in the effect. Note that this function
304 * will be called with (NULL, NULL, SkMatrix::I()) to query for support,
305 * so returning "true" indicates support for all possible matrices.
307 virtual bool asNewEffect(GrEffect** effect,
309 const SkMatrix& matrix,
310 const SkIRect& bounds) const;
313 bool usesSrcInput() const { return fUsesSrcInput; }
315 typedef SkFlattenable INHERITED;
317 SkImageFilter** fInputs;
320 uint32_t fUniqueID; // Globally unique