LCOV - code coverage report
Current view: top level - gfx/skia/skia/include/core - SkImageFilter.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 40 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 :         explicit OutputProperties(SkColorSpace* colorSpace) : fColorSpace(colorSpace) {}
      45             : 
      46           0 :         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           0 :         Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache,
      57             :                 const OutputProperties& outputProperties)
      58           0 :             : fCTM(ctm)
      59             :             , fClipBounds(clipBounds)
      60             :             , fCache(cache)
      61           0 :             , fOutputProperties(outputProperties)
      62           0 :         {}
      63             : 
      64           0 :         const SkMatrix& ctm() const { return fCTM; }
      65           0 :         const SkIRect& clipBounds() const { return fClipBounds; }
      66           0 :         SkImageFilterCache* cache() const { return fCache; }
      67           0 :         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             :         };
      85           0 :         CropRect() {}
      86           0 :         explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge)
      87           0 :             : fRect(rect), fFlags(flags) {}
      88           0 :         uint32_t flags() const { return fFlags; }
      89           0 :         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             :      */
     167           0 :     bool isColorFilterNode(SkColorFilter** filterPtr) const {
     168           0 :         return this->onIsColorFilterNode(filterPtr);
     169             :     }
     170             : 
     171             :     // DEPRECATED : use isColorFilterNode() instead
     172             :     bool asColorFilter(SkColorFilter** filterPtr) const {
     173             :         return this->isColorFilterNode(filterPtr);
     174             :     }
     175             : 
     176             :     static sk_sp<SkImageFilter> MakeBlur(SkScalar sigmaX, SkScalar sigmaY,
     177             :                                          sk_sp<SkImageFilter> input,
     178             :                                          const CropRect* cropRect = nullptr);
     179             : 
     180             :     /**
     181             :      *  Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely
     182             :      *  replaced by the returned colorfilter. i.e. the two effects will affect drawing in the
     183             :      *  same way.
     184             :      */
     185             :     bool asAColorFilter(SkColorFilter** filterPtr) const;
     186             : 
     187             :     /**
     188             :      *  Returns the number of inputs this filter will accept (some inputs can
     189             :      *  be NULL).
     190             :      */
     191           0 :     int countInputs() const { return fInputs.count(); }
     192             : 
     193             :     /**
     194             :      *  Returns the input filter at a given index, or NULL if no input is
     195             :      *  connected.  The indices used are filter-specific.
     196             :      */
     197           0 :     SkImageFilter* getInput(int i) const {
     198           0 :         SkASSERT(i < fInputs.count());
     199           0 :         return fInputs[i].get();
     200             :     }
     201             : 
     202             :     /**
     203             :      *  Returns whether any edges of the crop rect have been set. The crop
     204             :      *  rect is set at construction time, and determines which pixels from the
     205             :      *  input image will be processed, and which pixels in the output image will be allowed.
     206             :      *  The size of the crop rect should be
     207             :      *  used as the size of the destination image. The origin of this rect
     208             :      *  should be used to offset access to the input images, and should also
     209             :      *  be added to the "offset" parameter in onFilterImage.
     210             :      */
     211           0 :     bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
     212             : 
     213           0 :     CropRect getCropRect() const { return fCropRect; }
     214             : 
     215             :     // Default impl returns union of all input bounds.
     216             :     virtual SkRect computeFastBounds(const SkRect&) const;
     217             : 
     218             :     // Can this filter DAG compute the resulting bounds of an object-space rectangle?
     219             :     bool canComputeFastBounds() const;
     220             : 
     221             :     /**
     222             :      *  If this filter can be represented by another filter + a localMatrix, return that filter,
     223             :      *  else return null.
     224             :      */
     225             :     sk_sp<SkImageFilter> makeWithLocalMatrix(const SkMatrix&) const;
     226             : 
     227             :     /**
     228             :      *  ImageFilters can natively handle scaling and translate components in the CTM. Only some of
     229             :      *  them can handle affine (or more complex) matrices. This call returns true iff the filter
     230             :      *  and all of its (non-null) inputs can handle these more complex matrices.
     231             :      */
     232             :     bool canHandleComplexCTM() const;
     233             : 
     234             :     /**
     235             :      * Return an imagefilter which transforms its input by the given matrix.
     236             :      */
     237             :     static sk_sp<SkImageFilter> MakeMatrixFilter(const SkMatrix& matrix,
     238             :                                                  SkFilterQuality quality,
     239             :                                                  sk_sp<SkImageFilter> input);
     240             : 
     241             :     SK_TO_STRING_PUREVIRT()
     242           0 :     SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter)
     243             :     SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
     244             : 
     245             : protected:
     246           0 :     class Common {
     247             :     public:
     248             :         /**
     249             :          *  Attempt to unflatten the cropRect and the expected number of input filters.
     250             :          *  If any number of input filters is valid, pass -1.
     251             :          *  If this fails (i.e. corrupt buffer or contents) then return false and common will
     252             :          *  be left uninitialized.
     253             :          *  If this returns true, then inputCount() is the number of found input filters, each
     254             :          *  of which may be NULL or a valid imagefilter.
     255             :          */
     256             :         bool unflatten(SkReadBuffer&, int expectedInputs);
     257             : 
     258           0 :         const CropRect& cropRect() const { return fCropRect; }
     259           0 :         int             inputCount() const { return fInputs.count(); }
     260           0 :         sk_sp<SkImageFilter>* inputs() const { return fInputs.get(); }
     261             : 
     262           0 :         sk_sp<SkImageFilter>  getInput(int index) const { return fInputs[index]; }
     263             : 
     264             :     private:
     265             :         CropRect fCropRect;
     266             :         // most filters accept at most 2 input-filters
     267             :         SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
     268             : 
     269             :         void allocInputs(int count);
     270             :     };
     271             : 
     272             :     SkImageFilter(sk_sp<SkImageFilter>* inputs, int inputCount, const CropRect* cropRect);
     273             : 
     274             :     ~SkImageFilter() override;
     275             : 
     276             :     /**
     277             :      *  Constructs a new SkImageFilter read from an SkReadBuffer object.
     278             :      *
     279             :      *  @param inputCount    The exact number of inputs expected for this SkImageFilter object.
     280             :      *                       -1 can be used if the filter accepts any number of inputs.
     281             :      *  @param rb            SkReadBuffer object from which the SkImageFilter is read.
     282             :      */
     283             :     explicit SkImageFilter(int inputCount, SkReadBuffer& rb);
     284             : 
     285             :     void flatten(SkWriteBuffer&) const override;
     286             : 
     287           0 :     const CropRect* getCropRectIfSet() const {
     288           0 :         return this->cropRectIsSet() ? &fCropRect : nullptr;
     289             :     }
     290             : 
     291             :     /**
     292             :      *  This is the virtual which should be overridden by the derived class
     293             :      *  to perform image filtering.
     294             :      *
     295             :      *  src is the original primitive bitmap. If the filter has a connected
     296             :      *  input, it should recurse on that input and use that in place of src.
     297             :      *
     298             :      *  The matrix is the current matrix on the canvas.
     299             :      *
     300             :      *  Offset is the amount to translate the resulting image relative to the
     301             :      *  src when it is drawn. This is an out-param.
     302             :      *
     303             :      *  If the result image cannot be created (either because of error or if, say, the result
     304             :      *  is entirely clipped out), this should return nullptr.
     305             :      *  Callers that affect transparent black should explicitly handle nullptr
     306             :      *  results and press on. In the error case this behavior will produce a better result
     307             :      *  than nothing and is necessary for the clipped out case.
     308             :      *  If the return value is nullptr then offset should be ignored.
     309             :      */
     310             :     virtual sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
     311             :                                                 SkIPoint* offset) const = 0;
     312             : 
     313             :     /**
     314             :      * This function recurses into its inputs with the given rect (first
     315             :      * argument), calls filterBounds() with the given map direction on each,
     316             :      * and returns the union of those results. If a derived class has special
     317             :      * recursion requirements (e.g., it has an input which does not participate
     318             :      * in bounds computation), it can be overridden here.
     319             :      *
     320             :      * Note that this function is *not* responsible for mapping the rect for
     321             :      * this node's filter bounds requirements (i.e., calling
     322             :      * onFilterNodeBounds()); that is handled by filterBounds().
     323             :      */
     324             :     virtual SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const;
     325             : 
     326             :     /**
     327             :      * Performs a forwards or reverse mapping of the given rect to accommodate
     328             :      * this filter's margin requirements. kForward_MapDirection is used to
     329             :      * determine the destination pixels which would be touched by filtering
     330             :      * the given given source rect (e.g., given source bitmap bounds,
     331             :      * determine the optimal bounds of the filtered offscreen bitmap).
     332             :      * kReverse_MapDirection is used to determine which pixels of the
     333             :      * input(s) would be required to fill the given destination rect
     334             :      * (e.g., clip bounds). NOTE: these operations may not be the
     335             :      * inverse of the other. For example, blurring expands the given rect
     336             :      * in both forward and reverse directions. Unlike
     337             :      * onFilterBounds(), this function is non-recursive.
     338             :      */
     339             :     virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const;
     340             : 
     341             :     // Helper function which invokes filter processing on the input at the
     342             :     // specified "index". If the input is null, it returns "src" and leaves
     343             :     // "offset" untouched. If the input is non-null, it
     344             :     // calls filterImage() on that input, and returns the result.
     345             :     sk_sp<SkSpecialImage> filterInput(int index,
     346             :                                       SkSpecialImage* src,
     347             :                                       const Context&, 
     348             :                                       SkIPoint* offset) const;
     349             : 
     350             :     /**
     351             :      *  Return true (and return a ref'd colorfilter) if this node in the DAG is just a
     352             :      *  colorfilter w/o CropRect constraints.
     353             :      */
     354           0 :     virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const {
     355           0 :         return false;
     356             :     }
     357             : 
     358             :     /**
     359             :      *  Override this to describe the behavior of your subclass - as a leaf node. The caller will
     360             :      *  take care of calling your inputs (and return false if any of them could not handle it).
     361             :      */
     362           0 :     virtual bool onCanHandleComplexCTM() const { return false; }
     363             : 
     364             :     /** Given a "srcBounds" rect, computes destination bounds for this filter.
     365             :      *  "dstBounds" are computed by transforming the crop rect by the context's
     366             :      *  CTM, applying it to the initial bounds, and intersecting the result with
     367             :      *  the context's clip bounds.  "srcBounds" (if non-null) are computed by
     368             :      *  intersecting the initial bounds with "dstBounds", to ensure that we never
     369             :      *  sample outside of the crop rect (this restriction may be relaxed in the
     370             :      *  future).
     371             :      */
     372             :     bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const;
     373             : 
     374             :     /** A variant of the above call which takes the original source bitmap and
     375             :      *  source offset. If the resulting crop rect is not entirely contained by
     376             :      *  the source bitmap's bounds, it creates a new bitmap in "result" and
     377             :      *  pads the edges with transparent black. In that case, the srcOffset is
     378             :      *  modified to be the same as the bounds, since no further adjustment is
     379             :      *  needed by the caller. This version should only be used by filters
     380             :      *  which are not capable of processing a smaller source bitmap into a
     381             :      *  larger destination.
     382             :      */
     383             :     sk_sp<SkSpecialImage> applyCropRect(const Context&, SkSpecialImage* src, SkIPoint* srcOffset,
     384             :                                         SkIRect* bounds) const;
     385             : 
     386             :     /**
     387             :      *  Creates a modified Context for use when recursing up the image filter DAG.
     388             :      *  The clip bounds are adjusted to accommodate any margins that this
     389             :      *  filter requires by calling this node's
     390             :      *  onFilterNodeBounds(..., kReverse_MapDirection).
     391             :      */
     392             :     Context mapContext(const Context& ctx) const;
     393             : 
     394             : #if SK_SUPPORT_GPU
     395             :     /**
     396             :      *  Returns a version of the passed-in image (possibly the original), that is in a colorspace
     397             :      *  with the same gamut as the one from the OutputProperties. This allows filters that do many
     398             :      *  texture samples to guarantee that any color space conversion has happened before running.
     399             :      */
     400             :     static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src, const OutputProperties&);
     401             : #endif
     402             : 
     403             :     /**
     404             :      *  Returns an image filter transformed into a new color space via the |xformer|.
     405             :      */
     406           0 :     sk_sp<SkImageFilter> makeColorSpace(SkColorSpaceXformer* xformer) const {
     407           0 :         return this->onMakeColorSpace(xformer);
     408             :     }
     409           0 :     virtual sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const {
     410           0 :         return sk_ref_sp(const_cast<SkImageFilter*>(this));
     411             :     }
     412             : 
     413             : private:
     414             :     // For makeColorSpace().
     415             :     friend class ArithmeticImageFilterImpl;
     416             :     friend class SkAlphaThresholdFilterImpl;
     417             :     friend class SkBlurImageFilterImpl;
     418             :     friend class SkColorFilterImageFilter;
     419             :     friend class SkColorSpaceXformer;
     420             :     friend class SkComposeImageFilter;
     421             :     friend class SkDisplacementMapEffect;
     422             :     friend class SkDropShadowImageFilter;
     423             :     friend class SkImageSource;
     424             :     friend class SkMagnifierImageFilter;
     425             :     friend class SkMatrixConvolutionImageFilter;
     426             :     friend class SkMergeImageFilter;
     427             :     friend class SkMorphologyImageFilter;
     428             :     friend class SkOffsetImageFilter;
     429             :     friend class SkTileImageFilter;
     430             :     friend class SkXfermodeImageFilter_Base;
     431             : 
     432             :     friend class SkGraphics;
     433             : 
     434             :     static void PurgeCache();
     435             : 
     436             :     void init(sk_sp<SkImageFilter>* inputs, int inputCount, const CropRect* cropRect);
     437             : 
     438           0 :     bool usesSrcInput() const { return fUsesSrcInput; }
     439           0 :     virtual bool affectsTransparentBlack() const { return false; }
     440             : 
     441             :     SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
     442             : 
     443             :     bool fUsesSrcInput;
     444             :     CropRect fCropRect;
     445             :     uint32_t fUniqueID; // Globally unique
     446             :     mutable SkTArray<SkImageFilterCacheKey> fCacheKeys;
     447             :     mutable SkMutex fMutex;
     448             :     typedef SkFlattenable INHERITED;
     449             : };
     450             : 
     451             : /**
     452             :  *  Helper to unflatten the common data, and return NULL if we fail.
     453             :  */
     454             : #define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount)    \
     455             :     Common localVar;                                                \
     456             :     do {                                                            \
     457             :         if (!localVar.unflatten(buffer, expectedCount)) {           \
     458             :             return NULL;                                            \
     459             :         }                                                           \
     460             :     } while (0)
     461             : 
     462             : #endif

Generated by: LCOV version 1.13