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