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