From b7da7239f73554abebc579a1525e1f4993fee8d8 Mon Sep 17 00:00:00 2001 From: Cary Clark Date: Fri, 1 Sep 2017 13:49:54 -0400 Subject: [PATCH] generated SkCanvas.h SkCanvas.h generated from docs/SkCanvas.bmh using bookmaker. Also added corrections to SkPaint.h, and generated SkPath.h. Once these are functionally correct (e.g., they don't break anything) I plan to check them in -- feel free to continue to review them before and after the check in event. R=brianosman@google.com TBR=reed@google.com Bug: skia:6898 Change-Id: I6d01e9eee422304e5ab871b3870a7ed710efd645 Reviewed-on: https://skia-review.googlesource.com/30460 Commit-Queue: Cary Clark Reviewed-by: Cary Clark Reviewed-by: Yuqian Li --- include/core/SkCanvas.h | 2474 ++++++++++++++++++++++++++++----------- include/core/SkPaint.h | 101 +- include/core/SkPath.h | 1724 +++++++++++++++++---------- 3 files changed, 2931 insertions(+), 1368 deletions(-) diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index e856eebcf4..09d2ed5bb0 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -42,19 +42,26 @@ class SkTextBlob; class SkVertices; /** \class SkCanvas + SkCanvas provides an interface for drawing, and how the drawing is clipped and transformed. + SkCanvas contains a stack of SkMatrix and clip values. - A Canvas encapsulates all of the state about drawing into a device (bitmap). - This includes a reference to the device itself, and a stack of matrix/clip - values. For any given draw call (e.g. drawRect), the geometry of the object - being drawn is transformed by the concatenation of all the matrices in the - stack. The transformed geometry is clipped by the intersection of all of - the clips in the stack. + SkCanvas and SkPaint together provide the state to draw into SkSurface or SkBaseDevice. + Each SkCanvas draw call transforms the geometry of the object by the concatenation of all + SkMatrix values in the stack. The transformed geometry is clipped by the intersection + of all of clip values in the stack. The SkCanvas draw calls use SkPaint to supply drawing + state such as color, SkTypeface, text size, stroke width, SkShader and so on. - While the Canvas holds the state of the drawing device, the state (style) - of the object being drawn is held by the Paint, which is provided as a - parameter to each of the draw() methods. The Paint holds attributes such as - color, typeface, textSize, strokeWidth, shader (e.g. gradients, patterns), - etc. + To draw to a pixel-based destination, create raster surface or GPU surface. + Request SkCanvas from SkSurface to obtain the interface to draw. + SkCanvas generated by raster surface draws to memory visible to the CPU. + SkCanvas generated by GPU surface uses Vulkan or OpenGL to draw to the GPU. + + To draw to a document, obtain SkCanvas from svg canvas, document pdf, or SkPictureRecorder. + SkDocument based SkCanvas and other SkCanvas Subclasses reference SkBaseDevice describing the + destination. + + SkCanvas can be constructed to draw to SkBitmap without first creating raster surface. + This approach may be deprecated in the future. */ class SK_API SkCanvas : SkNoncopyable { enum PrivateSaveLayerFlags { @@ -62,274 +69,468 @@ class SK_API SkCanvas : SkNoncopyable { }; public: - /** - * Attempt to allocate raster canvas, matching the ImageInfo, that will draw directly into the - * specified pixels. To access the pixels after drawing to them, the caller should call - * flush() or call peekPixels(...). - * - * On failure, return NULL. This can fail for several reasons: - * 1. invalid ImageInfo (e.g. negative dimensions) - * 2. unsupported ImageInfo for a canvas - * - kUnknown_SkColorType, kIndex_8_SkColorType - * - kUnknown_SkAlphaType - * - this list is not complete, so others may also be unsupported - * - * Note: it is valid to request a supported ImageInfo, but with zero - * dimensions. - */ + + /** Allocates raster SkCanvas that will draw directly into pixels. + To access pixels after drawing, call flush() or peekPixels(). + + SkCanvas is returned if all parameters are valid. + Valid parameters include: + info dimensions are zero or positive; + info contains SkColorType and SkAlphaType supported by raster surface; + pixels is not nullptr; + rowBytes is zero or large enough to contain info width pixels of SkColorType. + + Pass zero for rowBytes to compute rowBytes from info width and size of pixel. + If rowBytes is greater than zero, it must be equal to or greater than + info width times bytes required for SkColorType. + + Pixel buffer size should be info height times computed rowBytes. + + @param info width, height, SkColorType, SkAlphaType, color space, of raster surface; + width, or height, or both, may be zero + @param pixels pointer to destination pixels buffer + @param rowBytes interval from one SkSurface row to the next, or zero + @return SkCanvas if all parameters are valid; otherwise, nullptr + */ static std::unique_ptr MakeRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes); + /** Allocates raster SkCanvas specified by inline image specification. Subsequent SkCanvas + calls draw into pixels. + SkColorType is set to kN32_SkColorType. + SkAlphaType is set to kPremul_SkAlphaType. + To access pixels after drawing, call flush() or peekPixels(). + + SkCanvas is returned if all parameters are valid. + Valid parameters include: + width and height are zero or positive; + pixels is not nullptr; + rowBytes is zero or large enough to contain width pixels of kN32_SkColorType. + + Pass zero for rowBytes to compute rowBytes from width and size of pixel. + If rowBytes is greater than zero, it must be equal to or greater than + width times bytes required for SkColorType. + + Pixel buffer size should be height times rowBytes. + + @param width pixel column count on raster surface created; must be zero or greater + @param height pixel row count on raster surface created.; must be zero or greater + @param pixels pointer to destination pixels buffer; buffer size should be height + times rowBytes + @param rowBytes interval from one SkSurface row to the next, or zero + @return SkCanvas if all parameters are valid; otherwise, nullptr + */ static std::unique_ptr MakeRasterDirectN32(int width, int height, SkPMColor* pixels, size_t rowBytes) { return MakeRasterDirect(SkImageInfo::MakeN32Premul(width, height), pixels, rowBytes); } - /** - * Creates an empty canvas with no backing device/pixels, and zero - * dimensions. - */ + /** Creates an empty canvas with no backing device or pixels, with + a width and height of zero. + + @return empty canvas + */ SkCanvas(); - /** - * Creates a canvas of the specified dimensions, but explicitly not backed - * by any device/pixels. Typically this use used by subclasses who handle - * the draw calls in some other way. - */ + /** Creates SkCanvas of the specified dimensions without a SkSurface. + Used by Subclasses with custom implementations for draw methods. + + If props equals nullptr, SkSurfaceProps are created with SkSurfaceProps::InitType settings, + which choose the pixel striping direction and order. Since a platform may dynamically + change its direction when the device is rotated, and since a platform may have + multiple monitors with different characteristics, it's best not to rely on this + legacy behavior. + + @param width zero or greater + @param height zero or greater + @param props LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkCanvas placeholder with dimensions + */ SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr); - /** Construct a canvas with the specified device to draw into. + /** Construct a canvas that draws into device. + Used by child classes of SkCanvas. - @param device Specifies a device for the canvas to draw into. + @param device specifies a device for the canvas to draw into + @return SkCanvas that can be used to draw into device */ explicit SkCanvas(SkBaseDevice* device); - /** Construct a canvas with the specified bitmap to draw into. - @param bitmap Specifies a bitmap for the canvas to draw into. Its - structure are copied to the canvas. + /** Construct a canvas that draws into bitmap. + Sets SkSurfaceProps::kLegacyFontHost_InitType in constructed SkSurface. + + SkBitmap is copied so that subsequently editing bitmap will not affect + constructed SkCanvas. + + May be deprecated in the future. + + @param bitmap width, height, SkColorType, SkAlphaType, and pixel + storage of raster surface + @return SkCanvas that can be used to draw into bitmap */ explicit SkCanvas(const SkBitmap& bitmap); #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK enum class ColorBehavior { - kLegacy, + kLegacy, //!< Is a placeholder to allow specialized constructor; has no meaning. }; - /** - * Android framework only constructor. - * Allows the creation of a legacy SkCanvas even though the |bitmap| - * and its pixel ref may have an SkColorSpace. - */ + /** Android framework only. + + @param bitmap specifies a bitmap for the canvas to draw into + @param behavior specializes this constructor; value is unused + @return SkCanvas that can be used to draw into bitmap + */ SkCanvas(const SkBitmap& bitmap, ColorBehavior behavior); #endif - /** Construct a canvas with the specified bitmap to draw into. - @param bitmap Specifies a bitmap for the canvas to draw into. Its - structure are copied to the canvas. - @param props New canvas surface properties. + /** Construct a canvas that draws into bitmap. + Use props to match the device characteristics, like LCD striping. + + bitmap is copied so that subsequently editing bitmap will not affect + constructed SkCanvas. + + @param bitmap width, height, SkColorType, SkAlphaType, + and pixel storage of raster surface + @param props order and orientation of RGB striping; and whether to use + device independent fonts + @return SkCanvas that can be used to draw into bitmap */ SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props); + /** Draw saved SkCanvas::_anonymous, if any. + Free up resources used by SkCanvas. + */ virtual ~SkCanvas(); + /** Returns storage to associate additional data with the canvas. + The storage is freed when SkCanvas is deleted. + + @return storage that can be read from and written to + */ SkMetaData& getMetaData(); - /** - * Return ImageInfo for this canvas. If the canvas is not backed by pixels - * (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType. - */ + /** Returns SkImageInfo for SkCanvas. If SkCanvas is not associated with raster surface or + GPU surface, returned SkColorType is set to kUnknown_SkColorType. + + @return dimensions and SkColorType of SkCanvas + */ SkImageInfo imageInfo() const; - /** - * If the canvas is backed by pixels (cpu or gpu), this writes a copy of the SurfaceProps - * for the canvas to the location supplied by the caller, and returns true. Otherwise, - * return false and leave the supplied props unchanged. - */ + /** If SkCanvas is associated with raster surface or + GPU surface, copies SkSurfaceProps and returns true. Otherwise, + return false and leave props unchanged. + + @param props storage for writable SkSurfaceProps + @return true if SkSurfaceProps was copied + */ bool getProps(SkSurfaceProps* props) const; - /////////////////////////////////////////////////////////////////////////// - - /** - * Trigger the immediate execution of all pending draw operations. For the GPU - * backend this will resolve all rendering to the GPU surface backing the - * SkSurface that owns this canvas. - */ + /** Triggers the immediate execution of all pending draw operations. + If SkCanvas is associated with GPU surface, resolves all pending GPU operations. + */ void flush(); - /** - * Gets the size of the base or root layer in global canvas coordinates. The - * origin of the base layer is always (0,0). The current drawable area may be - * smaller (due to clipping or saveLayer). - */ + /** Gets the size of the base or root SkCanvas::_anonymous in global canvas coordinates. The + origin of the base SkCanvas::_anonymous is always (0,0). The area available for drawing may be + smaller (due to clipping or saveLayer). + + @return integral width and height of base SkCanvas::_anonymous + */ virtual SkISize getBaseLayerSize() const; - /** - * Create a new surface matching the specified info, one that attempts to - * be maximally compatible when used with this canvas. If there is no matching Surface type, - * NULL is returned. - * - * If surfaceprops is specified, those are passed to the new surface, otherwise the new surface - * inherits the properties of the surface that owns this canvas. If this canvas has no parent - * surface, then the new surface is created with default properties. - */ + /** Creates SkSurface matching info and props, and associates it with SkCanvas. + Returns nullptr if no match found. + + If props is nullptr, matches SkSurfaceProps in SkCanvas. If props is nullptr and SkCanvas + does not have SkSurfaceProps, creates SkSurface with default SkSurfaceProps. + + @param info width, height, SkColorType, SkAlphaType, and color space + @param props SkSurfaceProps to match; may be nullptr to match SkCanvas + @return SkSurface matching info and props, or nullptr if no match is available + */ sk_sp makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr); - /** - * Return the GPU context of the device that is associated with the canvas. - * For a canvas with non-GPU device, NULL is returned. - */ + /** Returns GPU context of the GPU surface associated with SkCanvas. + + @return GPU context, if available; nullptr otherwise + */ virtual GrContext* getGrContext(); - /////////////////////////////////////////////////////////////////////////// + /** Returns the pixel base address, SkImageInfo, rowBytes, and origin if the pixels + can be read directly. The returned address is only valid + while SkCanvas is in scope and unchanged. Any SkCanvas call or SkSurface call + may invalidate the returned address and other returned values. - /** - * If the canvas has writable pixels in its top layer (and is not recording to a picture - * or other non-raster target) and has direct access to its pixels (i.e. they are in - * local RAM) return the address of those pixels, and if not null, - * return the ImageInfo, rowBytes and origin. The returned address is only valid - * while the canvas object is in scope and unchanged. Any API calls made on - * canvas (or its parent surface if any) will invalidate the - * returned address (and associated information). - * - * On failure, returns NULL and the info, rowBytes, and origin parameters are ignored. - */ + If pixels are inaccessible, info, rowBytes, and origin are unchanged. + + @param info storage for writable pixels' SkImageInfo; may be nullptr + @param rowBytes storage for writable pixels' row bytes; may be nullptr + @param origin storage for SkCanvas top SkCanvas::_anonymous origin, its top left corner; + may be nullptr + @return address of pixels, or nullptr if inaccessible + */ void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr); + /** Returns custom context that tracks the SkMatrix and clip. + + Use SkRasterHandleAllocator to blend Skia drawing with custom drawing, typically performed + by the host platform's user interface. The custom context returned is generated by + SkRasterHandleAllocator::MakeCanvas, which creates a custom canvas with raster storage for + the drawing destination. + + @return context of custom allocation + */ SkRasterHandleAllocator::Handle accessTopRasterHandle() const; - /** - * If the canvas has readable pixels in its base layer (and is not recording to a picture - * or other non-raster target) and has direct access to its pixels (i.e. they are in - * local RAM) return true, and if not null, return in the pixmap parameter information about - * the pixels. The pixmap's pixel address is only valid - * while the canvas object is in scope and unchanged. Any API calls made on - * canvas (or its parent surface if any) will invalidate the pixel address - * (and associated information). - * - * On failure, returns false and the pixmap parameter will be ignored. - */ + /** Returns true if SkCanvas has direct access to its pixels. + + Pixels are readable when SkBaseDevice is raster. Pixels are not readable when SkCanvas + is returned from GPU surface, returned by SkDocument::beginPage, returned by + SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility class + like SkDumpCanvas. + + pixmap is valid only while SkCanvas is in scope and unchanged. Any + SkCanvas or SkSurface call may invalidate the pixmap values. + + @param pixmap storage for SkCanvas pixel state if SkCanvas pixels are readable; + otherwise, ignored + @return true if SkCanvas has direct access to pixels + */ bool peekPixels(SkPixmap* pixmap); - /** - * Copy the pixels from the base-layer into the specified buffer (pixels + rowBytes), - * converting them into the requested format (SkImageInfo). The base-layer pixels are read - * starting at the specified (srcX,srcY) location in the coordinate system of the base-layer. - * - * The specified ImageInfo and (srcX,srcY) offset specifies a source rectangle - * - * srcR.setXYWH(srcX, srcY, dstInfo.width(), dstInfo.height()); - * - * srcR is intersected with the bounds of the base-layer. If this intersection is not empty, - * then we have two sets of pixels (of equal size). Replace the dst pixels with the - * corresponding src pixels, performing any colortype/alphatype transformations needed - * (in the case where the src and dst have different colortypes or alphatypes). - * - * This call can fail, returning false, for several reasons: - * - If srcR does not intersect the base-layer bounds. - * - If the requested colortype/alphatype cannot be converted from the base-layer's types. - * - If this canvas is not backed by pixels (e.g. picture or PDF) - */ + /** Copies rectangle of pixels from SkCanvas into dstPixels. SkMatrix and clip are + ignored. Source rectangle corners are (srcX, srcY) and + + @param dstInfo width, height, SkColorType, and SkAlphaType of dstPixels + @param dstPixels storage for pixels; dstInfo.height() times dstRowBytes, or larger + @param dstRowBytes size of one destination row; dstInfo.width() times pixel size, or larger + @param srcX offset into readable pixels in x; may be negative + @param srcY offset into readable pixels in y; may be negative + @return true if pixels were copied + */ bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY); + + /** Copies rectangle of pixels from SkCanvas into pixmap. SkMatrix and clip are + ignored. Source rectangle corners are (srcX, srcY) and + + @param pixmap storage for pixels copied from SkCanvas + @param srcX offset into readable pixels in x; may be negative + @param srcY offset into readable pixels in y; may be negative + @return true if pixels were copied + */ bool readPixels(const SkPixmap& pixmap, int srcX, int srcY); + + /** Copies rectangle of pixels from SkCanvas into bitmap. SkMatrix and clip are + ignored. Source rectangle corners are (srcX, srcY) and + + @param bitmap storage for pixels copied from SkCanvas + @param srcX offset into readable pixels in x; may be negative + @param srcY offset into readable pixels in y; may be negative + @return true if pixels were copied + */ bool readPixels(const SkBitmap& bitmap, int srcX, int srcY); - /** - * This method affects the pixels in the base-layer, and operates in pixel coordinates, - * ignoring the matrix and clip. - * - * The specified ImageInfo and (x,y) offset specifies a rectangle: target. - * - * target.setXYWH(x, y, info.width(), info.height()); - * - * Target is intersected with the bounds of the base-layer. If this intersection is not empty, - * then we have two sets of pixels (of equal size), the "src" specified by info+pixels+rowBytes - * and the "dst" by the canvas' backend. Replace the dst pixels with the corresponding src - * pixels, performing any colortype/alphatype transformations needed (in the case where the - * src and dst have different colortypes or alphatypes). - * - * This call can fail, returning false, for several reasons: - * - If the src colortype/alphatype cannot be converted to the canvas' types - * - If this canvas is not backed by pixels (e.g. picture or PDF) - */ + /** Copies rectangle from pixels to SkCanvas. SkMatrix and clip are ignored. + Source rectangle corners are (0, 0) and (info.width(), info.height()). + Destination rectangle corners are (x, y) and + + @param info width, height, SkColorType, and SkAlphaType of pixels + @param pixels pixels to copy, of size info.height() times rowBytes, or larger + @param rowBytes size of one pixels row; info.width() times pixel size, or larger + @param x offset into SkCanvas writable pixels in x; may be negative + @param y offset into SkCanvas writable pixels in y; may be negative + @return true if pixels were written to SkCanvas + */ bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y); - /** - * Helper for calling writePixels(info, ...) by passing its pixels and rowbytes. If the bitmap - * is just wrapping a texture, returns false and does nothing. - */ + /** Copies rectangle from pixels to SkCanvas. SkMatrix and clip are ignored. + Source rectangle corners are (0, 0) and + + @param bitmap contains pixels copied to SkCanvas + @param x offset into SkCanvas writable pixels in x; may be negative + @param y offset into SkCanvas writable pixels in y; may be negative + @return true if pixels were written to SkCanvas + */ bool writePixels(const SkBitmap& bitmap, int x, int y); - /////////////////////////////////////////////////////////////////////////// + /** Saves SkMatrix, clip, and SkDrawFilter (Draw_Filter deprecated on most platforms). + Calling restore() discards changes to SkMatrix, clip, and SkDrawFilter, + restoring the SkMatrix, clip, and SkDrawFilter to their state when save() was called. - /** This call saves the current matrix, clip, and drawFilter, and pushes a - copy onto a private stack. Subsequent calls to translate, scale, - rotate, skew, concat or clipRect, clipPath, and setDrawFilter all - operate on this copy. - When the balancing call to restore() is made, the previous matrix, clip, - and drawFilter are restored. + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix(), + and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), clipPath(), clipRegion(). - @return The value to pass to restoreToCount() to balance this save() + Saved SkCanvas state is put on a stack; multiple calls to save() should be balance + by an equal number of calls to restore(). + + Call restoreToCount() with result to restore this and subsequent saves. + + @return depth of saved stack */ int save(); - /** This behaves the same as save(), but in addition it allocates an - offscreen bitmap. All drawing calls are directed there, and only when - the balancing call to restore() is made is that offscreen transfered to - the canvas (or the previous layer). - @param bounds (may be null) This rect, if non-null, is used as a hint to - limit the size of the offscreen, and thus drawing may be - clipped to it, though that clipping is not guaranteed to - happen. If exact clipping is desired, use clipRect(). - @param paint (may be null) This is copied, and is applied to the - offscreen when restore() is called - @return The value to pass to restoreToCount() to balance this save() + /** Saves SkMatrix, clip, and SkDrawFilter (Draw_Filter deprecated on most platforms), + and allocates a SkBitmap for subsequent drawing. + Calling restore() discards changes to SkMatrix, clip, and SkDrawFilter, + and draws the SkBitmap. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define the SkBitmap size. To clip drawing to + a specific rectangle, use clipRect(). + + Optional SkPaint paint applies color alpha, SkColorFilter, SkImageFilter, and + SkBlendMode when restore() is called. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param bounds hint to limit the size of the SkCanvas::_anonymous; may be nullptr + @param paint graphics state for SkCanvas::_anonymous; may be nullptr + @return depth of saved stack */ int saveLayer(const SkRect* bounds, const SkPaint* paint); + + /** Saves SkMatrix, clip, and SkDrawFilter (Draw_Filter deprecated on most platforms), + and allocates a SkBitmap for subsequent drawing. + Calling restore() discards changes to SkMatrix, clip, and SkDrawFilter, + and draws the SkBitmap. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define the SkCanvas::_anonymous size. To clip drawing to + a specific rectangle, use clipRect(). + + Optional SkPaint paint applies color alpha, SkColorFilter, SkImageFilter, and + SkBlendMode when restore() is called. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param bounds hint to limit the size of SkCanvas::_anonymous; may be nullptr + @param paint graphics state for SkCanvas::_anonymous; may be nullptr + @return depth of saved stack + */ int saveLayer(const SkRect& bounds, const SkPaint* paint) { return this->saveLayer(&bounds, paint); } - /** - * Temporary name. - * Will allow any requests for LCD text to be respected, so the caller must be careful to - * only draw on top of opaque sections of the layer to get good results. - */ + /** Saves SkMatrix, clip, and SkDrawFilter (Draw_Filter deprecated on most platforms), + and allocates a SkBitmap for subsequent drawing. + lcd text is preserved when the SkCanvas::_anonymous is drawn to the prior SkCanvas::_anonymous. + + Calling restore() discards changes to SkMatrix, clip, and SkDrawFilter, + and draws SkCanvas::_anonymous. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define the SkCanvas::_anonymous size. To clip drawing to + a specific rectangle, use clipRect(). + + Optional SkPaint paint applies color alpha, SkColorFilter, SkImageFilter, and + SkBlendMode when restore() is called. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + Draw text on an opaque background so that lcd text blends correctly with the + prior SkCanvas::_anonymous. lcd text drawn on a background with transparency may result in + incorrect banding. + + @param bounds hint to limit the size of SkCanvas::_anonymous; may be nullptr + @param paint graphics state for SkCanvas::_anonymous; may be nullptr + @return depth of saved stack + */ int saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint); - /** This behaves the same as save(), but in addition it allocates an - offscreen bitmap. All drawing calls are directed there, and only when - the balancing call to restore() is made is that offscreen transfered to - the canvas (or the previous layer). - @param bounds (may be null) This rect, if non-null, is used as a hint to - limit the size of the offscreen, and thus drawing may be - clipped to it, though that clipping is not guaranteed to - happen. If exact clipping is desired, use clipRect(). - @param alpha This is applied to the offscreen when restore() is called. - @return The value to pass to restoreToCount() to balance this save() + /** Saves SkMatrix, clip, and SkDrawFilter (Draw_Filter deprecated on most platforms), + and allocates SkBitmap for subsequent drawing. + + Calling restore() discards changes to SkMatrix, clip, and SkDrawFilter, + and blends SkCanvas::_anonymous with alpha opacity onto prior SkCanvas::_anonymous. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define SkCanvas::_anonymous size. To clip drawing to + a specific rectangle, use clipRect(). + + alpha of zero is fully transparent, 255 is fully opaque. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param bounds hint to limit the size of SkCanvas::_anonymous; may be nullptr + @param alpha opacity of SkCanvas::_anonymous + @return depth of saved stack */ int saveLayerAlpha(const SkRect* bounds, U8CPU alpha); + /** \enum + SaveLayerFlags provides options that may be used in any combination in SaveLayerRec, + defining how _anonymous allocated by saveLayer() operates. + */ enum { - kIsOpaque_SaveLayerFlag = 1 << 0, - kPreserveLCDText_SaveLayerFlag = 1 << 1, + /** Creates _anonymous without transparency. Flag is ignored if _anonymous SkPaint contains + SkImageFilter or SkColorFilter. + */ + kIsOpaque_SaveLayerFlag = 1 << 0, - /** initialize the new layer with the contents of the previous layer */ - kInitWithPrevious_SaveLayerFlag = 1 << 2, + /** Creates _anonymous for LCD text. Flag is ignored if _anonymous SkPaint contains + SkImageFilter or SkColorFilter. + */ + kPreserveLCDText_SaveLayerFlag = 1 << 1, + + /** Initializes _anonymous with the contents of the previous _anonymous. */ + kInitWithPrevious_SaveLayerFlag = 1 << 2, #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG + /** to be deprecated: bug.skia.org/2440 */ kDontClipToLayer_Legacy_SaveLayerFlag = kDontClipToLayer_PrivateSaveLayerFlag, #endif }; + typedef uint32_t SaveLayerFlags; + /** \struct SkCanvas::SaveLayerRec + SaveLayerRec contains the state used to create the SkCanvas::_anonymous. + */ struct SaveLayerRec { + + /** Sets fBounds, fPaint, and fBackdrop to nullptr. Clears fSaveLayerFlags. + + @return empty SaveLayerRec + */ SaveLayerRec() {} + + /** Sets fBounds, fPaint, and fSaveLayerFlags; sets fBackdrop to nullptr. + + @param bounds SkCanvas::_anonymous dimensions; may be nullptr + @param paint applied to SkCanvas::_anonymous when overlaying prior SkCanvas::_anonymous; may be nullptr + @param saveLayerFlags SaveLayerRec options to modify SkCanvas::_anonymous + @return SaveLayerRec with empty backdrop + */ SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0) : fBounds(bounds) , fPaint(paint) , fSaveLayerFlags(saveLayerFlags) {} + + /** Sets fBounds, fPaint, fBackdrop, and fSaveLayerFlags. + + @param bounds SkCanvas::_anonymous dimensions; may be nullptr + @param paint applied to SkCanvas::_anonymous when overlaying prior SkCanvas::_anonymous; + may be nullptr + @param backdrop prior SkCanvas::_anonymous copied with SkImageFilter; may be nullptr + @param saveLayerFlags SaveLayerRec options to modify SkCanvas::_anonymous + @return SaveLayerRec fully specified + */ SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, SaveLayerFlags saveLayerFlags) : fBounds(bounds) @@ -338,7 +539,24 @@ public: , fSaveLayerFlags(saveLayerFlags) {} - // EXPERIMENTAL: not ready for general use. + /** EXPERIMENTAL: Not ready for general use. + Sets fBounds, fPaint, fBackdrop, fClipMask, fClipMatrix, and fSaveLayerFlags. + clipMatrix uses color alpha channel of image, transformed by clipMatrix, to clip + SkCanvas::_anonymous when drawn to SkCanvas. + + Implementation is incomplete; has no effect if SkBaseDevice is GPU-backed. + + @param bounds SkCanvas::_anonymous dimensions; may be nullptr + @param paint graphics state applied to SkCanvas::_anonymous when overlaying prior + SkCanvas::_anonymous; may be nullptr + @param backdrop prior SkCanvas::_anonymous copied with SkImageFilter; + may be nullptr + @param clipMask clip applied to SkCanvas::_anonymous; may be nullptr + @param clipMatrix matrix applied to clipMask; may be nullptr to use + identity matrix + @param saveLayerFlags SaveLayerRec options to modify SkCanvas::_anonymous + @return SaveLayerRec fully specified + */ SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, const SkImage* clipMask, const SkMatrix* clipMatrix, SaveLayerFlags saveLayerFlags) @@ -350,300 +568,525 @@ public: , fSaveLayerFlags(saveLayerFlags) {} - const SkRect* fBounds = nullptr; // optional - const SkPaint* fPaint = nullptr; // optional - const SkImageFilter* fBackdrop = nullptr; // optional - const SkImage* fClipMask = nullptr; // optional - const SkMatrix* fClipMatrix = nullptr; // optional -- only used with fClipMask - SaveLayerFlags fSaveLayerFlags = 0; + /** fBounds is used as a hint to limit the size of SkCanvas::_anonymous; may be nullptr. + fBounds suggests but does not define SkCanvas::_anonymous size. To clip drawing to + a specific rectangle, use clipRect(). + */ + const SkRect* fBounds = nullptr; + + /** fPaint modifies how SkCanvas::_anonymous overlays the prior SkCanvas::_anonymous; may be nullptr. + color alpha, SkBlendMode, SkColorFilter, SkDrawLooper, SkImageFilter, and + SkMaskFilter affect SkCanvas::_anonymous draw. + */ + const SkPaint* fPaint = nullptr; + + /** fBackdrop applies SkImageFilter to the prior SkCanvas::_anonymous when copying to the SkCanvas::_anonymous; + may be nullptr. Use kInitWithPrevious_SaveLayerFlag to copy the + prior SkCanvas::_anonymous without an SkImageFilter. + */ + const SkImageFilter* fBackdrop = nullptr; + + /** restore() clips SkCanvas::_anonymous by the color alpha channel of fClipMask when + SkCanvas::_anonymous is copied to SkBaseDevice. fClipMask may be nullptr. . + */ + const SkImage* fClipMask = nullptr; + + /** fClipMatrix transforms fClipMask before it clips SkCanvas::_anonymous. If + fClipMask describes a translucent gradient, it may be scaled and rotated + without introducing artifacts. fClipMatrix may be nullptr. + */ + const SkMatrix* fClipMatrix = nullptr; + + /** fSaveLayerFlags are used to create SkCanvas::_anonymous without transparency, + create SkCanvas::_anonymous for LCD text, and to create SkCanvas::_anonymous with the + contents of the previous SkCanvas::_anonymous. + */ + SaveLayerFlags fSaveLayerFlags = 0; + }; + /** Saves SkMatrix, clip, and SkDrawFilter (Draw_Filter deprecated on most platforms), + and allocates SkBitmap for subsequent drawing. + + Calling restore() discards changes to SkMatrix, clip, and SkDrawFilter, + and blends SkBitmap with color alpha opacity onto the prior SkCanvas::_anonymous. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SaveLayerRec contains the state used to create the SkCanvas::_anonymous. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param layerRec SkCanvas::_anonymous state + @return depth of save state stack + */ int saveLayer(const SaveLayerRec& layerRec); - /** This call balances a previous call to save(), and is used to remove all - modifications to the matrix/clip/drawFilter state since the last save - call. - It is an error to call restore() more times than save() was called. + /** Removes changes to SkMatrix, clip, and SkDrawFilter since SkCanvas state was + last saved. The state is removed from the stack. + + Does nothing if the stack is empty. */ void restore(); - /** Returns the number of matrix/clip states on the SkCanvas' private stack. - This will equal # save() calls - # restore() calls + 1. The save count on - a new canvas is 1. + /** Returns the number of saved states, each containing: SkMatrix, clip, and SkDrawFilter. + Equals the number of save() calls less the number of restore() calls plus one. + The save count of a new canvas is one. + + @return depth of save state stack */ int getSaveCount() const; - /** Efficient way to pop any calls to save() that happened after the save - count reached saveCount. It is an error for saveCount to be greater than - getSaveCount(). To pop all the way back to the initial matrix/clip context - pass saveCount == 1. - @param saveCount The number of save() levels to restore from + /** Restores state to SkMatrix, clip, and SkDrawFilter values when save(), saveLayer(), + saveLayerPreserveLCDTextRequests(), or saveLayerAlpha() returned saveCount. + + Does nothing if saveCount is greater than state stack count. + Restores state to initial values if saveCount is less than or equal to one. + + @param saveCount depth of state stack to restore */ void restoreToCount(int saveCount); - /** Preconcat the current matrix with the specified translation - @param dx The distance to translate in X - @param dy The distance to translate in Y + /** Translate SkMatrix by dx along the x-axis and dy along the y-axis. + + Mathematically, replace SkMatrix with a translation matrix + premultiplied with SkMatrix. + + This has the effect of moving the drawing by (dx, dy) before transforming + the result with SkMatrix. + + @param dx distance to translate in x + @param dy distance to translate in y */ void translate(SkScalar dx, SkScalar dy); - /** Preconcat the current matrix with the specified scale. - @param sx The amount to scale in X - @param sy The amount to scale in Y + /** Scale SkMatrix by sx on the x-axis and sy on the y-axis. + + Mathematically, replace SkMatrix with a scale matrix + premultiplied with SkMatrix. + + This has the effect of scaling the drawing by (sx, sy) before transforming + the result with SkMatrix. + + @param sx amount to scale in x + @param sy amount to scale in y */ void scale(SkScalar sx, SkScalar sy); - /** Preconcat the current matrix with the specified rotation about the origin. - @param degrees The amount to rotate, in degrees + /** Rotate SkMatrix by degrees. Positive degrees rotates clockwise. + + Mathematically, replace SkMatrix with a rotation matrix + premultiplied with SkMatrix. + + This has the effect of rotating the drawing by degrees before transforming + the result with SkMatrix. + + @param degrees amount to rotate, in degrees */ void rotate(SkScalar degrees); - /** Preconcat the current matrix with the specified rotation about a given point. - @param degrees The amount to rotate, in degrees - @param px The x coordinate of the point to rotate about. - @param py The y coordinate of the point to rotate about. + /** Rotate SkMatrix by degrees. Positive degrees rotates clockwise. + + Mathematically, replace SkMatrix with a rotation matrix + premultiplied with SkMatrix. + + This has the effect of rotating the drawing by degrees before transforming + the result with SkMatrix. + + @param degrees amount to rotate, in degrees */ void rotate(SkScalar degrees, SkScalar px, SkScalar py); - /** Preconcat the current matrix with the specified skew. - @param sx The amount to skew in X - @param sy The amount to skew in Y + /** Skew SkMatrix by sx on the x-axis and sy on the y-axis. A positive value of sx + skews the drawing right as y increases; a positive value of sy skews the drawing + down as x increases. + + Mathematically, replace SkMatrix with a skew matrix premultiplied with SkMatrix. + + This has the effect of skewing the drawing by (sx, sy) before transforming + the result with SkMatrix. + + @param sx amount to skew in x + @param sy amount to skew in y */ void skew(SkScalar sx, SkScalar sy); - /** Preconcat the current matrix with the specified matrix. - @param matrix The matrix to preconcatenate with the current matrix + /** Replace SkMatrix with matrix premultiplied with existing SkMatrix. + + This has the effect of transforming the drawn geometry by matrix, before + transforming the result with existing SkMatrix. + + @param matrix matrix to premultiply with existing SkMatrix */ void concat(const SkMatrix& matrix); - /** Replace the current matrix with a copy of the specified matrix. - @param matrix The matrix that will be copied into the current matrix. + /** Replace SkMatrix with matrix. + Unlike concat(), any prior matrix state is overwritten. + + @param matrix matrix to copy, replacing existing SkMatrix */ void setMatrix(const SkMatrix& matrix); - /** Helper for setMatrix(identity). Sets the current matrix to identity. + /** Sets SkMatrix to the identity matrix. + Any prior matrix state is overwritten. */ void resetMatrix(); - /** - * Modify the current clip with the specified rectangle. - * @param rect The rect to combine with the current clip - * @param op The region op to apply to the current clip - * @param doAntiAlias true if the clip should be antialiased - */ + /** Replace clip with the intersection or difference of clip and rect, + with an aliased or anti-aliased clip edge. rect is transformed by SkMatrix + before it is combined with clip. + + @param rect SkRect to combine with clip + @param op SkClipOp to apply to clip + @param doAntiAlias true if clip is to be anti-aliased + */ void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias); + + /** Replace clip with the intersection or difference of clip and rect. + Resulting clip is aliased; pixels are fully contained by the clip. + rect is transformed by SkMatrix before it is combined with clip. + + @param rect SkRect to combine with clip + @param op SkClipOp to apply to clip + */ void clipRect(const SkRect& rect, SkClipOp op) { this->clipRect(rect, op, false); } + + /** Replace clip with the intersection of clip and rect. + Resulting clip is aliased; pixels are fully contained by the clip. + rect is transformed by SkMatrix + before it is combined with clip. + + @param rect SkRect to combine with clip + @param doAntiAlias true if clip is to be anti-aliased + */ void clipRect(const SkRect& rect, bool doAntiAlias = false) { this->clipRect(rect, SkClipOp::kIntersect, doAntiAlias); } - /** - * Sets the max clip rectangle, which can be set by clipRect, clipRRect and - * clipPath and intersect the current clip with the specified rect. - * The max clip affects only future ops (it is not retroactive). - * We DON'T record the clip restriction in pictures. - * This is private API to be used only by Android framework. - * @param rect The maximum allowed clip in device coordinates. - * Empty rect means max clip is not enforced. - */ + /** Sets the maximum clip rectangle, which can be set by clipRect(), clipRRect() and + clipPath() and intersect the current clip with the specified rect. + The maximum clip affects only future clipping operations; it is not retroactive. + The clip restriction is not recorded in pictures. + + Pass an empty rect to disable maximum clip. + This is private API to be used only by Android framework. + + @param rect maximum allowed clip in device coordinates + */ void androidFramework_setDeviceClipRestriction(const SkIRect& rect); - /** - * Modify the current clip with the specified SkRRect. - * @param rrect The rrect to combine with the current clip - * @param op The region op to apply to the current clip - * @param doAntiAlias true if the clip should be antialiased - */ + /** Replace clip with the intersection or difference of clip and rrect, + with an aliased or anti-aliased clip edge. + rrect is transformed by SkMatrix + before it is combined with clip. + + @param rrect SkRRect to combine with clip + @param op SkClipOp to apply to clip + @param doAntiAlias true if clip is to be anti-aliased + */ void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias); + + /** Replace clip with the intersection or difference of clip and rrect. + Resulting clip is aliased; pixels are fully contained by the clip. + rrect is transformed by SkMatrix before it is combined with clip. + + @param rrect SkRRect to combine with clip + @param op SkClipOp to apply to clip + */ void clipRRect(const SkRRect& rrect, SkClipOp op) { this->clipRRect(rrect, op, false); } + + /** Replace clip with the intersection of clip and rrect, + with an aliased or anti-aliased clip edge. + rrect is transformed by SkMatrix before it is combined with clip. + + @param rrect SkRRect to combine with clip + @param doAntiAlias true if clip is to be anti-aliased + */ void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) { this->clipRRect(rrect, SkClipOp::kIntersect, doAntiAlias); } - /** - * Modify the current clip with the specified path. - * @param path The path to combine with the current clip - * @param op The region op to apply to the current clip - * @param doAntiAlias true if the clip should be antialiased - */ + /** Replace clip with the intersection or difference of clip and path, + with an aliased or anti-aliased clip edge. SkPath::FillType determines if path + describes the area inside or outside its contours; and if path contour overlaps + itself or another path contour, whether the overlaps form part of the area. + path is transformed by SkMatrix before it is combined with clip. + + @param path SkPath to combine with clip + @param op SkClipOp to apply to clip + @param doAntiAlias true if clip is to be anti-aliased + */ void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias); + + /** Replace clip with the intersection or difference of clip and path. + Resulting clip is aliased; pixels are fully contained by the clip. + SkPath::FillType determines if path + describes the area inside or outside its contours; and if path contour overlaps + itself or another path contour, whether the overlaps form part of the area. + path is transformed by SkMatrix + before it is combined with clip. + + @param path SkPath to combine with clip + @param op SkClipOp to apply to clip + */ void clipPath(const SkPath& path, SkClipOp op) { this->clipPath(path, op, false); } + + /** Replace clip with the intersection of clip and path. + Resulting clip is aliased; pixels are fully contained by the clip. + SkPath::FillType determines if path + describes the area inside or outside its contours; and if path contour overlaps + itself or another path contour, whether the overlaps form part of the area. + path is transformed by SkMatrix before it is combined with clip. + + @param path SkPath to combine with clip + @param doAntiAlias true if clip is to be anti-aliased + */ void clipPath(const SkPath& path, bool doAntiAlias = false) { this->clipPath(path, SkClipOp::kIntersect, doAntiAlias); } - /** EXPERIMENTAL -- only used for testing - Set to simplify clip stack using path ops. - */ + /** EXPERIMENTAL: Only used for testing. + Set to simplify clip stack using PathOps. + */ void setAllowSimplifyClip(bool allow) { fAllowSimplifyClip = allow; } - /** Modify the current clip with the specified region. Note that unlike - clipRect() and clipPath() which transform their arguments by the current - matrix, clipRegion() assumes its argument is already in device - coordinates, and so no transformation is performed. - @param deviceRgn The region to apply to the current clip - @param op The region op to apply to the current clip + /** Replace clip with the intersection or difference of clip and SkRegion deviceRgn. + Resulting clip is aliased; pixels are fully contained by the clip. + deviceRgn is unaffected by SkMatrix. + + @param deviceRgn SkRegion to combine with clip + @param op SkClipOp to apply to clip */ void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect); - /** Return true if the specified rectangle, after being transformed by the - current matrix, would lie completely outside of the current clip. Call - this to check if an area you intend to draw into is clipped out (and - therefore you can skip making the draw calls). - @param rect the rect to compare with the current clip - @return true if the rect (transformed by the canvas' matrix) does not - intersect with the canvas' clip + /** Return true if SkRect rect, transformed by SkMatrix, can be quickly determined to be + outside of clip. May return false even though rect is outside of clip. + + Use to check if an area to be drawn is clipped out, to skip subsequent draw calls. + + @param rect SkRect to compare with clip + @return true if rect, transformed by SkMatrix, does not intersect clip */ bool quickReject(const SkRect& rect) const; - /** Return true if the specified path, after being transformed by the - current matrix, would lie completely outside of the current clip. Call - this to check if an area you intend to draw into is clipped out (and - therefore you can skip making the draw calls). Note, for speed it may - return false even if the path itself might not intersect the clip - (i.e. the bounds of the path intersects, but the path does not). - @param path The path to compare with the current clip - @return true if the path (transformed by the canvas' matrix) does not - intersect with the canvas' clip + /** Return true if path, transformed by SkMatrix, can be quickly determined to be + outside of clip. May return false even though path is outside of clip. + + Use to check if an area to be drawn is clipped out, to skip subsequent draw calls. + + @param path SkPath to compare with clip + @return true if path, transformed by SkMatrix, does not intersect clip */ bool quickReject(const SkPath& path) const; - /** - * Return the bounds of the current clip in local coordinates. If the clip is empty, - * return { 0, 0, 0, 0 }. - */ + /** Return bounds of clip, transformed by inverse of SkMatrix. If clip is empty, + return SkRect::MakeEmpty, where all SkRect sides equal zero. + + SkRect returned is outset by one to account for partial pixel coverage if clip + is anti-aliased. + + @return bounds of clip in local coordinates + */ SkRect getLocalClipBounds() const { return this->onGetLocalClipBounds(); } - /** - * Returns true if the clip bounds are non-empty. - */ + /** Return bounds of clip, transformed by inverse of SkMatrix. If clip is empty, + return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero. + + bounds is outset by one to account for partial pixel coverage if clip + is anti-aliased. + + @param bounds SkRect of clip in local coordinates + @return true if clip bounds is not empty + */ bool getLocalClipBounds(SkRect* bounds) const { *bounds = this->onGetLocalClipBounds(); return !bounds->isEmpty(); } - /** - * Return the bounds of the current clip in device coordinates. If the clip is empty, - * return { 0, 0, 0, 0 }. - */ + /** Return SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty, + return SkRect::MakeEmpty, where all SkRect sides equal zero. + + Unlike getLocalClipBounds(), returned SkIRect is not outset. + + @return bounds of clip in SkBaseDevice coordinates + */ SkIRect getDeviceClipBounds() const { return this->onGetDeviceClipBounds(); } - /** - * Returns true if the clip bounds are non-empty. - */ + /** Return SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty, + return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero. + + Unlike getLocalClipBounds(), bounds is not outset. + + @param bounds SkRect of clip in device coordinates + @return true if clip bounds is not empty + */ bool getDeviceClipBounds(SkIRect* bounds) const { *bounds = this->onGetDeviceClipBounds(); return !bounds->isEmpty(); } - /** Fill the entire canvas' bitmap (restricted to the current clip) with the - specified color and mode. - @param color the color to draw with - @param mode the mode to apply the color in (defaults to SrcOver) + /** Fill clip with color color. + mode determines how ARGB is combined with destination. + + @param color Unpremultiplied ARGB + @param mode SkBlendMode used to combine source color and destination */ void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver); - /** - * Helper method for drawing a color in SRC mode, completely replacing all the pixels - * in the current clip with this color. - */ + /** Fill clip with color color using SkBlendMode::kSrc. + This has the effect of replacing all pixels contained by clip with color. + + @param color Unpremultiplied ARGB + */ void clear(SkColor color) { this->drawColor(color, SkBlendMode::kSrc); } - /** - * This makes the contents of the canvas undefined. Subsequent calls that - * require reading the canvas contents will produce undefined results. Examples - * include blending and readPixels. The actual implementation is backend- - * dependent and one legal implementation is to do nothing. This method - * ignores the current clip. - * - * This function should only be called if the caller intends to subsequently - * draw to the canvas. The canvas may do real work at discard() time in order - * to optimize performance on subsequent draws. Thus, if you call this and then - * never draw to the canvas subsequently you may pay a perfomance penalty. - */ + /** Make SkCanvas contents undefined. Subsequent calls that read SkCanvas pixels, + such as drawing with SkBlendMode, return undefined results. discard() does + not change clip or SkMatrix. + + discard() may do nothing, depending on the implementation of SkSurface or SkBaseDevice + that created SkCanvas. + + discard() allows optimized performance on subsequent draws by removing + cached data associated with SkSurface or SkBaseDevice. + It is not necessary to call discard() once done with SkCanvas; + any cached data is deleted when owning SkSurface or SkBaseDevice is deleted. + */ void discard() { this->onDiscard(); } - /** - * Fill the entire canvas (restricted to the current clip) with the - * specified paint. - * @param paint The paint used to fill the canvas - */ + /** Fill clip with SkPaint paint. SkPaint components SkRasterizer, SkMaskFilter, SkShader, + SkColorFilter, SkImageFilter, and SkBlendMode affect drawing; + SkPathEffect in paint is ignored. + + @param paint graphics state used to fill SkCanvas + */ void drawPaint(const SkPaint& paint); + /** \enum SkCanvas::PointMode + Selects if an array of points are drawn as discrete points, as lines, or as + an open polygon. + */ enum PointMode { - /** drawPoints draws each point separately */ - kPoints_PointMode, - /** drawPoints draws each pair of points as a line segment */ - kLines_PointMode, - /** drawPoints draws the array of points as a polygon */ - kPolygon_PointMode + kPoints_PointMode, //!< Draw each point separately. + kLines_PointMode, //!< Draw each pair of points as a line segment. + kPolygon_PointMode, //!< Draw the array of points as a open polygon. }; - /** Draw a series of points, interpreted based on the PointMode mode. For - all modes, the count parameter is interpreted as the total number of - points. For kLine mode, count/2 line segments are drawn. - For kPoint mode, each point is drawn centered at its coordinate, and its - size is specified by the paint's stroke-width. It draws as a square, - unless the paint's cap-type is round, in which the points are drawn as - circles. - For kLine mode, each pair of points is drawn as a line segment, - respecting the paint's settings for cap/join/width. - For kPolygon mode, the entire array is drawn as a series of connected - line segments. - Note that, while similar, kLine and kPolygon modes draw slightly - differently than the equivalent path built with a series of moveto, - lineto calls, in that the path will draw all of its contours at once, - with no interactions if contours intersect each other (think XOR - xfermode). drawPoints always draws each element one at a time. - @param mode PointMode specifying how to draw the array of points. - @param count The number of points in the array - @param pts Array of points to draw - @param paint The paint used to draw the points + /** Draw pts using clip, SkMatrix and SkPaint paint. + count is the number of points; if count is less than one, has no effect. + mode may be one of: kPoints_PointMode, kLines_PointMode, or kPolygon_PointMode. + + If mode is kPoints_PointMode, the shape of point drawn depends on paint + SkPaint::Cap. If paint is set to SkPaint::kRound_Cap, each point draws a + circle of diameter SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap + or SkPaint::kButt_Cap, each point draws a square of width and height + SkPaint stroke width. + + If mode is kLines_PointMode, each pair of points draws a line segment. + One line is drawn for every two points; each point is used once. If count is odd, + the final point is ignored. + + If mode is kPolygon_PointMode, each adjacent pair of points draws a line segment. + count minus one lines are drawn; the first and last point are used once. + + Each line segment respects paint SkPaint::Cap and SkPaint stroke width. + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + Always draws each element one at a time; is not affected by + SkPaint::Join, and unlike drawPath(), does not create a mask from all points + and lines before drawing. + + @param mode whether pts draws points or lines + @param count number of points in the array + @param pts array of points to draw + @param paint stroke, blend, color, and so on, used to draw */ void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint); - /** Helper method for drawing a single point. See drawPoints() for more details. - */ + /** Draw point at (x, y) using clip, SkMatrix and SkPaint paint. + + The shape of point drawn depends on paint SkPaint::Cap. + If paint is set to SkPaint::kRound_Cap, draw a circle of diameter + SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, + draw a square of width and height SkPaint stroke width. + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param x left edge of circle or square + @param y top edge of circle or square + @param paint stroke, blend, color, and so on, used to draw + */ void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint); + + /** Draw point p using clip, SkMatrix and SkPaint paint. + + The shape of point drawn depends on paint SkPaint::Cap. + If paint is set to SkPaint::kRound_Cap, draw a circle of diameter + SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, + draw a square of width and height SkPaint stroke width. + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param p top-left edge of circle or square + @param paint stroke, blend, color, and so on, used to draw + */ void drawPoint(SkPoint p, const SkPaint& paint) { this->drawPoint(p.x(), p.y(), paint); } - /** Draw a line segment with the specified start and stop x,y coordinates, - using the specified paint. NOTE: since a line is always "framed", the - paint's Style is ignored. - @param x0 The x-coordinate of the start point of the line - @param y0 The y-coordinate of the start point of the line - @param x1 The x-coordinate of the end point of the line - @param y1 The y-coordinate of the end point of the line - @param paint The paint used to draw the line + /** Draws line segment from (x0, y0) to (x1, y1) using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint stroke width describes the line thickness; + SkPaint::Cap draws the end rounded or square; + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param x0 start of line segment on x-axis + @param y0 start of line segment on y-axis + @param x1 end of line segment on x-axis + @param y1 end of line segment on y-axis + @param paint stroke, blend, color, and so on, used to draw */ void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint); + + /** Draws line segment from p0 to p1 using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint stroke width describes the line thickness; + SkPaint::Cap draws the end rounded or square; + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param p0 start of line segment + @param p1 end of line segment + @param paint stroke, blend, color, and so on, used to draw + */ void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint) { this->drawLine(p0.x(), p0.y(), p1.x(), p1.y(), paint); } - /** Draw the specified rectangle using the specified paint. The rectangle - will be filled or stroked based on the Style in the paint. - @param rect The rect to be drawn - @param paint The paint used to draw the rect + /** Draw SkRect rect using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rectangle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness, and + SkPaint::Join draws the corners rounded or square. + + @param rect rectangle to be drawn + @param paint stroke or fill, blend, color, and so on, used to draw */ void drawRect(const SkRect& rect, const SkPaint& paint); - /** Draw the specified rectangle using the specified paint. The rectangle - will be filled or framed based on the Style in the paint. - @param rect The rect to be drawn - @param paint The paint used to draw the rect + /** Draw SkIRect rect using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rectangle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness, and + SkPaint::Join draws the corners rounded or square. + + @param rect rectangle to be drawn + @param paint stroke or fill, blend, color, and so on, used to draw */ void drawIRect(const SkIRect& rect, const SkPaint& paint) { SkRect r; @@ -651,319 +1094,683 @@ public: this->drawRect(r, paint); } - /** Draw the outline of the specified region using the specified paint. - @param region The region to be drawn - @param paint The paint used to draw the region + /** Draw SkRegion region using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rectangle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness, and + SkPaint::Join draws the corners rounded or square. + + @param region region to be drawn + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw */ void drawRegion(const SkRegion& region, const SkPaint& paint); - /** Draw the specified oval using the specified paint. The oval will be - filled or framed based on the Style in the paint. - @param oval The rectangle bounds of the oval to be drawn - @param paint The paint used to draw the oval + /** Draw oval oval using clip, SkMatrix, and SkPaint. + In paint: SkPaint::Style determines if oval is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + @param oval SkRect bounds of oval + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw */ void drawOval(const SkRect& oval, const SkPaint& paint); - /** - * Draw the specified RRect using the specified paint The rrect will be filled or stroked - * based on the Style in the paint. - * - * @param rrect The round-rect to draw - * @param paint The paint used to draw the round-rect - */ + /** Draw SkRRect rrect using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rrect is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + rrect may represent a rectangle, circle, oval, uniformly rounded rectangle, or + may have any combination of positive non-square radii for the four corners. + + @param rrect SkRRect with up to eight corner radii to draw + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + */ void drawRRect(const SkRRect& rrect, const SkPaint& paint); - /** - * Draw the annulus formed by the outer and inner rrects. The results - * are undefined if the outer does not contain the inner. - */ + /** Draw SkRRect outer and inner + using clip, SkMatrix, and SkPaint paint. + outer must contain inner or the drawing is undefined. + In paint: SkPaint::Style determines if SkRRect is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + If stroked and SkRRect corner has zero length radii, SkPaint::Join can + draw corners rounded or square. + + GPU-backed platforms optimize drawing when both outer and inner are + concave and outer contains inner. These platforms may not be able to draw + SkPath built with identical data as fast. + + @param outer SkRRect outer bounds to draw + @param inner SkRRect inner bounds to draw + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + */ void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint); - /** Draw the specified circle using the specified paint. If radius is <= 0, - then nothing will be drawn. The circle will be filled - or framed based on the Style in the paint. - @param cx The x-coordinate of the center of the cirle to be drawn - @param cy The y-coordinate of the center of the cirle to be drawn - @param radius The radius of the cirle to be drawn - @param paint The paint used to draw the circle + /** Draw circle at (cx, cy) with radius using clip, SkMatrix, and SkPaint paint. + If radius is zero or less, nothing is drawn. + In paint: SkPaint::Style determines if circle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + @param cx Circle center on the x-axis + @param cy Circle center on the y-axis + @param radius half the diameter of circle + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw */ void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint); + + /** Draw circle at center with radius using clip, SkMatrix, and SkPaint paint. + If radius is zero or less, nothing is drawn. + In paint: SkPaint::Style determines if circle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + @param center Circle center + @param radius half the diameter of circle + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + */ void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint) { this->drawCircle(center.x(), center.y(), radius, paint); } - /** Draw the specified arc, which will be scaled to fit inside the - specified oval. Sweep angles are not treated as modulo 360 and thus can - exceed a full sweep of the oval. Note that this differs slightly from - SkPath::arcTo, which treats the sweep angle mod 360. If the oval is empty - or the sweep angle is zero nothing is drawn. If useCenter is true the oval - center is inserted into the implied path before the arc and the path is - closed back to the, center forming a wedge. Otherwise, the implied path - contains just the arc and is not closed. - @param oval The bounds of oval used to define the shape of the arc. - @param startAngle Starting angle (in degrees) where the arc begins - @param sweepAngle Sweep angle (in degrees) measured clockwise. - @param useCenter true means include the center of the oval. - @param paint The paint used to draw the arc + /** Draw arc using clip, SkMatrix, and SkPaint paint. + + Arc is part of oval bounded by oval, sweeping from startAngle to startAngle plus + sweepAngle. startAngle and sweepAngle are in degrees. + + startAngle of zero places start point at the right middle edge of oval. + A positive sweepAngle places arc end point clockwise from start point; + a negative sweepAngle places arc end point counterclockwise from start point. + sweepAngle may exceed 360 degrees, a full circle. + If useCenter is true, draw a wedge that includes lines from oval + center to arc end points. If useCenter is false, draw arc between end points. + + If SkRect oval is empty or sweepAngle is zero, nothing is drawn. + + @param oval SkRect bounds of oval containing arc to draw + @param startAngle angle in degrees where arc begins + @param sweepAngle sweep angle in degrees; positive is clockwise + @param useCenter if true, include the center of the oval + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw */ void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint); - /** Draw the specified round-rect using the specified paint. The round-rect - will be filled or framed based on the Style in the paint. - @param rect The rectangular bounds of the roundRect to be drawn - @param rx The x-radius of the oval used to round the corners - @param ry The y-radius of the oval used to round the corners - @param paint The paint used to draw the roundRect + /** Draw SkRRect bounded by SkRect rect, with corner radii (rx, ry) using clip, + SkMatrix, and SkPaint paint. + + In paint: SkPaint::Style determines if SkRRect is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + If rx or ry are less than zero, they are treated as if they are zero. + If rx plus ry exceeds rect width or rect height, radii are scaled down to fit. + If rx and ry are zero, SkRRect is drawn as SkRect and if stroked is affected by + SkPaint::Join. + + @param rect SkRect bounds of SkRRect to draw + @param rx axis length in x of oval describing rounded corners + @param ry axis length in y of oval describing rounded corners + @param paint stroke, blend, color, and so on, used to draw */ void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint); - /** Draw the specified path using the specified paint. The path will be - filled or framed based on the Style in the paint. - @param path The path to be drawn - @param paint The paint used to draw the path + /** Draw SkPath path using clip, SkMatrix, and SkPaint paint. + SkPath contains an array of path contour, each of which may be open or closed. + + In paint: SkPaint::Style determines if SkRRect is stroked or filled: + if filled, SkPath::FillType determines whether path contour describes inside or + outside of fill; if stroked, SkPaint stroke width describes the line thickness, + SkPaint::Cap describes line ends, and SkPaint::Join describes how + corners are drawn. + + @param path SkPath to draw + @param paint stroke, blend, color, and so on, used to draw */ void drawPath(const SkPath& path, const SkPaint& paint); - /** Draw the specified image, with its top/left corner at (x,y), using the - specified paint, transformed by the current matrix. + /** Draw SkImage image, with its top-left corner at (left, top), + using clip, SkMatrix, and optional SkPaint paint. - @param image The image to be drawn - @param left The position of the left side of the image being drawn - @param top The position of the top side of the image being drawn - @param paint The paint used to draw the image, or NULL - */ + If paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, SkBlendMode, + and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. If generated + mask extends beyond image bounds, replicate image edge colors, just as SkShader + made from SkImage::makeShader with SkShader::kClamp_TileMode set replicates the + image's edge color when it samples outside of its bounds. + + @param image uncompressed rectangular map of pixels + @param left left side of image + @param top top side of image + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ void drawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint = nullptr); + + /** Draw SkImage image, with its top-left corner at (left, top), + using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. If generated + mask extends beyond image bounds, replicate image edge colors, just as SkShader + made from SkImage::makeShader with SkShader::kClamp_TileMode set replicates the + image's edge color when it samples outside of its bounds. + + @param image uncompressed rectangular map of pixels + @param left left side of image + @param top pop side of image + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ void drawImage(const sk_sp& image, SkScalar left, SkScalar top, const SkPaint* paint = nullptr) { this->drawImage(image.get(), left, top, paint); } - /** - * Controls the behavior at the edge of the src-rect, when specified in drawImageRect, - * trading off speed for exactness. - * - * When filtering is enabled (in the Paint), skia may need to sample in a neighborhood around - * the pixels in the image. If there is a src-rect specified, it is intended to restrict the - * pixels that will be read. However, for performance reasons, some implementations may slow - * down if they cannot read 1-pixel past the src-rect boundary at times. - * - * This enum allows the caller to specify if such a 1-pixel "slop" will be visually acceptable. - * If it is, the caller should pass kFast, and it may result in a faster draw. If the src-rect - * must be strictly respected, the caller should pass kStrict. - */ + /** \enum SkCanvas::SrcRectConstraint + SrcRectConstraint controls the behavior at the edge of source SkRect, + provided to drawImageRect(), trading off speed for precision. + + SkImageFilter in SkPaint may sample multiple pixels in the image. Source SkRect + restricts the bounds of pixels that may be read. SkImageFilter may slow down if + it cannot read outside the bounds, when sampling near the edge of source SkRect. + SrcRectConstraint specifies whether an SkImageFilter is allowed to read pixels + outside source SkRect. + */ enum SrcRectConstraint { - /** - * If kStrict is specified, the implementation must respect the src-rect - * (if specified) strictly, and will never sample outside of those bounds during sampling - * even when filtering. This may be slower than kFast. - */ + /** sampling only inside of its bounds, possibly with a performance penalty. */ kStrict_SrcRectConstraint, - /** - * If kFast is specified, the implementation may sample outside of the src-rect - * (if specified) by half the width of filter. This allows greater flexibility - * to the implementation and can make the draw much faster. - */ + /** by half the width of SkImageFilter, permitting it to run faster but with + error at the image edges. + */ kFast_SrcRectConstraint, }; - /** Draw the specified image, scaling and translating so that it fills the specified - * dst rect. If the src rect is non-null, only that subset of the image is transformed - * and drawn. - * - * @param image The image to be drawn - * @param src Optional: specify the subset of the image to be drawn - * @param dst The destination rectangle where the scaled/translated - * image will be drawn - * @param paint The paint used to draw the image, or NULL - * @param constraint Control the tradeoff between speed and exactness w.r.t. the src-rect. - */ + /** Draw SkRect src of SkImage image, scaled and translated to fill SkRect dst. + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image's edge color when it samples outside of its bounds. + + constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to + sample within src; set to kFast_SrcRectConstraint allows sampling outside to + improve performance. + + @param image SkImage containing pixels, dimensions, and format + @param src source SkRect of image to draw from + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + @param constraint filter strictly within src or draw faster + */ void drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint); - // variant that takes src SkIRect + + /** Draw SkIRect isrc of SkImage image, scaled and translated to fill SkRect dst. + Note that isrc is on integer pixel boundaries; dst may include fractional + boundaries. Additionally transform draw using clip, SkMatrix, and optional SkPaint + paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image's edge color when it samples outside of its bounds. + + constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to + sample within isrc; set to kFast_SrcRectConstraint allows sampling outside to + improve performance. + + @param image SkImage containing pixels, dimensions, and format + @param isrc source SkIRect of image to draw from + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + @param constraint filter strictly within isrc or draw faster + */ void drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint); - // variant that assumes src == image-bounds + + /** Draw SkImage image, scaled and translated to fill SkRect dst, using clip, SkMatrix, + and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image's edge color when it samples outside of its bounds. + + constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to + sample within image; set to kFast_SrcRectConstraint allows sampling outside to + improve performance. + + @param image SkImage containing pixels, dimensions, and format + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + @param constraint filter strictly within image or draw faster + */ void drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint); + /** Draw SkRect src of SkImage image, scaled and translated to fill SkRect dst. + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image's edge color when it samples outside of its bounds. + + constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to + sample within src; set to kFast_SrcRectConstraint allows sampling outside to + improve performance. + + @param image SkImage containing pixels, dimensions, and format + @param src source SkRect of image to draw from + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + @param constraint filter strictly within src or draw faster + */ void drawImageRect(const sk_sp& image, const SkRect& src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) { this->drawImageRect(image.get(), src, dst, paint, constraint); } + + /** Draw SkIRect isrc of SkImage image, scaled and translated to fill SkRect dst. + isrc is on integer pixel boundaries; dst may include fractional boundaries. + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image's edge color when it samples outside of its bounds. + + constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to + sample within image; set to kFast_SrcRectConstraint allows sampling outside to + improve performance. + + @param image SkImage containing pixels, dimensions, and format + @param isrc source SkIRect of image to draw from + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + @param constraint filter strictly within image or draw faster + */ void drawImageRect(const sk_sp& image, const SkIRect& isrc, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) { this->drawImageRect(image.get(), isrc, dst, paint, constraint); } + + /** Draw SkImage image, scaled and translated to fill SkRect dst, + using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image's edge color when it samples outside of its bounds. + + constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to + sample within image; set to kFast_SrcRectConstraint allows sampling outside to + improve performance. + + @param image SkImage containing pixels, dimensions, and format + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + @param constraint filter strictly within image or draw faster + */ void drawImageRect(const sk_sp& image, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) { this->drawImageRect(image.get(), dst, paint, constraint); } - /** - * Draw the image stretched differentially to fit into dst. - * center is a rect within the image, and logically divides the image - * into 9 sections (3x3). For example, if the middle pixel of a [5x5] - * image is the "center", then the center-rect should be [2, 2, 3, 3]. - * - * If the dst is >= the image size, then... - * - The 4 corners are not stretched at all. - * - The sides are stretched in only one axis. - * - The center is stretched in both axes. - * Else, for each axis where dst < image, - * - The corners shrink proportionally - * - The sides (along the shrink axis) and center are not drawn - */ + /** Draw SkImage image stretched differentially to fit into SkRect dst. + SkIRect center divides the image into nine sections: four sides, four corners, and + the center. Corners are unmodified or scaled down proportionately if their sides + are larger than dst; center and four sides are scaled to fit remaining space, if any. + + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image's edge color when it samples outside of its bounds. + + @param image SkImage containing pixels, dimensions, and format + @param center SkIRect edge of image corners and sides + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, const SkPaint* paint = nullptr); + + /** Draw SkImage image stretched differentially to fit into SkRect dst. + SkIRect center divides the image into nine sections: four sides, four corners, and + the center. Corners are not scaled, or scaled down proportionately if their sides + are larger than dst; center and four sides are scaled to fit remaining space, if any. + + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image's edge color when it samples outside of its bounds. + + @param image SkImage containing pixels, dimensions, and format + @param center SkIRect edge of image corners and sides + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ void drawImageNine(const sk_sp& image, const SkIRect& center, const SkRect& dst, const SkPaint* paint = nullptr) { this->drawImageNine(image.get(), center, dst, paint); } - /** Draw the specified bitmap, with its top/left corner at (x,y), using the - specified paint, transformed by the current matrix. Note: if the paint - contains a maskfilter that generates a mask which extends beyond the - bitmap's original width/height, then the bitmap will be drawn as if it - were in a Shader with CLAMP mode. Thus the color outside of the original - width/height will be the edge color replicated. + /** Draw SkBitmap bitmap, with its top-left corner at (left, top), + using clip, SkMatrix, and optional SkPaint paint. - If a shader is present on the paint it will be ignored, except in the - case where the bitmap is kAlpha_8_SkColorType. In that case, the color is - generated by the shader. + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from bitmap bounds. - @param bitmap The bitmap to be drawn - @param left The position of the left side of the bitmap being drawn - @param top The position of the top side of the bitmap being drawn - @param paint The paint used to draw the bitmap, or NULL + If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, + just as SkShader made from SkShader::MakeBitmapShader with + SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + outside of its bounds. + + @param bitmap SkBitmap containing pixels, dimensions, and format + @param left left side of bitmap + @param top top side of bitmap + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr */ void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint = nullptr); - /** Draw the specified bitmap, scaling and translating so that it fills the specified - * dst rect. If the src rect is non-null, only that subset of the bitmap is transformed - * and drawn. - * - * @param bitmap The bitmap to be drawn - * @param src Optional: specify the subset of the bitmap to be drawn - * @param dst The destination rectangle where the scaled/translated - * bitmap will be drawn - * @param paint The paint used to draw the bitmap, or NULL - * @param constraint Control the tradeoff between speed and exactness w.r.t. the src-rect. - */ + /** Draw SkRect src of SkBitmap bitmap, scaled and translated to fill SkRect dst. + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from bitmap bounds. + + If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, + just as SkShader made from SkShader::MakeBitmapShader with + SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + outside of its bounds. + + constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to + sample within src; set to kFast_SrcRectConstraint allows sampling outside to + improve performance. + + @param bitmap SkBitmap containing pixels, dimensions, and format + @param src source SkRect of image to draw from + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + @param constraint filter strictly within src or draw faster + */ void drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint); - // variant where src is SkIRect + + /** Draw SkIRect isrc of SkBitmap bitmap, scaled and translated to fill SkRect dst. + isrc is on integer pixel boundaries; dst may include fractional boundaries. + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from bitmap bounds. + + If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, + just as SkShader made from SkShader::MakeBitmapShader with + SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + outside of its bounds. + + constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to + sample within isrc; set to kFast_SrcRectConstraint allows sampling outside to + improve performance. + + @param bitmap SkBitmap containing pixels, dimensions, and format + @param isrc source SkIRect of image to draw from + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + @param constraint sample strictly within isrc, or draw faster + */ void drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint); + + /** Draw SkBitmap bitmap, scaled and translated to fill SkRect dst. + bitmap bounds is on integer pixel boundaries; dst may include fractional boundaries. + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from bitmap bounds. + + If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, + just as SkShader made from SkShader::MakeBitmapShader with + SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + outside of its bounds. + + constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to + sample within bitmap; set to kFast_SrcRectConstraint allows sampling outside to + improve performance. + + @param bitmap SkBitmap containing pixels, dimensions, and format + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + @param constraint filter strictly within bitmap or draw faster + */ void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint); - /** - * Draw the bitmap stretched or shrunk differentially to fit into dst. - * center is a rect within the bitmap, and logically divides the bitmap - * into 9 sections (3x3). For example, if the middle pixel of a [5x5] - * bitmap is the "center", then the center-rect should be [2, 2, 3, 3]. - * - * If the dst is >= the bitmap size, then... - * - The 4 corners are not stretched at all. - * - The sides are stretched in only one axis. - * - The center is stretched in both axes. - * Else, for each axis where dst < bitmap, - * - The corners shrink proportionally - * - The sides (along the shrink axis) and center are not drawn - */ + /** Draw SkBitmap bitmap stretched differentially to fit into SkRect dst. + SkIRect center divides the bitmap into nine sections: four sides, four corners, + and the center. Corners are not scaled, or scaled down proportionately if their + sides are larger than dst; center and four sides are scaled to fit remaining + space, if any. + + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from bitmap bounds. + + If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, + just as SkShader made from SkShader::MakeBitmapShader with + SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + outside of its bounds. + + @param bitmap SkBitmap containing pixels, dimensions, and format + @param center SkIRect edge of image corners and sides + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint = nullptr); - /** - * Specifies coordinates to divide a bitmap into (xCount*yCount) rects. - * - * If the lattice divs or bounds are invalid, the entire lattice - * struct will be ignored on the draw call. - */ + /** \struct SkCanvas::Lattice + */ struct Lattice { + + /** \enum SkCanvas::Lattice::Flags + Optional setting per rectangular grid entry to make it transparent. + */ enum Flags : uint8_t { - // If set, indicates that we should not draw corresponding rect. + /** Set to skip lattice rectangle by making it transparent. */ kTransparent_Flags = 1 << 0, }; - // An array of x-coordinates that divide the bitmap vertically. - // These must be unique, increasing, and in the set [fBounds.fLeft, fBounds.fRight). - // Does not have ownership. + /** Array of x-coordinates that divide the bitmap vertically. + Array entries must be unique, increasing, greater than or equal to + fBounds left edge, and less than fBounds right edge. + Set the first element to fBounds left to collapse the left column of + fixed grid entries. + */ const int* fXDivs; - // An array of y-coordinates that divide the bitmap horizontally. - // These must be unique, increasing, and in the set [fBounds.fTop, fBounds.fBottom). - // Does not have ownership. + /** Array of y-coordinates that divide the bitmap horizontally. + Array entries must be unique, increasing, greater than or equal to + fBounds top edge, and less than fBounds bottom edge. + Set the first element to fBounds top to collapse the top row of fixed + grid entries. + */ const int* fYDivs; - // If non-null, the length of this array must be equal to - // (fXCount + 1) * (fYCount + 1). Note that we allow the first rect - // in each direction to be empty (ex: fXDivs[0] = fBounds.fLeft). - // In this case, the caller still must specify a flag (as a placeholder) - // for these empty rects. - // The flags correspond to the rects in the lattice, first moving - // left to right and then top to bottom. + /** Optional array of flags, one per rectangular grid entry: + array length must be (fXCount + 1) * (fYCount + 1). + Array entries correspond to the rectangular grid entries, ascending + left to right and then top to bottom. + */ const Flags* fFlags; - // The number of fXDivs. + /** Number of entries in fXDivs array; one less than the number of + horizontal divisions. + */ int fXCount; - // The number of fYDivs. + /** Number of entries in fYDivs array; one less than the number of vertical + divisions. + */ int fYCount; - // The bound to draw from. Must be contained by the src that is being drawn, - // non-empty, and non-inverted. - // If nullptr, the bounds are the entire src. + /** Optional subset SkIRect source to draw from. + If nullptr, source bounds is dimensions of SkBitmap or SkImage. + */ const SkIRect* fBounds; + }; - /** - * Draw the bitmap stretched or shrunk differentially to fit into dst. - * - * Moving horizontally across the bitmap, alternating rects will be "scalable" - * (in the x-dimension) to fit into dst or must be left "fixed". The first rect - * is treated as "fixed", but it's possible to specify an empty first rect by - * making lattice.fXDivs[0] = 0. - * - * The scale factor for all "scalable" rects will be the same, and may be greater - * than or less than 1 (meaning we can stretch or shrink). If the number of - * "fixed" pixels is greater than the width of the dst, we will collapse all of - * the "scalable" regions and appropriately downscale the "fixed" regions. - * - * The same interpretation also applies to the y-dimension. - */ + /** Draw SkBitmap bitmap stretched differentially to fit into SkRect dst. + + Lattice lattice divides bitmap into a rectangular grid. + Each intersection of an even-numbered row and column is fixed; like the corners + of drawBitmapNine(), fixed lattice elements never scale larger than their initial + size and shrink proportionately when all fixed elements exceed the bitmap's + dimension. All other grid elements scale to fill the available space, if any. + + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from bitmap bounds. + + If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, + just as SkShader made from SkShader::MakeBitmapShader with + SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + outside of its bounds. + + @param bitmap SkBitmap containing pixels, dimensions, and format + @param lattice division of bitmap into fixed and variable rectangles + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst, const SkPaint* paint = nullptr); + + /** Draw SkImage image stretched differentially to fit into SkRect dst. + + Lattice lattice divides image into a rectangular grid. + Each intersection of an even-numbered row and column is fixed; like the corners + of drawBitmapNine(), fixed lattice elements never scale larger than their initial + size and shrink proportionately when all fixed elements exceed the bitmap's + dimension. All other grid elements scale to fill the available space, if any. + + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from bitmap bounds. + + If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, + just as SkShader made from SkShader::MakeBitmapShader with + SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + outside of its bounds. + + @param image SkImage containing pixels, dimensions, and format + @param lattice division of bitmap into fixed and variable rectangles + @param dst destination SkRect of image to draw to + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, const SkPaint* paint = nullptr); - /** Draw the text, with origin at (x,y), using the specified paint. - The origin is interpreted based on the Align setting in the paint. - @param text The text to be drawn - @param byteLength The number of bytes to read from the text parameter - @param x The x-coordinate of the origin of the text being drawn - @param y The y-coordinate of the origin of the text being drawn - @param paint The paint used for the text (e.g. color, size, style) + /** Draw text, with origin at (x, y), using clip, SkMatrix, and SkPaint paint. + + text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + UTF-8. + + x and y meaning depends on SkPaint::Align and SkPaint vertical text; by default + text draws left to right, positioning the first glyph's left side bearing at x + and its baseline at y. Text size is affected by SkMatrix and SkPaint text size. + + All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, + SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws + filled 12 point black glyphs. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param x start of text on x-axis + @param y start of text on y-axis + @param paint text size, blend, color, and so on, used to draw */ void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint); - /** Draw null-terminated UTF-8 string, with origin at (x,y), using the specified paint. - The origin is interpreted based on the Align setting in the paint. - @param string The null-terminated string to be drawn - @param x The x-coordinate of the origin of the string being drawn - @param y The y-coordinate of the origin of the string being drawn - @param paint The paint used for the string (e.g. color, size, style) + /** Draw null terminated string, with origin at (x, y), using clip, SkMatrix, and + SkPaint paint. + + string's meaning depends on SkPaint::TextEncoding; by default, string encoding is + UTF-8. Other values of SkPaint::TextEncoding are unlikely to produce the desired + results, since zero bytes may be embedded in the string. + + x and y meaning depends on SkPaint::Align and SkPaint vertical text; by default + string draws left to right, positioning the first glyph's left side bearing at x + and its baseline at y. Text size is affected by SkMatrix and SkPaint text size. + + All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, + SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws + filled 12 point black glyphs. + + @param string character code points or glyphs drawn, + ending with a char value of zero + @param x start of string on x-axis + @param y start of string on y-axis + @param paint text size, blend, color, and so on, used to draw */ void drawString(const char* string, SkScalar x, SkScalar y, const SkPaint& paint) { if (!string) { @@ -972,202 +1779,463 @@ public: this->drawText(string, strlen(string), x, y, paint); } - /** Draw string, with origin at (x,y), using the specified paint. - The origin is interpreted based on the Align setting in the paint. - @param string The string to be drawn - @param x The x-coordinate of the origin of the string being drawn - @param y The y-coordinate of the origin of the string being drawn - @param paint The paint used for the string (e.g. color, size, style) + /** Draw null terminated string, with origin at (x, y), using clip, SkMatrix, and + SkPaint paint. + + string's meaning depends on SkPaint::TextEncoding; by default, string encoding is + UTF-8. Other values of SkPaint::TextEncoding are unlikely to produce the desired + results, since zero bytes may be embedded in the string. + + x and y meaning depends on SkPaint::Align and SkPaint vertical text; by default + string draws left to right, positioning the first glyph's left side bearing at x + and its baseline at y. Text size is affected by SkMatrix and SkPaint text size. + + All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, + SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws + filled 12 point black glyphs. + + @param string character code points or glyphs drawn, + ending with a char value of zero + @param x start of string on x-axis + @param y start of string on y-axis + @param paint text size, blend, color, and so on, used to draw */ void drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint); - /** Draw the text, with each character/glyph origin specified by the pos[] - array. The origin is interpreted by the Align setting in the paint. - @param text The text to be drawn - @param byteLength The number of bytes to read from the text parameter - @param pos Array of positions, used to position each character - @param paint The paint used for the text (e.g. color, size, style) - */ + /** Draw each glyph in text with the origin in pos array, using clip, SkMatrix, and + SkPaint paint. The number of entries in pos array must match the number of glyphs + described by byteLength of text. + + text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + UTF-8. pos elements' meaning depends on SkPaint::Align and SkPaint vertical text; + by default each glyph's left side bearing is positioned at x and its + baseline is positioned at y. Text size is affected by SkMatrix and + SkPaint text size. + + All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, + SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws + filled 12 point black glyphs. + + Layout engines such as Harfbuzz typically position each glyph + rather than using the font's advance widths. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param pos array of glyph origins + @param paint text size, blend, color, and so on, used to draw + */ void drawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint); - /** Draw the text, with each character/glyph origin specified by the x - coordinate taken from the xpos[] array, and the y from the constY param. - The origin is interpreted by the Align setting in the paint. - @param text The text to be drawn - @param byteLength The number of bytes to read from the text parameter - @param xpos Array of x-positions, used to position each character - @param constY The shared Y coordinate for all of the positions - @param paint The paint used for the text (e.g. color, size, style) - */ + /** Draw each glyph in text with its (x, y) origin composed from xpos array and + constY, using clip, SkMatrix, and SkPaint paint. The number of entries in xpos array + must match the number of glyphs described by byteLength of text. + + text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + UTF-8. xpos elements' meaning depends on SkPaint::Align and SkPaint vertical text; + by default each glyph's left side bearing is positioned at an xpos element and + its baseline is positioned at constY. Text size is affected by SkMatrix and + SkPaint text size. + + All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, + SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws + filled 12 point black glyphs. + + Layout engines such as Harfbuzz typically position each glyph + rather than using the font's advance widths if all glyphs share the same + baseline. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param xpos array of x positions, used to position each glyph + @param constY shared y coordinate for all of x positions + @param paint text size, blend, color, and so on, used to draw + */ void drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint); - /** Draw the text, with origin at (x,y), using the specified paint, along - the specified path. The paint's Align setting determins where along the - path to start the text. - @param text The text to be drawn - @param byteLength The number of bytes to read from the text parameter - @param path The path the text should follow for its baseline - @param hOffset The distance along the path to add to the text's - starting position - @param vOffset The distance above(-) or below(+) the path to - position the text - @param paint The paint used for the text + /** Draw text on SkPath path, using clip, SkMatrix, and SkPaint paint. + + Origin of text is at distance hOffset along the path, offset by a perpendicular + vector of length vOffset. If the path section corresponding the glyph advance is + curved, the glyph is drawn curved to match; control points in the glyph are + mapped to projected points parallel to the path. If the text's advance is larger + than the path length, the excess text is clipped. + + text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + UTF-8. Origin meaning depends on SkPaint::Align and SkPaint vertical text; by + default text positions the first glyph's left side bearing at origin x and its + baseline at origin y. Text size is affected by SkMatrix and SkPaint text size. + + All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, + SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws + filled 12 point black glyphs. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param path SkPath providing text baseline + @param hOffset distance along path to offset origin + @param vOffset offset of text above (if negative) or below (if positive) the path + @param paint text size, blend, color, and so on, used to draw */ void drawTextOnPathHV(const void* text, size_t byteLength, const SkPath& path, SkScalar hOffset, SkScalar vOffset, const SkPaint& paint); - /** Draw the text, with origin at (x,y), using the specified paint, along - the specified path. The paint's Align setting determins where along the - path to start the text. - @param text The text to be drawn - @param byteLength The number of bytes to read from the text parameter - @param path The path the text should follow for its baseline - @param matrix (may be null) Applied to the text before it is - mapped onto the path - @param paint The paint used for the text - */ + /** Draw text on SkPath path, using clip, SkMatrix, and SkPaint paint. + + Origin of text is at beginning of path offset by matrix, if provided, before it + is mapped to path. If the path section corresponding the glyph advance is + curved, the glyph is drawn curved to match; control points in the glyph are + mapped to projected points parallel to the path. If the text's advance is larger + than the path length, the excess text is clipped. + + text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + UTF-8. Origin meaning depends on SkPaint::Align and SkPaint vertical text; by + default text positions the first glyph's left side bearing at origin x and its + baseline at origin y. Text size is affected by SkMatrix and SkPaint text size. + + All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, + SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws + filled 12 point black glyphs. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param path SkPath providing text baseline + @param matrix transform of glyphs before mapping to path; may be nullptr + to use identity SkMatrix + @param paint text size, blend, color, and so on, used to draw + */ void drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint); - /** - * Draw the text with each character/glyph individually transformed by its xform. - * If cullRect is not null, it is a conservative bounds of what will be drawn - * taking into account the xforms and the paint, and will be used to accelerate culling. - */ + /** Draw text, transforming each glyph by the corresponding SkRSXform, + using clip, SkMatrix, and SkPaint paint. + + SkRSXform array specifies a separate square scale, rotation, and translation for + each glyph. + + Optional SkRect cullRect is a conservative bounds of text, taking into account + SkRSXform and paint. If cullRect is outside of clip, canvas can skip drawing. + + All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, + SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws + filled 12 point black glyphs. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param xform SkRSXform rotates, scales, and translates each glyph individually + @param cullRect SkRect bounds of text for efficient clipping; or nullptr + @param paint text size, blend, color, and so on, used to draw + */ void drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], const SkRect* cullRect, const SkPaint& paint); - /** Draw the text blob, offset by (x,y), using the specified paint. - @param blob The text blob to be drawn - @param x The x-offset of the text being drawn - @param y The y-offset of the text being drawn - @param paint The paint used for the text (e.g. color, size, style) + /** Draw SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint. + + blob contains glyphs, their positions, and paint attributes specific to text: + SkTypeface, SkPaint text size, SkPaint text scale x, SkPaint text skew x, + SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold, + font embedded bitmaps, full hinting spacing, lcd text, linear text, + subpixel text, and SkPaint vertical text. + + Elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, SkColorFilter, + SkImageFilter, and SkDrawLooper; apply to blob. + + @param blob Glyphs, positions, and their paints' text size, typeface, and so on + @param x horizontal offset applied to blob + @param y vertical offset applied to blob + @param paint blend, color, stroking, and so on, used to draw */ void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint); + + /** Draw SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint. + + blob contains glyphs, their positions, and paint attributes specific to text: + SkTypeface, SkPaint text size, SkPaint text scale x, SkPaint text skew x, + SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold, + font embedded bitmaps, full hinting spacing, lcd text, linear text, + subpixel text, and SkPaint vertical text. + + Elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, SkColorFilter, + SkImageFilter, and SkDrawLooper; apply to blob. + + @param blob Glyphs, positions, and their paints' text size, typeface, and so on + @param x horizontal offset applied to blob + @param y vertical offset applied to blob + @param paint blend, color, stroking, and so on, used to draw + */ void drawTextBlob(const sk_sp& blob, SkScalar x, SkScalar y, const SkPaint& paint) { this->drawTextBlob(blob.get(), x, y, paint); } - /** Draw the picture into this canvas. This method effective brackets the - playback of the picture's draw calls with save/restore, so the state - of this canvas will be unchanged after this call. - @param picture The recorded drawing commands to playback into this - canvas. + /** Draw picture picture, using clip and SkMatrix. + Clip and SkMatrix are unchanged by picture contents, as if + save() was called before and restore() was called after drawPicture(). + + Picture records a series of draw commands for later playback. + + @param picture recorded drawing commands to play */ void drawPicture(const SkPicture* picture) { this->drawPicture(picture, nullptr, nullptr); } + + /** Draw picture picture, using clip and SkMatrix. + Clip and SkMatrix are unchanged by picture contents, as if + save() was called before and restore() was called after drawPicture(). + + Picture records a series of draw commands for later playback. + + @param picture recorded drawing commands to play + */ void drawPicture(const sk_sp& picture) { this->drawPicture(picture.get()); } - /** - * Draw the picture into this canvas. - * - * If matrix is non-null, apply that matrix to the CTM when drawing this picture. This is - * logically equivalent to - * save/concat/drawPicture/restore - * - * If paint is non-null, draw the picture into a temporary buffer, and then apply the paint's - * alpha/colorfilter/imagefilter/xfermode to that buffer as it is drawn to the canvas. - * This is logically equivalent to - * saveLayer(paint)/drawPicture/restore - */ + /** Draw picture picture, using clip and SkMatrix; transforming picture with + SkMatrix matrix, if provided; and use SkPaint paint color alpha, SkColorFilter, + SkImageFilter, and SkBlendMode, if provided. + + matrix transformation is equivalent to: save(), concat(), drawPicture(), restore(). + paint use is equivalent to: saveLayer(), drawPicture(), restore(). + + @param picture recorded drawing commands to play + @param matrix SkMatrix to rotate, scale, translate, and so on; may be nullptr + @param paint SkPaint to apply transparency, filtering, and so on; may be nullptr + */ void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint); + + /** Draw picture picture, using clip and SkMatrix; transforming picture with + SkMatrix matrix, if provided; and use SkPaint paint color alpha, SkColorFilter, + SkImageFilter, and SkBlendMode, if provided. + + matrix transformation is equivalent to: save(), concat(), drawPicture(), restore(). + paint use is equivalent to: saveLayer(), drawPicture(), restore(). + + @param picture recorded drawing commands to play + @param matrix SkMatrix to rotate, scale, translate, and so on; may be nullptr + @param paint SkPaint to apply transparency, filtering, and so on; may be nullptr + */ void drawPicture(const sk_sp& picture, const SkMatrix* matrix, const SkPaint* paint) { this->drawPicture(picture.get(), matrix, paint); } - /** Draw vertices from an immutable SkVertices object. + /** Draw vertices vertices, a triangle mesh, using clip and SkMatrix. + If vertices texs and vertices colors are defined in vertices, and SkPaint paint + contains SkShader, SkBlendMode mode combines vertices colors with SkShader. - @param vertices The mesh to draw. - @param mode Used if both texs and colors are present and paint has a - shader. In this case the colors are combined with the texture - using mode, before being drawn using the paint. - @param paint Specifies the shader/texture if present. - */ + @param vertices triangle mesh to draw + @param mode combines vertices colors with SkShader, if both are present + @param paint specifies the SkShader, used as vertices texture; may be nullptr + */ void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint); + + /** Draw vertices vertices, a triangle mesh, using clip and SkMatrix. + If vertices texs and vertices colors are defined in vertices, and SkPaint paint + contains SkShader, SkBlendMode mode combines vertices colors with SkShader. + + @param vertices triangle mesh to draw + @param mode combines vertices colors with SkShader, if both are present + @param paint specifies the SkShader, used as vertices texture, may be nullptr + */ void drawVertices(const sk_sp& vertices, SkBlendMode mode, const SkPaint& paint); - /** - Draw a cubic coons patch + /** Draws a Coons patch: the interpolation of four cubics with shared corners, + associating a color, and optionally a texture coordinate, with each corner. - @param cubic specifies the 4 bounding cubic bezier curves of a patch with clockwise order - starting at the top left corner. - @param colors specifies the colors for the corners which will be bilerp across the patch, - their order is clockwise starting at the top left corner. - @param texCoords specifies the texture coordinates that will be bilerp across the patch, - their order is the same as the colors. - @param mode specifies how are the colors and the textures combined if both of them are - present. - @param paint Specifies the shader/texture if present. - */ + The Coons patch uses clip and SkMatrix, SkPaint paint's SkShader, SkColorFilter, + color alpha, SkImageFilter, and SkBlendMode. If SkShader is provided it is treated + as the Coons patch texture; SkBlendMode mode combines color colors and SkShader if + both are provided. + + SkPoint array cubics specifies four cubics starting at the top left corner, + in clockwise order, sharing every fourth point. The last cubic ends at the + first point. + + Color array color associates colors with corners in top left, top right, + bottom right, bottom left order. + + If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to + corners in top left, top right, bottom right, bottom left order. + + @param cubics SkPath cubic array, sharing common points + @param colors Color array, one for each corner + @param texCoords SkPoint array of texture coordinates, mapping SkShader to corners; + may be nullptr + @param mode SkBlendMode for colors, and for SkShader if paint has one + @param paint SkShader, SkColorFilter, SkBlendMode, used to draw + */ void drawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint); + + /** Draws cubic Coons patch: the interpolation of four cubics with shared corners, + associating a color, and optionally a texture coordinate, with each corner. + + The Coons patch uses clip and SkMatrix, SkPaint paint's SkShader, SkColorFilter, + color alpha, SkImageFilter, and SkBlendMode. If SkShader is provided it is treated + as the Coons patch texture; SkBlendMode mode combines color colors and SkShader if + both are provided. + + SkPoint array cubics specifies four cubics starting at the top left corner, + in clockwise order, sharing every fourth point. The last cubic ends at the + first point. + + Color array color associates colors with corners in top left, top right, + bottom right, bottom left order. + + If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to + corners in top left, top right, bottom right, bottom left order. + + @param cubics SkPath cubic array, sharing common points + @param colors Color array, one for each corner + @param texCoords SkPoint array of texture coordinates, mapping SkShader to corners; + may be nullptr + @param paint SkShader, SkColorFilter, SkBlendMode, used to draw + */ void drawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], const SkPaint& paint) { this->drawPatch(cubics, colors, texCoords, SkBlendMode::kModulate, paint); } - /** - * Draw a set of sprites from the atlas. Each is specified by a tex rectangle in the - * coordinate space of the atlas, and a corresponding xform which transforms the tex rectangle - * into a quad. - * - * xform maps [0, 0, tex.width, tex.height] -> quad - * - * The color array is optional. When specified, each color modulates the pixels in its - * corresponding quad (via the specified SkBlendMode). - * - * The cullRect is optional. When specified, it must be a conservative bounds of all of the - * resulting transformed quads, allowing the canvas to skip drawing if the cullRect does not - * intersect the current clip. - * - * The paint is optional. If specified, its antialiasing, alpha, color-filter, image-filter - * and blendmode are used to affect each of the quads. - */ + /** Draw a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint. + paint uses anti-alias, color alpha, SkColorFilter, SkImageFilter, and SkBlendMode + to draw, if present. For each entry in the array, SkRect tex locates sprite in + atlas, and SkRSXform xform transforms it into destination space. + + xform, text, and colors if present, must contain count entries. + Optional colors are applied for each sprite using SkBlendMode. + Optional cullRect is a conservative bounds of all transformed sprites. + If cullRect is outside of clip, canvas can skip drawing. + + @param atlas SkImage containing sprites + @param xform SkRSXform mappings for sprites in atlas + @param tex SkRect locations of sprites in atlas + @param colors Color, one per sprite, blended with sprite using SkBlendMode; may be nullptr + @param count number of sprites to draw + @param mode SkBlendMode combining colors and sprites + @param cullRect SkRect bounds of transformed sprites for efficient clipping; may be nullptr + @param paint SkPaint SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr + */ void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect, const SkPaint* paint); + + /** Draw a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint. + paint uses anti-alias, color alpha, SkColorFilter, SkImageFilter, and SkBlendMode + to draw, if present. For each entry in the array, SkRect tex locates sprite in + atlas, and SkRSXform xform transforms it into destination space. + + xform, text, and colors if present, must contain count entries. + Optional colors is applied for each sprite using SkBlendMode. + Optional cullRect is a conservative bounds of all transformed sprites. + If cullRect is outside of clip, canvas can skip drawing. + + @param atlas SkImage containing sprites + @param xform SkRSXform mappings for sprites in atlas + @param tex SkRect locations of sprites in atlas + @param colors Color, one per sprite, blended with sprite using SkBlendMode; may be nullptr + @param count number of sprites to draw + @param mode SkBlendMode combining colors and sprites + @param cullRect SkRect bounds of transformed sprites for efficient clipping; may be nullptr + @param paint SkPaint SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr + */ void drawAtlas(const sk_sp& atlas, const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect, const SkPaint* paint) { this->drawAtlas(atlas.get(), xform, tex, colors, count, mode, cullRect, paint); } + + /** Draw a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint. + paint uses anti-alias, color alpha, SkColorFilter, SkImageFilter, and SkBlendMode + to draw, if present. For each entry in the array, SkRect tex locates sprite in + atlas, and SkRSXform xform transforms it into destination space. + + xform and text must contain count entries. + Optional cullRect is a conservative bounds of all transformed sprites. + If cullRect is outside of clip, canvas can skip drawing. + + @param atlas SkImage containing sprites + @param xform SkRSXform mappings for sprites in atlas + @param tex SkRect locations of sprites in atlas + @param count number of sprites to draw + @param cullRect SkRect bounds of transformed sprites for efficient clipping; may be nullptr + @param paint SkPaint SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr + */ void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count, const SkRect* cullRect, const SkPaint* paint) { this->drawAtlas(atlas, xform, tex, nullptr, count, SkBlendMode::kDst, cullRect, paint); } + + /** Draw a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint. + paint uses anti-alias, color alpha, SkColorFilter, SkImageFilter, and SkBlendMode + to draw, if present. For each entry in the array, SkRect tex locates sprite in + atlas, and SkRSXform xform transforms it into destination space. + + xform and text must contain count entries. + Optional cullRect is a conservative bounds of all transformed sprites. + If cullRect is outside of clip, canvas can skip drawing. + + @param atlas SkImage containing sprites + @param xform SkRSXform mappings for sprites in atlas + @param tex SkRect locations of sprites in atlas + @param count number of sprites to draw + @param cullRect SkRect bounds of transformed sprites for efficient clipping; may be nullptr + @param paint SkPaint SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr + */ void drawAtlas(const sk_sp& atlas, const SkRSXform xform[], const SkRect tex[], int count, const SkRect* cullRect, const SkPaint* paint) { this->drawAtlas(atlas.get(), xform, tex, nullptr, count, SkBlendMode::kDst, cullRect, paint); } - /** - * Draw the contents of this drawable into the canvas. If the canvas is async - * (e.g. it is recording into a picture) then the drawable will be referenced instead, - * to have its draw() method called when the picture is finalized. - * - * If the intent is to force the contents of the drawable into this canvas immediately, - * then drawable->draw(canvas) may be called. - */ + /** Draw SkDrawable drawable using clip and SkMatrix, concatenated with + optional matrix. + + If SkCanvas has an asynchronous implementation, as is the case + when it is recording into picture, then drawable will be referenced, + so that SkDrawable::draw() can be called when the operation is finalized. To force + immediate drawing, call SkDrawable::draw() instead. + + @param drawable custom struct encapsulating drawing commands + @param matrix transformation applied to drawing; may be nullptr + */ void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr); + + /** Draw SkDrawable drawable using clip and SkMatrix, offset by (x, y). + + If SkCanvas has an asynchronous implementation, as is the case + when it is recording into picture, then drawable will be referenced, + so that SkDrawable::draw() can be called when the operation is finalized. To force + immediate drawing, call SkDrawable::draw() instead. + + @param drawable custom struct encapsulating drawing commands + @param x offset into SkCanvas writable pixels in x + @param y offset into SkCanvas writable pixels in y + */ void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y); - /** - * Send an "annotation" to the canvas. The annotation is a key/value pair, where the key is - * a null-terminated utf8 string, and the value is a blob of data stored in an SkData - * (which may be null). The annotation is associated with the specified rectangle. - * - * The caller still retains its ownership of the data (if any). - * - * Note: on may canvas types, this information is ignored, but some canvases (e.g. recording - * a picture or drawing to a PDF document) will pass on this information. - */ + /** Associate SkRect on SkCanvas when an annotation; a key-value pair, where the key is + a null-terminated utf8 string, and optional value is stored as data. + + Only some canvas implementations, such as recording to picture, or drawing to + document pdf, use annotations. + + @param rect SkRect extent of canvas to annotate + @param key string used for lookup + @param value data holding value stored in annotation + */ void drawAnnotation(const SkRect& rect, const char key[], SkData* value); + + /** Associate SkRect on SkCanvas when an annotation; a key-value pair, where the key is + a null-terminated utf8 string, and optional value is stored as data. + + Only some canvas implementations, such as recording to picture, or drawing to + document pdf, use annotations. + + @param rect SkRect extent of canvas to annotate + @param key string used for lookup + @param value data holding value stored in annotation + */ void drawAnnotation(const SkRect& rect, const char key[], const sk_sp& value) { this->drawAnnotation(rect, key, value.get()); } @@ -1175,42 +2243,36 @@ public: ////////////////////////////////////////////////////////////////////////// #ifdef SK_SUPPORT_LEGACY_DRAWFILTER - /** Get the current filter object. The filter's reference count is not - affected. The filter is saved/restored, just like the matrix and clip. - @return the canvas' filter (or NULL). + /** Legacy call to be deprecated. */ SkDrawFilter* getDrawFilter() const; - /** Set the new filter (or NULL). Pass NULL to clear any existing filter. - As a convenience, the parameter is returned. If an existing filter - exists, its refcnt is decrement. If the new filter is not null, its - refcnt is incremented. The filter is saved/restored, just like the - matrix and clip. - @param filter the new filter (or NULL) - @return the new filter + /** Legacy call to be deprecated. */ virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter); #endif - ////////////////////////////////////////////////////////////////////////// - /** - * Return true if the current clip is empty (i.e. nothing will draw). - * Note: this is not always a free call, so it should not be used - * more often than necessary. However, once the canvas has computed this - * result, subsequent calls will be cheap (until the clip state changes, - * which can happen on any clip..() or restore() call. - */ + /** Returns true if clip is empty; that is, nothing will draw. + + May do work when called; it should not be called + more often than needed. However, once called, subsequent calls perform no + work until clip changes. + + @return true if clip is empty + */ virtual bool isClipEmpty() const; - /** - * Returns true if the current clip is just a (non-empty) rectangle. - * Returns false if the clip is empty, or if it is complex. - */ + /** Returns true if clip is SkRect and not empty. + Returns false if the clip is empty, or if it is not SkRect. + + @return true if clip is SkRect and not empty + */ virtual bool isClipRect() const; - /** Return the current matrix on the canvas. - This does not account for the translate in any of the devices. - @return The current matrix on the canvas. + /** Returns SkMatrix. + This does not account for translation by SkBaseDevice or SkSurface. + + @return SkMatrix in SkCanvas */ const SkMatrix& getTotalMatrix() const; diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index e2937c9ea5..98e3cb2b39 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -57,7 +57,8 @@ class SkTypeface; The objects contained by SkPaint are opaque, and cannot be edited outside of the SkPaint to affect it. The implementation is free to defer computations associated with the SkPaint, or ignore them altogether. For instance, some GPU implementations draw all - SkPath geometries with anti-aliasing, regardless of SkPaint::kAntiAlias_Flag setting. + SkPath geometries with anti-aliasing, regardless of how SkPaint::kAntiAlias_Flag + is set in SkPaint. SkPaint describes a single color, a single font, a single image quality, and so on. Multiple colors are drawn either by using multiple paints or with objects like @@ -74,7 +75,8 @@ public: /** Makes a shallow copy of SkPaint. SkTypeface, SkPathEffect, SkShader, SkMaskFilter, SkColorFilter, SkRasterizer, SkDrawLooper, and SkImageFilter are shared - between the original paint and the copy. These objects' SkRefCnt are increased. + between the original paint and the copy. Objects containing SkRefCnt increment + their references by one. The referenced objects SkPathEffect, SkShader, SkMaskFilter, SkColorFilter, SkRasterizer, SkDrawLooper, and SkImageFilter cannot be modified after they are created. @@ -97,16 +99,16 @@ public: /** Decreases SkPaint SkRefCnt of owned objects: SkTypeface, SkPathEffect, SkShader, SkMaskFilter, SkColorFilter, SkRasterizer, SkDrawLooper, and SkImageFilter. If the - objects' reference count goes to zero, they are deleted. + objects containing SkRefCnt go to zero, they are deleted. */ ~SkPaint(); /** Makes a shallow copy of SkPaint. SkTypeface, SkPathEffect, SkShader, SkMaskFilter, SkColorFilter, SkRasterizer, SkDrawLooper, and SkImageFilter are shared - between the original paint and the copy. The objects' SkRefCnt are in the + between the original paint and the copy. Objects containing SkRefCnt in the prior destination are decreased by one, and the referenced objects are deleted if the - resulting count is zero. The objects' SkRefCnt in the parameter paint are increased - by one. paint is unmodified. + resulting count is zero. Objects containing SkRefCnt in the parameter paint + are increased by one. paint is unmodified. @param paint original to copy @return content of paint @@ -114,9 +116,9 @@ public: SkPaint& operator=(const SkPaint& paint); /** Moves the paint to avoid incrementing the reference counts - of objects referenced by the paint parameter. The objects' SkRefCnt are in the - prior destination are decreased by one, and the referenced objects are deleted if the - resulting count is zero. + of objects referenced by the paint parameter. Objects containing SkRefCnt in the + prior destination are decreased by one; those objects are deleted if the resulting count + is zero. After the call, paint is undefined, and can be safely destructed. @@ -174,7 +176,7 @@ public: SkReadBuffer class is not public, so unflatten() cannot be meaningfully called by the client. - @param buffer serialized data to unflatten + @param buffer serialized data describing SkPaint content */ void unflatten(SkReadBuffer& buffer); @@ -459,7 +461,7 @@ public: return SkToBool(this->getFlags() & kFakeBoldText_Flag); } - /** Use increased stroke width when creating glyph bitmaps to approximate bolding. + /** Use increased stroke width when creating glyph bitmaps to approximate a bold typeface. Sets kFakeBoldText_Flag if fakeBoldText is true. Clears kFakeBoldText_Flag if fakeBoldText is false. @@ -526,9 +528,8 @@ public: kFill_Style, /** Set to stroke geometry. - Applies to SkRect, SkRegion, SkRRect, arcs, circles, ovals, - SkPath, and text. - Arcs, lines, SkPoint, and SkPoint arrays are always drawn as if kStroke_Style is set, + Applies to SkRect, SkRegion, SkRRect, arcs, circles, ovals, SkPath, and text. + Arcs, lines, and SkPoint, are always drawn as if kStroke_Style is set, and ignore the set Style. The stroke construction is unaffected by the FillType. */ @@ -571,7 +572,7 @@ public: SkColor getColor() const { return fColor; } /** Sets alpha and RGB used when stroking and filling. The color is a 32-bit value, - unpremutiplied, packing 8-bit components for alpha, red, blue, and green. + unpremultiplied, packing 8-bit components for alpha, red, blue, and green. @param color Unpremultiplied ARGB */ @@ -579,7 +580,7 @@ public: /** Retrieves alpha from the color used when stroking and filling. - @return alpha ranging from zero, fully transparent, to 255, fully opaque + @return Alpha ranging from zero, fully transparent, to 255, fully opaque */ uint8_t getAlpha() const { return SkToU8(SkColorGetA(fColor)); } @@ -589,18 +590,17 @@ public: a set to zero makes color fully transparent; a set to 255 makes color fully opaque. - @param a alpha component of color + @param a Alpha component of color */ void setAlpha(U8CPU a); /** Sets color used when drawing solid fills. The color components range from 0 to 255. - The color is unpremultiplied; - alpha sets the transparency independent of RGB. + The color is unpremultiplied; alpha sets the transparency independent of RGB. - @param a amount of alpha, from fully transparent (0) to fully opaque (255) - @param r amount of red, from no red (0) to full red (255) - @param g amount of green, from no green (0) to full green (255) - @param b amount of blue, from no blue (0) to full blue (255) + @param a amount of color alpha, from fully transparent (0) to fully opaque (255) + @param r amount of color rgb red, from no red (0) to full red (255) + @param g amount of color rgb green, from no green (0) to full green (255) + @param b amount of color rgb blue, from no blue (0) to full blue (255) */ void setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b); @@ -953,7 +953,7 @@ public: Pass nullptr to clear SkDrawLooper and leave SkDrawLooper effect on drawing unaltered. Does not alter drawLooper SkRefCnt. - @param drawLooper Iterates through drawing one or more time, altering SkPaint + @param drawLooper iterates through drawing one or more time, altering SkPaint */ void setDrawLooper(sk_sp drawLooper); @@ -1100,7 +1100,7 @@ public: /** \struct SkPaint::FontMetrics FontMetrics is filled out by getFontMetrics(). FontMetrics contents reflect the values computed by font manager using SkTypeface. Values are set to zero if they are - not availble. + not available. fUnderlineThickness and fUnderlinePosition have a bit set in fFlags if their values are valid, since their value may be zero. @@ -1208,8 +1208,8 @@ public: SkScalar fStrikeoutPosition; /** If SkPaint::FontMetrics has a valid underline thickness, return true, and set - thickness to that value. If it doesn't, return false, and ignore - thickness. + thickness to that value. If the underline thickness is not valid, + return false, and ignore thickness. @param thickness storage for underline width @return true if font specifies underline width @@ -1223,8 +1223,8 @@ public: } /** If SkPaint::FontMetrics has a valid underline position, return true, and set - position to that value. If it doesn't, return false, and ignore - position. + position to that value. If the underline position is not valid, + return false, and ignore position. @param position storage for underline position @return true if font specifies underline position @@ -1238,8 +1238,8 @@ public: } /** If SkPaint::FontMetrics has a valid strikeout thickness, return true, and set - thickness to that value. If it doesn't, return false, and ignore - thickness. + thickness to that value. If the underline thickness is not valid, + return false, and ignore thickness. @param thickness storage for strikeout width @return true if font specifies strikeout width @@ -1253,8 +1253,8 @@ public: } /** If SkPaint::FontMetrics has a valid strikeout position, return true, and set - position to that value. If it doesn't, return false, and ignore - position. + position to that value. If the underline position is not valid, + return false, and ignore position. @param position storage for strikeout position @return true if font specifies strikeout position @@ -1309,7 +1309,7 @@ public: If SkPaint::TextEncoding is kUTF8_TextEncoding and text contains an invalid UTF-8 sequence, zero is returned. - @param text character stroage encoded with SkPaint::TextEncoding + @param text character storage encoded with SkPaint::TextEncoding @param byteLength length of character storage in bytes @param glyphs storage for glyph indices; may be nullptr @return number of glyphs represented by text of length byteLength @@ -1325,7 +1325,7 @@ public: returns true if all glyph indices in text are non-zero; does not check to see if text contains valid glyph indices for SkTypeface. - Returns true if bytelength is zero. + Returns true if byteLength is zero. @param text array of characters or glyphs @param byteLength number of bytes in text array @@ -1350,7 +1350,7 @@ public: Uses SkPaint::TextEncoding to count the glyphs. Returns the same result as textToGlyphs(). - @param text character stroage encoded with SkPaint::TextEncoding + @param text character storage encoded with SkPaint::TextEncoding @param byteLength length of character storage in bytes @return number of glyphs represented by text of length byteLength */ @@ -1500,7 +1500,7 @@ public: @param pos positions of each glyph @param bounds lower and upper line parallel to the advance @param intervals returned intersections; may be nullptr - @return The number of intersections; may be zero + @return number of intersections; may be zero */ int getPosTextIntercepts(const void* text, size_t length, const SkPoint pos[], const SkScalar bounds[2], SkScalar* intervals) const; @@ -1534,13 +1534,13 @@ public: the string. Uses SkPaint::TextEncoding to decode text, SkTypeface to get the glyph paths, and text size, fake bold, and SkPathEffect to scale and modify the glyph paths. - Uses pos array and SkPaint::Align to position intervals. + Uses run array and SkPaint::Align to position intervals. Pass nullptr for intervals to determine the size of the interval array. intervals are cached to improve performance for multiple calls. - @param blob glyphs, positions, and text paint attributes + @param blob Glyphs, positions, and text paint attributes @param bounds lower and upper line parallel to the advance @param intervals returned intersections; may be nullptr @return number of intersections; may be zero @@ -1564,8 +1564,8 @@ public: /** Returns true if SkPaint prevents all drawing; otherwise, the SkPaint may or may not allow drawing. - Returns true if SkBlendMode and alpha are enabled, - and computed alpha is zero. + Returns true if, for example, SkBlendMode combined with color alpha computes a + new alpha of zero. @return true if SkPaint prevents all drawing */ @@ -1584,13 +1584,13 @@ public: Only call this if canComputeFastBounds() returned true. This takes a raw rectangle (the raw bounds of a shape), and adjusts it for stylistic effects in the paint (e.g. stroking). If needed, it uses the storage - rect parameter. It returns the adjusted bounds that can then be used + parameter. It returns the adjusted bounds that can then be used for SkCanvas::quickReject tests. - The returned rect will either be orig or storage, thus the caller + The returned SkRect will either be orig or storage, thus the caller should not rely on storage being set to the result, but should always - use the retured value. It is legal for orig and storage to be the same - rect. + use the returned value. It is legal for orig and storage to be the same + SkRect. e.g. if (paint.canComputeFastBounds()) { SkRect r, storage; @@ -1635,8 +1635,9 @@ public: } /** (to be made private) - Take the style explicitly, so the caller can force us to be stroked - without having to make a copy of the paint just to change that field. + Computes the bounds, overriding the SkPaint SkPaint::Style. This can be used to + account for additional width required by stroking orig, without + altering SkPaint::Style set to fill. @param orig geometry modified by SkPaint when drawn @param storage computed bounds of geometry @@ -1647,9 +1648,11 @@ public: Style style) const; /** macro expands to: void toString(SkString* str) const; - Converts SkPaint to machine parsable form in developer mode. + Creates string representation of SkPaint. The representation is read by + internal debugging tools. The interface and implementation may be + suppressed by defining SK_IGNORE_TO_STRING. - @param str storage for string containing parsable SkPaint + @param str storage for string representation of SkPaint */ SK_TO_STRING_NONVIRT() diff --git a/include/core/SkPath.h b/include/core/SkPath.h index fb25b03426..e38b464d85 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -17,112 +17,199 @@ class SkRRect; class SkWStream; /** \class SkPath - - The SkPath class encapsulates compound (multiple contour) geometric paths - consisting of straight line segments, quadratic curves, and cubic curves. - - SkPath is not thread safe unless you've first called SkPath::updateBoundsCache(). */ class SK_API SkPath { public: - enum Direction { - /** clockwise direction for adding closed contours */ - kCW_Direction, - /** counter-clockwise direction for adding closed contours */ - kCCW_Direction, - }; +/** \enum SkPath::Direction + Direction describes whether contour is clockwise or counterclockwise. + When SkPath contains multiple overlapping contours, Direction together with + FillType determines whether overlaps are filled or form holes. + + Direction also determines how contour is measured. For instance, dashing + measures along SkPath to determine where to start and stop stroke; Direction + will change dashed results as it steps clockwise or counterclockwise. + + Closed contours like SkRect, SkRRect, circle, and oval added with + kCW_Direction travel clockwise; the same added with kCCW_Direction + travel counterclockwise. +*/ +enum Direction { + kCW_Direction, //!< Contour travels in a clockwise direction. + kCCW_Direction, //!< Contour travels in a counterclockwise direction. +}; + + /** By default, SkPath has no SkPath::Verb, no SkPoint, and no weights. + SkPath::FillType is set to kWinding_FillType. + + @return empty SkPath + */ SkPath(); + + /** Copy constructor makes two paths identical by value. Internally, path and + the returned result share pointer values. The underlying verb array, SkPoint arrays + and weights are copied when modified. + + Creating a SkPath copy is very efficient and never allocates memory. + SkPath are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param path SkPath to copy by value + @return copy of SkPath + */ SkPath(const SkPath& path); + + /** Releases ownership of any shared data and deletes data if SkPath is sole owner. + */ ~SkPath(); + /** SkPath assignment makes two paths identical by value. Internally, assignment + shares pointer values. The underlying verb array, SkPoint arrays and weights + are copied when modified. + + Copying SkPath by assignment is very efficient and never allocates memory. + SkPath are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param path verb array, SkPoint arrays, weights, and SkPath::FillType to copy + @return SkPath copied by value + */ SkPath& operator=(const SkPath& path); - // mac chromium dbg requires SK_API to make operator== visible + + /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint arrays, and weights + are equivalent. + + @param a SkPath to compare + @param b SkPath to compare + @return true if SkPath pair are equivalent + */ friend SK_API bool operator==(const SkPath& a, const SkPath& b); + + /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint arrays, and weights + are not equivalent. + + @param a SkPath to compare + @param b SkPath to compare + @return true if SkPath pair are not equivalent + */ friend bool operator!=(const SkPath& a, const SkPath& b) { return !(a == b); } - /** Return true if the paths contain an equal array of verbs and weights. Paths - * with equal verb counts can be readily interpolated. If the paths contain one - * or more conics, the conics' weights must also match. - * - * @param compare The path to compare. - * - * @return true if the paths have the same verbs and weights. - */ + /** Return true if SkPath contain equal SkPath::Verb and equal weights. + If SkPath contain one or more conics, the weights must match. + + conicTo() may add different SkPath::Verb depending on conic weight, so it is not + trivial to interpolate a pair of SkPath containing conics with different + conic weight values. + + @param compare SkPath to compare + @return true if SkPath verb array and weights are equivalent + */ bool isInterpolatable(const SkPath& compare) const; - /** Interpolate between two paths with same-sized point arrays. - * The out path contains the verbs and weights of this path. - * The out points are a weighted average of this path and the ending path. - * - * @param ending The path to interpolate between. - * @param weight The weight, from 0 to 1. The output points are set to - * (this->points * weight) + ending->points * (1 - weight). - * @return true if the paths could be interpolated. - */ + /** Interpolate between SkPath with equal sized point arrays. + Copy verb array and weights to out, + and set out SkPoint arrays to a weighted average of this SkPoint arrays and ending + SkPoint arrays, using the formula: + + @param ending SkPoint arrays averaged with this SkPoint arrays + @param weight contribution of ending SkPoint arrays, and + one minus contribution of this SkPoint arrays + @param out SkPath replaced by interpolated averages + @return true if SkPath contain same number of SkPoint + */ bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const; #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - /** Returns true if the caller is the only owner of the underlying path data */ + /** To be deprecated; only valid for Android framework. + + @return true if SkPath has one owner + */ bool unique() const { return fPathRef->unique(); } #endif + /** \enum SkPath::FillType + FillType selects the rule used to fill SkPath. SkPath set to kWinding_FillType + fills if the sum of contour edges is not zero, where clockwise edges add one, and + counterclockwise edges subtract one. SkPath set to kEvenOdd_FillType fills if the + number of contour edges is odd. Each FillType has an inverse variant that + reverses the rule: + kInverseWinding_FillType fills where the sum of contour edges is zero; + kInverseEvenOdd_FillType fills where the number of contour edges is even. + */ enum FillType { - /** Specifies that "inside" is computed by a non-zero sum of signed - edge crossings - */ + /** Specifies fill as area is enclosed by a non-zero sum of contour Direction. */ kWinding_FillType, - /** Specifies that "inside" is computed by an odd number of edge - crossings - */ + + /** Specifies fill as area enclosed by an odd number of contours. */ kEvenOdd_FillType, - /** Same as Winding, but draws outside of the path, rather than inside - */ + + /** Specifies fill as area is enclosed by a zero sum of contour Direction. */ kInverseWinding_FillType, - /** Same as EvenOdd, but draws outside of the path, rather than inside - */ + + /** Specifies fill as area enclosed by an even number of contours. */ kInverseEvenOdd_FillType, }; - /** Return the path's fill type. This is used to define how "inside" is - computed. The default value is kWinding_FillType. + /** Returns FillType, the rule used to fill SkPath. FillType of a new SkPath is + kWinding_FillType. - @return the path's fill type + @return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType, + kInverseEvenOdd_FillType */ FillType getFillType() const { return (FillType)fFillType; } - /** Set the path's fill type. This is used to define how "inside" is - computed. The default value is kWinding_FillType. + /** Sets FillType, the rule used to fill SkPath. While there is no check + that ft is legal, values outside of FillType are not supported. - @param ft The new fill type for this path + @param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType, + kInverseEvenOdd_FillType */ void setFillType(FillType ft) { fFillType = SkToU8(ft); } - /** Returns true if the filltype is one of the Inverse variants */ + /** Returns if FillType describes area outside SkPath geometry. The inverse fill area + extends indefinitely. + + @return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType + */ bool isInverseFillType() const { return IsInverseFillType((FillType)fFillType); } - /** - * Toggle between inverse and normal filltypes. This reverse the return - * value of isInverseFillType() - */ + /** Replace FillType with its inverse. The inverse of FillType describes the area + unmodified by the original FillType. + */ void toggleInverseFillType() { fFillType ^= 2; } + /** \enum SkPath::Convexity + SkPath is convex if it contains one contour and contour loops no more than + 360 degrees, and contour angles all have same Direction. Convex SkPath + may have better performance and require fewer resources on GPU surface. + + SkPath is concave when either at least one Direction change is clockwise and + another is counterclockwise, or the sum of the changes in Direction is not 360 + degrees. + + Initially SkPath Convexity is kUnknown_Convexity. SkPath Convexity is computed + if needed by destination SkSurface. + */ enum Convexity { - kUnknown_Convexity, + kUnknown_Convexity, //!< Indicates Convexity has not been determined. + + /** SkPath has one contour made of a simple geometry without indentations. */ kConvex_Convexity, - kConcave_Convexity, + kConcave_Convexity, //!< SkPath has more than one contour, or a geometry with indentations. }; - /** - * Return the path's convexity, as stored in the path. If it is currently unknown, - * then this function will attempt to compute the convexity (and cache the result). - */ + /** Computes SkPath::Convexity if required, and returns stored value. + SkPath::Convexity is computed if stored value is kUnknown_Convexity, + or if SkPath has been altered since SkPath::Convexity was computed or set. + + @return computed or stored SkPath::Convexity + */ Convexity getConvexity() const { if (kUnknown_Convexity != fConvexity) { return static_cast(fConvexity); @@ -131,56 +218,63 @@ public: } } - /** - * Return the currently cached value for convexity, even if that is set to - * kUnknown_Convexity. Note: getConvexity() will automatically call - * ComputeConvexity and cache its return value if the current setting is - * kUnknown. - */ + /** Returns last computed SkPath::Convexity, or kUnknown_Convexity if + SkPath has been altered since SkPath::Convexity was computed or set. + + @return stored SkPath::Convexity + */ Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; } - /** - * Store a convexity setting in the path. There is no automatic check to - * see if this value actually agrees with the return value that would be - * computed by getConvexity(). - * - * Note: even if this is set to a "known" value, if the path is later - * changed (e.g. lineTo(), addRect(), etc.) then the cached value will be - * reset to kUnknown_Convexity. - */ + /** Stores convexity so that it is later returned by getConvexity() or getConvexityOrUnknown(). + convexity may differ from getConvexity(), although setting an incorrect value may + cause incorrect or inefficient drawing. + + If convexity is kUnknown_Convexity: getConvexity() will + compute SkPath::Convexity, and getConvexityOrUnknown() will return kUnknown_Convexity. + + If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity() + and getConvexityOrUnknown() will return convexity until the path is + altered. + + @param convexity one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity + */ void setConvexity(Convexity convexity); - /** - * Returns true if the path is flagged as being convex. This is not a - * confirmed by any analysis, it is just the value set earlier. - */ + /** Computes SkPath::Convexity if required, and returns true if value is kConvex_Convexity. + If setConvexity() was called with kConvex_Convexity or kConcave_Convexity, and + the path has not been altered, SkPath::Convexity is not recomputed. + + @return true if SkPath::Convexity stored or computed is kConvex_Convexity + */ bool isConvex() const { return kConvex_Convexity == this->getConvexity(); } - /** - * Set the isConvex flag to true or false. Convex paths may draw faster if - * this flag is set, though setting this to true on a path that is in fact - * not convex can give undefined results when drawn. Paths default to - * isConvex == false - */ + /** Deprecated. Use setConvexity(). + */ SK_ATTR_DEPRECATED("use setConvexity") void setIsConvex(bool isConvex) { this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity); } - /** Returns true if the path is an oval. - * - * @param rect returns the bounding rect of this oval. It's a circle - * if the height and width are the same. - * @param dir is the oval CCW (or CW if false). - * @param start indicates where the contour starts on the oval (see - * SkPath::addOval for intepretation of the index). - * @return true if this path is an oval. - * Tracking whether a path is an oval is considered an - * optimization for performance and so some paths that are in - * fact ovals can report false. - */ + /** Returns true if constructed by addCircle(), addOval(); and in some cases, + addRoundRect(), addRRect(). SkPath constructed with conicTo() or rConicTo() will not + return true though SkPath draws oval. + + rect receives bounds of oval. + dir receives SkPath::Direction of oval: kCW_Direction if clockwise, kCCW_Direction if + counterclockwise. + start receives start of oval: 0 for top, 1 for right, 2 for bottom, 3 for left. + + rect, dir, and start are unmodified if oval is not found. + + Triggers performance optimizations on some GPU surface implementations. + + @param rect storage for bounding SkRect of oval; may be nullptr + @param dir storage for SkPath::Direction; may be nullptr + @param start storage for start of oval; may be nullptr + @return true if SkPath was constructed by method that reduces to oval + */ bool isOval(SkRect* rect, Direction* dir = nullptr, unsigned* start = nullptr) const { bool isCCW = false; @@ -191,18 +285,24 @@ public: return result; } - /** Returns true if the path is a round rect. - * - * @param rrect Returns the bounding rect and radii of this round rect. - * @param dir is the rrect CCW (or CW if false). - * @param start indicates where the contour starts on the rrect (see - * SkPath::addRRect for intepretation of the index). - * - * @return true if this path is a round rect. - * Tracking whether a path is a round rect is considered an - * optimization for performance and so some paths that are in - * fact round rects can report false. - */ + /** Returns true if constructed by addRoundRect(), addRRect(); and if construction + is not empty, not SkRect, and not oval. SkPath constructed with other calls + will not return true though SkPath draws SkRRect. + + rrect receives bounds of SkRRect. + dir receives SkPath::Direction of oval: kCW_Direction if clockwise, kCCW_Direction if + counterclockwise. + start receives start of SkRRect: 0 for top, 1 for right, 2 for bottom, 3 for left. + + rrect, dir, and start are unmodified if SkRRect is not found. + + Triggers performance optimizations on some GPU surface implementations. + + @param rrect storage for bounding SkRect of SkRRect; may be nullptr + @param dir storage for SkPath::Direction; may be nullptr + @param start storage for start of SkRRect; may be nullptr + @return true if SkPath contains only SkRRect + */ bool isRRect(SkRRect* rrect, Direction* dir = nullptr, unsigned* start = nullptr) const { bool isCCW = false; @@ -213,69 +313,105 @@ public: return result; } - /** Clear any lines and curves from the path, making it empty. This frees up - internal storage associated with those segments. - On Android, does not change fSourcePath. + /** Sets SkPath to its initial state. + Removes verb array, SkPoint arrays, and weights, and sets FillType to kWinding_FillType. + Internal storage associated with SkPath is released. */ void reset(); - /** Similar to reset(), in that all lines and curves are removed from the - path. However, any internal storage for those lines/curves is retained, - making reuse of the path potentially faster. - On Android, does not change fSourcePath. + /** Sets SkPath to its initial state, preserving internal storage. + Removes verb array, SkPoint arrays, and weights, and sets FillType to kWinding_FillType. + Internal storage associated with SkPath is retained. + + Use rewind() instead of reset() if SkPath storage will be reused and performance + is critical. */ void rewind(); - /** Returns true if the path is empty (contains no lines or curves) + /** Empty SkPath may have FillType but has no SkPoint, SkPath::Verb, or conic weight. + SkPath() constructs empty SkPath; reset() and (rewind) make SkPath empty. - @return true if the path is empty (contains no lines or curves) + @return true if the path contains no SkPath::Verb array */ bool isEmpty() const { SkDEBUGCODE(this->validate();) return 0 == fPathRef->countVerbs(); } - /** Return true if the last contour of this path ends with a close verb. - */ + /** Contour is closed if SkPath SkPath::Verb array was last modified by close(). When stroked, + closed contour draws SkPaint::Join instead of SkPaint::Cap at first and last SkPoint. + + @return true if the last contour ends with a kClose_Verb + */ bool isLastContourClosed() const; - /** - * Returns true if all of the points in this path are finite, meaning there - * are no infinities and no NaNs. - */ + /** Returns true for finite SkPoint array values between negative SK_ScalarMax and + positive SK_ScalarMax. Returns false for any SkPoint array value of + SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN. + + @return true if all SkPoint values are finite + */ bool isFinite() const { SkDEBUGCODE(this->validate();) return fPathRef->isFinite(); } - /** Returns true if the path is volatile (i.e. should not be cached by devices.) - */ + /** Returns true if the path is volatile; it will not be altered or discarded + by the caller after it is drawn. SkPath by default have volatile set false, allowing + SkSurface to attach a cache of data which speeds repeated drawing. If true, SkSurface + may not speed repeated drawing. + + @return true if caller will alter SkPath after drawing + */ bool isVolatile() const { return SkToBool(fIsVolatile); } - /** Specify whether this path is volatile. Paths are not volatile by - default. Temporary paths that are discarded or modified after use should be - marked as volatile. This provides a hint to the device that the path - should not be cached. Providing this hint when appropriate can - improve performance by avoiding unnecessary overhead and resource - consumption on the device. - */ + /** Specify whether SkPath is volatile; whether it will be altered or discarded + by the caller after it is drawn. SkPath by default have volatile set false, allowing + SkBaseDevice to attach a cache of data which speeds repeated drawing. + + Mark temporary paths, discarded or modified after use, as volatile + to inform SkBaseDevice that the path need not be cached. + + Mark animating SkPath volatile to improve performance. + Mark unchanging SkPath non-volatile to improve repeated rendering. + + raster surface SkPath draws are affected by volatile for some shadows. + GPU surface SkPath draws are affected by volatile for some shadows and concave geometries. + + @param isVolatile true if caller will alter SkPath after drawing + */ void setIsVolatile(bool isVolatile) { fIsVolatile = isVolatile; } - /** Test a line for zero length + /** Test if line between SkPoint pair is degenerate. + Line with no length or that moves a very short distance is degenerate; it is + treated as a point. - @return true if the line is of zero length; otherwise false. + exact changes the equality test. If true, returns true only if p1 equals p2. + If false, returns true if p1 equals or nearly equals p2. + + @param p1 line start point + @param p2 line end point + @param exact if false, allow nearly equals + @return true if line is degenerate; its length is effectively zero */ static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact) { return exact ? p1 == p2 : p1.equalsWithinTolerance(p2); } - /** Test a quad for zero length + /** Test if quad is degenerate. + Quad with no length or that moves a very short distance is degenerate; it is + treated as a point. - @return true if the quad is of zero length; otherwise false. + @param p1 Quad start point + @param p2 Quad control point + @param p3 Quad end point + @param exact if true, returns true only if p1, p2, and p3 are equal; + if false, returns true if p1, p2, and p3 are equal or nearly equal + @return true if quad is degenerate; its length is effectively zero */ static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3, bool exact) { @@ -283,9 +419,17 @@ public: p2.equalsWithinTolerance(p3); } - /** Test a cubic curve for zero length + /** Test if cubic is degenerate. + Cubic with no length or that moves a very short distance is degenerate; it is + treated as a point. - @return true if the cubic is of zero length; otherwise false. + @param p1 Cubic start point + @param p2 Cubic control point 1 + @param p3 Cubic control point 2 + @param p4 Cubic end point + @param exact if true, returns true only if p1, p2, p3, and p4 are equal; + if false, returns true if p1, p2, p3, and p4 are equal or nearly equal + @return true if cubic is degenerate; its length is effectively zero */ static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3, const SkPoint& p4, bool exact) { @@ -294,329 +438,515 @@ public: p3.equalsWithinTolerance(p4); } - /** - * Returns true if the path specifies a single line (i.e. it contains just - * a moveTo and a lineTo). If so, and line[] is not null, it sets the 2 - * points in line[] to the end-points of the line. If the path is not a - * line, returns false and ignores line[]. - */ + /** Returns true if SkPath contains only one line; + SkPath::Verb array has two entries: kMove_Verb, kLine_Verb. + If SkPath contains one line and line is not nullptr, line is set to + line start point and line end point. + Returns false if SkPath is not one line; line is unaltered. + + @param line storage for line. May be nullptr + @return true if SkPath contains exactly one line + */ bool isLine(SkPoint line[2]) const; - /** Return the number of points in the path - */ + /** Returns the number of points in SkPath. + SkPoint count is initially zero. + + @return SkPath SkPoint array length + */ int countPoints() const; - /** Return the point at the specified index. If the index is out of range - (i.e. is not 0 <= index < countPoints()) then the returned coordinates - will be (0,0) - */ + /** Returns SkPoint at index in SkPoint arrays. Valid range for index is + 0 to countPoints() - 1. + Returns (0, 0) if index is out of range. + + @param index SkPoint array element selector + @return SkPoint array value or (0, 0) + */ SkPoint getPoint(int index) const; - /** Returns the number of points in the path. Up to max points are copied. + /** Returns number of points in SkPath. Up to max points are copied. + points may be nullptr; then, max must be zero. + If max is greater than number of points, excess points storage is unaltered. - @param points If not null, receives up to max points - @param max The maximum number of points to copy into points - @return the actual number of points in the path + @param points storage for SkPath SkPoint array. May be nullptr + @param max maximum to copy; must be greater than or equal to zero + @return SkPath SkPoint array length */ int getPoints(SkPoint points[], int max) const; - /** Return the number of verbs in the path - */ + /** Returns the number of SkPath::Verb: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb, + kCubic_Verb, and kClose_Verb; added to SkPath. + + @return length of verb array + */ int countVerbs() const; /** Returns the number of verbs in the path. Up to max verbs are copied. The verbs are copied as one byte per verb. - @param verbs If not null, receives up to max verbs - @param max The maximum number of verbs to copy into verbs - @return the actual number of verbs in the path + @param verbs storage for verbs, may be nullptr + @param max maximum number to copy into verbs + @return the actual number of verbs in the path */ int getVerbs(uint8_t verbs[], int max) const; - //! Swap contents of this and other. Guaranteed not to throw + /** Exchanges the verb array, SkPoint arrays, weights, and SkPath::FillType with other. + Cached state is also exchanged. swap() internally exchanges pointers, so + it is lightweight and does not allocate memory. + + swap() usage has largely been replaced by operator=(const SkPath& path). + SkPath do not copy their content on assignment until they are written to, + making assignment as efficient as swap(). + + @param other SkPath exchanged by value + */ void swap(SkPath& other); - /** - * Returns the bounds of the path's points. If the path contains zero points/verbs, this - * will return the "empty" rect [0, 0, 0, 0]. - * Note: this bounds may be larger than the actual shape, since curves - * do not extend as far as their control points. Additionally this bound encompases all points, - * even isolated moveTos either preceeding or following the last non-degenerate contour. + /** Returns minimum and maximum x and y values of SkPoint arrays. + Returns (0, 0, 0, 0) if SkPath contains no points. Returned bounds width and height may + be larger or smaller than area affected when SkPath is drawn. + + SkRect returned includes all SkPoint added to SkPath, including SkPoint associated with + kMove_Verb that define empty contours. + + @return bounds of all SkPoint in SkPoint arrays */ const SkRect& getBounds() const { return fPathRef->getBounds(); } - /** Calling this will, if the internal cache of the bounds is out of date, - update it so that subsequent calls to getBounds will be instantaneous. - This also means that any copies or simple transformations of the path - will inherit the cached bounds. - */ + /** Update internal bounds so that subsequent calls to getBounds() are instantaneous. + Unaltered copies of SkPath may also access cached bounds through getBounds(). + + For now, identical to calling getBounds() and ignoring the returned value. + + Call to prepare SkPath subsequently drawn from multiple threads, + to avoid a race condition where each draw separately computes the bounds. + */ void updateBoundsCache() const { // for now, just calling getBounds() is sufficient this->getBounds(); } - /** - * Computes a bounds that is conservatively "snug" around the path. This assumes that the - * path will be filled. It does not attempt to collapse away contours that are logically - * empty (e.g. moveTo(x, y) + lineTo(x, y)) but will include them in the calculation. - * - * It differs from getBounds() in that it will look at the snug bounds of curves, whereas - * getBounds() just returns the bounds of the control-points. Thus computing this may be - * slower than just calling getBounds(). - * - * If the path is empty (i.e. no points or verbs), it will return SkRect::MakeEmpty(). - */ + /** Returns minimum and maximum x and y values of the lines and curves in SkPath. + Returns (0, 0, 0, 0) if SkPath contains no points. + Returned bounds width and height may be larger or smaller than area affected + when SkPath is drawn. + + Includes SkPoint associated with kMove_Verb that define empty + contours. + + Behaves identically to getBounds() when SkPath contains + only lines. If SkPath contains curves, computed bounds includes + the maximum extent of the quad, conic, or cubic; is slower than getBounds(); + and unlike getBounds(), does not cache the result. + + @return tight bounds of curves in SkPath + */ SkRect computeTightBounds() const; - /** - * Does a conservative test to see whether a rectangle is inside a path. Currently it only - * will ever return true for single convex contour paths. The empty-status of the rect is not - * considered (e.g. a rect that is a point can be inside a path). Points or line segments where - * the rect edge touches the path border are not considered containment violations. - */ + /** Returns true if rect is contained by SkPath. + May return false when rect is contained by SkPath. + + For now, only returns true if SkPath has one contour and is convex. + rect may share points and edges with SkPath and be contained. + Returns true if rect is empty, that is, it has zero width or height; and + the SkPoint or line described by rect is contained by SkPath. + + @param rect SkRect, line, or SkPoint checked for containment + @return true if rect is contained + */ bool conservativelyContainsRect(const SkRect& rect) const; - // Construction methods + /** grows SkPath verb array and SkPoint arrays to contain extraPtCount additional SkPoint. + May improve performance and use less memory by + reducing the number and size of allocations when creating SkPath. - /** Hint to the path to prepare for adding more points. This can allow the - path to more efficiently grow its storage. - - @param extraPtCount The number of extra points the path should - preallocate for. + @param extraPtCount number of additional SkPoint to allocate */ void incReserve(unsigned extraPtCount); - /** Set the beginning of the next contour to the point (x,y). + /** Adds beginning of contour at SkPoint (x, y). - @param x The x-coordinate of the start of a new contour - @param y The y-coordinate of the start of a new contour + @param x x-coordinate of contour start + @param y y-coordinate of contour start */ void moveTo(SkScalar x, SkScalar y); - /** Set the beginning of the next contour to the point + /** Adds beginning of contour at SkPoint p. - @param p The start of a new contour + @param p contour start */ void moveTo(const SkPoint& p) { this->moveTo(p.fX, p.fY); } - /** Set the beginning of the next contour relative to the last point on the - previous contour. If there is no previous contour, this is treated the - same as moveTo(). + /** Adds beginning of contour relative to last point. + If SkPath is empty, starts contour at (dx, dy). + Otherwise, start contour at last point offset by (dx, dy). + Function name stands for "relative move to". - @param dx The amount to add to the x-coordinate of the end of the - previous contour, to specify the start of a new contour - @param dy The amount to add to the y-coordinate of the end of the - previous contour, to specify the start of a new contour + @param dx offset from last point x to contour start x + @param dy offset from last point y to contour start y */ void rMoveTo(SkScalar dx, SkScalar dy); - /** Add a line from the last point to the specified point (x,y). If no - moveTo() call has been made for this contour, the first point is - automatically set to (0,0). + /** Adds line from last point to (x, y). If SkPath is empty, or last SkPath::Verb is + kClose_Verb, last point is set to (0, 0) before adding line. - @param x The x-coordinate of the end of a line - @param y The y-coordinate of the end of a line + lineTo() appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, if needed. + lineTo() then appends kLine_Verb to verb array and (x, y) to SkPoint arrays. + + @param x end of added line in x + @param y end of added line in y */ void lineTo(SkScalar x, SkScalar y); - /** Add a line from the last point to the specified point. If no moveTo() - call has been made for this contour, the first point is automatically - set to (0,0). + /** Adds line from last point to SkPoint p. If SkPath is empty, or last SkPath::Verb is + kClose_Verb, last point is set to (0, 0) before adding line. - @param p The end of a line + lineTo() first appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, if needed. + lineTo() then appends kLine_Verb to verb array and SkPoint p to SkPoint arrays. + + @param p end SkPoint of added line */ void lineTo(const SkPoint& p) { this->lineTo(p.fX, p.fY); } - /** Same as lineTo, but the coordinates are considered relative to the last - point on this contour. If there is no previous point, then a moveTo(0,0) - is inserted automatically. + /** Adds line from last point to SkVector (dx, dy). If SkPath is empty, or last SkPath::Verb is + kClose_Verb, last point is set to (0, 0) before adding line. - @param dx The amount to add to the x-coordinate of the previous point - on this contour, to specify a line - @param dy The amount to add to the y-coordinate of the previous point - on this contour, to specify a line + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, if needed; + then appends kLine_Verb to verb array and line end to SkPoint arrays. + Line end is last point plus SkVector (dx, dy). + Function name stands for "relative line to". + + @param dx offset from last point x to line end x + @param dy offset from last point y to line end y */ void rLineTo(SkScalar dx, SkScalar dy); - /** Add a quadratic bezier from the last point, approaching control point - (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for - this contour, the first point is automatically set to (0,0). + /** Adds quad from last point towards (x1, y1), to (x2, y2). + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding quad. - @param x1 The x-coordinate of the control point on a quadratic curve - @param y1 The y-coordinate of the control point on a quadratic curve - @param x2 The x-coordinate of the end point on a quadratic curve - @param y2 The y-coordinate of the end point on a quadratic curve + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, if needed; + then appends kQuad_Verb to verb array; and (x1, y1), (x2, y2) + to SkPoint arrays. + + @param x1 control SkPoint of quad in x + @param y1 control SkPoint of quad in y + @param x2 end SkPoint of quad in x + @param y2 end SkPoint of quad in y */ void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); - /** Add a quadratic bezier from the last point, approaching control point - p1, and ending at p2. If no moveTo() call has been made for this - contour, the first point is automatically set to (0,0). + /** Adds quad from last point towards SkPoint p1, to SkPoint p2. + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding quad. - @param p1 The control point on a quadratic curve - @param p2 The end point on a quadratic curve + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, if needed; + then appends kQuad_Verb to verb array; and SkPoint p1, p2 + to SkPoint arrays. + + @param p1 control SkPoint of added quad + @param p2 end SkPoint of added quad */ void quadTo(const SkPoint& p1, const SkPoint& p2) { this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); } - /** Same as quadTo, but the coordinates are considered relative to the last - point on this contour. If there is no previous point, then a moveTo(0,0) - is inserted automatically. + /** Adds quad from last point towards SkVector (dx1, dy1), to SkVector (dx2, dy2). + If SkPath is empty, or last SkPath::Verb + is kClose_Verb, last point is set to (0, 0) before adding quad. - @param dx1 The amount to add to the x-coordinate of the last point on - this contour, to specify the control point of a quadratic curve - @param dy1 The amount to add to the y-coordinate of the last point on - this contour, to specify the control point of a quadratic curve - @param dx2 The amount to add to the x-coordinate of the last point on - this contour, to specify the end point of a quadratic curve - @param dy2 The amount to add to the y-coordinate of the last point on - this contour, to specify the end point of a quadratic curve + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, + if needed; then appends kQuad_Verb to verb array; and appends quad + control and quad end to SkPoint arrays. + Quad control is last point plus SkVector (dx1, dy1). + Quad end is last point plus SkVector (dx2, dy2). + Function name stands for "relative quad to". + + @param dx1 offset from last point x to quad control x + @param dy1 offset from last point x to quad control y + @param dx2 offset from last point x to quad end x + @param dy2 offset from last point x to quad end y */ void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); + /** Adds conic from last point towards (x1, y1), to (x2, y2), weighted by w. + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding conic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, if needed. + + If w is finite and not one, appends kConic_Verb to verb array; + and (x1, y1), (x2, y2) to SkPoint arrays; and w to conic weights. + + If w is one, appends kQuad_Verb to verb array, and + (x1, y1), (x2, y2) to SkPoint arrays. + + If w is not finite, appends kLine_Verb twice to verb array, and + (x1, y1), (x2, y2) to SkPoint arrays. + + @param x1 control SkPoint of conic in x + @param y1 control SkPoint of conic in y + @param x2 end SkPoint of conic in x + @param y2 end SkPoint of conic in y + @param w weight of added conic + */ void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w); + + /** Adds conic from last point towards SkPoint p1, to SkPoint p2, weighted by w. + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding conic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, if needed. + + If w is finite and not one, appends kConic_Verb to verb array; + and SkPoint p1, p2 to SkPoint arrays; and w to conic weights. + + If w is one, appends kQuad_Verb to verb array, and SkPoint p1, p2 + to SkPoint arrays. + + If w is not finite, appends kLine_Verb twice to verb array, and + SkPoint p1, p2 to SkPoint arrays. + + @param p1 control SkPoint of added conic + @param p2 end SkPoint of added conic + @param w weight of added conic + */ void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) { this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w); } + + /** Adds conic from last point towards SkVector (dx1, dy1), to SkVector (dx2, dy2), + weighted by w. If SkPath is empty, or last SkPath::Verb + is kClose_Verb, last point is set to (0, 0) before adding conic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, + if needed. + + If w is finite and not one, next appends kConic_Verb to verb array, + and w is recorded as conic weight; otherwise, if w is one, appends + kQuad_Verb to verb array; or if w is not finite, appends kLine_Verb + twice to verb array. + + In all cases appends SkPoint control and end to SkPoint arrays. + control is last point plus SkVector (dx1, dy1). + end is last point plus SkVector (dx2, dy2). + + Function name stands for "relative conic to". + + @param dx1 offset from last point x to conic control x + @param dy1 offset from last point x to conic control y + @param dx2 offset from last point x to conic end x + @param dy2 offset from last point x to conic end y + @param w weight of added conic + */ void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, SkScalar w); - /** Add a cubic bezier from the last point, approaching control points - (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been - made for this contour, the first point is automatically set to (0,0). + /** Adds cubic from last point towards (x1, y1), then towards (x2, y2), ending at + (x3, y3). If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to + (0, 0) before adding cubic. - @param x1 The x-coordinate of the 1st control point on a cubic curve - @param y1 The y-coordinate of the 1st control point on a cubic curve - @param x2 The x-coordinate of the 2nd control point on a cubic curve - @param y2 The y-coordinate of the 2nd control point on a cubic curve - @param x3 The x-coordinate of the end point on a cubic curve - @param y3 The y-coordinate of the end point on a cubic curve + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, if needed; + then appends kCubic_Verb to verb array; and (x1, y1), (x2, y2), (x3, y3) + to SkPoint arrays. + + @param x1 first control SkPoint of cubic in x + @param y1 first control SkPoint of cubic in y + @param x2 second control SkPoint of cubic in x + @param y2 second control SkPoint of cubic in y + @param x3 end SkPoint of cubic in x + @param y3 end SkPoint of cubic in y */ void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3); - /** Add a cubic bezier from the last point, approaching control points p1 - and p2, and ending at p3. If no moveTo() call has been made for this - contour, the first point is automatically set to (0,0). + /** Adds cubic from last point towards SkPoint p1, then towards SkPoint p2, ending at + SkPoint p3. If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to + (0, 0) before adding cubic. - @param p1 The 1st control point on a cubic curve - @param p2 The 2nd control point on a cubic curve - @param p3 The end point on a cubic curve + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, if needed; + then appends kCubic_Verb to verb array; and SkPoint p1, p2, p3 + to SkPoint arrays. + + @param p1 first control SkPoint of cubic + @param p2 second control SkPoint of cubic + @param p3 end SkPoint of cubic */ void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); } - /** Same as cubicTo, but the coordinates are considered relative to the - current point on this contour. If there is no previous point, then a - moveTo(0,0) is inserted automatically. + /** Adds cubic from last point towards SkVector (dx1, dy1), then towards + SkVector (dx2, dy2), to SkVector (dx3, dy3). + If SkPath is empty, or last SkPath::Verb + is kClose_Verb, last point is set to (0, 0) before adding cubic. - @param x1 The amount to add to the x-coordinate of the last point on - this contour, to specify the 1st control point of a cubic curve - @param y1 The amount to add to the y-coordinate of the last point on - this contour, to specify the 1st control point of a cubic curve - @param x2 The amount to add to the x-coordinate of the last point on - this contour, to specify the 2nd control point of a cubic curve - @param y2 The amount to add to the y-coordinate of the last point on - this contour, to specify the 2nd control point of a cubic curve - @param x3 The amount to add to the x-coordinate of the last point on - this contour, to specify the end point of a cubic curve - @param y3 The amount to add to the y-coordinate of the last point on - this contour, to specify the end point of a cubic curve + Appends kMove_Verb to verb array and (0, 0) to SkPoint arrays, + if needed; then appends kCubic_Verb to verb array; and appends cubic + control and cubic end to SkPoint arrays. + Cubic control is last point plus SkVector (dx1, dy1). + Cubic end is last point plus SkVector (dx2, dy2). + Function name stands for "relative cubic to". + + @param x1 offset from last point x to first cubic control x + @param y1 offset from last point x to first cubic control y + @param x2 offset from last point x to second cubic control x + @param y2 offset from last point x to second cubic control y + @param x3 offset from last point x to cubic end x + @param y3 offset from last point x to cubic end y */ void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3); - /** - * Append the specified arc to the path. If the start of the arc is different from the path's - * current last point, then an automatic lineTo() is added to connect the current contour - * to the start of the arc. However, if the path is empty, then we call moveTo() with - * the first point of the arc. The sweep angle is treated mod 360. - * - * @param oval The bounding oval defining the shape and size of the arc - * @param startAngle Starting angle (in degrees) where the arc begins - * @param sweepAngle Sweep angle (in degrees) measured clockwise. This is treated mod 360. - * @param forceMoveTo If true, always begin a new contour with the arc - */ + /** Append arc to SkPath. Arc added is part of ellipse + bounded by oval, from startAngle through sweepAngle. Both startAngle and + sweepAngle are measured in degrees, where zero degrees is aligned with the + positive x-axis, and positive sweeps extends arc clockwise. + + arcTo() adds line connecting SkPath last SkPoint to initial arc SkPoint if forceMoveTo + is false and SkPath is not empty. Otherwise, added contour begins with first point + of arc. Angles greater than -360 and less than 360 are treated modulo 360. + + @param oval bounds of ellipse containing arc + @param startAngle starting angle of arc in degrees + @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 + @param forceMoveTo true to start a new contour with arc + */ void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo); - /** - * Append a line and arc to the current path. This is the same as the PostScript call "arct". - */ + /** Append arc to SkPath, after appending line if needed. Arc is implemented by conic + weighted to describe part of circle. Arc is contained by tangent from + last SkPath point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc + is part of circle sized to radius, positioned so it touches both tangent lines. + + @param x1 x common to pair of tangents + @param y1 y common to pair of tangents + @param x2 x end of second tangent + @param y2 y end of second tangent + @param radius distance from arc to circle center + */ void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius); - /** Append a line and arc to the current path. This is the same as the - PostScript call "arct". + /** Append arc to SkPath, after appending line if needed. Arc is implemented by conic + weighted to describe part of circle. Arc is contained by tangent from + last SkPath point to p1, and tangent from p1 to p2. Arc + is part of circle sized to radius, positioned so it touches both tangent lines. + + If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath. + The length of SkVector from p1 to p2 does not affect arc. + + Arc sweep is always less than 180 degrees. If radius is zero, or if + tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1. + + arcTo() appends at most one line and one conic. + arcTo() implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo. + + @param p1 SkPoint common to pair of tangents + @param p2 end of second tangent + @param radius distance from arc to circle center */ void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); } + /** \enum SkPath::ArcSize + Four oval parts with radii (rx, ry) start at last SkPath SkPoint and ends at (x, y). + ArcSize and Direction select one of the four oval parts. + */ enum ArcSize { - /** the smaller of the two possible SVG arcs. */ - kSmall_ArcSize, - /** the larger of the two possible SVG arcs. */ - kLarge_ArcSize, + kSmall_ArcSize, //!< Smaller of arc pair. + kLarge_ArcSize, //!< Larger of arc pair. }; - /** - * Append an elliptical arc from the current point in the format used by SVG. - * The center of the ellipse is computed to satisfy the constraints below. - * - * @param rx,ry The radii in the x and y directions respectively. - * @param xAxisRotate The angle in degrees relative to the x-axis. - * @param largeArc Determines whether the smallest or largest arc possible - * is drawn. - * @param sweep Determines if the arc should be swept in an anti-clockwise or - * clockwise direction. Note that this enum value is opposite the SVG - * arc sweep value. - * @param x,y The destination coordinates. - */ + /** Append arc to SkPath. Arc is implemented by one or more conics weighted to describe part of oval + with radii (rx, ry) rotated by xAxisRotate degrees. Arc curves from last SkPath SkPoint to (x, y), + choosing one of four possible routes: clockwise or counterclockwise, and smaller or larger. + + Arc sweep is always less than 360 degrees. arcTo() appends line to (x, y) if either radii are zero, + or if last SkPath SkPoint equals (x, y). arcTo() scales radii (rx, ry) to fit last SkPath SkPoint and + (x, y) if both are greater than zero but too small. + + arcTo() appends up to four conic curves. + arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value is + opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while kCW_Direction + cast to int is zero. + + @param rx radius in x before x-axis rotation + @param ry radius in y before x-axis rotation + @param xAxisRotate x-axis rotation in degrees; positive values are clockwise + @param largeArc chooses smaller or larger arc + @param sweep chooses clockwise or counterclockwise arc + @param x end of arc + @param y end of arc + */ void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep, SkScalar x, SkScalar y); + /** Append arc to SkPath. Arc is implemented by one or more conic weighted to describe part of oval + with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves from last SkPath SkPoint to + (xy.fX, xy.fY), choosing one of four possible routes: clockwise or counterclockwise, + and smaller or larger. + + Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either radii are zero, + or if last SkPath SkPoint equals (x, y). arcTo() scales radii r to fit last SkPath SkPoint and + xy if both are greater than zero but too small to describe an arc. + + arcTo() appends up to four conic curves. + arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value is + opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while + kCW_Direction cast to int is zero. + + @param r radii in x and y before x-axis rotation + @param xAxisRotate x-axis rotation in degrees; positive values are clockwise + @param largeArc chooses smaller or larger arc + @param sweep chooses clockwise or counterclockwise arc + @param xy end of arc + */ void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep, const SkPoint xy) { this->arcTo(r.fX, r.fY, xAxisRotate, largeArc, sweep, xy.fX, xy.fY); } - /** Same as arcTo format used by SVG, but the destination coordinate is relative to the - * last point on this contour. If there is no previous point, then a - * moveTo(0,0) is inserted automatically. - * - * @param rx,ry The radii in the x and y directions respectively. - * @param xAxisRotate The angle in degrees relative to the x-axis. - * @param largeArc Determines whether the smallest or largest arc possible - * is drawn. - * @param sweep Determines if the arc should be swept in an anti-clockwise or - * clockwise direction. Note that this enum value is opposite the SVG - * arc sweep value. - * @param dx,dy The destination coordinates relative to the last point. - */ + /** Append arc to SkPath, relative to last SkPath SkPoint. Arc is implemented by one or + more conic, weighted to describe part of oval with radii (rx, ry) rotated by + xAxisRotate degrees. Arc curves from last SkPath SkPoint (x0, y0) to end SkPoint + + @param rx radius in x before x-axis rotation + @param ry radius in y before x-axis rotation + @param xAxisRotate x-axis rotation in degrees; positive values are clockwise + @param largeArc chooses smaller or larger arc + @param sweep chooses clockwise or counterclockwise arc + @param dx x offset end of arc from last SkPath SkPoint + @param dy y offset end of arc from last SkPath SkPoint + */ void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep, SkScalar dx, SkScalar dy); - /** Close the current contour. If the current point is not equal to the - first point of the contour, a line segment is automatically added. + /** Append kClose_Verb to SkPath. A closed contour connects the first and last SkPoint + with line, forming a continuous loop. Open and closed contour draw the same + with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open contour draws + SkPaint::Cap at contour start and end; closed contour draws + SkPaint::Join at contour start and end. + + close() has no effect if SkPath is empty or last SkPath SkPath::Verb is kClose_Verb. */ void close(); - /** - * Returns whether or not a fill type is inverted - * - * kWinding_FillType -> false - * kEvenOdd_FillType -> false - * kInverseWinding_FillType -> true - * kInverseEvenOdd_FillType -> true - */ + /** Returns true if fill is inverted and SkPath with fill represents area outside + of its geometric bounds. + + @param fill one of: kWinding_FillType, kEvenOdd_FillType, + kInverseWinding_FillType, kInverseEvenOdd_FillType + @return true if SkPath fills outside its bounds + */ static bool IsInverseFillType(FillType fill) { static_assert(0 == kWinding_FillType, "fill_type_mismatch"); static_assert(1 == kEvenOdd_FillType, "fill_type_mismatch"); @@ -625,14 +955,13 @@ public: return (fill & 2) != 0; } - /** - * Returns the equivalent non-inverted fill type to the given fill type - * - * kWinding_FillType -> kWinding_FillType - * kEvenOdd_FillType -> kEvenOdd_FillType - * kInverseWinding_FillType -> kWinding_FillType - * kInverseEvenOdd_FillType -> kEvenOdd_FillType - */ + /** Returns equivalent SkPath::FillType representing SkPath fill inside its bounds. + . + + @param fill one of: kWinding_FillType, kEvenOdd_FillType, + kInverseWinding_FillType, kInverseEvenOdd_FillType + @return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted + */ static FillType ConvertToNonInverseFillType(FillType fill) { static_assert(0 == kWinding_FillType, "fill_type_mismatch"); static_assert(1 == kEvenOdd_FillType, "fill_type_mismatch"); @@ -641,225 +970,235 @@ public: return (FillType)(fill & 1); } - /** - * Chop a conic into N quads, stored continguously in pts[], where - * N = 1 << pow2. The amount of storage needed is (1 + 2 * N) - */ + /** Approximates conic with quad array. Conic is constructed from start SkPoint p0, + control SkPoint p1, end SkPoint p2, and weight w. + Quad array is stored in pts; this storage is supplied by caller. + Maximum quad count is 2 to the pow2. + Every third point in array shares last SkPoint of previous quad and first SkPoint of + next quad. Maximum pts storage size is given by: + + @param p0 Conic start SkPoint + @param p1 Conic control SkPoint + @param p2 Conic end SkPoint + @param w Conic weight + @param pts storage for quad array + @param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 quad curves) + @return number of quad curves written to pts + */ static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2, SkScalar w, SkPoint pts[], int pow2); - /** - * Returns true if the path specifies a rectangle. - * - * If this returns false, then all output parameters are ignored, and left - * unchanged. If this returns true, then each of the output parameters - * are checked for NULL. If they are not, they return their value. - * - * @param rect If not null, set to the bounds of the rectangle. - * Note : this bounds may be smaller than the path's bounds, since it is just - * the bounds of the "drawable" parts of the path. e.g. a trailing MoveTo would - * be ignored in this rect, but not by the path's bounds - * @param isClosed If not null, set to true if the path is closed - * @param direction If not null, set to the rectangle's direction - * @return true if the path specifies a rectangle - */ + /** Returns true if SkPath is equivalent to SkRect when filled. + If false: rect, isClosed, and direction are unchanged. + If true: rect, isClosed, and direction are written to if not nullptr. + + rect may be smaller than the SkPath bounds. SkPath bounds may include kMove_Verb points + that do not alter the area drawn by the returned rect. + + @param rect storage for bounds of SkRect; may be nullptr + @param isClosed storage set to true if SkPath is closed; may be nullptr + @param direction storage set to SkRect direction; may be nullptr + @return true if SkPath contains SkRect + */ bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const; - /** Returns true if the path specifies a pair of nested rectangles, or would draw a - pair of nested rectangles when filled. If so, and if - rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner - rectangle. If so, and dirs is not null, set dirs[0] to the direction of - the outer rectangle and dirs[1] to the direction of the inner rectangle. If - the path does not specify a pair of nested rectangles, return - false and ignore rect and dirs. + /** Returns true if SkPath is equivalent to nested SkRect pair when filled. + If false, rect and dirs are unchanged. + If true, rect and dirs are written to if not nullptr: + setting rect[0] to outer SkRect, and rect[1] to inner SkRect; + setting dirs[0] to SkPath::Direction of outer SkRect, and dirs[1] to SkPath::Direction of inner + SkRect. - @param rect If not null, returns the path as a pair of nested rectangles - @param dirs If not null, returns the direction of the rects - @return true if the path describes a pair of nested rectangles + @param rect storage for SkRect pair; may be nullptr + @param dirs storage for SkPath::Direction pair; may be nullptr + @return true if SkPath contains nested SkRect pair */ bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const; - /** - * Add a closed rectangle contour to the path - * @param rect The rectangle to add as a closed contour to the path - * @param dir The direction to wind the rectangle's contour. - * - * Note: the contour initial point index is 0 (as defined below). - */ + /** Add SkRect to SkPath, appending kMove_Verb, three kLine_Verb, and kClose_Verb, + starting with top-left corner of SkRect; followed by top-right, bottom-right, + and bottom-left if dir is kCW_Direction; or followed by bottom-left, + bottom-right, and top-right if dir is kCCW_Direction. + + @param rect SkRect to add as a closed contour + @param dir SkPath::Direction to wind added contour + */ void addRect(const SkRect& rect, Direction dir = kCW_Direction); - /** - * Add a closed rectangle contour to the path - * @param rect The rectangle to add as a closed contour to the path - * @param dir The direction to wind the rectangle's contour. - * @param start Initial point of the contour (initial moveTo), expressed as - * a corner index, starting in the upper-left position, clock-wise: - * - * 0 1 - * *-------* - * | | - * *-------* - * 3 2 - */ + /** Add SkRect to SkPath, appending kMove_Verb, three kLine_Verb, and kClose_Verb. + If dir is kCW_Direction, SkRect corners are added clockwise; if dir is + kCCW_Direction, SkRect corners are added counterclockwise. + start determines the first corner added. + + @param rect SkRect to add as a closed contour + @param dir SkPath::Direction to wind added contour + @param start initial corner of SkRect to add + */ void addRect(const SkRect& rect, Direction dir, unsigned start); - /** - * Add a closed rectangle contour to the path - * - * @param left The left side of a rectangle to add as a closed contour - * to the path - * @param top The top of a rectangle to add as a closed contour to the - * path - * @param right The right side of a rectangle to add as a closed contour - * to the path - * @param bottom The bottom of a rectangle to add as a closed contour to - * the path - * @param dir The direction to wind the rectangle's contour. - * - * Note: the contour initial point index is 0 (as defined above). - */ + /** Add SkRect (left, top, right, bottom) to SkPath, + appending kMove_Verb, three kLine_Verb, and kClose_Verb, + starting with top-left corner of SkRect; followed by top-right, bottom-right, + and bottom-left if dir is kCW_Direction; or followed by bottom-left, + bottom-right, and top-right if dir is kCCW_Direction. + + @param left smaller x of SkRect + @param top smaller y of SkRect + @param right larger x of SkRect + @param bottom larger y of SkRect + @param dir SkPath::Direction to wind added contour + */ void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, Direction dir = kCW_Direction); - /** - * Add a closed oval contour to the path - * - * @param oval The bounding oval to add as a closed contour to the path - * @param dir The direction to wind the oval's contour. - * - * Note: the contour initial point index is 1 (as defined below). - */ + /** Add oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb. + Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width + and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues + clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction. + + This form is identical to addOval(oval, dir, 1). + + @param oval bounds of ellipse added + @param dir SkPath::Direction to wind ellipse + */ void addOval(const SkRect& oval, Direction dir = kCW_Direction); - /** - * Add a closed oval contour to the path - * - * @param oval The bounding oval to add as a closed contour to the path - * @param dir The direction to wind the oval's contour. - * @param start Initial point of the contour (initial moveTo), expressed - * as an ellipse vertex index, starting at the top, clock-wise - * (90/0/270/180deg order): - * - * 0 - * -*- - * | | - * 3 * * 1 - * | | - * -*- - * 2 - */ + /** Add oval to SkPath, appending kMove_Verb, four kConic_Verb, and kClose_Verb. + Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width + and half oval height. Oval begins at start and continues + clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction. + + @param oval bounds of ellipse added + @param dir SkPath::Direction to wind ellipse + @param start index of initial point of ellipse + */ void addOval(const SkRect& oval, Direction dir, unsigned start); - /** - * Add a closed circle contour to the path. The circle contour begins at - * the right-most point (as though 1 were passed to addOval's 'start' param). - * - * @param x The x-coordinate of the center of a circle to add as a - * closed contour to the path - * @param y The y-coordinate of the center of a circle to add as a - * closed contour to the path - * @param radius The radius of a circle to add as a closed contour to the - * path - * @param dir The direction to wind the circle's contour. - */ + /** Add circle centered at (x, y) of size radius to SkPath, appending kMove_Verb, + four kConic_Verb, and kClose_Verb. Circle begins at + + @param x center of circle + @param y center of circle + @param radius distance from center to edge + @param dir SkPath::Direction to wind circle + */ void addCircle(SkScalar x, SkScalar y, SkScalar radius, Direction dir = kCW_Direction); - /** Add the specified arc to the path as a new contour. + /** Append arc to SkPath, as the start of new contour. Arc added is part of ellipse + bounded by oval, from startAngle through sweepAngle. Both startAngle and + sweepAngle are measured in degrees, where zero degrees is aligned with the + positive x-axis, and positive sweeps extends arc clockwise. - @param oval The bounds of oval used to define the size of the arc - @param startAngle Starting angle (in degrees) where the arc begins - @param sweepAngle Sweep angle (in degrees) measured clockwise + If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly + zero, append oval instead of arc. Otherwise, sweepAngle values are treated + modulo 360, and arc may or may not draw depending on numeric rounding. + + @param oval bounds of ellipse containing arc + @param startAngle starting angle of arc in degrees + @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 */ void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); - /** - * Add a closed round-rectangle contour to the path - * @param rect The bounds of a round-rectangle to add as a closed contour - * @param rx The x-radius of the rounded corners on the round-rectangle - * @param ry The y-radius of the rounded corners on the round-rectangle - * @param dir The direction to wind the rectangle's contour. - */ + /** Append SkRRect to SkPath, creating a new closed contour. SkRRect has bounds + equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If + dir is kCW_Direction, SkRRect starts at top-left of the lower-left corner and + winds clockwise. If dir is kCCW_Direction, SkRRect starts at the bottom-left + of the upper-left corner and winds counterclockwise. + + If either rx or ry is too large, rx and ry are scaled uniformly until the + corners fit. If rx or ry is less than or equal to zero, addRoundRect() appends + SkRect rect to SkPath. + + After appending, SkPath may be empty, or may contain: SkRect, oval, or RoundRect. + + @param rect bounds of SkRRect + @param rx x-radius of rounded corners on the SkRRect + @param ry y-radius of rounded corners on the SkRRect + @param dir SkPath::Direction to wind SkRRect + */ void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, Direction dir = kCW_Direction); - /** - * Add a closed round-rectangle contour to the path. Each corner receives - * two radius values [X, Y]. The corners are ordered top-left, top-right, - * bottom-right, bottom-left. - * @param rect The bounds of a round-rectangle to add as a closed contour - * @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner - * @param dir The direction to wind the rectangle's contour. - * Note: The radii here now go through the same constraint handling as the - * SkRRect radii (i.e., either radii at a corner being 0 implies a - * sqaure corner and oversized radii are proportionally scaled down). - */ + /** Append SkRRect to SkPath, creating a new closed contour. SkRRect has bounds + equal to rect; each corner is 90 degrees of an ellipse with radii from the + array. + + @param rect bounds of SkRRect + @param radii array of 8 SkScalar values, a radius pair for each corner + @param dir SkPath::Direction to wind SkRRect + */ void addRoundRect(const SkRect& rect, const SkScalar radii[], Direction dir = kCW_Direction); - /** - * Add an SkRRect contour to the path - * @param rrect The rounded rect to add as a closed contour - * @param dir The winding direction for the new contour. - * - * Note: the contour initial point index is either 6 (for dir == kCW_Direction) - * or 7 (for dir == kCCW_Direction), as defined below. - * - */ + /** Add rrect to SkPath, creating a new closed contour. If + dir is kCW_Direction, rrect starts at top-left of the lower-left corner and + winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left + of the upper-left corner and winds counterclockwise. + + After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect. + + @param rrect bounds and radii of rounded rectangle + @param dir SkPath::Direction to wind SkRRect + */ void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction); - /** - * Add an SkRRect contour to the path - * @param rrect The rounded rect to add as a closed contour - * @param dir The winding direction for the new contour. - * @param start Initial point of the contour (initial moveTo), expressed as - * an index of the radii minor/major points, ordered clock-wise: - * - * 0 1 - * *----* - * 7 * * 2 - * | | - * 6 * * 3 - * *----* - * 5 4 - */ + /** Add rrect to SkPath, creating a new closed contour. If dir is kCW_Direction, rrect + winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise. + start determines the first point of rrect to add. + + @param rrect bounds and radii of rounded rectangle + @param dir SkPath::Direction to wind SkRRect + @param start index of initial point of SkRRect + */ void addRRect(const SkRRect& rrect, Direction dir, unsigned start); - /** - * Add a new contour made of just lines. This is just a fast version of - * the following: - * this->moveTo(pts[0]); - * for (int i = 1; i < count; ++i) { - * this->lineTo(pts[i]); - * } - * if (close) { - * this->close(); - * } - */ + /** Add contour created from line array, adding + + @param pts array of line sharing end and start SkPoint + @param count length of SkPoint array + @param close true to add line connecting contour end and start + */ void addPoly(const SkPoint pts[], int count, bool close); + /** \enum SkPath::AddPathMode + AddPathMode chooses how addPath() appends. Adding one SkPath to another can extend + the last contour or start a new contour. + */ enum AddPathMode { - /** Source path contours are added as new contours. + /** Since SkPath verb array begins with kMove_Verb if src is not empty, this + starts a new contour. */ kAppend_AddPathMode, - /** Path is added by extending the last contour of the destination path - with the first contour of the source path. If the last contour of - the destination path is closed, then it will not be extended. - Instead, the start of source path will be extended by a straight - line to the end point of the destination path. + + /** is not empty, add line from last point to added SkPath first SkPoint. Skip added + SkPath initial kMove_Verb, then append remining Verb, SkPoint, and conic weights. */ kExtend_AddPathMode, }; - /** Add a copy of src to the path, offset by (dx,dy) - @param src The path to add as a new contour - @param dx The amount to translate the path in X as it is added - @param dx The amount to translate the path in Y as it is added + /** Append src to SkPath, offset by (dx, dy). + + If mode is kAppend_AddPathMode, src verb array, SkPoint arrays, and conic weights are + added unaltered. If mode is kExtend_AddPathMode, add line before appending + SkPath::Verb, SkPoint, and conic weights. + + @param src SkPath SkPath::Verb, SkPoint, and conic weights to add + @param dx offset added to src SkPoint arrays x coordinates + @param dy offset added to src SkPoint arrays y coordinates + @param mode kAppend_AddPathMode or kExtend_AddPathMode */ void addPath(const SkPath& src, SkScalar dx, SkScalar dy, AddPathMode mode = kAppend_AddPathMode); - /** Add a copy of src to the path + /** Append src to SkPath. + + If mode is kAppend_AddPathMode, src verb array, SkPoint arrays, and conic weights are + added unaltered. If mode is kExtend_AddPathMode, add line before appending + SkPath::Verb, SkPoint, and conic weights. + + @param src SkPath SkPath::Verb, SkPoint, and conic weights to add + @param mode kAppend_AddPathMode or kExtend_AddPathMode */ void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) { SkMatrix m; @@ -867,127 +1206,198 @@ public: this->addPath(src, m, mode); } - /** Add a copy of src to the path, transformed by matrix - @param src The path to add as a new contour - @param matrix Transform applied to src - @param mode Determines how path is added + /** Append src to SkPath, transformed by matrix. Transformed curves may have different + SkPath::Verb, SkPoint, and conic weights. + + If mode is kAppend_AddPathMode, src verb array, SkPoint arrays, and conic weights are + added unaltered. If mode is kExtend_AddPathMode, add line before appending + SkPath::Verb, SkPoint, and conic weights. + + @param src SkPath SkPath::Verb, SkPoint, and conic weights to add + @param matrix transform applied to src + @param mode kAppend_AddPathMode or kExtend_AddPathMode */ void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode); - /** - * Same as addPath(), but reverses the src input - */ + /** Append src to SkPath, from back to front. + Reversed src always appends a new contour to SkPath. + + @param src SkPath SkPath::Verb, SkPoint, and conic weights to add + */ void reverseAddPath(const SkPath& src); - /** Offset the path by (dx,dy), returning true on success + /** Offset SkPoint arrays by (dx, dy). Offset SkPath replaces dst. + If dst is nullptr, SkPath is replaced by offset data. - @param dx The amount in the X direction to offset the entire path - @param dy The amount in the Y direction to offset the entire path - @param dst The translated path is written here + @param dx offset added to SkPoint arrays x coordinates + @param dy offset added to SkPoint arrays y coordinates + @param dst overwritten, translated copy of SkPath; may be nullptr */ void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; - /** Offset the path by (dx,dy), returning true on success + /** Offset SkPoint arrays by (dx, dy). Offset SkPath replaces dst. + If dst is nullptr, SkPath is replaced by offset data. - @param dx The amount in the X direction to offset the entire path - @param dy The amount in the Y direction to offset the entire path + @param dx offset added to SkPoint arrays x coordinates + @param dy offset added to SkPoint arrays y coordinates + @param dst overwritten, translated copy of SkPath; may be nullptr */ void offset(SkScalar dx, SkScalar dy) { this->offset(dx, dy, this); } - /** Transform the points in this path by matrix, and write the answer into - dst. + /** Transform verb array, SkPoint arrays, and weight by matrix. + transform may change SkPath::Verb and increase their number. + Transformed SkPath replaces dst; if dst is nullptr, original data + is replaced. - @param matrix The matrix to apply to the path - @param dst The transformed path is written here + @param matrix SkMatrix to apply to SkPath + @param dst overwritten, transformed copy of SkPath; may be nullptr */ void transform(const SkMatrix& matrix, SkPath* dst) const; - /** Transform the points in this path by matrix + /** Transform verb array, SkPoint arrays, and weight by matrix. + transform may change SkPath::Verb and increase their number. + Transformed SkPath replaces dst; if dst is nullptr, original data + is replaced. - @param matrix The matrix to apply to the path + @param matrix SkMatrix to apply to SkPath + @param dst overwritten, transformed copy of SkPath; may be nullptr */ void transform(const SkMatrix& matrix) { this->transform(matrix, this); } - /** Return the last point on the path. If no points have been added, (0,0) - is returned. If there are no points, this returns false, otherwise it - returns true. + /** Returns last point on SkPath in lastPt. Returns false if SkPoint arrays is empty, + storing (0, 0) if lastPt is not nullptr. - @param lastPt The last point on the path is returned here + @param lastPt storage for final SkPoint in SkPoint arrays; may be nullptr + @return true if SkPoint arrays contains one or more SkPoint */ bool getLastPt(SkPoint* lastPt) const; - /** Set the last point on the path. If no points have been added, - moveTo(x,y) is automatically called. + /** Set last point to (x, y). If SkPoint arrays is empty, append kMove_Verb to + verb array and (x, y) to SkPoint arrays. - @param x The new x-coordinate for the last point - @param y The new y-coordinate for the last point + @param x set x-coordinate of last point + @param y set y-coordinate of last point */ void setLastPt(SkScalar x, SkScalar y); /** Set the last point on the path. If no points have been added, moveTo(p) is automatically called. - @param p The new location for the last point + @param p set value of last point */ void setLastPt(const SkPoint& p) { this->setLastPt(p.fX, p.fY); } + /** \enum SkPath::SegmentMask + SegmentMask constants correspond to each drawing Verb type in SkPath; for + instance, if SkPath only contains lines, only the kLine_SegmentMask bit is set. + */ enum SegmentMask { - kLine_SegmentMask = 1 << 0, - kQuad_SegmentMask = 1 << 1, - kConic_SegmentMask = 1 << 2, - kCubic_SegmentMask = 1 << 3, + kLine_SegmentMask = 1 << 0, //!< Set if verb array contains kLine_Verb. + + /** Set if verb array contains kQuad_Verb. Note that conicTo() may add a quad. */ + kQuad_SegmentMask = 1 << 1, + kConic_SegmentMask = 1 << 2, //!< Set if verb array contains kConic_Verb. + kCubic_SegmentMask = 1 << 3, //!< Set if verb array contains kCubic_Verb. }; - /** - * Returns a mask, where each bit corresponding to a SegmentMask is - * set if the path contains 1 or more segments of that type. - * Returns 0 for an empty path (no segments). - */ + /** Returns a mask, where each set bit corresponds to a SegmentMask constant + if SkPath contains one or more SkPath::Verb of that type. + Returns zero if SkPath contains no lines, or curves: quads, conics, or cubics. + + getSegmentMasks() returns a cached result; it is very fast. + + @return SegmentMask bits or zero + */ uint32_t getSegmentMasks() const { return fPathRef->getSegmentMasks(); } + /** \enum SkPath::Verb + Verb instructs SkPath how to interpret one or more SkPoint and optional conic weight; + manage contour, and terminate SkPath. + */ enum Verb { - kMove_Verb, //!< iter.next returns 1 point - kLine_Verb, //!< iter.next returns 2 points - kQuad_Verb, //!< iter.next returns 3 points - kConic_Verb, //!< iter.next returns 3 points + iter.conicWeight() - kCubic_Verb, //!< iter.next returns 4 points - kClose_Verb, //!< iter.next returns 0 points - kDone_Verb, //!< iter.next returns 0 points + kMove_Verb, //!< Starts new contour at next SkPoint. + + /** Adds line from last point to next SkPoint. + Line is a straight segment from SkPoint to SkPoint. + */ + kLine_Verb, + + /** Adds quad from last point, using control SkPoint, and end SkPoint. + Quad is a parabolic section within tangents from last point to control SkPoint, + and control SkPoint to end SkPoint. + */ + kQuad_Verb, + + /** Adds conic from last point, using control SkPoint, end SkPoint, and conic weight. + Conic is a elliptical, parabolic, or hyperbolic section within tangents + from last point to control SkPoint, and control SkPoint to end SkPoint, constrained + by conic weight. conic weight less than one is elliptical; equal to one is + parabolic (and identical to Quad); greater than one hyperbolic. + */ + kConic_Verb, + + /** Adds cubic from last point, using two control SkPoint, and end SkPoint. + Cubic is a third-order Bezier section within tangents from last point to + first control SkPoint, and from second control SkPoint to end SkPoint. + */ + kCubic_Verb, + kClose_Verb, //!< Closes contour, connecting last point to kMove_Verb SkPoint. + kDone_Verb, //!< Terminates SkPath. Not in verb array, but returned by SkPath iterator. }; - /** Iterate through all of the segments (lines, quadratics, cubics) of - each contours in a path. - - The iterator cleans up the segments along the way, removing degenerate - segments and adding close verbs where necessary. When the forceClose - argument is provided, each contour (as defined by a new starting - move command) will be completed with a close verb regardless of the - contour's contents. + /** \class SkPath::Iter */ class SK_API Iter { - public: + + public: + + /** Initializes iter with an empty SkPath. next() on iter returns kDone_Verb. + Call setPath to initialize iter at a later time. + + @return Iter of empty SkPath + */ Iter(); + + /** Sets iter to return elements of verb array, SkPoint arrays, and conic weight in path. + If forceClose is true, iter will add kLine_Verb and kClose_Verb after each + open contour. path is not altered. + + @param path SkPath to iterate + @param forceClose true if open contours generate kClose_Verb + @return Iter of path + */ Iter(const SkPath& path, bool forceClose); + /** Sets iter to return elements of verb array, SkPoint arrays, and conic weight in path. + If forceClose is true, iter will add kLine_Verb and kClose_Verb after each + open contour. path is not altered. + + @param path SkPath to iterate + @param forceClose true if open contours generate kClose_Verb + */ void setPath(const SkPath& path, bool forceClose); - /** Return the next verb in this iteration of the path. When all - segments have been visited, return kDone_Verb. + /** Returns next SkPath::Verb in verb array, and advances iter. + When verb array is exhausted, returns kDone_Verb. - @param pts The points representing the current verb and/or segment - @param doConsumeDegerates If true, first scan for segments that are - deemed degenerate (too short) and skip those. - @param exact if doConsumeDegenerates is true and exact is true, skip only - degenerate elements with lengths exactly equal to zero. If exact - is false, skip degenerate elements with lengths close to zero. If - doConsumeDegenerates is false, exact has no effect. - @return The verb for the current segment + Zero to four points are stored in pts, depending on the returned SkPath::Verb. + + If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning + only the last in the series; and skip very small lines, quads, and conics; and + skip kClose_Verb following kMove_Verb. + if doConsumeDegenerates is true and exact is true, only skip lines, quads, and + conics with zero lengths. + + @param pts storage for SkPoint data describing returned SkPath::Verb + @param doConsumeDegenerates if true, skip degenerate verbs + @param exact skip zero length curves + @return next SkPath::Verb from verb array */ Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false) { if (doConsumeDegenerates) { @@ -996,24 +1406,31 @@ public: return this->doNext(pts); } - /** - * Return the weight for the current conic. Only valid if the current - * segment return by next() was a conic. - */ + /** Returns conic weight if next() returned kConic_Verb. + + If next() has not been called, or next() did not return kConic_Verb, + result is undefined. + + @return conic weight for conic points returned by next() + */ SkScalar conicWeight() const { return *fConicWeights; } - /** If next() returns kLine_Verb, then this query returns true if the - line was the result of a close() command (i.e. the end point is the - initial moveto for this contour). If next() returned a different - verb, this returns an undefined value. + /** Returns true if last kLine_Verb returned by next() was generated + by kClose_Verb. When true, the end point returned by next() is + also the start point of contour. - @return If the last call to next() returned kLine_Verb, return true - if it was the result of an explicit close command. + If next() has not been called, or next() did not return kLine_Verb, + result is undefined. + + @return true if last kLine_Verb was generated by kClose_Verb */ bool isCloseLine() const { return SkToBool(fCloseLine); } - /** Returns true if the current contour is closed (has a kClose_Verb) - @return true if the current contour is closed (has a kClose_Verb) + /** Returns true if subsequent calls to next() return kClose_Verb before returning + kMove_Verb. if true, contour iter is processing may end with kClose_Verb, or + iter may have been initialized with force close set to true. + + @return true if contour is closed */ bool isClosedContour() const; @@ -1033,40 +1450,65 @@ public: Verb autoClose(SkPoint pts[2]); void consumeDegenerateSegments(bool exact); Verb doNext(SkPoint pts[4]); + }; - /** Iterate through the verbs in the path, providing the associated points. + /** \class SkPath::RawIter */ class SK_API RawIter { - public: + + public: + + /** Initializes RawIter with an empty SkPath. next() on RawIter returns kDone_Verb. + Call setPath to initialize iter at a later time. + + @return RawIter of empty SkPath + */ RawIter() {} + + /** Sets RawIter to return elements of verb array, SkPoint arrays, and conic weight in path. + + @param path SkPath to iterate + @return RawIter of path + */ RawIter(const SkPath& path) { setPath(path); } + /** Sets iter to return elements of verb array, SkPoint arrays, and conic weight in path. + + @param path SkPath to iterate + */ void setPath(const SkPath& path) { fRawIter.setPathRef(*path.fPathRef.get()); } - /** Return the next verb in this iteration of the path. When all - segments have been visited, return kDone_Verb. + /** Returns next SkPath::Verb in verb array, and advances RawIter. + When verb array is exhausted, returns kDone_Verb. + Zero to four points are stored in pts, depending on the returned SkPath::Verb. - @param pts The points representing the current verb and/or segment - This must not be NULL. - @return The verb for the current segment + @param pts storage for SkPoint data describing returned SkPath::Verb + @return next SkPath::Verb from verb array */ Verb next(SkPoint pts[4]) { return (Verb) fRawIter.next(pts); } - /** Return what the next verb will be, but do not visit the next segment. + /** Returns next SkPath::Verb, but does not advance RawIter. - @return The verb for the next segment + @return next SkPath::Verb from verb array */ Verb peek() const { return (Verb) fRawIter.peek(); } + /** Returns conic weight if next() returned kConic_Verb. + + If next() has not been called, or next() did not return kConic_Verb, + result is undefined. + + @return conic weight for conic points returned by next() + */ SkScalar conicWeight() const { return fRawIter.conicWeight(); } @@ -1074,42 +1516,98 @@ public: private: SkPathRef::Iter fRawIter; friend class SkPath; + }; - /** - * Returns true if the point { x, y } is contained by the path, taking into - * account the FillType. - */ + /** Returns true if the point (x, y) is contained by SkPath, taking into + account FillType. + + @param x x-coordinate of containment test + @param y y-coordinate of containment test + @return true if SkPoint is in SkPath + */ bool contains(SkScalar x, SkScalar y) const; + /** Writes text representation of SkPath to stream. If stream is nullptr, dump() writes to + standard output. Set forceClose to true to get + edges used to fill SkPath. Set dumpAsHex true to get exact binary representations + of floating point numbers used in SkPoint arrays and conic weights. + + @param stream writable SkFlattenable receiving SkPath text representation; may be nullptr + @param forceClose true if missing kClose_Verb is output + @param dumpAsHex true if SkScalar values are written as hexadecimal + */ void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const; + + /** Writes text representation of SkPath to stream. If stream is nullptr, dump() writes to + standard output. Set forceClose to true to get + edges used to fill SkPath. Set dumpAsHex true to get exact binary representations + of floating point numbers used in SkPoint arrays and conic weights. + + @param stream writable SkFlattenable receiving SkPath text representation; may be nullptr + @param forceClose true if missing kClose_Verb is output + @param dumpAsHex true if SkScalar values are written as hexadecimal + */ void dump() const; + + /** Writes text representation of SkPath to standard output. The representation may be + directly compiled as C++ code. Floating point values are written + in hexadecimal to preserve their exact bit pattern. The output reconstructs the + original SkPath. + + Use instead of dump() when submitting + */ void dumpHex() const; - /** - * Write the path to the buffer, and return the number of bytes written. - * If buffer is NULL, it still returns the number of bytes. - */ + /** Writes SkPath to buffer, returning the number of bytes written. + Pass nullptr to obtain the storage size. + + Writes SkPath::FillType, verb array, SkPoint arrays, conic weight, and + additionally writes computed information like SkPath::Convexity and bounds. + + Use only be used in concert with readFromMemory(); + the format used for SkPath in memory is not guaranteed. + + @param buffer storage for SkPath; may be nullptr + @return size of storage required for SkPath; always a multiple of 4 + */ size_t writeToMemory(void* buffer) const; - /** - * Write the path to a buffer. Can recreate the path by calling readFromMemory(). - */ + /** Write SkPath to buffer, returning the buffer written to, wrapped in data. + + serialize() writes SkPath::FillType, verb array, SkPoint arrays, conic weight, and + additionally writes computed information like SkPath::Convexity and bounds. + + serialize() should only be used in concert with readFromMemory(). + The format used for SkPath in memory is not guaranteed. + + @return SkPath data wrapped in data buffer + */ sk_sp serialize() const; - /** - * Initializes the path from the buffer - * - * @param buffer Memory to read from - * @param length Amount of memory available in the buffer - * @return number of bytes read (must be a multiple of 4) or - * 0 if there was not enough memory available - */ + /** Initializes SkPath from buffer of size length. Returns zero if the buffer is + data is inconsistent, or the length is too small. + + Reads SkPath::FillType, verb array, SkPoint arrays, conic weight, and + additionally reads computed information like SkPath::Convexity and bounds. + + Used only in concert with writeToMemory(); + the format used for SkPath in memory is not guaranteed. + + @param buffer storage for SkPath + @param length buffer size in bytes; must be multiple of 4 + @return number of bytes read, or zero on failure + */ size_t readFromMemory(const void* buffer, size_t length); - /** Returns a non-zero, globally unique value corresponding to the set of verbs - and points in the path (but not the fill type [except on Android skbug.com/1762]). - Each time the path is modified, a different generation ID will be returned. + /** Returns a non-zero, globally unique value. A different value is returned + if verb array, SkPoint arrays, or conic weight changes. + + Setting SkPath::FillType does not change generation id. + + Each time the path is modified, a different generation id will be returned. + + @return non-zero, globally unique value */ uint32_t getGenerationID() const;