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