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