• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "../private/SkTArray.h"
12 #include "../private/SkTemplates.h"
13 #include "../private/SkMutex.h"
14 #include "SkColorSpace.h"
15 #include "SkFilterQuality.h"
16 #include "SkFlattenable.h"
17 #include "SkMatrix.h"
18 #include "SkRect.h"
19 
20 class GrContext;
21 class GrFragmentProcessor;
22 class SkColorFilter;
23 class SkColorSpaceXformer;
24 struct SkIPoint;
25 class SkSpecialImage;
26 class SkImageFilterCache;
27 struct SkImageFilterCacheKey;
28 
29 /**
30  *  Base class for image filters. If one is installed in the paint, then
31  *  all drawing occurs as usual, but it is as if the drawing happened into an
32  *  offscreen (before the xfermode is applied). This offscreen bitmap will
33  *  then be handed to the imagefilter, who in turn creates a new bitmap which
34  *  is what will finally be drawn to the device (using the original xfermode).
35  */
36 class SK_API SkImageFilter : public SkFlattenable {
37 public:
38     // Extra information about the output of a filter DAG. For now, this is just the color space
39     // (of the original requesting device). This is used when constructing intermediate rendering
40     // surfaces, so that we ensure we land in a surface that's similar/compatible to the final
41     // consumer of the DAG's output.
42     class OutputProperties {
43     public:
OutputProperties(SkColorSpace * colorSpace)44         explicit OutputProperties(SkColorSpace* colorSpace) : fColorSpace(colorSpace) {}
45 
colorSpace()46         SkColorSpace* colorSpace() const { return fColorSpace; }
47 
48     private:
49         // This will be a pointer to the device's color space, and our lifetime is bounded by
50         // the device, so we can store a bare pointer.
51         SkColorSpace* fColorSpace;
52     };
53 
54     class Context {
55     public:
Context(const SkMatrix & ctm,const SkIRect & clipBounds,SkImageFilterCache * cache,const OutputProperties & outputProperties)56         Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache,
57                 const OutputProperties& outputProperties)
58             : fCTM(ctm)
59             , fClipBounds(clipBounds)
60             , fCache(cache)
61             , fOutputProperties(outputProperties)
62         {}
63 
ctm()64         const SkMatrix& ctm() const { return fCTM; }
clipBounds()65         const SkIRect& clipBounds() const { return fClipBounds; }
cache()66         SkImageFilterCache* cache() const { return fCache; }
outputProperties()67         const OutputProperties& outputProperties() const { return fOutputProperties; }
68 
69     private:
70         SkMatrix               fCTM;
71         SkIRect                fClipBounds;
72         SkImageFilterCache*    fCache;
73         OutputProperties       fOutputProperties;
74     };
75 
76     class CropRect {
77     public:
78         enum CropEdge {
79             kHasLeft_CropEdge   = 0x01,
80             kHasTop_CropEdge    = 0x02,
81             kHasWidth_CropEdge  = 0x04,
82             kHasHeight_CropEdge = 0x08,
83             kHasAll_CropEdge    = 0x0F,
84         };
CropRect()85         CropRect() {}
86         explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge)
fRect(rect)87             : fRect(rect), fFlags(flags) {}
flags()88         uint32_t flags() const { return fFlags; }
rect()89         const SkRect& rect() const { return fRect; }
90 #ifndef SK_IGNORE_TO_STRING
91         void toString(SkString* str) const;
92 #endif
93 
94         /**
95          *  Apply this cropRect to the imageBounds. If a given edge of the cropRect is not
96          *  set, then the corresponding edge from imageBounds will be used. If "embiggen"
97          *  is true, the crop rect is allowed to enlarge the size of the rect, otherwise
98          *  it may only reduce the rect. Filters that can affect transparent black should
99          *  pass "true", while all other filters should pass "false".
100          *
101          *  Note: imageBounds is in "device" space, as the output cropped rectangle will be,
102          *  so the matrix is ignored for those. It is only applied the croprect's bounds.
103          */
104         void applyTo(const SkIRect& imageBounds, const SkMatrix&, bool embiggen,
105                      SkIRect* cropped) const;
106 
107     private:
108         SkRect fRect;
109         uint32_t fFlags;
110     };
111 
112     enum TileUsage {
113         kPossible_TileUsage,    //!< the created device may be drawn tiled
114         kNever_TileUsage,       //!< the created device will never be drawn tiled
115     };
116 
117     /**
118      *  Request a new filtered image to be created from the src image.
119      *
120      *  The context contains the environment in which the filter is occurring.
121      *  It includes the clip bounds, CTM and cache.
122      *
123      *  Offset is the amount to translate the resulting image relative to the
124      *  src when it is drawn. This is an out-param.
125      *
126      *  If the result image cannot be created, or the result would be
127      *  transparent black, return null, in which case the offset parameter
128      *  should be ignored by the caller.
129      *
130      *  TODO: Right now the imagefilters sometimes return empty result bitmaps/
131      *        specialimages. That doesn't seem quite right.
132      */
133     sk_sp<SkSpecialImage> filterImage(SkSpecialImage* src, const Context&, SkIPoint* offset) const;
134 
135     enum MapDirection {
136         kForward_MapDirection,
137         kReverse_MapDirection
138     };
139     /**
140      * Map a device-space rect recursively forward or backward through the
141      * filter DAG. kForward_MapDirection is used to determine which pixels of
142      * the destination canvas a source image rect would touch after filtering.
143      * kReverse_MapDirection is used to determine which rect of the source
144      * image would be required to fill the given rect (typically, clip bounds).
145      * Used for clipping and temp-buffer allocations, so the result need not
146      * be exact, but should never be smaller than the real answer. The default
147      * implementation recursively unions all input bounds, or returns the
148      * source rect if no inputs.
149      */
150     SkIRect filterBounds(const SkIRect& src, const SkMatrix& ctm,
151                          MapDirection = kReverse_MapDirection) const;
152 
153 #if SK_SUPPORT_GPU
154     static sk_sp<SkSpecialImage> DrawWithFP(GrContext* context,
155                                             sk_sp<GrFragmentProcessor> fp,
156                                             const SkIRect& bounds,
157                                             const OutputProperties& outputProperties);
158 #endif
159 
160     /**
161      *  Returns whether this image filter is a color filter and puts the color filter into the
162      *  "filterPtr" parameter if it can. Does nothing otherwise.
163      *  If this returns false, then the filterPtr is unchanged.
164      *  If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
165      *  (i.e. it may not be set to NULL).
166      */
isColorFilterNode(SkColorFilter ** filterPtr)167     bool isColorFilterNode(SkColorFilter** filterPtr) const {
168         return this->onIsColorFilterNode(filterPtr);
169     }
170 
171     // DEPRECATED : use isColorFilterNode() instead
asColorFilter(SkColorFilter ** filterPtr)172     bool asColorFilter(SkColorFilter** filterPtr) const {
173         return this->isColorFilterNode(filterPtr);
174     }
175 
176     void removeKey(const SkImageFilterCacheKey& key) const;
177 
178     /**
179      *  Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely
180      *  replaced by the returned colorfilter. i.e. the two effects will affect drawing in the
181      *  same way.
182      */
183     bool asAColorFilter(SkColorFilter** filterPtr) const;
184 
185     /**
186      *  Returns the number of inputs this filter will accept (some inputs can
187      *  be NULL).
188      */
countInputs()189     int countInputs() const { return fInputs.count(); }
190 
191     /**
192      *  Returns the input filter at a given index, or NULL if no input is
193      *  connected.  The indices used are filter-specific.
194      */
getInput(int i)195     SkImageFilter* getInput(int i) const {
196         SkASSERT(i < fInputs.count());
197         return fInputs[i].get();
198     }
199 
200     /**
201      *  Returns whether any edges of the crop rect have been set. The crop
202      *  rect is set at construction time, and determines which pixels from the
203      *  input image will be processed, and which pixels in the output image will be allowed.
204      *  The size of the crop rect should be
205      *  used as the size of the destination image. The origin of this rect
206      *  should be used to offset access to the input images, and should also
207      *  be added to the "offset" parameter in onFilterImage.
208      */
cropRectIsSet()209     bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
210 
getCropRect()211     CropRect getCropRect() const { return fCropRect; }
212 
213     // Default impl returns union of all input bounds.
214     virtual SkRect computeFastBounds(const SkRect&) const;
215 
216     // Can this filter DAG compute the resulting bounds of an object-space rectangle?
217     bool canComputeFastBounds() const;
218 
219     /**
220      *  If this filter can be represented by another filter + a localMatrix, return that filter,
221      *  else return null.
222      */
223     sk_sp<SkImageFilter> makeWithLocalMatrix(const SkMatrix&) const;
224 
225     /**
226      *  ImageFilters can natively handle scaling and translate components in the CTM. Only some of
227      *  them can handle affine (or more complex) matrices. This call returns true iff the filter
228      *  and all of its (non-null) inputs can handle these more complex matrices.
229      */
230     bool canHandleComplexCTM() const;
231 
232     /**
233      * Return an imagefilter which transforms its input by the given matrix.
234      */
235     static sk_sp<SkImageFilter> MakeMatrixFilter(const SkMatrix& matrix,
236                                                  SkFilterQuality quality,
237                                                  sk_sp<SkImageFilter> input);
238 
239     SK_TO_STRING_PUREVIRT()
SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter)240     SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter)
241     SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
242 
243 protected:
244     class Common {
245     public:
246         /**
247          *  Attempt to unflatten the cropRect and the expected number of input filters.
248          *  If any number of input filters is valid, pass -1.
249          *  If this fails (i.e. corrupt buffer or contents) then return false and common will
250          *  be left uninitialized.
251          *  If this returns true, then inputCount() is the number of found input filters, each
252          *  of which may be NULL or a valid imagefilter.
253          */
254         bool unflatten(SkReadBuffer&, int expectedInputs);
255 
256         const CropRect& cropRect() const { return fCropRect; }
257         int             inputCount() const { return fInputs.count(); }
258         sk_sp<SkImageFilter>* inputs() const { return fInputs.get(); }
259 
260         sk_sp<SkImageFilter>  getInput(int index) const { return fInputs[index]; }
261 
262     private:
263         CropRect fCropRect;
264         // most filters accept at most 2 input-filters
265         SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
266 
267         void allocInputs(int count);
268     };
269 
270     SkImageFilter(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect);
271 
272     ~SkImageFilter() override;
273 
274     /**
275      *  Constructs a new SkImageFilter read from an SkReadBuffer object.
276      *
277      *  @param inputCount    The exact number of inputs expected for this SkImageFilter object.
278      *                       -1 can be used if the filter accepts any number of inputs.
279      *  @param rb            SkReadBuffer object from which the SkImageFilter is read.
280      */
281     explicit SkImageFilter(int inputCount, SkReadBuffer& rb);
282 
283     void flatten(SkWriteBuffer&) const override;
284 
getCropRectIfSet()285     const CropRect* getCropRectIfSet() const {
286         return this->cropRectIsSet() ? &fCropRect : nullptr;
287     }
288 
289     /**
290      *  This is the virtual which should be overridden by the derived class
291      *  to perform image filtering.
292      *
293      *  src is the original primitive bitmap. If the filter has a connected
294      *  input, it should recurse on that input and use that in place of src.
295      *
296      *  The matrix is the current matrix on the canvas.
297      *
298      *  Offset is the amount to translate the resulting image relative to the
299      *  src when it is drawn. This is an out-param.
300      *
301      *  If the result image cannot be created (either because of error or if, say, the result
302      *  is entirely clipped out), this should return nullptr.
303      *  Callers that affect transparent black should explicitly handle nullptr
304      *  results and press on. In the error case this behavior will produce a better result
305      *  than nothing and is necessary for the clipped out case.
306      *  If the return value is nullptr then offset should be ignored.
307      */
308     virtual sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
309                                                 SkIPoint* offset) const = 0;
310 
311     /**
312      * This function recurses into its inputs with the given rect (first
313      * argument), calls filterBounds() with the given map direction on each,
314      * and returns the union of those results. If a derived class has special
315      * recursion requirements (e.g., it has an input which does not participate
316      * in bounds computation), it can be overridden here.
317      *
318      * Note that this function is *not* responsible for mapping the rect for
319      * this node's filter bounds requirements (i.e., calling
320      * onFilterNodeBounds()); that is handled by filterBounds().
321      */
322     virtual SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const;
323 
324     /**
325      * Performs a forwards or reverse mapping of the given rect to accommodate
326      * this filter's margin requirements. kForward_MapDirection is used to
327      * determine the destination pixels which would be touched by filtering
328      * the given given source rect (e.g., given source bitmap bounds,
329      * determine the optimal bounds of the filtered offscreen bitmap).
330      * kReverse_MapDirection is used to determine which pixels of the
331      * input(s) would be required to fill the given destination rect
332      * (e.g., clip bounds). NOTE: these operations may not be the
333      * inverse of the other. For example, blurring expands the given rect
334      * in both forward and reverse directions. Unlike
335      * onFilterBounds(), this function is non-recursive.
336      */
337     virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const;
338 
339     // Helper function which invokes filter processing on the input at the
340     // specified "index". If the input is null, it returns "src" and leaves
341     // "offset" untouched. If the input is non-null, it
342     // calls filterImage() on that input, and returns the result.
343     sk_sp<SkSpecialImage> filterInput(int index,
344                                       SkSpecialImage* src,
345                                       const Context&,
346                                       SkIPoint* offset) const;
347 
348     /**
349      *  Return true (and return a ref'd colorfilter) if this node in the DAG is just a
350      *  colorfilter w/o CropRect constraints.
351      */
onIsColorFilterNode(SkColorFilter **)352     virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const {
353         return false;
354     }
355 
356     /**
357      *  Override this to describe the behavior of your subclass - as a leaf node. The caller will
358      *  take care of calling your inputs (and return false if any of them could not handle it).
359      */
onCanHandleComplexCTM()360     virtual bool onCanHandleComplexCTM() const { return false; }
361 
362     /** Given a "srcBounds" rect, computes destination bounds for this filter.
363      *  "dstBounds" are computed by transforming the crop rect by the context's
364      *  CTM, applying it to the initial bounds, and intersecting the result with
365      *  the context's clip bounds.  "srcBounds" (if non-null) are computed by
366      *  intersecting the initial bounds with "dstBounds", to ensure that we never
367      *  sample outside of the crop rect (this restriction may be relaxed in the
368      *  future).
369      */
370     bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const;
371 
372     /** A variant of the above call which takes the original source bitmap and
373      *  source offset. If the resulting crop rect is not entirely contained by
374      *  the source bitmap's bounds, it creates a new bitmap in "result" and
375      *  pads the edges with transparent black. In that case, the srcOffset is
376      *  modified to be the same as the bounds, since no further adjustment is
377      *  needed by the caller. This version should only be used by filters
378      *  which are not capable of processing a smaller source bitmap into a
379      *  larger destination.
380      */
381     sk_sp<SkSpecialImage> applyCropRect(const Context&, SkSpecialImage* src, SkIPoint* srcOffset,
382                                         SkIRect* bounds) const;
383 
384     /**
385      *  Creates a modified Context for use when recursing up the image filter DAG.
386      *  The clip bounds are adjusted to accommodate any margins that this
387      *  filter requires by calling this node's
388      *  onFilterNodeBounds(..., kReverse_MapDirection).
389      */
390     Context mapContext(const Context& ctx) const;
391 
392 #if SK_SUPPORT_GPU
393     /**
394      *  Returns a version of the passed-in image (possibly the original), that is in a colorspace
395      *  with the same gamut as the one from the OutputProperties. This allows filters that do many
396      *  texture samples to guarantee that any color space conversion has happened before running.
397      */
398     static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src, const OutputProperties&);
399 #endif
400 
401     /**
402      *  Returns an image filter transformed into a new color space via the |xformer|.
403      */
makeColorSpace(SkColorSpaceXformer * xformer)404     sk_sp<SkImageFilter> makeColorSpace(SkColorSpaceXformer* xformer) const {
405         return this->onMakeColorSpace(xformer);
406     }
407     virtual sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const = 0;
408 
refMe()409     sk_sp<SkImageFilter> refMe() const {
410         return sk_ref_sp(const_cast<SkImageFilter*>(this));
411     }
412 
413 private:
414     // For makeColorSpace().
415     friend class SkColorSpaceXformer;
416 
417     friend class SkGraphics;
418 
419     static void PurgeCache();
420 
421     void init(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect);
422 
usesSrcInput()423     bool usesSrcInput() const { return fUsesSrcInput; }
affectsTransparentBlack()424     virtual bool affectsTransparentBlack() const { return false; }
425 
426     SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
427 
428     bool fUsesSrcInput;
429     CropRect fCropRect;
430     uint32_t fUniqueID; // Globally unique
431     mutable SkTArray<SkImageFilterCacheKey> fCacheKeys;
432     mutable SkMutex fMutex;
433     typedef SkFlattenable INHERITED;
434 };
435 
436 /**
437  *  Helper to unflatten the common data, and return NULL if we fail.
438  */
439 #define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount)    \
440     Common localVar;                                                \
441     do {                                                            \
442         if (!localVar.unflatten(buffer, expectedCount)) {           \
443             return NULL;                                            \
444         }                                                           \
445     } while (0)
446 
447 #endif
448