michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef SkCanvas_DEFINED michael@0: #define SkCanvas_DEFINED michael@0: michael@0: #include "SkTypes.h" michael@0: #include "SkBitmap.h" michael@0: #include "SkDeque.h" michael@0: #include "SkClipStack.h" michael@0: #include "SkPaint.h" michael@0: #include "SkRefCnt.h" michael@0: #include "SkPath.h" michael@0: #include "SkRegion.h" michael@0: #include "SkXfermode.h" michael@0: michael@0: // if not defined, we always assume ClipToLayer for saveLayer() michael@0: //#define SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG michael@0: michael@0: michael@0: //#define SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG michael@0: //#define SK_SUPPORT_LEGACY_GETCLIPTYPE michael@0: //#define SK_SUPPORT_LEGACY_GETTOTALCLIP michael@0: //#define SK_SUPPORT_LEGACY_GETTOPDEVICE michael@0: michael@0: class SkBounder; michael@0: class SkBaseDevice; michael@0: class SkDraw; michael@0: class SkDrawFilter; michael@0: class SkMetaData; michael@0: class SkPicture; michael@0: class SkRRect; michael@0: class SkSurface; michael@0: class SkSurface_Base; michael@0: class GrContext; michael@0: class GrRenderTarget; michael@0: michael@0: /** \class SkCanvas michael@0: michael@0: A Canvas encapsulates all of the state about drawing into a device (bitmap). michael@0: This includes a reference to the device itself, and a stack of matrix/clip michael@0: values. For any given draw call (e.g. drawRect), the geometry of the object michael@0: being drawn is transformed by the concatenation of all the matrices in the michael@0: stack. The transformed geometry is clipped by the intersection of all of michael@0: the clips in the stack. michael@0: michael@0: While the Canvas holds the state of the drawing device, the state (style) michael@0: of the object being drawn is held by the Paint, which is provided as a michael@0: parameter to each of the draw() methods. The Paint holds attributes such as michael@0: color, typeface, textSize, strokeWidth, shader (e.g. gradients, patterns), michael@0: etc. michael@0: */ michael@0: class SK_API SkCanvas : public SkRefCnt { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkCanvas) michael@0: michael@0: /** michael@0: * Attempt to allocate an offscreen raster canvas, matching the ImageInfo. michael@0: * On success, return a new canvas that will draw into that offscreen. michael@0: * michael@0: * The caller can access the pixels after drawing into this canvas by michael@0: * calling readPixels() or peekPixels(). michael@0: * michael@0: * If the requested ImageInfo is opaque (either the colortype is michael@0: * intrinsically opaque like RGB_565, or the info's alphatype is kOpaque) michael@0: * then the pixel memory may be uninitialized. Otherwise, the pixel memory michael@0: * will be initialized to 0, which is interpreted as transparent. michael@0: * michael@0: * On failure, return NULL. This can fail for several reasons: michael@0: * 1. the memory allocation failed (e.g. request is too large) michael@0: * 2. invalid ImageInfo (e.g. negative dimensions) michael@0: * 3. unsupported ImageInfo for a canvas michael@0: * - kUnknown_SkColorType, kIndex_8_SkColorType michael@0: * - kIgnore_SkAlphaType michael@0: * - this list is not complete, so others may also be unsupported michael@0: * michael@0: * Note: it is valid to request a supported ImageInfo, but with zero michael@0: * dimensions. michael@0: */ michael@0: static SkCanvas* NewRaster(const SkImageInfo&); michael@0: michael@0: static SkCanvas* NewRasterN32(int width, int height) { michael@0: return NewRaster(SkImageInfo::MakeN32Premul(width, height)); michael@0: } michael@0: michael@0: /** michael@0: * Attempt to allocate raster canvas, matching the ImageInfo, that will draw directly into the michael@0: * specified pixels. To access the pixels after drawing to them, the caller should call michael@0: * flush() or call peekPixels(...). michael@0: * michael@0: * On failure, return NULL. This can fail for several reasons: michael@0: * 1. invalid ImageInfo (e.g. negative dimensions) michael@0: * 2. unsupported ImageInfo for a canvas michael@0: * - kUnknown_SkColorType, kIndex_8_SkColorType michael@0: * - kIgnore_SkAlphaType michael@0: * - this list is not complete, so others may also be unsupported michael@0: * michael@0: * Note: it is valid to request a supported ImageInfo, but with zero michael@0: * dimensions. michael@0: */ michael@0: static SkCanvas* NewRasterDirect(const SkImageInfo&, void*, size_t); michael@0: michael@0: static SkCanvas* NewRasterDirectN32(int width, int height, SkPMColor* pixels, size_t rowBytes) { michael@0: return NewRasterDirect(SkImageInfo::MakeN32Premul(width, height), pixels, rowBytes); michael@0: } michael@0: michael@0: /** michael@0: * Creates an empty canvas with no backing device/pixels, and zero michael@0: * dimensions. michael@0: */ michael@0: SkCanvas(); michael@0: michael@0: /** michael@0: * Creates a canvas of the specified dimensions, but explicitly not backed michael@0: * by any device/pixels. Typically this use used by subclasses who handle michael@0: * the draw calls in some other way. michael@0: */ michael@0: SkCanvas(int width, int height); michael@0: michael@0: /** Construct a canvas with the specified device to draw into. michael@0: michael@0: @param device Specifies a device for the canvas to draw into. michael@0: */ michael@0: explicit SkCanvas(SkBaseDevice* device); michael@0: michael@0: /** Construct a canvas with the specified bitmap to draw into. michael@0: @param bitmap Specifies a bitmap for the canvas to draw into. Its michael@0: structure are copied to the canvas. michael@0: */ michael@0: explicit SkCanvas(const SkBitmap& bitmap); michael@0: virtual ~SkCanvas(); michael@0: michael@0: SkMetaData& getMetaData(); michael@0: michael@0: /** michael@0: * Return ImageInfo for this canvas. If the canvas is not backed by pixels michael@0: * (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType. michael@0: */ michael@0: SkImageInfo imageInfo() const; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Trigger the immediate execution of all pending draw operations. michael@0: */ michael@0: void flush(); michael@0: michael@0: /** michael@0: * Gets the size of the base or root layer in global canvas coordinates. The michael@0: * origin of the base layer is always (0,0). The current drawable area may be michael@0: * smaller (due to clipping or saveLayer). michael@0: */ michael@0: SkISize getBaseLayerSize() const; michael@0: michael@0: /** michael@0: * DEPRECATED: call getBaseLayerSize michael@0: */ michael@0: SkISize getDeviceSize() const { return this->getBaseLayerSize(); } michael@0: michael@0: /** michael@0: * DEPRECATED. michael@0: * Return the canvas' device object, which may be null. The device holds michael@0: * the bitmap of the pixels that the canvas draws into. The reference count michael@0: * of the returned device is not changed by this call. michael@0: */ michael@0: SkBaseDevice* getDevice() const; michael@0: michael@0: /** michael@0: * saveLayer() can create another device (which is later drawn onto michael@0: * the previous device). getTopDevice() returns the top-most device current michael@0: * installed. Note that this can change on other calls like save/restore, michael@0: * so do not access this device after subsequent canvas calls. michael@0: * The reference count of the device is not changed. michael@0: * michael@0: * @param updateMatrixClip If this is true, then before the device is michael@0: * returned, we ensure that its has been notified about the current michael@0: * matrix and clip. Note: this happens automatically when the device michael@0: * is drawn to, but is optional here, as there is a small perf hit michael@0: * sometimes. michael@0: */ michael@0: #ifndef SK_SUPPORT_LEGACY_GETTOPDEVICE michael@0: private: michael@0: #endif michael@0: SkBaseDevice* getTopDevice(bool updateMatrixClip = false) const; michael@0: public: michael@0: michael@0: /** michael@0: * Create a new surface matching the specified info, one that attempts to michael@0: * be maximally compatible when used with this canvas. michael@0: */ michael@0: SkSurface* newSurface(const SkImageInfo&); michael@0: michael@0: /** michael@0: * Return the GPU context of the device that is associated with the canvas. michael@0: * For a canvas with non-GPU device, NULL is returned. michael@0: */ michael@0: GrContext* getGrContext(); michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * If the canvas has writable pixels in its top layer (and is not recording to a picture michael@0: * or other non-raster target) and has direct access to its pixels (i.e. they are in michael@0: * local RAM) return the address of those pixels, and if not null, michael@0: * return the ImageInfo and rowBytes. The returned address is only valid michael@0: * while the canvas object is in scope and unchanged. Any API calls made on michael@0: * canvas (or its parent surface if any) will invalidate the michael@0: * returned address (and associated information). michael@0: * michael@0: * On failure, returns NULL and the info and rowBytes parameters are michael@0: * ignored. michael@0: */ michael@0: void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes); michael@0: michael@0: /** michael@0: * If the canvas has readable pixels in its base layer (and is not recording to a picture michael@0: * or other non-raster target) and has direct access to its pixels (i.e. they are in michael@0: * local RAM) return the const-address of those pixels, and if not null, michael@0: * return the ImageInfo and rowBytes. The returned address is only valid michael@0: * while the canvas object is in scope and unchanged. Any API calls made on michael@0: * canvas (or its parent surface if any) will invalidate the michael@0: * returned address (and associated information). michael@0: * michael@0: * On failure, returns NULL and the info and rowBytes parameters are michael@0: * ignored. michael@0: */ michael@0: const void* peekPixels(SkImageInfo* info, size_t* rowBytes); michael@0: michael@0: /** michael@0: * This enum can be used with read/writePixels to perform a pixel ops to or michael@0: * from an 8888 config other than Skia's native config (SkPMColor). There michael@0: * are three byte orders supported: native, BGRA, and RGBA. Each has a michael@0: * premultiplied and unpremultiplied variant. michael@0: * michael@0: * Components of a 8888 pixel can be packed/unpacked from a 32bit word using michael@0: * either byte offsets or shift values. Byte offsets are endian-invariant michael@0: * while shifts are not. BGRA and RGBA configs are defined by byte michael@0: * orderings. The native config is defined by shift values (SK_A32_SHIFT, michael@0: * ..., SK_B32_SHIFT). michael@0: */ michael@0: enum Config8888 { michael@0: /** michael@0: * Skia's native order specified by: michael@0: * SK_A32_SHIFT, SK_R32_SHIFT, SK_G32_SHIFT, and SK_B32_SHIFT michael@0: * michael@0: * kNative_Premul_Config8888 is equivalent to SkPMColor michael@0: * kNative_Unpremul_Config8888 has the same component order as SkPMColor michael@0: * but is not premultiplied. michael@0: */ michael@0: kNative_Premul_Config8888, michael@0: kNative_Unpremul_Config8888, michael@0: /** michael@0: * low byte to high byte: B, G, R, A. michael@0: */ michael@0: kBGRA_Premul_Config8888, michael@0: kBGRA_Unpremul_Config8888, michael@0: /** michael@0: * low byte to high byte: R, G, B, A. michael@0: */ michael@0: kRGBA_Premul_Config8888, michael@0: kRGBA_Unpremul_Config8888 michael@0: }; michael@0: michael@0: /** michael@0: * On success (returns true), copy the canvas pixels into the bitmap. michael@0: * On failure, the bitmap parameter is left unchanged and false is michael@0: * returned. michael@0: * michael@0: * The canvas' pixels are converted to the bitmap's config. The only michael@0: * supported config is kARGB_8888_Config, though this is likely to be michael@0: * relaxed in the future. The meaning of config kARGB_8888_Config is michael@0: * modified by the enum param config8888. The default value interprets michael@0: * kARGB_8888_Config as SkPMColor michael@0: * michael@0: * If the bitmap has pixels already allocated, the canvas pixels will be michael@0: * written there. If not, bitmap->allocPixels() will be called michael@0: * automatically. If the bitmap is backed by a texture readPixels will michael@0: * fail. michael@0: * michael@0: * The actual pixels written is the intersection of the canvas' bounds, and michael@0: * the rectangle formed by the bitmap's width,height and the specified x,y. michael@0: * If bitmap pixels extend outside of that intersection, they will not be michael@0: * modified. michael@0: * michael@0: * Other failure conditions: michael@0: * * If the canvas is backed by a non-raster device (e.g. PDF) then michael@0: * readPixels will fail. michael@0: * * If bitmap is texture-backed then readPixels will fail. (This may be michael@0: * relaxed in the future.) michael@0: * michael@0: * Example that reads the entire canvas into a bitmap using the native michael@0: * SkPMColor: michael@0: * SkISize size = canvas->getDeviceSize(); michael@0: * bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth, michael@0: * size.fHeight); michael@0: * if (canvas->readPixels(bitmap, 0, 0)) { michael@0: * // use the pixels michael@0: * } michael@0: */ michael@0: bool readPixels(SkBitmap* bitmap, michael@0: int x, int y, michael@0: Config8888 config8888 = kNative_Premul_Config8888); michael@0: michael@0: /** michael@0: * DEPRECATED: This will be removed as soon as webkit is no longer relying michael@0: * on it. The bitmap is resized to the intersection of srcRect and the michael@0: * canvas bounds. New pixels are always allocated on success. Bitmap is michael@0: * unmodified on failure. michael@0: */ michael@0: bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap); michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG michael@0: /** michael@0: * DEPRECATED michael@0: * Similar to draw sprite, this method will copy the pixels in bitmap onto michael@0: * the canvas, with the top/left corner specified by (x, y). The canvas' michael@0: * pixel values are completely replaced: there is no blending. michael@0: * michael@0: * Currently if bitmap is backed by a texture this is a no-op. This may be michael@0: * relaxed in the future. michael@0: * michael@0: * If the bitmap has config kARGB_8888_Config then the config8888 param michael@0: * will determines how the pixel valuess are intepreted. If the bitmap is michael@0: * not kARGB_8888_Config then this parameter is ignored. michael@0: * michael@0: * Note: If you are recording drawing commands on this canvas to michael@0: * SkPicture, writePixels() is ignored! michael@0: */ michael@0: void writePixels(const SkBitmap& bitmap, int x, int y, Config8888 config8888); michael@0: #endif michael@0: michael@0: /** michael@0: * This method affects the pixels in the base-layer, and operates in pixel coordinates, michael@0: * ignoring the matrix and clip. michael@0: * michael@0: * The specified ImageInfo and (x,y) offset specifies a rectangle: target. michael@0: * michael@0: * target.setXYWH(x, y, info.width(), info.height()); michael@0: * michael@0: * Target is intersected with the bounds of the base-layer. If this intersection is not empty, michael@0: * then we have two sets of pixels (of equal size), the "src" specified by info+pixels+rowBytes michael@0: * and the "dst" by the canvas' backend. Replace the dst pixels with the corresponding src michael@0: * pixels, performing any colortype/alphatype transformations needed (in the case where the michael@0: * src and dst have different colortypes or alphatypes). michael@0: * michael@0: * This call can fail, returning false, for several reasons: michael@0: * - If the src colortype/alphatype cannot be converted to the canvas' types michael@0: * - If this canvas is not backed by pixels (e.g. picture or PDF) michael@0: */ michael@0: bool writePixels(const SkImageInfo&, const void* pixels, size_t rowBytes, int x, int y); michael@0: michael@0: /** michael@0: * Helper for calling writePixels(info, ...) by passing its pixels and rowbytes. If the bitmap michael@0: * is just wrapping a texture, returns false and does nothing. michael@0: */ michael@0: bool writePixels(const SkBitmap& bitmap, int x, int y); michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: michael@0: enum SaveFlags { michael@0: /** save the matrix state, restoring it on restore() */ michael@0: kMatrix_SaveFlag = 0x01, michael@0: /** save the clip state, restoring it on restore() */ michael@0: kClip_SaveFlag = 0x02, michael@0: /** the layer needs to support per-pixel alpha */ michael@0: kHasAlphaLayer_SaveFlag = 0x04, michael@0: /** the layer needs to support 8-bits per color component */ michael@0: kFullColorLayer_SaveFlag = 0x08, michael@0: /** michael@0: * the layer should clip against the bounds argument michael@0: * michael@0: * if SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG is undefined, this is treated as always on. michael@0: */ michael@0: kClipToLayer_SaveFlag = 0x10, michael@0: michael@0: // helper masks for common choices michael@0: kMatrixClip_SaveFlag = 0x03, michael@0: #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG michael@0: kARGB_NoClipLayer_SaveFlag = 0x0F, michael@0: #endif michael@0: kARGB_ClipLayer_SaveFlag = 0x1F michael@0: }; michael@0: michael@0: /** This call saves the current matrix, clip, and drawFilter, and pushes a michael@0: copy onto a private stack. Subsequent calls to translate, scale, michael@0: rotate, skew, concat or clipRect, clipPath, and setDrawFilter all michael@0: operate on this copy. michael@0: When the balancing call to restore() is made, the previous matrix, clip, michael@0: and drawFilter are restored. michael@0: @param flags The flags govern what portion of the Matrix/Clip/drawFilter michael@0: state the save (and matching restore) effect. For example, michael@0: if only kMatrix is specified, then only the matrix state michael@0: will be pushed and popped. Likewise for the clip if kClip michael@0: is specified. However, the drawFilter is always affected michael@0: by calls to save/restore. michael@0: @return The value to pass to restoreToCount() to balance this save() michael@0: */ michael@0: int save(SaveFlags flags = kMatrixClip_SaveFlag); michael@0: michael@0: /** This behaves the same as save(), but in addition it allocates an michael@0: offscreen bitmap. All drawing calls are directed there, and only when michael@0: the balancing call to restore() is made is that offscreen transfered to michael@0: the canvas (or the previous layer). michael@0: @param bounds (may be null) This rect, if non-null, is used as a hint to michael@0: limit the size of the offscreen, and thus drawing may be michael@0: clipped to it, though that clipping is not guaranteed to michael@0: happen. If exact clipping is desired, use clipRect(). michael@0: @param paint (may be null) This is copied, and is applied to the michael@0: offscreen when restore() is called michael@0: @param flags LayerFlags michael@0: @return The value to pass to restoreToCount() to balance this save() michael@0: */ michael@0: int saveLayer(const SkRect* bounds, const SkPaint* paint, michael@0: SaveFlags flags = kARGB_ClipLayer_SaveFlag); michael@0: michael@0: /** This behaves the same as save(), but in addition it allocates an michael@0: offscreen bitmap. All drawing calls are directed there, and only when michael@0: the balancing call to restore() is made is that offscreen transfered to michael@0: the canvas (or the previous layer). michael@0: @param bounds (may be null) This rect, if non-null, is used as a hint to michael@0: limit the size of the offscreen, and thus drawing may be michael@0: clipped to it, though that clipping is not guaranteed to michael@0: happen. If exact clipping is desired, use clipRect(). michael@0: @param alpha This is applied to the offscreen when restore() is called. michael@0: @param flags LayerFlags michael@0: @return The value to pass to restoreToCount() to balance this save() michael@0: */ michael@0: int saveLayerAlpha(const SkRect* bounds, U8CPU alpha, michael@0: SaveFlags flags = kARGB_ClipLayer_SaveFlag); michael@0: michael@0: /** This call balances a previous call to save(), and is used to remove all michael@0: modifications to the matrix/clip/drawFilter state since the last save michael@0: call. michael@0: It is an error to call restore() more times than save() was called. michael@0: */ michael@0: void restore(); michael@0: michael@0: /** Returns the number of matrix/clip states on the SkCanvas' private stack. michael@0: This will equal # save() calls - # restore() calls + 1. The save count on michael@0: a new canvas is 1. michael@0: */ michael@0: int getSaveCount() const; michael@0: michael@0: /** Efficient way to pop any calls to save() that happened after the save michael@0: count reached saveCount. It is an error for saveCount to be greater than michael@0: getSaveCount(). To pop all the way back to the initial matrix/clip context michael@0: pass saveCount == 1. michael@0: @param saveCount The number of save() levels to restore from michael@0: */ michael@0: void restoreToCount(int saveCount); michael@0: michael@0: /** Returns true if drawing is currently going to a layer (from saveLayer) michael@0: * rather than to the root device. michael@0: */ michael@0: virtual bool isDrawingToLayer() const; michael@0: michael@0: /** Preconcat the current matrix with the specified translation michael@0: @param dx The distance to translate in X michael@0: @param dy The distance to translate in Y michael@0: returns true if the operation succeeded (e.g. did not overflow) michael@0: */ michael@0: bool translate(SkScalar dx, SkScalar dy); michael@0: michael@0: /** Preconcat the current matrix with the specified scale. michael@0: @param sx The amount to scale in X michael@0: @param sy The amount to scale in Y michael@0: returns true if the operation succeeded (e.g. did not overflow) michael@0: */ michael@0: bool scale(SkScalar sx, SkScalar sy); michael@0: michael@0: /** Preconcat the current matrix with the specified rotation. michael@0: @param degrees The amount to rotate, in degrees michael@0: returns true if the operation succeeded (e.g. did not overflow) michael@0: */ michael@0: bool rotate(SkScalar degrees); michael@0: michael@0: /** Preconcat the current matrix with the specified skew. michael@0: @param sx The amount to skew in X michael@0: @param sy The amount to skew in Y michael@0: returns true if the operation succeeded (e.g. did not overflow) michael@0: */ michael@0: bool skew(SkScalar sx, SkScalar sy); michael@0: michael@0: /** Preconcat the current matrix with the specified matrix. michael@0: @param matrix The matrix to preconcatenate with the current matrix michael@0: @return true if the operation succeeded (e.g. did not overflow) michael@0: */ michael@0: bool concat(const SkMatrix& matrix); michael@0: michael@0: /** Replace the current matrix with a copy of the specified matrix. michael@0: @param matrix The matrix that will be copied into the current matrix. michael@0: */ michael@0: void setMatrix(const SkMatrix& matrix); michael@0: michael@0: /** Helper for setMatrix(identity). Sets the current matrix to identity. michael@0: */ michael@0: void resetMatrix(); michael@0: michael@0: /** michael@0: * Modify the current clip with the specified rectangle. michael@0: * @param rect The rect to combine with the current clip michael@0: * @param op The region op to apply to the current clip michael@0: * @param doAntiAlias true if the clip should be antialiased michael@0: */ michael@0: void clipRect(const SkRect& rect, michael@0: SkRegion::Op op = SkRegion::kIntersect_Op, michael@0: bool doAntiAlias = false); michael@0: michael@0: /** michael@0: * Modify the current clip with the specified SkRRect. michael@0: * @param rrect The rrect to combine with the current clip michael@0: * @param op The region op to apply to the current clip michael@0: * @param doAntiAlias true if the clip should be antialiased michael@0: */ michael@0: void clipRRect(const SkRRect& rrect, michael@0: SkRegion::Op op = SkRegion::kIntersect_Op, michael@0: bool doAntiAlias = false); michael@0: michael@0: /** michael@0: * Modify the current clip with the specified path. michael@0: * @param path The path to combine with the current clip michael@0: * @param op The region op to apply to the current clip michael@0: * @param doAntiAlias true if the clip should be antialiased michael@0: */ michael@0: void clipPath(const SkPath& path, michael@0: SkRegion::Op op = SkRegion::kIntersect_Op, michael@0: bool doAntiAlias = false); michael@0: michael@0: /** EXPERIMENTAL -- only used for testing michael@0: Set to false to force clips to be hard, even if doAntiAlias=true is michael@0: passed to clipRect or clipPath. michael@0: */ michael@0: void setAllowSoftClip(bool allow) { michael@0: fAllowSoftClip = allow; michael@0: } michael@0: michael@0: /** EXPERIMENTAL -- only used for testing michael@0: Set to simplify clip stack using path ops. michael@0: */ michael@0: void setAllowSimplifyClip(bool allow) { michael@0: fAllowSimplifyClip = allow; michael@0: } michael@0: michael@0: /** Modify the current clip with the specified region. Note that unlike michael@0: clipRect() and clipPath() which transform their arguments by the current michael@0: matrix, clipRegion() assumes its argument is already in device michael@0: coordinates, and so no transformation is performed. michael@0: @param deviceRgn The region to apply to the current clip michael@0: @param op The region op to apply to the current clip michael@0: */ michael@0: void clipRegion(const SkRegion& deviceRgn, michael@0: SkRegion::Op op = SkRegion::kIntersect_Op); michael@0: michael@0: /** Helper for clipRegion(rgn, kReplace_Op). Sets the current clip to the michael@0: specified region. This does not intersect or in any other way account michael@0: for the existing clip region. michael@0: @param deviceRgn The region to copy into the current clip. michael@0: */ michael@0: void setClipRegion(const SkRegion& deviceRgn) { michael@0: this->clipRegion(deviceRgn, SkRegion::kReplace_Op); michael@0: } michael@0: michael@0: /** Return true if the specified rectangle, after being transformed by the michael@0: current matrix, would lie completely outside of the current clip. Call michael@0: this to check if an area you intend to draw into is clipped out (and michael@0: therefore you can skip making the draw calls). michael@0: @param rect the rect to compare with the current clip michael@0: @return true if the rect (transformed by the canvas' matrix) does not michael@0: intersect with the canvas' clip michael@0: */ michael@0: bool quickReject(const SkRect& rect) const; michael@0: michael@0: /** Return true if the specified path, after being transformed by the michael@0: current matrix, would lie completely outside of the current clip. Call michael@0: this to check if an area you intend to draw into is clipped out (and michael@0: therefore you can skip making the draw calls). Note, for speed it may michael@0: return false even if the path itself might not intersect the clip michael@0: (i.e. the bounds of the path intersects, but the path does not). michael@0: @param path The path to compare with the current clip michael@0: @return true if the path (transformed by the canvas' matrix) does not michael@0: intersect with the canvas' clip michael@0: */ michael@0: bool quickReject(const SkPath& path) const; michael@0: michael@0: /** Return true if the horizontal band specified by top and bottom is michael@0: completely clipped out. This is a conservative calculation, meaning michael@0: that it is possible that if the method returns false, the band may still michael@0: in fact be clipped out, but the converse is not true. If this method michael@0: returns true, then the band is guaranteed to be clipped out. michael@0: @param top The top of the horizontal band to compare with the clip michael@0: @param bottom The bottom of the horizontal and to compare with the clip michael@0: @return true if the horizontal band is completely clipped out (i.e. does michael@0: not intersect the current clip) michael@0: */ michael@0: bool quickRejectY(SkScalar top, SkScalar bottom) const { michael@0: SkASSERT(top <= bottom); michael@0: michael@0: #ifndef SK_WILL_NEVER_DRAW_PERSPECTIVE_TEXT michael@0: // TODO: add a hasPerspective method similar to getLocalClipBounds. This michael@0: // would cache the SkMatrix::hasPerspective result. Alternatively, have michael@0: // the MC stack just set a hasPerspective boolean as it is updated. michael@0: if (this->getTotalMatrix().hasPerspective()) { michael@0: // TODO: consider implementing some half-plane test between the michael@0: // two Y planes and the device-bounds (i.e., project the top and michael@0: // bottom Y planes and then determine if the clip bounds is completely michael@0: // outside either one). michael@0: return false; michael@0: } michael@0: #endif michael@0: michael@0: const SkRect& clipR = this->getLocalClipBounds(); michael@0: // In the case where the clip is empty and we are provided with a michael@0: // negative top and positive bottom parameter then this test will return michael@0: // false even though it will be clipped. We have chosen to exclude that michael@0: // check as it is rare and would result double the comparisons. michael@0: return top >= clipR.fBottom || bottom <= clipR.fTop; michael@0: } michael@0: michael@0: /** Return the bounds of the current clip (in local coordinates) in the michael@0: bounds parameter, and return true if it is non-empty. This can be useful michael@0: in a way similar to quickReject, in that it tells you that drawing michael@0: outside of these bounds will be clipped out. michael@0: */ michael@0: virtual bool getClipBounds(SkRect* bounds) const; michael@0: michael@0: /** Return the bounds of the current clip, in device coordinates; returns michael@0: true if non-empty. Maybe faster than getting the clip explicitly and michael@0: then taking its bounds. michael@0: */ michael@0: virtual bool getClipDeviceBounds(SkIRect* bounds) const; michael@0: michael@0: michael@0: /** Fill the entire canvas' bitmap (restricted to the current clip) with the michael@0: specified ARGB color, using the specified mode. michael@0: @param a the alpha component (0..255) of the color to fill the canvas michael@0: @param r the red component (0..255) of the color to fill the canvas michael@0: @param g the green component (0..255) of the color to fill the canvas michael@0: @param b the blue component (0..255) of the color to fill the canvas michael@0: @param mode the mode to apply the color in (defaults to SrcOver) michael@0: */ michael@0: void drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, michael@0: SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode); michael@0: michael@0: /** Fill the entire canvas' bitmap (restricted to the current clip) with the michael@0: specified color and mode. michael@0: @param color the color to draw with michael@0: @param mode the mode to apply the color in (defaults to SrcOver) michael@0: */ michael@0: void drawColor(SkColor color, michael@0: SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode); michael@0: michael@0: /** michael@0: * This erases the entire drawing surface to the specified color, michael@0: * irrespective of the clip. It does not blend with the previous pixels, michael@0: * but always overwrites them. michael@0: * michael@0: * It is roughly equivalent to the following: michael@0: * canvas.save(); michael@0: * canvas.clipRect(hugeRect, kReplace_Op); michael@0: * paint.setColor(color); michael@0: * paint.setXfermodeMode(kSrc_Mode); michael@0: * canvas.drawPaint(paint); michael@0: * canvas.restore(); michael@0: * though it is almost always much more efficient. michael@0: */ michael@0: virtual void clear(SkColor); michael@0: michael@0: /** michael@0: * Fill the entire canvas' bitmap (restricted to the current clip) with the michael@0: * specified paint. michael@0: * @param paint The paint used to fill the canvas michael@0: */ michael@0: virtual void drawPaint(const SkPaint& paint); michael@0: michael@0: enum PointMode { michael@0: /** drawPoints draws each point separately */ michael@0: kPoints_PointMode, michael@0: /** drawPoints draws each pair of points as a line segment */ michael@0: kLines_PointMode, michael@0: /** drawPoints draws the array of points as a polygon */ michael@0: kPolygon_PointMode michael@0: }; michael@0: michael@0: /** Draw a series of points, interpreted based on the PointMode mode. For michael@0: all modes, the count parameter is interpreted as the total number of michael@0: points. For kLine mode, count/2 line segments are drawn. michael@0: For kPoint mode, each point is drawn centered at its coordinate, and its michael@0: size is specified by the paint's stroke-width. It draws as a square, michael@0: unless the paint's cap-type is round, in which the points are drawn as michael@0: circles. michael@0: For kLine mode, each pair of points is drawn as a line segment, michael@0: respecting the paint's settings for cap/join/width. michael@0: For kPolygon mode, the entire array is drawn as a series of connected michael@0: line segments. michael@0: Note that, while similar, kLine and kPolygon modes draw slightly michael@0: differently than the equivalent path built with a series of moveto, michael@0: lineto calls, in that the path will draw all of its contours at once, michael@0: with no interactions if contours intersect each other (think XOR michael@0: xfermode). drawPoints always draws each element one at a time. michael@0: @param mode PointMode specifying how to draw the array of points. michael@0: @param count The number of points in the array michael@0: @param pts Array of points to draw michael@0: @param paint The paint used to draw the points michael@0: */ michael@0: virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], michael@0: const SkPaint& paint); michael@0: michael@0: /** Helper method for drawing a single point. See drawPoints() for a more michael@0: details. michael@0: */ michael@0: void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint); michael@0: michael@0: /** Draws a single pixel in the specified color. michael@0: @param x The X coordinate of which pixel to draw michael@0: @param y The Y coordiante of which pixel to draw michael@0: @param color The color to draw michael@0: */ michael@0: void drawPoint(SkScalar x, SkScalar y, SkColor color); michael@0: michael@0: /** Draw a line segment with the specified start and stop x,y coordinates, michael@0: using the specified paint. NOTE: since a line is always "framed", the michael@0: paint's Style is ignored. michael@0: @param x0 The x-coordinate of the start point of the line michael@0: @param y0 The y-coordinate of the start point of the line michael@0: @param x1 The x-coordinate of the end point of the line michael@0: @param y1 The y-coordinate of the end point of the line michael@0: @param paint The paint used to draw the line michael@0: */ michael@0: void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, michael@0: const SkPaint& paint); michael@0: michael@0: /** Draw the specified rectangle using the specified paint. The rectangle michael@0: will be filled or stroked based on the Style in the paint. michael@0: @param rect The rect to be drawn michael@0: @param paint The paint used to draw the rect michael@0: */ michael@0: virtual void drawRect(const SkRect& rect, const SkPaint& paint); michael@0: michael@0: /** Draw the specified rectangle using the specified paint. The rectangle michael@0: will be filled or framed based on the Style in the paint. michael@0: @param rect The rect to be drawn michael@0: @param paint The paint used to draw the rect michael@0: */ michael@0: void drawIRect(const SkIRect& rect, const SkPaint& paint) { michael@0: SkRect r; michael@0: r.set(rect); // promotes the ints to scalars michael@0: this->drawRect(r, paint); michael@0: } michael@0: michael@0: /** Draw the specified rectangle using the specified paint. The rectangle michael@0: will be filled or framed based on the Style in the paint. michael@0: @param left The left side of the rectangle to be drawn michael@0: @param top The top side of the rectangle to be drawn michael@0: @param right The right side of the rectangle to be drawn michael@0: @param bottom The bottom side of the rectangle to be drawn michael@0: @param paint The paint used to draw the rect michael@0: */ michael@0: void drawRectCoords(SkScalar left, SkScalar top, SkScalar right, michael@0: SkScalar bottom, const SkPaint& paint); michael@0: michael@0: /** Draw the specified oval using the specified paint. The oval will be michael@0: filled or framed based on the Style in the paint. michael@0: @param oval The rectangle bounds of the oval to be drawn michael@0: @param paint The paint used to draw the oval michael@0: */ michael@0: virtual void drawOval(const SkRect& oval, const SkPaint&); michael@0: michael@0: /** michael@0: * Draw the specified RRect using the specified paint The rrect will be filled or stroked michael@0: * based on the Style in the paint. michael@0: * michael@0: * @param rrect The round-rect to draw michael@0: * @param paint The paint used to draw the round-rect michael@0: */ michael@0: virtual void drawRRect(const SkRRect& rrect, const SkPaint& paint); michael@0: michael@0: /** michael@0: * Draw the annulus formed by the outer and inner rrects. The results michael@0: * are undefined if the outer does not contain the inner. michael@0: */ michael@0: void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint&); michael@0: michael@0: /** Draw the specified circle using the specified paint. If radius is <= 0, michael@0: then nothing will be drawn. The circle will be filled michael@0: or framed based on the Style in the paint. michael@0: @param cx The x-coordinate of the center of the cirle to be drawn michael@0: @param cy The y-coordinate of the center of the cirle to be drawn michael@0: @param radius The radius of the cirle to be drawn michael@0: @param paint The paint used to draw the circle michael@0: */ michael@0: void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, michael@0: const SkPaint& paint); michael@0: michael@0: /** Draw the specified arc, which will be scaled to fit inside the michael@0: specified oval. If the sweep angle is >= 360, then the oval is drawn michael@0: completely. Note that this differs slightly from SkPath::arcTo, which michael@0: treats the sweep angle mod 360. michael@0: @param oval The bounds of oval used to define the shape of the arc michael@0: @param startAngle Starting angle (in degrees) where the arc begins michael@0: @param sweepAngle Sweep angle (in degrees) measured clockwise michael@0: @param useCenter true means include the center of the oval. For filling michael@0: this will draw a wedge. False means just use the arc. michael@0: @param paint The paint used to draw the arc michael@0: */ michael@0: void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, michael@0: bool useCenter, const SkPaint& paint); michael@0: michael@0: /** Draw the specified round-rect using the specified paint. The round-rect michael@0: will be filled or framed based on the Style in the paint. michael@0: @param rect The rectangular bounds of the roundRect to be drawn michael@0: @param rx The x-radius of the oval used to round the corners michael@0: @param ry The y-radius of the oval used to round the corners michael@0: @param paint The paint used to draw the roundRect michael@0: */ michael@0: void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, michael@0: const SkPaint& paint); michael@0: michael@0: /** Draw the specified path using the specified paint. The path will be michael@0: filled or framed based on the Style in the paint. michael@0: @param path The path to be drawn michael@0: @param paint The paint used to draw the path michael@0: */ michael@0: virtual void drawPath(const SkPath& path, const SkPaint& paint); michael@0: michael@0: /** Draw the specified bitmap, with its top/left corner at (x,y), using the michael@0: specified paint, transformed by the current matrix. Note: if the paint michael@0: contains a maskfilter that generates a mask which extends beyond the michael@0: bitmap's original width/height, then the bitmap will be drawn as if it michael@0: were in a Shader with CLAMP mode. Thus the color outside of the original michael@0: width/height will be the edge color replicated. michael@0: michael@0: If a shader is present on the paint it will be ignored, except in the michael@0: case where the bitmap is kA8_Config. In that case, the color is michael@0: generated by the shader. michael@0: michael@0: @param bitmap The bitmap to be drawn michael@0: @param left The position of the left side of the bitmap being drawn michael@0: @param top The position of the top side of the bitmap being drawn michael@0: @param paint The paint used to draw the bitmap, or NULL michael@0: */ michael@0: virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, michael@0: const SkPaint* paint = NULL); michael@0: michael@0: enum DrawBitmapRectFlags { michael@0: kNone_DrawBitmapRectFlag = 0x0, michael@0: /** michael@0: * When filtering is enabled, allow the color samples outside of michael@0: * the src rect (but still in the src bitmap) to bleed into the michael@0: * drawn portion michael@0: */ michael@0: kBleed_DrawBitmapRectFlag = 0x1, michael@0: }; michael@0: michael@0: /** Draw the specified bitmap, with the specified matrix applied (before the michael@0: canvas' matrix is applied). michael@0: @param bitmap The bitmap to be drawn michael@0: @param src Optional: specify the subset of the bitmap to be drawn michael@0: @param dst The destination rectangle where the scaled/translated michael@0: image will be drawn michael@0: @param paint The paint used to draw the bitmap, or NULL michael@0: */ michael@0: virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, michael@0: const SkRect& dst, michael@0: const SkPaint* paint = NULL, michael@0: DrawBitmapRectFlags flags = kNone_DrawBitmapRectFlag); michael@0: michael@0: void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, michael@0: const SkPaint* paint = NULL) { michael@0: this->drawBitmapRectToRect(bitmap, NULL, dst, paint, kNone_DrawBitmapRectFlag); michael@0: } michael@0: michael@0: void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* isrc, michael@0: const SkRect& dst, const SkPaint* paint = NULL, michael@0: DrawBitmapRectFlags flags = kNone_DrawBitmapRectFlag) { michael@0: SkRect realSrcStorage; michael@0: SkRect* realSrcPtr = NULL; michael@0: if (isrc) { michael@0: realSrcStorage.set(*isrc); michael@0: realSrcPtr = &realSrcStorage; michael@0: } michael@0: this->drawBitmapRectToRect(bitmap, realSrcPtr, dst, paint, flags); michael@0: } michael@0: michael@0: virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, michael@0: const SkPaint* paint = NULL); michael@0: michael@0: /** michael@0: * Draw the bitmap stretched differentially to fit into dst. michael@0: * center is a rect within the bitmap, and logically divides the bitmap michael@0: * into 9 sections (3x3). For example, if the middle pixel of a [5x5] michael@0: * bitmap is the "center", then the center-rect should be [2, 2, 3, 3]. michael@0: * michael@0: * If the dst is >= the bitmap size, then... michael@0: * - The 4 corners are not stretched at all. michael@0: * - The sides are stretched in only one axis. michael@0: * - The center is stretched in both axes. michael@0: * Else, for each axis where dst < bitmap, michael@0: * - The corners shrink proportionally michael@0: * - The sides (along the shrink axis) and center are not drawn michael@0: */ michael@0: virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, michael@0: const SkRect& dst, const SkPaint* paint = NULL); michael@0: michael@0: /** Draw the specified bitmap, with its top/left corner at (x,y), michael@0: NOT transformed by the current matrix. Note: if the paint michael@0: contains a maskfilter that generates a mask which extends beyond the michael@0: bitmap's original width/height, then the bitmap will be drawn as if it michael@0: were in a Shader with CLAMP mode. Thus the color outside of the original michael@0: width/height will be the edge color replicated. michael@0: @param bitmap The bitmap to be drawn michael@0: @param left The position of the left side of the bitmap being drawn michael@0: @param top The position of the top side of the bitmap being drawn michael@0: @param paint The paint used to draw the bitmap, or NULL michael@0: */ michael@0: virtual void drawSprite(const SkBitmap& bitmap, int left, int top, michael@0: const SkPaint* paint = NULL); michael@0: michael@0: /** Draw the text, with origin at (x,y), using the specified paint. michael@0: The origin is interpreted based on the Align setting in the paint. michael@0: @param text The text to be drawn michael@0: @param byteLength The number of bytes to read from the text parameter michael@0: @param x The x-coordinate of the origin of the text being drawn michael@0: @param y The y-coordinate of the origin of the text being drawn michael@0: @param paint The paint used for the text (e.g. color, size, style) michael@0: */ michael@0: virtual void drawText(const void* text, size_t byteLength, SkScalar x, michael@0: SkScalar y, const SkPaint& paint); michael@0: michael@0: /** Draw the text, with each character/glyph origin specified by the pos[] michael@0: array. The origin is interpreted by the Align setting in the paint. michael@0: @param text The text to be drawn michael@0: @param byteLength The number of bytes to read from the text parameter michael@0: @param pos Array of positions, used to position each character michael@0: @param paint The paint used for the text (e.g. color, size, style) michael@0: */ michael@0: virtual void drawPosText(const void* text, size_t byteLength, michael@0: const SkPoint pos[], const SkPaint& paint); michael@0: michael@0: /** Draw the text, with each character/glyph origin specified by the x michael@0: coordinate taken from the xpos[] array, and the y from the constY param. michael@0: The origin is interpreted by the Align setting in the paint. michael@0: @param text The text to be drawn michael@0: @param byteLength The number of bytes to read from the text parameter michael@0: @param xpos Array of x-positions, used to position each character michael@0: @param constY The shared Y coordinate for all of the positions michael@0: @param paint The paint used for the text (e.g. color, size, style) michael@0: */ michael@0: virtual void drawPosTextH(const void* text, size_t byteLength, michael@0: const SkScalar xpos[], SkScalar constY, michael@0: const SkPaint& paint); michael@0: michael@0: /** Draw the text, with origin at (x,y), using the specified paint, along michael@0: the specified path. The paint's Align setting determins where along the michael@0: path to start the text. michael@0: @param text The text to be drawn michael@0: @param byteLength The number of bytes to read from the text parameter michael@0: @param path The path the text should follow for its baseline michael@0: @param hOffset The distance along the path to add to the text's michael@0: starting position michael@0: @param vOffset The distance above(-) or below(+) the path to michael@0: position the text michael@0: @param paint The paint used for the text michael@0: */ michael@0: void drawTextOnPathHV(const void* text, size_t byteLength, michael@0: const SkPath& path, SkScalar hOffset, michael@0: SkScalar vOffset, const SkPaint& paint); michael@0: michael@0: /** Draw the text, with origin at (x,y), using the specified paint, along michael@0: the specified path. The paint's Align setting determins where along the michael@0: path to start the text. michael@0: @param text The text to be drawn michael@0: @param byteLength The number of bytes to read from the text parameter michael@0: @param path The path the text should follow for its baseline michael@0: @param matrix (may be null) Applied to the text before it is michael@0: mapped onto the path michael@0: @param paint The paint used for the text michael@0: */ michael@0: virtual void drawTextOnPath(const void* text, size_t byteLength, michael@0: const SkPath& path, const SkMatrix* matrix, michael@0: const SkPaint& paint); michael@0: michael@0: /** PRIVATE / EXPERIMENTAL -- do not call michael@0: Perform back-end analysis/optimization of a picture. This may attach michael@0: optimization data to the picture which can be used by a later michael@0: drawPicture call. michael@0: @param picture The recorded drawing commands to analyze/optimize michael@0: */ michael@0: void EXPERIMENTAL_optimize(SkPicture* picture); michael@0: michael@0: /** Draw the picture into this canvas. This method effective brackets the michael@0: playback of the picture's draw calls with save/restore, so the state michael@0: of this canvas will be unchanged after this call. michael@0: @param picture The recorded drawing commands to playback into this michael@0: canvas. michael@0: */ michael@0: virtual void drawPicture(SkPicture& picture); michael@0: michael@0: enum VertexMode { michael@0: kTriangles_VertexMode, michael@0: kTriangleStrip_VertexMode, michael@0: kTriangleFan_VertexMode michael@0: }; michael@0: michael@0: /** Draw the array of vertices, interpreted as triangles (based on mode). michael@0: @param vmode How to interpret the array of vertices michael@0: @param vertexCount The number of points in the vertices array (and michael@0: corresponding texs and colors arrays if non-null) michael@0: @param vertices Array of vertices for the mesh michael@0: @param texs May be null. If not null, specifies the coordinate michael@0: in _texture_ space (not uv space) for each vertex. michael@0: @param colors May be null. If not null, specifies a color for each michael@0: vertex, to be interpolated across the triangle. michael@0: @param xmode Used if both texs and colors are present. In this michael@0: case the colors are combined with the texture using mode, michael@0: before being drawn using the paint. If mode is null, then michael@0: kModulate_Mode is used. michael@0: @param indices If not null, array of indices to reference into the michael@0: vertex (texs, colors) array. michael@0: @param indexCount number of entries in the indices array (if not null) michael@0: @param paint Specifies the shader/texture if present. michael@0: */ michael@0: virtual void drawVertices(VertexMode vmode, int vertexCount, michael@0: const SkPoint vertices[], const SkPoint texs[], michael@0: const SkColor colors[], SkXfermode* xmode, michael@0: const uint16_t indices[], int indexCount, michael@0: const SkPaint& paint); michael@0: michael@0: /** Send a blob of data to the canvas. michael@0: For canvases that draw, this call is effectively a no-op, as the data michael@0: is not parsed, but just ignored. However, this call exists for michael@0: subclasses like SkPicture's recording canvas, that can store the data michael@0: and then play it back later (via another call to drawData). michael@0: */ michael@0: virtual void drawData(const void* data, size_t length) { michael@0: // do nothing. Subclasses may do something with the data michael@0: } michael@0: michael@0: /** Add comments. beginCommentGroup/endCommentGroup open/close a new group. michael@0: Each comment added via addComment is notionally attached to its michael@0: enclosing group. Top-level comments simply belong to no group. michael@0: */ michael@0: virtual void beginCommentGroup(const char* description) { michael@0: // do nothing. Subclasses may do something michael@0: } michael@0: virtual void addComment(const char* kywd, const char* value) { michael@0: // do nothing. Subclasses may do something michael@0: } michael@0: virtual void endCommentGroup() { michael@0: // do nothing. Subclasses may do something michael@0: } michael@0: michael@0: /** michael@0: * With this call the client asserts that subsequent draw operations (up to the michael@0: * matching popCull()) are fully contained within the given bounding box. The assertion michael@0: * is not enforced, but the information might be used to quick-reject command blocks, michael@0: * so an incorrect bounding box may result in incomplete rendering. michael@0: */ michael@0: void pushCull(const SkRect& cullRect) { michael@0: ++fCullCount; michael@0: this->onPushCull(cullRect); michael@0: } michael@0: michael@0: /** michael@0: * Terminates the current culling block, and restores the previous one (if any). michael@0: */ michael@0: void popCull() { michael@0: if (fCullCount > 0) { michael@0: --fCullCount; michael@0: this->onPopCull(); michael@0: } michael@0: } michael@0: ////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** Get the current bounder object. michael@0: The bounder's reference count is unchaged. michael@0: @return the canva's bounder (or NULL). michael@0: */ michael@0: SkBounder* getBounder() const { return fBounder; } michael@0: michael@0: /** Set a new bounder (or NULL). michael@0: Pass NULL to clear any previous bounder. michael@0: As a convenience, the parameter passed is also returned. michael@0: If a previous bounder exists, its reference count is decremented. michael@0: If bounder is not NULL, its reference count is incremented. michael@0: @param bounder the new bounder (or NULL) to be installed in the canvas michael@0: @return the set bounder object michael@0: */ michael@0: virtual SkBounder* setBounder(SkBounder* bounder); michael@0: michael@0: /** Get the current filter object. The filter's reference count is not michael@0: affected. The filter is saved/restored, just like the matrix and clip. michael@0: @return the canvas' filter (or NULL). michael@0: */ michael@0: SkDrawFilter* getDrawFilter() const; michael@0: michael@0: /** Set the new filter (or NULL). Pass NULL to clear any existing filter. michael@0: As a convenience, the parameter is returned. If an existing filter michael@0: exists, its refcnt is decrement. If the new filter is not null, its michael@0: refcnt is incremented. The filter is saved/restored, just like the michael@0: matrix and clip. michael@0: @param filter the new filter (or NULL) michael@0: @return the new filter michael@0: */ michael@0: virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter); michael@0: michael@0: ////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Return true if the current clip is empty (i.e. nothing will draw). michael@0: * Note: this is not always a free call, so it should not be used michael@0: * more often than necessary. However, once the canvas has computed this michael@0: * result, subsequent calls will be cheap (until the clip state changes, michael@0: * which can happen on any clip..() or restore() call. michael@0: */ michael@0: virtual bool isClipEmpty() const; michael@0: michael@0: /** michael@0: * Returns true if the current clip is just a (non-empty) rectangle. michael@0: * Returns false if the clip is empty, or if it is complex. michael@0: */ michael@0: virtual bool isClipRect() const; michael@0: michael@0: /** Return the current matrix on the canvas. michael@0: This does not account for the translate in any of the devices. michael@0: @return The current matrix on the canvas. michael@0: */ michael@0: const SkMatrix& getTotalMatrix() const; michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE michael@0: enum ClipType { michael@0: kEmpty_ClipType = 0, michael@0: kRect_ClipType, michael@0: kComplex_ClipType michael@0: }; michael@0: /** Returns a description of the total clip; may be cheaper than michael@0: getting the clip and querying it directly. michael@0: */ michael@0: virtual ClipType getClipType() const; michael@0: #endif michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP michael@0: /** DEPRECATED -- need to move this guy to private/friend michael@0: * Return the current device clip (concatenation of all clip calls). michael@0: * This does not account for the translate in any of the devices. michael@0: * @return the current device clip (concatenation of all clip calls). michael@0: */ michael@0: const SkRegion& getTotalClip() const; michael@0: #endif michael@0: michael@0: /** Return the clip stack. The clip stack stores all the individual michael@0: * clips organized by the save/restore frame in which they were michael@0: * added. michael@0: * @return the current clip stack ("list" of individual clip elements) michael@0: */ michael@0: const SkClipStack* getClipStack() const { michael@0: return &fClipStack; michael@0: } michael@0: michael@0: class ClipVisitor { michael@0: public: michael@0: virtual ~ClipVisitor(); michael@0: virtual void clipRect(const SkRect&, SkRegion::Op, bool antialias) = 0; michael@0: virtual void clipRRect(const SkRRect&, SkRegion::Op, bool antialias) = 0; michael@0: virtual void clipPath(const SkPath&, SkRegion::Op, bool antialias) = 0; michael@0: }; michael@0: michael@0: /** michael@0: * Replays the clip operations, back to front, that have been applied to michael@0: * the canvas, calling the appropriate method on the visitor for each michael@0: * clip. All clips have already been transformed into device space. michael@0: */ michael@0: void replayClips(ClipVisitor*) const; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** After calling saveLayer(), there can be any number of devices that make michael@0: up the top-most drawing area. LayerIter can be used to iterate through michael@0: those devices. Note that the iterator is only valid until the next API michael@0: call made on the canvas. Ownership of all pointers in the iterator stays michael@0: with the canvas, so none of them should be modified or deleted. michael@0: */ michael@0: class SK_API LayerIter /*: SkNoncopyable*/ { michael@0: public: michael@0: /** Initialize iterator with canvas, and set values for 1st device */ michael@0: LayerIter(SkCanvas*, bool skipEmptyClips); michael@0: ~LayerIter(); michael@0: michael@0: /** Return true if the iterator is done */ michael@0: bool done() const { return fDone; } michael@0: /** Cycle to the next device */ michael@0: void next(); michael@0: michael@0: // These reflect the current device in the iterator michael@0: michael@0: SkBaseDevice* device() const; michael@0: const SkMatrix& matrix() const; michael@0: const SkRegion& clip() const; michael@0: const SkPaint& paint() const; michael@0: int x() const; michael@0: int y() const; michael@0: michael@0: private: michael@0: // used to embed the SkDrawIter object directly in our instance, w/o michael@0: // having to expose that class def to the public. There is an assert michael@0: // in our constructor to ensure that fStorage is large enough michael@0: // (though needs to be a compile-time-assert!). We use intptr_t to work michael@0: // safely with 32 and 64 bit machines (to ensure the storage is enough) michael@0: intptr_t fStorage[32]; michael@0: class SkDrawIter* fImpl; // this points at fStorage michael@0: SkPaint fDefaultPaint; michael@0: bool fDone; michael@0: }; michael@0: michael@0: // don't call michael@0: const SkRegion& internal_private_getTotalClip() const; michael@0: // don't call michael@0: void internal_private_getTotalClipAsPath(SkPath*) const; michael@0: // don't call michael@0: GrRenderTarget* internal_private_accessTopLayerRenderTarget(); michael@0: michael@0: protected: michael@0: // default impl defers to getDevice()->newSurface(info) michael@0: virtual SkSurface* onNewSurface(const SkImageInfo&); michael@0: michael@0: // default impl defers to its device michael@0: virtual const void* onPeekPixels(SkImageInfo*, size_t* rowBytes); michael@0: virtual void* onAccessTopLayerPixels(SkImageInfo*, size_t* rowBytes); michael@0: michael@0: // Subclass save/restore notifiers. michael@0: // Overriders should call the corresponding INHERITED method up the inheritance chain. michael@0: // willSaveLayer()'s return value may suppress full layer allocation. michael@0: enum SaveLayerStrategy { michael@0: kFullLayer_SaveLayerStrategy, michael@0: kNoLayer_SaveLayerStrategy michael@0: }; michael@0: virtual void willSave(SaveFlags); michael@0: virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags); michael@0: virtual void willRestore(); michael@0: michael@0: virtual void didTranslate(SkScalar, SkScalar); michael@0: virtual void didScale(SkScalar, SkScalar); michael@0: virtual void didRotate(SkScalar); michael@0: virtual void didSkew(SkScalar, SkScalar); michael@0: virtual void didConcat(const SkMatrix&); michael@0: virtual void didSetMatrix(const SkMatrix&); michael@0: michael@0: virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&); michael@0: michael@0: enum ClipEdgeStyle { michael@0: kHard_ClipEdgeStyle, michael@0: kSoft_ClipEdgeStyle michael@0: }; michael@0: michael@0: virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle); michael@0: virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle); michael@0: virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle); michael@0: virtual void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op); michael@0: michael@0: // Returns the canvas to be used by DrawIter. Default implementation michael@0: // returns this. Subclasses that encapsulate an indirect canvas may michael@0: // need to overload this method. The impl must keep track of this, as it michael@0: // is not released or deleted by the caller. michael@0: virtual SkCanvas* canvasForDrawIter(); michael@0: michael@0: // Clip rectangle bounds. Called internally by saveLayer. michael@0: // returns false if the entire rectangle is entirely clipped out michael@0: // If non-NULL, The imageFilter parameter will be used to expand the clip michael@0: // and offscreen bounds for any margin required by the filter DAG. michael@0: bool clipRectBounds(const SkRect* bounds, SaveFlags flags, michael@0: SkIRect* intersection, michael@0: const SkImageFilter* imageFilter = NULL); michael@0: michael@0: // Called by child classes that override clipPath and clipRRect to only michael@0: // track fast conservative clip bounds, rather than exact clips. michael@0: void updateClipConservativelyUsingBounds(const SkRect&, SkRegion::Op, michael@0: bool inverseFilled); michael@0: michael@0: // notify our surface (if we have one) that we are about to draw, so it michael@0: // can perform copy-on-write or invalidate any cached images michael@0: void predrawNotify(); michael@0: michael@0: virtual void onPushCull(const SkRect& cullRect); michael@0: virtual void onPopCull(); michael@0: michael@0: private: michael@0: class MCRec; michael@0: michael@0: SkClipStack fClipStack; michael@0: SkDeque fMCStack; michael@0: // points to top of stack michael@0: MCRec* fMCRec; michael@0: // the first N recs that can fit here mean we won't call malloc michael@0: uint32_t fMCRecStorage[32]; michael@0: michael@0: SkBounder* fBounder; michael@0: int fSaveLayerCount; // number of successful saveLayer calls michael@0: int fCullCount; // number of active culls michael@0: michael@0: SkMetaData* fMetaData; michael@0: michael@0: SkSurface_Base* fSurfaceBase; michael@0: SkSurface_Base* getSurfaceBase() const { return fSurfaceBase; } michael@0: void setSurfaceBase(SkSurface_Base* sb) { michael@0: fSurfaceBase = sb; michael@0: } michael@0: friend class SkSurface_Base; michael@0: friend class SkSurface_Gpu; michael@0: michael@0: bool fDeviceCMDirty; // cleared by updateDeviceCMCache() michael@0: void updateDeviceCMCache(); michael@0: michael@0: friend class SkDrawIter; // needs setupDrawForLayerDevice() michael@0: friend class AutoDrawLooper; michael@0: friend class SkLua; // needs top layer size and offset michael@0: friend class SkDeferredDevice; // needs getTopDevice() michael@0: michael@0: SkBaseDevice* createLayerDevice(const SkImageInfo&); michael@0: michael@0: SkBaseDevice* init(SkBaseDevice*); michael@0: michael@0: /** michael@0: * DEPRECATED michael@0: * michael@0: * Specify a device for this canvas to draw into. If it is not null, its michael@0: * reference count is incremented. If the canvas was already holding a michael@0: * device, its reference count is decremented. The new device is returned. michael@0: */ michael@0: SkBaseDevice* setRootDevice(SkBaseDevice* device); michael@0: michael@0: /** michael@0: * Gets the size/origin of the top level layer in global canvas coordinates. We don't want this michael@0: * to be public because it exposes decisions about layer sizes that are internal to the canvas. michael@0: */ michael@0: SkISize getTopLayerSize() const; michael@0: SkIPoint getTopLayerOrigin() const; michael@0: michael@0: // internal methods are not virtual, so they can safely be called by other michael@0: // canvas apis, without confusing subclasses (like SkPictureRecording) michael@0: void internalDrawBitmap(const SkBitmap&, const SkMatrix& m, const SkPaint* paint); michael@0: void internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, michael@0: const SkRect& dst, const SkPaint* paint, michael@0: DrawBitmapRectFlags flags); michael@0: void internalDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, michael@0: const SkRect& dst, const SkPaint* paint); michael@0: void internalDrawPaint(const SkPaint& paint); michael@0: int internalSaveLayer(const SkRect* bounds, const SkPaint* paint, michael@0: SaveFlags, bool justForImageFilter, SaveLayerStrategy strategy); michael@0: void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*); michael@0: michael@0: // shared by save() and saveLayer() michael@0: int internalSave(SaveFlags flags); michael@0: void internalRestore(); michael@0: static void DrawRect(const SkDraw& draw, const SkPaint& paint, michael@0: const SkRect& r, SkScalar textSize); michael@0: static void DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, michael@0: const char text[], size_t byteLength, michael@0: SkScalar x, SkScalar y); michael@0: michael@0: /* These maintain a cache of the clip bounds in local coordinates, michael@0: (converted to 2s-compliment if floats are slow). michael@0: */ michael@0: mutable SkRect fCachedLocalClipBounds; michael@0: mutable bool fCachedLocalClipBoundsDirty; michael@0: bool fAllowSoftClip; michael@0: bool fAllowSimplifyClip; michael@0: michael@0: const SkRect& getLocalClipBounds() const { michael@0: if (fCachedLocalClipBoundsDirty) { michael@0: if (!this->getClipBounds(&fCachedLocalClipBounds)) { michael@0: fCachedLocalClipBounds.setEmpty(); michael@0: } michael@0: fCachedLocalClipBoundsDirty = false; michael@0: } michael@0: return fCachedLocalClipBounds; michael@0: } michael@0: michael@0: class AutoValidateClip : ::SkNoncopyable { michael@0: public: michael@0: explicit AutoValidateClip(SkCanvas* canvas) : fCanvas(canvas) { michael@0: fCanvas->validateClip(); michael@0: } michael@0: ~AutoValidateClip() { fCanvas->validateClip(); } michael@0: michael@0: private: michael@0: const SkCanvas* fCanvas; michael@0: }; michael@0: michael@0: #ifdef SK_DEBUG michael@0: void validateClip() const; michael@0: #else michael@0: void validateClip() const {} michael@0: #endif michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: /** Stack helper class to automatically call restoreToCount() on the canvas michael@0: when this object goes out of scope. Use this to guarantee that the canvas michael@0: is restored to a known state. michael@0: */ michael@0: class SkAutoCanvasRestore : SkNoncopyable { michael@0: public: michael@0: SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas), fSaveCount(0) { michael@0: if (fCanvas) { michael@0: fSaveCount = canvas->getSaveCount(); michael@0: if (doSave) { michael@0: canvas->save(); michael@0: } michael@0: } michael@0: } michael@0: ~SkAutoCanvasRestore() { michael@0: if (fCanvas) { michael@0: fCanvas->restoreToCount(fSaveCount); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Perform the restore now, instead of waiting for the destructor. Will michael@0: * only do this once. michael@0: */ michael@0: void restore() { michael@0: if (fCanvas) { michael@0: fCanvas->restoreToCount(fSaveCount); michael@0: fCanvas = NULL; michael@0: } michael@0: } michael@0: michael@0: private: michael@0: SkCanvas* fCanvas; michael@0: int fSaveCount; michael@0: }; michael@0: #define SkAutoCanvasRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoCanvasRestore) michael@0: michael@0: /** Stack helper class to automatically open and close a comment block michael@0: */ michael@0: class SkAutoCommentBlock : SkNoncopyable { michael@0: public: michael@0: SkAutoCommentBlock(SkCanvas* canvas, const char* description) { michael@0: fCanvas = canvas; michael@0: if (NULL != fCanvas) { michael@0: fCanvas->beginCommentGroup(description); michael@0: } michael@0: } michael@0: michael@0: ~SkAutoCommentBlock() { michael@0: if (NULL != fCanvas) { michael@0: fCanvas->endCommentGroup(); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: SkCanvas* fCanvas; michael@0: }; michael@0: #define SkAutoCommentBlock(...) SK_REQUIRE_LOCAL_VAR(SkAutoCommentBlock) michael@0: michael@0: /** michael@0: * If the caller wants read-only access to the pixels in a canvas, it can just michael@0: * call canvas->peekPixels(), since that is the fastest way to "peek" at the michael@0: * pixels on a raster-backed canvas. michael@0: * michael@0: * If the canvas has pixels, but they are not readily available to the CPU michael@0: * (e.g. gpu-backed), then peekPixels() will fail, but readPixels() will michael@0: * succeed (though be slower, since it will return a copy of the pixels). michael@0: * michael@0: * SkAutoROCanvasPixels encapsulates these two techniques, trying first to call michael@0: * peekPixels() (for performance), but if that fails, calling readPixels() and michael@0: * storing the copy locally. michael@0: * michael@0: * The caller must respect the restrictions associated with peekPixels(), since michael@0: * that may have been called: The returned information is invalidated if... michael@0: * - any API is called on the canvas (or its parent surface if present) michael@0: * - the canvas goes out of scope michael@0: */ michael@0: class SkAutoROCanvasPixels : SkNoncopyable { michael@0: public: michael@0: SkAutoROCanvasPixels(SkCanvas* canvas); michael@0: michael@0: // returns NULL on failure michael@0: const void* addr() const { return fAddr; } michael@0: michael@0: // undefined if addr() == NULL michael@0: size_t rowBytes() const { return fRowBytes; } michael@0: michael@0: // undefined if addr() == NULL michael@0: const SkImageInfo& info() const { return fInfo; } michael@0: michael@0: // helper that, if returns true, installs the pixels into the bitmap. Note michael@0: // that the bitmap may reference the address returned by peekPixels(), so michael@0: // the caller must respect the restrictions associated with peekPixels(). michael@0: bool asROBitmap(SkBitmap*) const; michael@0: michael@0: private: michael@0: SkBitmap fBitmap; // used if peekPixels() fails michael@0: const void* fAddr; // NULL on failure michael@0: SkImageInfo fInfo; michael@0: size_t fRowBytes; michael@0: }; michael@0: michael@0: #endif