/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkImageFilter_DEFINED #define SkImageFilter_DEFINED #include "SkFlattenable.h" #include "SkRect.h" class SkBitmap; class SkColorFilter; class SkDevice; class SkMatrix; struct SkIPoint; class SkShader; class GrEffectRef; class GrTexture; /** * Experimental. * * Base class for image filters. If one is installed in the paint, then * all drawing occurs as usual, but it is as if the drawing happened into an * offscreen (before the xfermode is applied). This offscreen bitmap will * then be handed to the imagefilter, who in turn creates a new bitmap which * is what will finally be drawn to the device (using the original xfermode). * * THIS SIGNATURE IS TEMPORARY * * There are several weaknesses in this function signature: * 1. Does not expose the destination/target device, so filters that can draw * directly to it are unable to take advantage of that optimization. * 2. Does not expose a way to create a "compabitible" image (i.e. gpu -> gpu) * 3. As with #1, the filter is unable to "read" the dest (which would be slow) * * Therefore, we should not create any real dependencies on this API yet -- it * is being checked in as a check-point so we can explore these and other * considerations. */ class SK_API SkImageFilter : public SkFlattenable { public: SK_DECLARE_INST_COUNT(SkImageFilter) class Proxy { public: virtual ~Proxy() {}; virtual SkDevice* createDevice(int width, int height) = 0; // returns true if the proxy can handle this filter natively virtual bool canHandleImageFilter(SkImageFilter*) = 0; // returns true if the proxy handled the filter itself. if this returns // false then the filter's code will be called. virtual bool filterImage(SkImageFilter*, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) = 0; }; /** * Request a new (result) image to be created from the src image. * If the src has no pixels (isNull()) then the request just wants to * receive the config and width/height of the result. * * The matrix is the current matrix on the canvas. * * Offset is the amount to translate the resulting image relative to the * src when it is drawn. * * If the result image cannot be created, return false, in which case both * the result and offset parameters will be ignored by the caller. */ bool filterImage(Proxy*, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset); /** * Given the src bounds of an image, this returns the bounds of the result * image after the filter has been applied. */ bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst); /** * Returns true if the filter can be expressed a single-pass * GrEffect, used to process this filter on the GPU, or false if * not. * * If effect is non-NULL, a new GrEffect instance is stored * in it. The caller assumes ownership of the stage, and it is up to the * caller to unref it. * * The effect can assume its vertexCoords space maps 1-to-1 with texels * in the texture. "offset" is the delta between the source and * destination rect's origins, when cropped processing is being performed. */ virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkIPoint& offset) const; /** * Returns true if the filter can be processed on the GPU. This is most * often used for multi-pass effects, where intermediate results must be * rendered to textures. For single-pass effects, use asNewEffect(). * The default implementation returns asNewEffect(NULL, NULL). */ virtual bool canFilterImageGPU() const; /** * Process this image filter on the GPU. This is most often used for * multi-pass effects, where intermediate results must be rendered to * textures. For single-pass effects, use asNewEffect(). src is the * source image for processing, as a texture-backed bitmap. result is * the destination bitmap, which should contain a texture-backed pixelref * on success. offset is the amount to translate the resulting image * relative to the src when it is drawn. The default implementation does * single-pass processing using asNewEffect(). */ virtual bool filterImageGPU(Proxy*, const SkBitmap& src, SkBitmap* result, SkIPoint* offset); /** * Returns whether this image filter is a color filter and puts the color filter into the * "filterPtr" parameter if it can. Does nothing otherwise. * If this returns false, then the filterPtr is unchanged. * If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler * (i.e. it may not be set to NULL). */ virtual bool asColorFilter(SkColorFilter** filterPtr) const; /** * Returns the number of inputs this filter will accept (some inputs can * be NULL). */ int countInputs() const { return fInputCount; } /** * Returns the input filter at a given index, or NULL if no input is * connected. The indices used are filter-specific. */ SkImageFilter* getInput(int i) const { SkASSERT(i < fInputCount); return fInputs[i]; } /** * Returns the crop rectangle of this filter. This is set at construction * time, and determines which pixels from the input image will * be processed. The size of this rectangle should be used as the size * of the destination image. The origin of this rect should be used to * offset access to the input images, and should also be added to the * "offset" parameter in onFilterImage and filterImageGPU(). (The latter * ensures that the resulting buffer is drawn in the correct location.) */ const SkIRect& cropRect() const { return fCropRect; } protected: SkImageFilter(int inputCount, SkImageFilter** inputs, const SkIRect* cropRect = NULL); // Convenience constructor for 1-input filters. explicit SkImageFilter(SkImageFilter* input, const SkIRect* cropRect = NULL); // Convenience constructor for 2-input filters. SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const SkIRect* cropRect = NULL); virtual ~SkImageFilter(); explicit SkImageFilter(SkFlattenableReadBuffer& rb); virtual void flatten(SkFlattenableWriteBuffer& wb) const SK_OVERRIDE; // Default impl returns false virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, SkBitmap* result, SkIPoint* offset); // Default impl copies src into dst and returns true virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*); // Sets rect to the intersection of rect and the crop rect. If there // is no overlap, returns false and leaves rect unchanged. bool applyCropRect(SkIRect* rect) const; private: typedef SkFlattenable INHERITED; int fInputCount; SkImageFilter** fInputs; SkIRect fCropRect; }; #endif