Home | History | Annotate | Download | only in core
      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 
     15 class SkBitmap;
     16 class SkColorFilter;
     17 class SkBaseDevice;
     18 struct SkIPoint;
     19 class GrEffectRef;
     20 class 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  */
     29 class SK_API SkImageFilter : public SkFlattenable {
     30 public:
     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 
    200 protected:
    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 
    289 private:
    290     typedef SkFlattenable INHERITED;
    291     int fInputCount;
    292     SkImageFilter** fInputs;
    293     CropRect fCropRect;
    294 };
    295 
    296 #endif
    297