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 "SkFilterQuality.h" 15 #include "SkFlattenable.h" 16 #include "SkMatrix.h" 17 #include "SkRect.h" 18 #include "SkSurfaceProps.h" 19 20 class GrFragmentProcessor; 21 class GrTexture; 22 class SkBaseDevice; 23 class SkBitmap; 24 class SkColorFilter; 25 struct SkIPoint; 26 class SkSpecialImage; 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 // This cache maps from (filter's unique ID + CTM + clipBounds + src bitmap generation ID) to 38 // (result, offset). 39 class Cache : public SkRefCnt { 40 public: 41 struct Key; ~Cache()42 virtual ~Cache() {} 43 static Cache* Create(size_t maxBytes); 44 static Cache* Get(); 45 virtual bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const = 0; 46 virtual SkSpecialImage* get(const Key& key, SkIPoint* offset) const = 0; 47 virtual void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) = 0; 48 virtual void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset) = 0; purge()49 virtual void purge() {} purgeByKeys(const Key[],int)50 virtual void purgeByKeys(const Key[], int) {} 51 }; 52 53 class Context { 54 public: Context(const SkMatrix & ctm,const SkIRect & clipBounds,Cache * cache)55 Context(const SkMatrix& ctm, const SkIRect& clipBounds, Cache* cache) 56 : fCTM(ctm) 57 , fClipBounds(clipBounds) 58 , fCache(cache) 59 {} 60 ctm()61 const SkMatrix& ctm() const { return fCTM; } clipBounds()62 const SkIRect& clipBounds() const { return fClipBounds; } cache()63 Cache* cache() const { return fCache; } 64 65 private: 66 SkMatrix fCTM; 67 SkIRect fClipBounds; 68 Cache* fCache; 69 }; 70 71 class CropRect { 72 public: 73 enum CropEdge { 74 kHasLeft_CropEdge = 0x01, 75 kHasTop_CropEdge = 0x02, 76 kHasWidth_CropEdge = 0x04, 77 kHasHeight_CropEdge = 0x08, 78 kHasAll_CropEdge = 0x0F, 79 }; CropRect()80 CropRect() {} 81 explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge) fRect(rect)82 : fRect(rect), fFlags(flags) {} flags()83 uint32_t flags() const { return fFlags; } rect()84 const SkRect& rect() const { return fRect; } 85 #ifndef SK_IGNORE_TO_STRING 86 void toString(SkString* str) const; 87 #endif 88 89 /** 90 * Apply this cropRect to the imageBounds. If a given edge of the cropRect is not 91 * set, then the corresponding edge from imageBounds will be used. 92 * 93 * Note: imageBounds is in "device" space, as the output cropped rectangle will be, 94 * so the matrix is ignored for those. It is only applied the croprect's bounds. 95 */ 96 void applyTo(const SkIRect& imageBounds, const SkMatrix&, SkIRect* cropped) const; 97 98 private: 99 SkRect fRect; 100 uint32_t fFlags; 101 }; 102 103 enum TileUsage { 104 kPossible_TileUsage, //!< the created device may be drawn tiled 105 kNever_TileUsage, //!< the created device will never be drawn tiled 106 }; 107 108 class Proxy { 109 public: ~Proxy()110 virtual ~Proxy() {} 111 112 virtual SkBaseDevice* createDevice(int width, int height, 113 TileUsage usage = kNever_TileUsage) = 0; 114 115 // Returns true if the proxy handled the filter itself. If this returns 116 // false then the filter's code will be called. 117 virtual bool filterImage(const SkImageFilter*, const SkBitmap& src, 118 const SkImageFilter::Context&, 119 SkBitmap* result, SkIPoint* offset) = 0; 120 }; 121 122 class DeviceProxy : public Proxy { 123 public: DeviceProxy(SkBaseDevice * device)124 DeviceProxy(SkBaseDevice* device) : fDevice(device) {} 125 126 SkBaseDevice* createDevice(int width, int height, 127 TileUsage usage = kNever_TileUsage) override; 128 129 // Returns true if the proxy handled the filter itself. If this returns 130 // false then the filter's code will be called. 131 bool filterImage(const SkImageFilter*, const SkBitmap& src, const SkImageFilter::Context&, 132 SkBitmap* result, SkIPoint* offset) override; 133 134 private: 135 SkBaseDevice* fDevice; 136 }; 137 138 /** 139 * Request a new (result) image to be created from the src image. 140 * If the src has no pixels (isNull()) then the request just wants to 141 * receive the config and width/height of the result. 142 * 143 * The matrix is the current matrix on the canvas. 144 * 145 * Offset is the amount to translate the resulting image relative to the 146 * src when it is drawn. This is an out-param. 147 * 148 * If the result image cannot be created, return false, in which case both 149 * the result and offset parameters will be ignored by the caller. 150 */ 151 bool filterImageDeprecated(Proxy*, const SkBitmap& src, const Context&, 152 SkBitmap* result, SkIPoint* offset) const; 153 154 enum MapDirection { 155 kForward_MapDirection, 156 kReverse_MapDirection 157 }; 158 /** 159 * Map a device-space rect recursively forward or backward through the 160 * filter DAG. kForward_MapDirection is used to determine which pixels of 161 * the destination canvas a source image rect would touch after filtering. 162 * kBackward_MapDirection is used to determine which rect of the source 163 * image would be required to fill the given rect (typically, clip bounds). 164 * Used for clipping and temp-buffer allocations, so the result need not 165 * be exact, but should never be smaller than the real answer. The default 166 * implementation recursively unions all input bounds, or returns false if 167 * no inputs. 168 */ 169 bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst, 170 MapDirection = kReverse_MapDirection) const; 171 172 /** 173 * Returns true if the filter can be processed on the GPU. This is most 174 * often used for multi-pass effects, where intermediate results must be 175 * rendered to textures. For single-pass effects, use asFragmentProcessor(). 176 * The default implementation returns asFragmentProcessor(NULL, NULL, SkMatrix::I(), 177 * SkIRect()). 178 */ 179 virtual bool canFilterImageGPU() const; 180 181 /** 182 * Process this image filter on the GPU. This is most often used for 183 * multi-pass effects, where intermediate results must be rendered to 184 * textures. For single-pass effects, use asFragmentProcessor(). src is the 185 * source image for processing, as a texture-backed bitmap. result is 186 * the destination bitmap, which should contain a texture-backed pixelref 187 * on success. offset is the amount to translate the resulting image 188 * relative to the src when it is drawn. The default implementation does 189 * single-pass processing using asFragmentProcessor(). 190 */ 191 virtual bool filterImageGPUDeprecated(Proxy*, const SkBitmap& src, const Context&, 192 SkBitmap* result, SkIPoint* offset) const; 193 194 /** 195 * Returns whether this image filter is a color filter and puts the color filter into the 196 * "filterPtr" parameter if it can. Does nothing otherwise. 197 * If this returns false, then the filterPtr is unchanged. 198 * If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler 199 * (i.e. it may not be set to NULL). 200 */ isColorFilterNode(SkColorFilter ** filterPtr)201 bool isColorFilterNode(SkColorFilter** filterPtr) const { 202 return this->onIsColorFilterNode(filterPtr); 203 } 204 205 // DEPRECATED : use isColorFilterNode() instead asColorFilter(SkColorFilter ** filterPtr)206 bool asColorFilter(SkColorFilter** filterPtr) const { 207 return this->isColorFilterNode(filterPtr); 208 } 209 210 /** 211 * Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely 212 * replaced by the returned colorfilter. i.e. the two effects will affect drawing in the 213 * same way. 214 */ 215 bool asAColorFilter(SkColorFilter** filterPtr) const; 216 217 /** 218 * Returns the number of inputs this filter will accept (some inputs can 219 * be NULL). 220 */ countInputs()221 int countInputs() const { return fInputCount; } 222 223 /** 224 * Returns the input filter at a given index, or NULL if no input is 225 * connected. The indices used are filter-specific. 226 */ getInput(int i)227 SkImageFilter* getInput(int i) const { 228 SkASSERT(i < fInputCount); 229 return fInputs[i]; 230 } 231 232 /** 233 * Returns whether any edges of the crop rect have been set. The crop 234 * rect is set at construction time, and determines which pixels from the 235 * input image will be processed, and which pixels in the output image will be allowed. 236 * The size of the crop rect should be 237 * used as the size of the destination image. The origin of this rect 238 * should be used to offset access to the input images, and should also 239 * be added to the "offset" parameter in onFilterImage and 240 * filterImageGPU(). (The latter ensures that the resulting buffer is 241 * drawn in the correct location.) 242 */ cropRectIsSet()243 bool cropRectIsSet() const { return fCropRect.flags() != 0x0; } 244 getCropRect()245 CropRect getCropRect() const { return fCropRect; } 246 247 // Default impl returns union of all input bounds. 248 virtual void computeFastBounds(const SkRect&, SkRect*) const; 249 250 // Can this filter DAG compute the resulting bounds of an object-space rectangle? 251 virtual bool canComputeFastBounds() const; 252 253 /** 254 * If this filter can be represented by another filter + a localMatrix, return that filter, 255 * else return null. 256 */ 257 SkImageFilter* newWithLocalMatrix(const SkMatrix& matrix) const; 258 259 /** 260 * Create an SkMatrixImageFilter, which transforms its input by the given matrix. 261 */ 262 static SkImageFilter* CreateMatrixFilter(const SkMatrix& matrix, 263 SkFilterQuality, 264 SkImageFilter* input = NULL); 265 266 #if SK_SUPPORT_GPU 267 // Helper function which invokes GPU filter processing on the 268 // input at the specified "index". If the input is null, it leaves 269 // "result" and "offset" untouched, and returns true. If the input 270 // has a GPU implementation, it will be invoked directly. 271 // Otherwise, the filter will be processed in software and 272 // uploaded to the GPU. 273 bool filterInputGPUDeprecated(int index, SkImageFilter::Proxy* proxy, 274 const SkBitmap& src, const Context&, 275 SkBitmap* result, SkIPoint* offset) const; 276 #endif 277 278 SK_TO_STRING_PUREVIRT() SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter)279 SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter) 280 281 protected: 282 class Common { 283 public: 284 Common() {} 285 ~Common(); 286 287 /** 288 * Attempt to unflatten the cropRect and the expected number of input filters. 289 * If any number of input filters is valid, pass -1. 290 * If this fails (i.e. corrupt buffer or contents) then return false and common will 291 * be left uninitialized. 292 * If this returns true, then inputCount() is the number of found input filters, each 293 * of which may be NULL or a valid imagefilter. 294 */ 295 bool unflatten(SkReadBuffer&, int expectedInputs); 296 297 const CropRect& cropRect() const { return fCropRect; } 298 int inputCount() const { return fInputs.count(); } 299 SkImageFilter** inputs() const { return fInputs.get(); } 300 301 SkImageFilter* getInput(int index) const { return fInputs[index]; } 302 303 // If the caller wants a copy of the inputs, call this and it will transfer ownership 304 // of the unflattened input filters to the caller. This is just a short-cut for copying 305 // the inputs, calling ref() on each, and then waiting for Common's destructor to call 306 // unref() on each. 307 void detachInputs(SkImageFilter** inputs); 308 309 private: 310 CropRect fCropRect; 311 // most filters accept at most 2 input-filters 312 SkAutoSTArray<2, SkImageFilter*> fInputs; 313 314 void allocInputs(int count); 315 }; 316 317 SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect = NULL); 318 319 virtual ~SkImageFilter(); 320 321 /** 322 * Constructs a new SkImageFilter read from an SkReadBuffer object. 323 * 324 * @param inputCount The exact number of inputs expected for this SkImageFilter object. 325 * -1 can be used if the filter accepts any number of inputs. 326 * @param rb SkReadBuffer object from which the SkImageFilter is read. 327 */ 328 explicit SkImageFilter(int inputCount, SkReadBuffer& rb); 329 330 void flatten(SkWriteBuffer&) const override; 331 332 /** 333 * This is the virtual which should be overridden by the derived class 334 * to perform image filtering. 335 * 336 * src is the original primitive bitmap. If the filter has a connected 337 * input, it should recurse on that input and use that in place of src. 338 * 339 * The matrix is the current matrix on the canvas. 340 * 341 * Offset is the amount to translate the resulting image relative to the 342 * src when it is drawn. This is an out-param. 343 * 344 * If the result image cannot be created, this should false, in which 345 * case both the result and offset parameters will be ignored by the 346 * caller. 347 */ 348 virtual bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&, 349 SkBitmap* result, SkIPoint* offset) const; 350 351 /** 352 * This function recurses into its inputs with the given clip rect (first 353 * argument), calls filterBounds() with the given map direction on each, 354 * and unions the result (third argument). If the rect cannot be mapped, 355 * false is returned and the destination rect is left unchanged. 356 * If a derived class has special recursion requirements (e.g., it has an 357 * input which does not participate in bounds computation), it can be 358 * overridden here. 359 * 360 * Note that this function is *not* responsible for mapping the rect for 361 * this node's filter bounds requirements (i.e., calling 362 * onFilterNodeBounds()); that is handled by filterBounds(). 363 */ 364 virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const; 365 366 /** 367 * Performs a forwards or reverse mapping of the given rect to accommodate 368 * this filter's margin requirements. kForward_MapDirection is used to 369 * determine the destination pixels which would be touched by filtering 370 * the given given source rect (e.g., given source bitmap bounds, 371 * determine the optimal bounds of the filtered offscreen bitmap). 372 * kReverse_MapDirection is used to determine which pixels of the 373 * input(s) would be required to fill the given destination rect 374 * (e.g., clip bounds). NOTE: these operations may not be the 375 * inverse of the other. For example, blurring expands the given rect 376 * in both forward and reverse directions. Unlike 377 * onFilterBounds(), this function is non-recursive. 378 */ 379 virtual void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const; 380 381 // Helper function which invokes filter processing on the input at the 382 // specified "index". If the input is null, it leaves "result" and 383 // "offset" untouched, and returns true. If the input is non-null, it 384 // calls filterImage() on that input, and returns true on success. 385 // i.e., return !getInput(index) || getInput(index)->filterImage(...); 386 bool filterInputDeprecated(int index, Proxy*, const SkBitmap& src, const Context&, 387 SkBitmap* result, SkIPoint* offset) const; 388 389 /** 390 * Return true (and return a ref'd colorfilter) if this node in the DAG is just a 391 * colorfilter w/o CropRect constraints. 392 */ onIsColorFilterNode(SkColorFilter **)393 virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const { 394 return false; 395 } 396 397 /** Given a "srcBounds" rect, computes destination bounds for this 398 * destination bounds for this filter. "dstBounds" are computed by 399 * transforming the crop rect by the context's CTM, applying it to the 400 * initial bounds, and intersecting the result with the context's clip 401 * bounds. "srcBounds" (if non-null) are computed by intersecting the 402 * initial bounds with "dstBounds", to ensure that we never sample 403 * outside of the crop rect (this restriction may be relaxed in the 404 * future). 405 */ 406 bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const; 407 408 /** A variant of the above call which takes the original source bitmap and 409 * source offset. If the resulting crop rect is not entirely contained by 410 * the source bitmap's bounds, it creates a new bitmap in "result" and 411 * pads the edges with transparent black. In that case, the srcOffset is 412 * modified to be the same as the bounds, since no further adjustment is 413 * needed by the caller. This version should only be used by filters 414 * which are not capable of processing a smaller source bitmap into a 415 * larger destination. 416 */ 417 bool applyCropRectDeprecated(const Context&, Proxy* proxy, const SkBitmap& src, 418 SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* result) const; 419 420 /** 421 * Returns true if the filter can be expressed a single-pass 422 * GrProcessor, used to process this filter on the GPU, or false if 423 * not. 424 * 425 * If effect is non-NULL, a new GrProcessor instance is stored 426 * in it. The caller assumes ownership of the stage, and it is up to the 427 * caller to unref it. 428 * 429 * The effect can assume its vertexCoords space maps 1-to-1 with texels 430 * in the texture. "matrix" is a transformation to apply to filter 431 * parameters before they are used in the effect. Note that this function 432 * will be called with (NULL, NULL, SkMatrix::I()) to query for support, 433 * so returning "true" indicates support for all possible matrices. 434 */ 435 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, 436 const SkIRect& bounds) const; 437 438 /** 439 * Creates a modified Context for use when recursing up the image filter DAG. 440 * The clip bounds are adjusted to accommodate any margins that this 441 * filter requires by calling this node's 442 * onFilterNodeBounds(..., kReverse_MapDirection). 443 */ 444 Context mapContext(const Context& ctx) const; 445 446 private: 447 friend class SkGraphics; 448 static void PurgeCache(); 449 usesSrcInput()450 bool usesSrcInput() const { return fUsesSrcInput; } 451 452 typedef SkFlattenable INHERITED; 453 int fInputCount; 454 SkImageFilter** fInputs; 455 bool fUsesSrcInput; 456 CropRect fCropRect; 457 uint32_t fUniqueID; // Globally unique 458 mutable SkTArray<Cache::Key> fCacheKeys; 459 mutable SkMutex fMutex; 460 }; 461 462 /** 463 * Helper to unflatten the common data, and return NULL if we fail. 464 */ 465 #define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount) \ 466 Common localVar; \ 467 do { \ 468 if (!localVar.unflatten(buffer, expectedCount)) { \ 469 return NULL; \ 470 } \ 471 } while (0) 472 473 #endif 474