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: 45 explicit OutputProperties(SkColorType colorType, SkColorSpace* colorSpace) 46 : fColorType(colorType), fColorSpace(colorSpace) {} 47 48 SkColorType colorType() const { return fColorType; } 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: 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 68 const SkMatrix& ctm() const { return fCTM; } 69 const SkIRect& clipBounds() const { return fClipBounds; } 70 SkImageFilterCache* cache() const { return fCache; } 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 */ 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 }; 99 CropRect() {} 100 explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge) 101 : fRect(rect), fFlags(flags) {} 102 uint32_t flags() const { return fFlags; } 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 */ 183 bool isColorFilterNode(SkColorFilter** filterPtr) const { 184 return this->onIsColorFilterNode(filterPtr); 185 } 186 187 // DEPRECATED : use isColorFilterNode() instead 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 */ 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 */ 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 */ 225 bool cropRectIsSet() const { return fCropRect.flags() != 0x0; } 226 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 257 static SkFlattenable::Type GetFlattenableType() { 258 return kSkImageFilter_Type; 259 } 260 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 285 const CropRect& cropRect() const { return fCropRect; } 286 int inputCount() const { return fInputs.count(); } 287 sk_sp<SkImageFilter>* inputs() { return fInputs.begin(); } 288 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 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 */ 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 */ 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 */ 439 sk_sp<SkImageFilter> makeColorSpace(SkColorSpaceXformer* xformer) const { 440 return this->onMakeColorSpace(xformer); 441 } 442 virtual sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const = 0; 443 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 467 bool usesSrcInput() const { return fUsesSrcInput; } 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