diff options
author | Cary Clark <caryclark@skia.org> | 2017-07-28 11:04:54 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-07-28 15:30:38 +0000 |
commit | 8032b983faaa8c76f81bf3cf028e9c64f4635478 (patch) | |
tree | ed3be061ff02a99dab1b3e443d48b7f5c906417e /docs | |
parent | acaa607328fb0dfac0894d4a2fcdead520e696b3 (diff) |
bookmaker initial checkin
bookmaker is a tool that generates documentation
backends from a canonical markup. Documentation for
bookmaker itself is evolving at docs/usingBookmaker.bmh,
which is visible online at skia.org/user/api/bmh_usingBookmaker
Change-Id: Ic76ddf29134895b5c2ebfbc84603e40ff08caf09
Reviewed-on: https://skia-review.googlesource.com/28000
Commit-Queue: Cary Clark <caryclark@google.com>
Reviewed-by: Cary Clark <caryclark@google.com>
Diffstat (limited to 'docs')
-rw-r--r-- | docs/SkCanvas.bmh | 5721 | ||||
-rw-r--r-- | docs/SkPaint.bmh | 5280 | ||||
-rw-r--r-- | docs/SkPath.bmh | 5801 | ||||
-rw-r--r-- | docs/markup.bmh | 88 | ||||
-rw-r--r-- | docs/overview.bmh | 8 | ||||
-rw-r--r-- | docs/undocumented.bmh | 528 | ||||
-rw-r--r-- | docs/usingBookmaker.bmh | 95 |
7 files changed, 17521 insertions, 0 deletions
diff --git a/docs/SkCanvas.bmh b/docs/SkCanvas.bmh new file mode 100644 index 0000000000..aefbae4d33 --- /dev/null +++ b/docs/SkCanvas.bmh @@ -0,0 +1,5721 @@ +#Topic Canvas + +Canvas provides an interface for drawing, and how the drawing is clipped and transformed. +Canvas contains a stack of Matrix and Clip values. + +Canvas and Paint together provide the state to draw into Surface or Device. +Each Canvas draw call transforms the geometry of the object by the concatenation of all Matrix +values in the stack. +The transformed geometry is clipped by the intersection of all of Clip values in the stack. +The Canvas draw calls take Paint parameter for drawing state. +Create Paint to supply the drawing state, such as Color, +Typeface, Paint_Text_Size, Paint_Stroke_Width, Shader and so on. + +To draw to a pixel-based destination, create Raster_Surface or GPU_Surface. +Request Canvas from Surface to obtain the interface to draw. +Canvas generated by Raster_Surface draws to memory visible to the CPU. +Canvas generated by GPU_Surface uses Vulkan or OpenGL to draw to the GPU. + +Canvas can be constructed to draw to Bitmap without first creating Raster_Surface. +This approach may be deprecated in the future. + +To draw to a document, obtain Canvas from SVG_Canvas, Document_PDF, or Picture_Recorder. +Document-based Canvas and other Canvas subclasses reference Device describing the destination. + +#Class SkCanvas + +#Topic Overview + +#Subtopic Subtopics +#Table +#Legend +# topics # description ## +#Legend ## +#ToDo generate a TOC here ## +#Table ## +#Subtopic ## + +#Subtopic Constants +#Table +#Legend +# constants # description ## +#Legend ## +# Lattice::Flags # Controls Lattice transparency. ## +# PointMode # Sets drawPoints options. ## +# SaveLayerFlags # Sets SaveLayerRec options. ## +# SrcRectConstraint # Sets drawImageRect options. ## +#Table ## +#Subtopic ## + +#Subtopic Structs +#Table +#Legend +# struct # description ## +#Legend ## +# Lattice # Divides Bitmap, Image into a rectangular grid. ## +# SaveLayerRec # Contains state to create the layer offscreen. ## +#Table ## +#Subtopic ## + +#Subtopic Constructors + +Create the desired type of Surface to obtain its Canvas when possible. Constructors are useful +when no Surface is required, and some helpers implicitly create Raster_Surface. + +#Table +#Legend +# # description ## +#Legend ## +# SkCanvas() # No Surface, no dimensions. ## +# SkCanvas(int width, int height, const SkSurfaceProps* = NULL) # No Surface, set dimensions, Surface_Properties. ## +# SkCanvas(SkBaseDevice* device) # Existing Device. (SkBaseDevice is private.) ## +# SkCanvas(const SkBitmap& bitmap) # Uses existing Bitmap. ## +# SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) # Uses existing Bitmap and Surface_Properties. ## +# MakeRasterDirect # Creates from SkImageInfo and Pixel_Storage. ## +# MakeRasterDirectN32 # Creates from image data and Pixel_Storage. ## +#ToDo incomplete ## +#Table ## +#Subtopic ## + +#Subtopic Member_Functions +#Table +#Legend +# function # description ## +#Legend ## +# accessTopLayerPixels # Returns writable pixel access if available. ## +# accessTopRasterHandle # Returns context that tracks Clip and Matrix. ## +# clear() # Fills Clip with Color. ## +# clipPath # Combines Clip with Path. ## +# clipRRect # Combines Clip with Round_Rect. ## +# clipRect # Combines Clip with Rect. ## +# clipRegion # Combines Clip with Region. ## +# concat() # Multiplies Matrix by Matrix. ## +# discard() # Makes Canvas contents undefined. ## +# drawAnnotation # Associates a Rect with a key-value pair.## +# drawArc # Draws Arc using Clip, Matrix, and Paint.## +# drawAtlas # Draws sprites using Clip, Matrix, and Paint.## +# drawBitmap # Draws Bitmap at (x, y) position. ## +# drawBitmapLattice # Draws differentially stretched Bitmap. ## +# drawBitmapNine # Draws Nine_Patch Bitmap. ## +# drawBitmapRect # Draws Bitmap, source Rect to destination Rect. ## +# drawCircle # Draws Circle using Clip, Matrix, and Paint. ## +# drawColor # Fills Clip with Color and Blend_Mode. ## +# drawDRRect # Draws double Round_Rect stroked or filled. ## +# drawDrawable # Draws Drawable, encapsulated drawing commands. ## +# drawIRect # Draws IRect using Clip, Matrix, and Paint. ## +# drawImage # Draws Image at (x, y) position. ## +# drawImageLattice # Draws differentially stretched Image. ## +# drawImageNine # Draws Nine_Patch Image. ## +# drawImageRect # Draws Image, source Rect to destination Rect. ## +# drawLine # Draws line segment between two points.## +# drawOval # Draws Oval using Clip, Matrix, and Paint. ## +# drawPaint # Fills Clip with Paint. ## +# drawPatch # Draws cubic Coons patch. ## +# drawPath # Draws Path using Clip, Matrix, and Paint. ## +# drawPicture # Draws Picture using Clip and Matrix. ## +# drawPoint # Draws point at (x, y) position. ## +# drawPoints # Draws array as points, lines, polygon. ## +# drawPosText # Draws text at array of (x, y) positions. ## +# drawPosTextH # Draws text at x positions with common baseline. ## +# drawRRect # Draws Round_Rect using Clip, Matrix, and Paint. ## +# drawRect # Draws Rect using Clip, Matrix, and Paint. ## +# drawRegion # Draws Region using Clip, Matrix, and Paint. ## +# drawRoundRect # Draws Round_Rect using Clip, Matrix, and Paint. ## +# drawText # Draws text at (x, y), using font advance. ## +# drawTextBlob # Draws text with arrays of positions and Paint. ## +# drawTextOnPath # Draws text following Path contour. ## +# drawTextOnPathHV # Draws text following Path with offsets. ## +# drawTextRSXform # Draws text with array of RSXform. ## +# drawString # Draws null terminated string at (x, y) using font advance. ## +# drawVertices # Draws Vertices, a triangle mesh. ## +# flush() # Triggers execution of all pending draw operations. ## +# getBaseLayerSize # Gets size of base layer in global coordinates. ## +# getDeviceClipBounds # Returns IRect bounds of Clip. ## +# getDrawFilter # Legacy; to be deprecated. ## +# getGrContext # Returns GPU_Context of the GPU_Surface. ## +# getLocalClipBounds # Returns Clip bounds in source coordinates. ## +# getMetaData # Associates additional data with the canvas. ## +# getProps # Copies Surface_Properties if available. ## +# getSaveCount # Returns depth of stack containing Clip and Matrix. ## +# getTotalMatrix # Returns Matrix. ## +# imageInfo # Returns Image_Info for Canvas. ## +# isClipEmpty # Returns if Clip is empty. ## +# isClipRect # Returns if Clip is Rect and not empty. ## +# MakeRasterDirect # Creates Canvas from SkImageInfo and pixel data. ## +# MakeRasterDirectN32 # Creates Canvas from image specifications and pixel data. ## +# makeSurface # Creates Surface matching SkImageInfo and SkSurfaceProps. ## +# peekPixels # Returns if Canvas has direct access to its pixels. ## +# quickReject # Returns if Rect is outside Clip. ## +# readPixels # Copies and converts rectangle of pixels from Canvas. ## +# resetMatrix # Resets Matrix to identity. ## +# restore() # Restores changes to Clip and Matrix, pops save stack. ## +# restoreToCount # Restores changes to Clip and Matrix to given depth. ## +# rotate() # Rotates Matrix. ## +# save() # Saves Clip and Matrix on stack. ## +# saveLayer # Saves Clip and Matrix on stack; creates offscreen. ## +# saveLayerAlpha # Saves Clip and Matrix on stack; creates offscreen; sets opacity. ## +# saveLayerPreserveLCDTextRequests # Saves Clip and Matrix on stack; creates offscreen for LCD text. ## +# scale() # Scales Matrix. ## +# setAllowSimplifyClip # Experimental. ## +# setDrawFilter # Legacy; to be deprecated. ## +# setMatrix # Sets Matrix. ## +# skew() # Skews Matrix. # +# translate() # Translates Matrix. ## +# writePixels # Copies and converts rectangle of pixels to Canvas. ## +#Table ## +#Subtopic ## + +#Topic Overview ## + +# ------------------------------------------------------------------------------ + +#Method static std::unique_ptr<SkCanvas> MakeRasterDirect(const SkImageInfo& info, + void* pixels, size_t rowBytes) + +Allocates raster canvas that will draw directly into pixels. +To access pixels after drawing, call flush() or peekPixels. + +#Param info Width, height, Image_Color_Type, Image_Alpha_Type, Color_Space, of Raster_Surface. + Width, or height, or both, may be zero. +## +#Param pixels Pointer to destination pixels buffer. Buffer size should be info height + times rowBytes times bytes required for Image_Color_Type. +## +#Param rowBytes The interval from one Surface row to the next; equal to or greater than + info width times bytes required for Image_Color_Type. +## + +#Return Canvas if all parameters are valid; otherwise, nullptr. + Valid parameters include: info dimensions must be zero or positive, and other checks; + info must contain Image_Color_Type and Image_Alpha_Type supported by Raster_Surface; + pixels must be not be nullptr; + rowBytes must be zero or large enough to contain width pixels of Image_Color_Type. +## + +#Example + #Description + Allocates a three by three bitmap, clears it to white, and draws a black pixel + in the center. + ## +void draw(SkCanvas* ) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(3, 3); // device aligned, 32 bpp, premultipled
+ const size_t minRowBytes = info.minRowBytes(); // bytes used by one bitmap row
+ const size_t size = info.getSafeSize(minRowBytes); // bytes used by all rows
+ SkAutoTMalloc<SkPMColor> storage(size); // allocate storage for pixels
+ SkPMColor* pixels = storage.get(); // get pointer to allocated storage
+ // create a SkCanvas backed by a raster device, and delete it when the
+ // function goes out of scope.
+ std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(info, pixels, minRowBytes);
+ canvas->clear(SK_ColorWHITE); // white is unpremultiplied, in ARGB order
+ canvas->flush(); // ensure that pixels are cleared
+ SkPMColor pmWhite = pixels[0]; // the premultiplied format may vary
+ SkPaint paint; // by default, draws black
+ canvas->drawPoint(1, 1, paint); // draw in the center
+ canvas->flush(); // ensure that point was drawn
+ for (int y = 0; y < info.height(); ++y) {
+ for (int x = 0; x < info.width(); ++x) {
+ SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
+ }
+ SkDebugf("\n");
+ }
+} + #StdOut + --- + -x- + --- + ## +## + +#ToDo incomplete ## + +#SeeAlso MakeRasterDirectN32 SkSurface::MakeRasterDirect +## + +# ------------------------------------------------------------------------------ + +#Method static std::unique_ptr<SkCanvas> MakeRasterDirectN32(int width, int height, SkPMColor* pixels, + size_t rowBytes) + +Creates Canvas with Raster_Surface with inline image specification that draws into pixels. +Image_Color_Type is set to kN32_SkColorType. +Image_Alpha_Type is set to kPremul_SkAlphaType. +To access pixels after drawing, call flush() or peekPixels. + +#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 times four. +## +#Param rowBytes The interval from one Surface row to the next; equal to or greater than + width times four. +## + +#Return Canvas if all parameters are valid; otherwise, nullptr. + Valid parameters include: width and height must be zero or positive; + pixels must be not be nullptr; + rowBytes must be zero or large enough to contain width pixels of Image_Color_Type. +## + +#Example + #Description + Allocates a three by three bitmap, clears it to white, and draws a black pixel + in the center. + ## +void draw(SkCanvas* ) { + const int width = 3; + const int height = 3; + SkPMColor pixels[height][width]; // allocate a 3x3 premultiplied bitmap on the stack + // create a SkCanvas backed by a raster device, and delete it when the + // function goes out of scope. + std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirectN32( + width, + height, + pixels[0], // top left of the bitmap + sizeof(pixels[0])); // byte width of the each row + // write a pre-multiplied value for white into all pixels in the bitmap + canvas->clear(SK_ColorWHITE); + SkPMColor pmWhite = pixels[0][0]; // the premultiplied format may vary + SkPaint paint; // by default, draws black + canvas->drawPoint(1, 1, paint); // draw in the center + canvas->flush(); // ensure that pixels is ready to be read + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + SkDebugf("%c", pixels[y][x] == pmWhite ? '-' : 'x'); + } + SkDebugf("\n"); + } +} + #StdOut + --- + -x- + --- + ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method SkCanvas() + +Creates an empty canvas with no backing device/pixels, and zero +dimensions. + +#Return An empty canvas. ## + +#Example + +#Description +Passes a placeholder to a function that requires one. +## + +#Function +// Returns true if either the canvas rotates the text by 90 degrees, or the paint does.
+static void check_for_up_and_down_text(const SkCanvas* canvas, const SkPaint& paint) {
+ bool paintHasVertical = paint.isVerticalText();
+ const SkMatrix& matrix = canvas->getTotalMatrix();
+ bool matrixIsVertical = matrix.preservesRightAngles() && !matrix.isScaleTranslate();
+ SkDebugf("paint draws text %s\n", paintHasVertical != matrixIsVertical ?
+ "top to bottom" : "left to right");
+}
+
+static void check_for_up_and_down_text(const SkPaint& paint) {
+ SkCanvas canvas; // placeholder only, does not have an associated device
+ check_for_up_and_down_text(&canvas, paint);
+}
+
+## +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ check_for_up_and_down_text(paint); // paint draws text left to right
+ paint.setVerticalText(true);
+ check_for_up_and_down_text(paint); // paint draws text top to bottom
+ paint.setVerticalText(false);
+ canvas->rotate(90);
+ check_for_up_and_down_text(canvas, paint); // paint draws text top to bottom
+}
+ + #StdOut + paint draws text left to right + paint draws text top to bottom + paint draws text top to bottom + ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method SkCanvas(int width, int height, const SkSurfaceProps* props = NULL) + +Creates Canvas of the specified dimensions without a Surface. +Used by subclasses with custom implementations for draw methods. + +#Param width Zero or greater. ## +#Param height Zero or greater. ## +#Param props The LCD striping orientation and setting for device independent fonts. + If nullptr, use Legacy_Font_Host settings. ## + +#Return Canvas placeholder with dimensions. ## + +#Example + SkCanvas canvas(10, 20); // 10 units wide, 20 units high + canvas.clipRect(SkRect::MakeXYWH(30, 40, 5, 10)); // clip is outside canvas' device + SkDebugf("canvas %s empty\n", canvas.getDeviceClipBounds().isEmpty() ? "is" : "is not"); + + #StdOut + canvas is empty + ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method explicit SkCanvas(SkBaseDevice* device) + +Construct a canvas that draws into device. +Used by child classes of SkCanvas. + +#ToDo Since SkBaseDevice is private, shouldn't this be private also? ## + +#Param device Specifies a device for the canvas to draw into. ## + +#Return Canvas that can be used to draw into device. ## + +#Example +#Error "Unsure how to create a meaningful example." + SkPDFCanvas::SkPDFCanvas(const sk_sp<SkPDFDevice>& dev) + : SkCanvas(dev.get()) {} +## + +#ToDo either remove doc of figure out a way to fiddle it ## + +## + +# ------------------------------------------------------------------------------ + +#Method explicit SkCanvas(const SkBitmap& bitmap) + +Construct a canvas that draws into bitmap. +Sets SkSurfaceProps::kLegacyFontHost_InitType in constructed Surface. + +#ToDo Should be deprecated? ## + +#Param bitmap Width, height, Image_Color_Type, Image_Alpha_Type, and pixel storage of Raster_Surface. + Bitmap is copied so that subsequently editing bitmap will not affect + constructed Canvas. +## + +#Return Canvas that can be used to draw into bitmap. ## + +#Example +#Description +The actual output depends on the installed fonts. +## + SkBitmap bitmap; + // create a bitmap 5 wide and 11 high + bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11)); + SkCanvas canvas(bitmap); + canvas.clear(SK_ColorWHITE); // white is unpremultiplied, in ARGB order + SkPixmap pixmap; // provides guaranteed access to the drawn pixels + if (!canvas.peekPixels(&pixmap)) { + SkDebugf("peekPixels should never fail.\n"); + } + const SkPMColor* pixels = pixmap.addr32(); // points to top left of bitmap + SkPMColor pmWhite = pixels[0]; // the premultiplied format may vary + SkPaint paint; // by default, draws black, 12 point text + canvas.drawString("!", 1, 10, paint); // 1 char at baseline (1, 10) + for (int y = 0; y < bitmap.height(); ++y) { + for (int x = 0; x < bitmap.width(); ++x) { + SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x'); + } + SkDebugf("\n"); + } + + #StdOut + ----- + --x-- + --x-- + --x-- + --x-- + --x-- + --x-- + ----- + --x-- + --x-- + ----- + #StdOut ## +## + +#ToDo incomplete ## + +## + +#Enum ColorBehavior + +#ToDo exclude this during build phase + (use SK_BUILD_FOR_ANDROID_FRAMEWORK as exclude directive) +## + +#Private +Android framework only. +## + +#Code + enum class ColorBehavior { + kLegacy, + }; +## +#Const kLegacy 0 +## +## + + +# ------------------------------------------------------------------------------ + +#Method SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) + +Construct a canvas that draws into bitmap. +Use props to match the device characteristics, like LCD striping. + +#Param bitmap Width, height, Image_Color_Type, Image_Alpha_Type, and pixel storage of Raster_Surface. + Bitmap is copied so that subsequently editing bitmap will not affect + constructed Canvas. +## +#Param props The order and orientation of RGB striping; and whether to use + device independent fonts. +## + +#Return Canvas that can be used to draw into bitmap. ## + +#Example +#Description +The actual output depends on the installed fonts. +## + SkBitmap bitmap; + // create a bitmap 5 wide and 11 high + bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11)); + SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); + canvas.clear(SK_ColorWHITE); // white is unpremultiplied, in ARGB order + SkPixmap pixmap; // provides guaranteed access to the drawn pixels + if (!canvas.peekPixels(&pixmap)) { + SkDebugf("peekPixels should never fail.\n"); + } + const SkPMColor* pixels = pixmap.addr32(); // points to top left of bitmap + SkPMColor pmWhite = pixels[0]; // the premultiplied format may vary + SkPaint paint; // by default, draws black, 12 point text + canvas.drawString("!", 1, 10, paint); // 1 char at baseline (1, 10) + for (int y = 0; y < bitmap.height(); ++y) { + for (int x = 0; x < bitmap.width(); ++x) { + SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x'); + } + SkDebugf("\n"); + } + + #StdOut + ----- + ---x- + ---x- + ---x- + ---x- + ---x- + ---x- + ----- + ---x- + ---x- + ----- + #StdOut ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method virtual ~SkCanvas() + +Draws State_Stack_Layer, if any. +Free up resources used by Canvas. + +#Example +#Error "Haven't thought of a useful example to put here." +## + +#ToDo create example to show how draw happens when canvas goes out of scope ## + +## + +# ------------------------------------------------------------------------------ + +#Method SkMetaData& getMetaData() + +Associates additional data with the canvas. +The storage is freed when Canvas is deleted. + +#Return storage that can be read from and written to. ## + +#Example + const char* kHelloMetaData = "HelloMetaData"; + SkCanvas canvas; + SkMetaData& metaData = canvas.getMetaData(); + SkDebugf("before: %s\n", metaData.findString(kHelloMetaData)); + metaData.setString(kHelloMetaData, "Hello!"); + SkDebugf("during: %s\n", metaData.findString(kHelloMetaData)); + metaData.removeString(kHelloMetaData); + SkDebugf("after: %s\n", metaData.findString(kHelloMetaData)); + + #StdOut + before: (null) + during: Hello! + after: (null) + #StdOut ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method SkImageInfo imageInfo() const + +Returns Image_Info for Canvas. If Canvas is not associated with Raster_Surface or +GPU_Surface, returns SkImageInfo::SkImageInfo() is returned Image_Color_Type is set to kUnknown_SkColorType. + +#Return dimensions and Image_Color_Type of Canvas. ## + +#Example + SkCanvas canvas; + SkImageInfo canvasInfo = canvas.imageInfo(); + SkImageInfo emptyInfo; + SkDebugf("emptyInfo %c= canvasInfo\n", emptyInfo == canvasInfo ? '=' : '!'); +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method bool getProps(SkSurfaceProps* props) const + +If Canvas is associated with Raster_Surface or +GPU_Surface, copies Surface_Properties and returns true. Otherwise, +return false and leave props unchanged. + +#Param props Pointer to writable SkSurfaceProps. ## + +#Return true if Surface_Properties was copied. ## + +#ToDo This seems old style. Deprecate? ## + +#Example + SkBitmap bitmap; + SkCanvas canvas(bitmap, SkSurfaceProps(0, kRGB_V_SkPixelGeometry)); + SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry); + SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry())); + if (!canvas.getProps(&surfaceProps)) { + SkDebugf("getProps failed unexpectedly.\n"); + } + SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry())); + + #StdOut + isRGB:0 + isRGB:1 + #StdOut ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void flush() + +Triggers the immediate execution of all pending draw operations. +If Canvas is associated with GPU_Surface, resolve all pending GPU operations. + +#Example +#Error "haven't thought of a useful example to put here" +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method virtual SkISize getBaseLayerSize() const + +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). + +#Return Integral width and height of base layer. ## + +#Example + SkBitmap bitmap; + bitmap.allocPixels(SkImageInfo::MakeN32Premul(20, 30)); + SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); + canvas.clipRect(SkRect::MakeWH(10, 40)); + SkIRect clipDeviceBounds = canvas.getDeviceClipBounds(); + if (clipDeviceBounds.isEmpty()) { + SkDebugf("Empty clip bounds is unexpected!\n"); + } + SkDebugf("clip=%d,%d\n", clipDeviceBounds.width(), clipDeviceBounds.height()); + SkISize baseLayerSize = canvas.getBaseLayerSize(); + SkDebugf("size=%d,%d\n", baseLayerSize.width(), baseLayerSize.height()); + + #StdOut + clip=10,30 + size=20,30 + ## +## + +#ToDo is this the same as the width and height of surface? ## + +## + +# ------------------------------------------------------------------------------ + +#Method sk_sp<SkSurface> makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr) + +Creates Surface matching info and props, and associates it with Canvas. +If Canvas is already associated with Surface, it cannot create a new Surface. + +#Param info Initialize Surface with width, height, Image_Color_Type, Image_Alpha_Type, and Color_Space. ## +#Param props Use to match if provided, or use the Surface_Properties in Canvas otherwise. ## + +#Return Surface matching info and props, or nullptr if no match is available. ## + +#Example + sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(5, 6); + SkCanvas* smallCanvas = surface->getCanvas(); + SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(3, 4); + sk_sp<SkSurface> compatible = smallCanvas->makeSurface(imageInfo); + SkDebugf("compatible %c= nullptr\n", compatible == nullptr ? '=' : '!'); + SkDebugf("size = %d, %d\n", compatible->width(), compatible->height()); + + #StdOut + compatible != nullptr
+ size = 3, 4 + ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method virtual GrContext* getGrContext() + +Returns GPU_Context of the GPU_Surface associated with Canvas. + +#Return GPU_Context, if available; nullptr otherwise. ## + +#Example +void draw(SkCanvas* canvas) { + if (canvas->getGrContext()) { + canvas->clear(SK_ColorRED); + } else { + canvas->clear(SK_ColorBLUE); + } +} +## + +#ToDo fiddle should show both CPU and GPU out ## + +## + +# ------------------------------------------------------------------------------ + +#Method void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = NULL) + +Returns the pixel base address, Image_Info, rowBytes, and origin if the pixels +can be read directly. +The returned address is only valid +while Canvas is in scope and unchanged. Any Canvas call or Surface call +may invalidate the returned address and other returned values. + +If pixels are inaccessible, info, rowBytes, and origin are unchanged. + +#Param info If not nullptr, copies writable pixels' Image_Info. ## +#Param rowBytes If not nullptr, copies writable pixels' row bytes. ## +#Param origin If not nullptr, copies Canvas top layer origin, its top left corner. ## + +#Return Address of pixels, or nullptr if inaccessible. ## + +#Example +void draw(SkCanvas* canvas) { + if (canvas->accessTopLayerPixels(nullptr, nullptr)) { + canvas->clear(SK_ColorRED); + } else { + canvas->clear(SK_ColorBLUE); + } +} +## + +#Example +#Description +Draws "ABC" on the device. Then draws "DEF" in an offscreen layer, and reads the +offscreen to add a large dotted "DEF". Finally blends the offscreen with the +device. + +The offscreen and blended result appear on the CPU and GPU but the large dotted +"DEF" appear only on the CPU. +## +void draw(SkCanvas* canvas) { + SkPaint paint;
+ paint.setTextSize(100);
+ canvas->drawString("ABC", 20, 160, paint);
+ SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192);
+ canvas->saveLayerAlpha(&layerBounds, 128);
+ canvas->clear(SK_ColorWHITE);
+ canvas->drawString("DEF", 20, 160, paint);
+ SkImageInfo imageInfo;
+ size_t rowBytes;
+ SkIPoint origin;
+ uint32_t* access = (uint32_t*) canvas->accessTopLayerPixels(&imageInfo, &rowBytes, &origin);
+ if (access) {
+ int h = imageInfo.height();
+ int v = imageInfo.width();
+ int rowWords = rowBytes / sizeof(uint32_t);
+ for (int y = 0; y < h; ++y) {
+ int newY = (y - h / 2) * 2 + h / 2;
+ if (newY < 0 || newY >= h) {
+ continue;
+ }
+ for (int x = 0; x < v; ++x) {
+ int newX = (x - v / 2) * 2 + v / 2;
+ if (newX < 0 || newX >= v) {
+ continue;
+ }
+ if (access[y * rowWords + x] == SK_ColorBLACK) {
+ access[newY * rowWords + newX] = SK_ColorGRAY;
+ }
+ }
+ }
+
+ }
+ canvas->restore(); +} +## + +#ToDo there are no callers of this that I can find. Deprecate? ## +#ToDo fiddle should show both CPU and GPU out ## + +## + +# ------------------------------------------------------------------------------ + +#Method SkRasterHandleAllocator::Handle accessTopRasterHandle() const + +Returns custom context that tracks the Matrix and Clip. + +Use Raster_Handle_Allocator to blend Skia drawing with custom drawing, typically performed +by the host platform's user interface. This accessor returns the custom context created +when SkRasterHandleAllocator::MakeCanvas creates a custom canvas with raster storage for +the drawing destination. + +#Return Context of custom allocator. ## + +#Example +#Description +#ToDo ## +## +#Function + static void DeleteCallback(void*, void* context) { + delete (char*) context; + } + + class CustomAllocator : public SkRasterHandleAllocator { + public: + bool allocHandle(const SkImageInfo& info, Rec* rec) override { + char* context = new char[4]{'s', 'k', 'i', 'a'}; + rec->fReleaseProc = DeleteCallback; + rec->fReleaseCtx = context; + rec->fHandle = context; + rec->fPixels = context; + rec->fRowBytes = 4; + return true; + } + + void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override { + // apply canvas matrix and clip to custom environment + } + }; + +## + void draw(SkCanvas* canvas) { + const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); + std::unique_ptr<SkCanvas> c2 = + SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<CustomAllocator>( + new CustomAllocator()), info); + char* context = (char*) c2->accessTopRasterHandle(); + SkDebugf("context = %.4s\n", context); + + } + #StdOut + context = skia + ## + #ToDo skstd::make_unique could not be used because def is private -- note to fix in c++14? ## +## + +#SeeAlso SkRasterHandleAllocator + +## + +# ------------------------------------------------------------------------------ + +#Method bool peekPixels(SkPixmap* pixmap) + +Returns true if Canvas has direct access to its pixels. + +Pixels are readable when Device 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 pixel address is only valid while Canvas is in scope and unchanged. Any Canvas or Surface call may +invalidate the pixmap values. + +#Param pixmap storage for Canvas pixel state if Canvas pixels are readable; otherwise, ignored. ## + +#Return true if Canvas has direct access to pixels. ## + +#Example + SkPixmap pixmap; + if (canvas->peekPixels(&pixmap)) { + SkDebugf("width=%d height=%d\n", pixmap.bounds().width(), pixmap.bounds().height()); + } + #StdOut + width=256 height=256 + ## +## + +## + +# ------------------------------------------------------------------------------ + +#Method bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + int srcX, int srcY) + +Copies rectangle of pixels from Canvas into dstPixels, converting their Image_Color_Type and Image_Alpha_Type. +Pixels are readable when Device 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. + +Pixel values are converted only if Canvas Image_Color_Type and Image_Alpha_Type does not match dstInfo. +Only pixels within the rectangle that intersect Canvas pixels are copied. +dstPixels outside the rectangle intersection are unchanged. + +#Table +#Legend +# source rectangle # value ## +## +# left # srcX ## +# top # srcY ## +# width # dstInfo.width() ## +# height # dstInfo.height() ## +## + + #Table +#Legend +# canvas pixel bounds # value ## +## +# left # 0 ## +# top # 0 ## +# width # imageInfo().width() ## +# height # imageInfo().height() ## +## + +Does not copy, and returns false if: + +#List +# Source rectangle and canvas pixel bounds do not intersect. ## +# Canvas pixels could not be converted to dstInfo Image_Color_Type or dstInfo Image_Alpha_Type. ## +# Canvas pixels are not readable; for instance, Canvas is not raster, or is document-based. ## +# dstRowBytes is too small to contain one row of pixels. ## +## + +#Param dstInfo Dimensions, Image_Color_Type, and Image_Alpha_Type of dstPixels. ## +#Param dstPixels Storage for pixels, of size dstInfo.height() times dstRowBytes. ## +#Param dstRowBytes Size of one destination row, dstInfo.width() times pixel size. ## +#Param srcX Offset into readable pixels in x. ## +#Param srcY Offset into readable pixels in y. ## + +#Return true if pixels were copied. ## + +#Example +#Description + Canvas returned by Raster_Surface has premultiplied pixel values. + clear() takes unpremultiplied input with Color_Alpha equal 0x80 + and Color_RGB equal 0x55, 0xAA, 0xFF. Color_RGB is multipled by Color_Alpha + to generate premultipled value 0x802B5580. readPixels converts pixel back + to unpremultipled value 0x8056A9FF, introducing error. +## + canvas->clear(0x8055aaff); + for (SkAlphaType alphaType : { kPremul_SkAlphaType, kUnpremul_SkAlphaType } ) { + uint32_t pixel = 0; + SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, alphaType); + if (canvas->readPixels(info, &pixel, 4, 0, 0)) { + SkDebugf("pixel = %08x\n", pixel); + } + } + + #StdOut + pixel = 802b5580 + pixel = 8056a9ff + ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method bool readPixels(const SkPixmap& pixmap, int srcX, int srcY) + +Copies rectangle of pixels from Canvas into Pixmap, converting their Image_Color_Type and Image_Alpha_Type. +Pixels are readable when Device 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. + +Pixel values are converted only if Canvas Image_Color_Type and Image_Alpha_Type does not match bitmap Image_Info. +Only Pixmap pixels within the rectangle that intersect Canvas pixels are copied. +Pixmap pixels outside the rectangle intersection are unchanged. + +#Table +#Legend +# source rectangle # value ## +## +# left # srcX ## +# top # srcY ## +# width # bitmap.width() ## +# height # bitmap.height() ## +## + + #Table +#Legend +# canvas pixel bounds # value ## +## +# left # 0 ## +# top # 0 ## +# width # imageInfo().width() ## +# height # imageInfo().height() ## +## + +Does not copy, and returns false if: + +#List +# Source rectangle and canvas pixel bounds do not intersect. ## +# Canvas pixels could not be converted to bitmap Image_Color_Type or bitmap Image_Alpha_Type. ## +# Canvas pixels are not readable; for instance, Canvas is not raster, or is document-based. ## +# bitmap pixels could not be allocated. ## +# Bitmap_Row_Bytes is too small to contain one row of pixels. ## +## + +#Param pixmap Receives pixels copied from Canvas. ## +#Param srcX Offset into readable pixels in x. ## +#Param srcY Offset into readable pixels in y. ## + +#Return true if pixels were copied. ## + +#Example +void draw(SkCanvas* canvas) { + canvas->clear(0x8055aaff); + uint32_t pixels[1] = { 0 }; + SkPixmap pixmap(SkImageInfo::MakeN32Premul(1, 1), pixels, 4);
+ canvas->readPixels(pixmap, 0, 0); + SkDebugf("pixel = %08x\n", pixels[0]); +} + #StdOut + pixel = 802b5580 + ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method bool readPixels(const SkBitmap& bitmap, int srcX, int srcY) + +Copies pixels enclosed by bitmap offset to (x, y) from Canvas into bitmap, converting their Image_Color_Type and Image_Alpha_Type. +Pixels are readable when Device 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. +Allocates pixel storage in bitmap if needed. + +Pixel values are converted only if Canvas Image_Color_Type and Image_Alpha_Type does not match bitmap Image_Info. +Only pixels within the rectangle that intersect Canvas pixels are copied. +Bitamp pixels outside the rectangle intersection are unchanged. + + #Table +#Legend +# canvas pixel bounds # value ## +## +# left # 0 ## +# top # 0 ## +# width # imageInfo().width() ## +# height # imageInfo().height() ## +## + +Does not copy, and returns false if: + +#List +# Bounds formed by (x, y) and bitmap (width, height) and canvas pixel bounds do not intersect. ## +# Canvas pixels could not be converted to bitmap Image_Color_Type or bitmap Image_Alpha_Type. ## +# Canvas pixels are not readable; for instance, Canvas is not raster, or is document-based. ## +# bitmap pixels could not be allocated. ## +# Bitmap_Row_Bytes is too small to contain one row of pixels. ## +## + +#Param bitmap Receives pixels copied from Canvas. ## +#Param srcX Offset into readable pixels in x. ## +#Param srcY Offset into readable pixels in y. ## + +#Return true if pixels were copied. ## + +#Example +void draw(SkCanvas* canvas) { + canvas->clear(0x8055aaff); + SkBitmap bitmap; + bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1)); + canvas->readPixels(bitmap, 0, 0); + SkDebugf("pixel = %08x\n", bitmap.getAddr32(0, 0)[0]); +} + #StdOut + pixel = 802b5580 + ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y) + +Copies to Canvas pixels, ignoring the Matrix and Clip, converting to match +info Image_Color_Type and info Image_Alpha_Type. + +Pixel values are converted only if Canvas Image_Color_Type and Image_Alpha_Type does not match info. +Only pixels within the source rectangle that intersect Canvas pixel bounds are copied. +Canvas pixels outside the rectangle intersection are unchanged. + +#Table +#Legend +# source rectangle # value ## +## +# left # x ## +# top # y ## +# width # info.width() ## +# height # info.height() ## +## + + #Table +#Legend +# canvas pixel bounds # value ## +## +# left # 0 ## +# top # 0 ## +# width # imageInfo().width() ## +# height # imageInfo().height() ## +## + +Does not copy, and returns false if: + +#List +# Source rectangle and canvas pixel bounds do not intersect. ## +# pixels could not be converted to Canvas Image_Color_Type or Canvas Image_Alpha_Type. ## +# Canvas pixels are not writable; for instance, Canvas is document-based. ## +# rowBytes is too small to contain one row of pixels. ## +## + +#Param info Dimensions, Image_Color_Type, and Image_Alpha_Type of pixels. ## +#Param pixels Pixels to copy, of size info.height() times rowBytes. ## +#Param rowBytes Offset from one row to the next, usually info.width() times pixel size. ## +#Param x Offset into Canvas writable pixels in x. ## +#Param y Offset into Canvas writable pixels in y. ## + +#Return true if pixels were written to Canvas. ## + +#Example + SkImageInfo imageInfo = SkImageInfo::MakeN32(256, 1, kPremul_SkAlphaType); + for (int y = 0; y < 256; ++y) { + uint32_t pixels[256]; + for (int x = 0; x < 256; ++x) { + pixels[x] = SkColorSetARGB(x, x + y, x, x - y); + } + canvas->writePixels(imageInfo, &pixels, sizeof(pixels), 0, y); + } +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method bool writePixels(const SkBitmap& bitmap, int x, int y) + +Writes to Canvas pixels, ignoring the Matrix and Clip, converting to match +bitmap Image_Color_Type and bitmap Image_Alpha_Type. + +Pixel values are converted only if Canvas Image_Color_Type and Image_Alpha_Type does not match bitmap. +Only pixels within the source rectangle that intersect Canvas pixel bounds are copied. +Canvas pixels outside the rectangle intersection are unchanged. + +#Table +#Legend +# source rectangle # value ## +## +# left # x ## +# top # y ## +# width # bitmap.width() ## +# height # bitmap.height() ## +## + + #Table +#Legend +# canvas pixel bounds # value ## +## +# left # 0 ## +# top # 0 ## +# width # imageInfo().width() ## +# height # imageInfo().height() ## +## + +Does not copy, and returns false if: + +#List +# Source rectangle and Canvas pixel bounds do not intersect. ## +# bitmap does not have allocated pixels. ## +# bitmap pixels could not be converted to Canvas Image_Color_Type or Canvas Image_Alpha_Type. ## +# Canvas pixels are not writable; for instance, Canvas is document-based. ## +# bitmap pixels are inaccessible; for instance, bitmap wraps a texture. ## +## + +#Param bitmap Provides pixels copied to Canvas. ## +#Param x Offset into Canvas writable pixels in x. ## +#Param y Offset into Canvas writable pixels in y. ## + +#Return true if pixels were written to Canvas. ## + +#Example +void draw(SkCanvas* canvas) { + SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(2, 2); + SkBitmap bitmap; + bitmap.setInfo(imageInfo); + uint32_t pixels[4]; + bitmap.setPixels(pixels); + for (int y = 0; y < 256; y += 2) { + for (int x = 0; x < 256; x += 2) { + pixels[0] = SkColorSetRGB(x, y, x | y); + pixels[1] = SkColorSetRGB(x ^ y, y, x); + pixels[2] = SkColorSetRGB(x, x & y, y); + pixels[3] = SkColorSetRGB(~x, ~y, x); + canvas->writePixels(bitmap, x, y); + } + } +} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ +#Topic State_Stack + +Canvas maintains a stack of state that allows hierarchical drawing, commonly used +to implement windows and views. The initial state has an identity matrix and and an infinite clip. +Even with a wide-open clip, drawing is constrained by the bounds of the +Canvas Surface or Device. + +Canvas savable state consists of Clip, Matrix, and Draw_Filter. +Clip describes the area that may be drawn to. +Matrix transforms the geometry. +Draw_Filter (deprecated on most platforms) modifies the paint before drawing. + +save(), saveLayer, saveLayerPreserveLCDTextRequests, and saveLayerAlpha +save state and return the depth of the stack. + +restore() and restoreToCount revert state to its value when saved. + +Each state on the stack intersects Clip with the previous Clip, +and concatenates Matrix with the previous Matrix. +The intersected Clip makes the drawing area the same or smaller; +the concatenated Matrix may move the origin and potentially scale or rotate +the coordinate space. + +Canvas does not require balancing the state stack but it is a good idea +to do so. Calling save() without restore() will eventually cause Skia to fail; +mismatched save() and restore() create hard to find bugs. + +It is not possible to use state to draw outside of the clip defined by the +previous state. + +#Example +#Description +Draw to ever smaller clips; then restore drawing to full canvas. +Note that the second clipRect is not permitted to enlarge Clip. +## +#Height 160 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ canvas->save(); // records stack depth to restore
+ canvas->clipRect(SkRect::MakeWH(100, 100)); // constrains drawing to clip
+ canvas->clear(SK_ColorRED); // draws to limit of clip
+ canvas->save(); // records stack depth to restore
+ canvas->clipRect(SkRect::MakeWH(50, 150)); // Rect below 100 is ignored
+ canvas->clear(SK_ColorBLUE); // draws to smaller clip
+ canvas->restore(); // enlarges clip
+ canvas->drawLine(20, 20, 150, 150, paint); // line below 100 is not drawn
+ canvas->restore(); // enlarges clip
+ canvas->drawLine(150, 20, 50, 120, paint); // line below 100 is drawn
+} +## + +Each Clip uses the current Matrix for its coordinates. + +#Example +#Description +While clipRect is given the same rectangle twice, Matrix makes the second +clipRect draw at half the size of the first. +## +#Height 128 +void draw(SkCanvas* canvas) {
+ canvas->clipRect(SkRect::MakeWH(100, 100));
+ canvas->clear(SK_ColorRED);
+ canvas->scale(.5, .5);
+ canvas->clipRect(SkRect::MakeWH(100, 100));
+ canvas->clear(SK_ColorBLUE);
+} +## + +#SeeAlso save() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha restore() restoreToCount + +#Method int save() + +Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms). +Calling restore() discards changes to Matrix, Clip, and Draw_Filter, +restoring the Matrix, Clip, and Draw_Filter to their state when save() was called. + +Matrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix, and resetMatrix. +Clip may be changed by clipRect, clipRRect, clipPath, clipRegion. + +Saved Canvas 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. ## + +#Example +#Description +The black square is translated 50 pixels down and to the right. +Restoring Canvas state removes translate() from Canvas stack; +the red square is not translated, and is drawn at the origin. +## +#Height 100 +void draw(SkCanvas* canvas) { + SkPaint paint; + SkRect rect = { 0, 0, 25, 25 }; + canvas->drawRect(rect, paint); + canvas->save(); + canvas->translate(50, 50); + canvas->drawRect(rect, paint); + canvas->restore(); + paint.setColor(SK_ColorRED); + canvas->drawRect(rect, paint); +} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ +#Subtopic Layer + +Layer allocates a temporary offscreen Bitmap to draw into. When the drawing is complete, +the Bitmap is drawn into the Canvas. + +Layer is saved in a stack along with other saved state. When state with a Layer +is restored, the offscreen Bitmap is drawn into the previous layer. + +Layer may be initialized with the contents of the previous layer. When Layer is +restored, its Bitmap can be modified by Paint passed to Layer to apply Color_Alpha, +Color_Filter, Image_Filter, and Blend_Mode. + +#Method int saveLayer(const SkRect* bounds, const SkPaint* paint) + +Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms), +and allocates an offscreen Bitmap for subsequent drawing. +Calling restore() discards changes to Matrix, Clip, and Draw_Filter, +and draws the offscreen bitmap. +The Matrix, Clip, and Draw_Filter are restored to their state when save() was called. + +Matrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix, and resetMatrix. +Clip may be changed by clipRect, clipRRect, clipPath, clipRegion. + +Rect bounds suggests but does not define the offscreen size. To clip drawing to a specific rectangle, +use clipRect. + +Optional Paint paint applies Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode when restore() is called. + +Call restoreToCount with result to restore this and subsequent saves. + +#Param bounds Used as a hint to limit the size of the offscreen; may be nullptr. ## +#Param paint Used when restore() is called to draw the offscreen; may be nullptr. ## + +#Return Depth of saved stack. ## + +#Example +#Description +Rectangles are blurred by Image_Filter when restore() draws offscreen to main Canvas. +## +#Height 128 +void draw(SkCanvas* canvas) { + SkPaint paint, blur; + blur.setImageFilter(SkImageFilter::MakeBlur(3, 3, nullptr)); + canvas->saveLayer(nullptr, &blur); + SkRect rect = { 25, 25, 50, 50}; + canvas->drawRect(rect, paint); + canvas->translate(50, 50); + paint.setColor(SK_ColorRED); + canvas->drawRect(rect, paint); + canvas->restore(); +} +## + +#ToDo incomplete ## + +## + +#Method int saveLayer(const SkRect& bounds, const SkPaint* paint) + +Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms), +and allocates an offscreen Bitmap for subsequent drawing. +Calling restore() discards changes to Matrix, Clip, and Draw_Filter, +and draws the offscreen Bitmap. +The Matrix, Clip, and Draw_Filter are restored to their state when save() was called. + +Matrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix, and resetMatrix. +Clip may be changed by clipRect, clipRRect, clipPath, clipRegion. + +bounds suggests but does not define the offscreen size. To clip drawing to a specific rectangle, +use clipRect. + +Optional Paint paint applies Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode when restore() is called. + +Call restoreToCount with result to restore this and subsequent saves. + +#Param bounds Used as a hint to limit the size of the offscreen; may be nullptr. ## +#Param paint Used when restore() is called to draw the offscreen; may be nullptr. ## + +#Return Depth of saved stack. ## + +#Example +#Description +Rectangles are blurred by Image_Filter when restore() draws offscreen to main Canvas. +The red rectangle is clipped; it does not fully fit on the offscreen Canvas. +Image_Filter blurs past edge of offscreen so red rectangle is blurred on all sides. +## +#Height 128 +void draw(SkCanvas* canvas) { + SkPaint paint, blur; + blur.setImageFilter(SkImageFilter::MakeBlur(3, 3, nullptr)); + canvas->saveLayer(SkRect::MakeWH(90, 90), &blur); + SkRect rect = { 25, 25, 50, 50}; + canvas->drawRect(rect, paint); + canvas->translate(50, 50); + paint.setColor(SK_ColorRED); + canvas->drawRect(rect, paint); + canvas->restore(); +} +## + +#ToDo incomplete ## + +## + +#Method int saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) + +Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms), +and allocates an offscreen bitmap for subsequent drawing. +LCD_Text is preserved when the offscreen is drawn to the prior layer. + +Draw text on an opaque background so that LCD_Text blends correctly with the prior layer. + +Calling restore() discards changes to Matrix, Clip, and Draw_Filter, +and draws the offscreen bitmap. +The Matrix, Clip, and Draw_Filter are restored to their state when save() was called. + +Matrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix, and resetMatrix. +Clip may be changed by clipRect, clipRRect, clipPath, clipRegion. + +Draw LCD_Text on an opaque background to get good results. + +bounds suggests but does not define the offscreen size. To clip drawing to a specific rectangle, +use clipRect. + +paint modifies how the offscreen overlays the prior layer. Color_Alpha, Blend_Mode, +Color_Filter, Draw_Looper, Image_Filter, and Mask_Filter, affect the offscreen draw. + +Call restoreToCount with result to restore this and subsequent saves. + +#Param bounds Used as a hint to limit the size of the offscreen; may be nullptr. ## +#Param paint Used when restore() is called to draw the offscreen; may be nullptr. ## + +#Return Depth of saved stack. ## + +#Example + SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setLCDRenderText(true);
+ paint.setTextSize(20);
+ for (auto preserve : { false, true } ) {
+ preserve ? canvas->saveLayerPreserveLCDTextRequests(nullptr, nullptr)
+ : canvas->saveLayer(nullptr, nullptr);
+ SkPaint p;
+ p.setColor(SK_ColorWHITE);
+ // Comment out the next line to draw on a non-opaque background.
+ canvas->drawRect(SkRect::MakeLTRB(25, 40, 200, 70), p);
+ canvas->drawString("Hamburgefons", 30, 60, paint);
+
+ p.setColor(0xFFCCCCCC);
+ canvas->drawRect(SkRect::MakeLTRB(25, 70, 200, 100), p);
+ canvas->drawString("Hamburgefons", 30, 90, paint);
+
+ canvas->restore();
+ canvas->translate(0, 80);
+ } + ## + +#ToDo incomplete ## + +## + +#Method int saveLayerAlpha(const SkRect* bounds, U8CPU alpha) + +Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms), +and allocates an offscreen bitmap for subsequent drawing. + +Calling restore() discards changes to Matrix, Clip, and Draw_Filter, +and blends the offscreen bitmap with alpha opacity onto the prior layer. +The Matrix, Clip, and Draw_Filter are restored to their state when save() was called. + +Matrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix, and resetMatrix. +Clip may be changed by clipRect, clipRRect, clipPath, clipRegion. + +bounds suggests but does not define the offscreen size. To clip drawing to a specific rectangle, +use clipRect. + +Call restoreToCount with result to restore this and subsequent saves. + +#Param bounds Used as a hint to limit the size of the offscreen; may be nullptr. ## +#Param alpha The opacity of the offscreen; zero is fully transparent, 255 is fully opaque. ## + +#Return Depth of saved stack. ## + +#Example + SkPaint paint;
+ paint.setColor(SK_ColorRED);
+ canvas->drawCircle(50, 50, 50, paint);
+ canvas->saveLayerAlpha(nullptr, 128);
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawCircle(100, 50, 50, paint);
+ paint.setColor(SK_ColorGREEN);
+ paint.setAlpha(128);
+ canvas->drawCircle(75, 90, 50, paint);
+ canvas->restore(); +## + +#ToDo incomplete ## + +## + +#Enum SaveLayerFlags + +#Code + enum { + kIsOpaque_SaveLayerFlag = 1 << 0, + kPreserveLCDText_SaveLayerFlag = 1 << 1, + kInitWithPrevious_SaveLayerFlag = 1 << 2, + }; + + typedef uint32_t SaveLayerFlags; +## + +SaveLayerFlags provides options that may be used in any combination in SaveLayerRec, +defining how the offscreen allocated by saveLayer operates. + +#Const kIsOpaque_SaveLayerFlag 1 + Creates offscreen without transparency. Flag is ignored if layer Paint contains + Image_Filter or Color_Filter. +## + +#Const kPreserveLCDText_SaveLayerFlag 2 + Creates offscreen for LCD text. Flag is ignored if layer Paint contains + Image_Filter or Color_Filter. +## + +#Const kInitWithPrevious_SaveLayerFlag 4 + Initializes offscreen with the contents of the previous layer. +## + +#Example +#Height 160 +#Description +Canvas layer captures red and blue circles scaled up by four. +scalePaint blends offscreen back with transparency. +## +void draw(SkCanvas* canvas) {
+ SkPaint redPaint, bluePaint, scalePaint;
+ redPaint.setColor(SK_ColorRED);
+ canvas->drawCircle(21, 21, 8, redPaint);
+ bluePaint.setColor(SK_ColorBLUE);
+ canvas->drawCircle(31, 21, 8, bluePaint);
+ SkMatrix matrix;
+ matrix.setScale(4, 4);
+ scalePaint.setAlpha(0x40);
+ scalePaint.setImageFilter(
+ SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr));
+ SkCanvas::SaveLayerRec saveLayerRec(nullptr, &scalePaint,
+ SkCanvas::kInitWithPrevious_SaveLayerFlag);
+ canvas->saveLayer(saveLayerRec);
+ canvas->restore();
+} +## + +#ToDo incomplete ## + +#Enum ## + +#Struct SaveLayerRec + +#Code + struct SaveLayerRec { + SaveLayerRec*(... + + const SkRect* fBounds; + const SkPaint* fPaint; + const SkImageFilter* fBackdrop; + SaveLayerFlags fSaveLayerFlags; + }; +## + +SaveLayerRec contains the state used to create the layer offscreen. + +#Member const SkRect* fBounds + fBounds is used as a hint to limit the size of the offscreen; may be nullptr. + fBounds suggests but does not define the offscreen size. To clip drawing to a specific rectangle, + use clipRect. +## + +#Member const SkPaint* fPaint + fPaint modifies how the offscreen overlays the prior layer; may be nullptr. Color_Alpha, Blend_Mode, + Color_Filter, Draw_Looper, Image_Filter, and Mask_Filter affect the offscreen draw. +## + +#Member const SkImageFilter* fBackdrop + fBackdrop applies Image_Filter to the prior layer when copying to the layer offscreen; may be nullptr. + Use kInitWithPrevious_SaveLayerFlag to copy the prior layer without a Image_Filter. +## + +#Member const SkImage* fClipMask +#ToDo header documentation is incomplete ## + may be nullptr. +## + +#Member const SkMatrix* fClipMatrix +#ToDo header documentation is incomplete ## + may be nullptr. +## + +#Member SaveLayerFlags fSaveLayerFlags + fSaveLayerFlags are used to create layer offscreen without transparency, create layer offscreen for + LCD text, and to create layer offscreen with the contents of the previous layer. +## + +#Example +#Height 160 +#Description +Canvas layer captures a red anti-aliased circle and a blue aliased circle scaled up by four. +After drawing another unscaled red circle on top, the offscreen is transferred to the main canvas. +## +void draw(SkCanvas* canvas) {
+ SkPaint redPaint, bluePaint;
+ redPaint.setAntiAlias(true);
+ redPaint.setColor(SK_ColorRED);
+ canvas->drawCircle(21, 21, 8, redPaint);
+ bluePaint.setColor(SK_ColorBLUE);
+ canvas->drawCircle(31, 21, 8, bluePaint);
+ SkMatrix matrix;
+ matrix.setScale(4, 4);
+ auto scaler = SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr);
+ SkCanvas::SaveLayerRec saveLayerRec(nullptr, nullptr, scaler.get(), 0);
+ canvas->saveLayer(saveLayerRec);
+ canvas->drawCircle(125, 85, 8, redPaint);
+ canvas->restore();
+} +## + +#Method SaveLayerRec() + +Sets fBounds, fPaint, and fBackdrop to nullptr. Clears fSaveLayerFlags. + +#Return empty SaveLayerRec. ## + +#Example + SkCanvas::SaveLayerRec rec1;
+ rec1.fSaveLayerFlags = SkCanvas::kIsOpaque_SaveLayerFlag;
+ SkCanvas::SaveLayerRec rec2(nullptr, nullptr, SkCanvas::kIsOpaque_SaveLayerFlag);
+ SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
+ && rec1.fPaint == rec2.fPaint
+ && rec1.fBackdrop == rec2.fBackdrop
+ && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!'); + #StdOut + rec1 == rec2 + ## +## + +## + +#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0) + +Sets fBounds, fPaint, and fSaveLayerFlags; sets fBackdrop to nullptr. + +#Param bounds Offscreen dimensions; may be nullptr. ## +#Param paint Applied to offscreen when overlaying prior layer; may be nullptr. ## +#Param saveLayerFlags SaveLayerRec options to modify offscreen. ## + +#Return SaveLayerRec with empty backdrop. ## + +#Example + SkCanvas::SaveLayerRec rec1;
+ SkCanvas::SaveLayerRec rec2(nullptr, nullptr);
+ SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
+ && rec1.fPaint == rec2.fPaint
+ && rec1.fBackdrop == rec2.fBackdrop
+ && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!'); + #StdOut + rec1 == rec2 + ## +## + +## + +#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, + SaveLayerFlags saveLayerFlags) + +Sets fBounds, fPaint, fBackdrop, and fSaveLayerFlags. + +#Param bounds Offscreen dimensions; may be nullptr. ## +#Param paint Applied to offscreen when overlaying prior layer; may be nullptr. ## +#Param backdrop Copies prior layer to offscreen with Image_Filter; may be nullptr. ## +#Param saveLayerFlags SaveLayerRec options to modify offscreen. ## + +#Return SaveLayerRec fully specified. ## + +#Example + SkCanvas::SaveLayerRec rec1;
+ SkCanvas::SaveLayerRec rec2(nullptr, nullptr, nullptr, 0);
+ SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
+ && rec1.fPaint == rec2.fPaint
+ && rec1.fBackdrop == rec2.fBackdrop
+ && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!'); + #StdOut + rec1 == rec2 + ## +## + +## + +#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, + const SkImage* clipMask, const SkMatrix* clipMatrix, + SaveLayerFlags saveLayerFlags) + +#Experimental +Not ready for general use. +## + +#Param bounds Offscreen dimensions; may be nullptr. ## +#Param paint Applied to offscreen when overlaying prior layer; may be nullptr. ## +#Param backdrop Copies prior layer to offscreen with Image_Filter; may be nullptr. ## +#Param clipMask May be nullptr. ## +#Param clipMatrix May be nullptr. ## +#Param saveLayerFlags SaveLayerRec options to modify offscreen. ## + +#Return SaveLayerRec fully specified. ## + +#ToDo incomplete ## + +## + +#Struct ## + +#Method int saveLayer(const SaveLayerRec& layerRec) + +Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms), +and allocates an offscreen bitmap for subsequent drawing. + +Calling restore() discards changes to Matrix, Clip, and Draw_Filter, +and blends the offscreen bitmap with alpha opacity onto the prior layer. +The Matrix, Clip, and Draw_Filter are restored to their state when save() was called. + +Matrix 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 layer offscreen. + +Call restoreToCount with result to restore this and subsequent saves. + +#Param layerRec offscreen state. ## + +#Return depth of save state stack. ## + +#Example +#Description +The example draws an image, and saves it into a layer with kInitWithPrevious_SaveLayerFlag. +Next it punches a hole in the layer and restore with SkBlendMode::kPlus. +Where the layer was cleared, the original image will draw unchanged. +Outside of the circle the mandrill is brightened. +## + #Image 3 + // sk_sp<SkImage> image = GetResourceAsImage("mandrill_256.png"); + canvas->drawImage(image, 0, 0, nullptr); + SkCanvas::SaveLayerRec rec; + SkPaint paint; + paint.setBlendMode(SkBlendMode::kPlus); + rec.fSaveLayerFlags = SkCanvas::kInitWithPrevious_SaveLayerFlag; + rec.fPaint = &paint; + canvas->saveLayer(rec); + paint.setBlendMode(SkBlendMode::kClear); + canvas->drawCircle(128, 128, 96, paint); + canvas->restore(); +## + +#ToDo above example needs to replace GetResourceAsImage with way to select image in fiddle ## + +## + +#Subtopic Layer ## + +# ------------------------------------------------------------------------------ + +#Method void restore() + +Removes changes to Matrix, Clip, and Draw_Filter since Canvas state was +last saved. The state is removed from the stack. + +Does nothing if the stack is empty. + +#Example +void draw(SkCanvas* canvas) {
+ SkCanvas simple;
+ SkDebugf("depth = %d\n", simple.getSaveCount());
+ simple.restore();
+ SkDebugf("depth = %d\n", simple.getSaveCount());
+} +## + +## + +# ------------------------------------------------------------------------------ + +#Method int getSaveCount() const + +Returns the number of saved states, each containing: Matrix, Clip, and Draw_Filter. +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. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkCanvas simple;
+ SkDebugf("depth = %d\n", simple.getSaveCount());
+ simple.save();
+ SkDebugf("depth = %d\n", simple.getSaveCount());
+ simple.restore();
+ SkDebugf("depth = %d\n", simple.getSaveCount());
+} +#StdOut +depth = 1
+depth = 2
+depth = 1 +## +## + +## + +# ------------------------------------------------------------------------------ + +#Method void restoreToCount(int saveCount) + +Restores state to Matrix, Clip, and Draw_Filter +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 The depth of state stack to restore. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkDebugf("depth = %d\n", canvas->getSaveCount());
+ canvas->save();
+ canvas->save();
+ SkDebugf("depth = %d\n", canvas->getSaveCount());
+ canvas->restoreToCount(0);
+ SkDebugf("depth = %d\n", canvas->getSaveCount());
+} +#StdOut +depth = 1
+depth = 3
+depth = 1 +## +## + +## + +#Topic State_Stack ## + +# ------------------------------------------------------------------------------ +#Topic Matrix + +#Method void translate(SkScalar dx, SkScalar dy) + +Translate Matrix by dx along the x-axis and dy along the y-axis. + +Mathematically, replace Matrix with a translation matrix +pre-multiplied with Matrix. + +This has the effect of moving the drawing by (dx, dy) before transforming +the result with Matrix. + +#Param dx The distance to translate in x. ## +#Param dy The distance to translate in y. ## + +#Example +#Height 128 +#Description +scale() followed by translate() produces different results from translate() followed +by scale(). + +The blue stroke follows translate of (50, 50); a black +fill follows scale of (2, 1/2.f). After restoring the clip, which resets +Matrix, a red frame follows the same scale of (2, 1/2.f); a gray fill +follows translate of (50, 50). +## +void draw(SkCanvas* canvas) {
+ SkPaint filledPaint;
+ SkPaint outlinePaint;
+ outlinePaint.setStyle(SkPaint::kStroke_Style);
+ outlinePaint.setColor(SK_ColorBLUE);
+ canvas->save();
+ canvas->translate(50, 50);
+ canvas->drawCircle(28, 28, 15, outlinePaint); // blue center: (50+28, 50+28)
+ canvas->scale(2, 1/2.f);
+ canvas->drawCircle(28, 28, 15, filledPaint); // black center: (50+(28*2), 50+(28/2))
+ canvas->restore();
+ filledPaint.setColor(SK_ColorGRAY);
+ outlinePaint.setColor(SK_ColorRED);
+ canvas->scale(2, 1/2.f);
+ canvas->drawCircle(28, 28, 15, outlinePaint); // red center: (28*2, 28/2)
+ canvas->translate(50, 50);
+ canvas->drawCircle(28, 28, 15, filledPaint); // gray center: ((50+28)*2, (50+28)/2)
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void scale(SkScalar sx, SkScalar sy) + +Scale Matrix by sx on the x-axis and sy on the y-axis. + +Mathematically, replace Matrix with a scale matrix +pre-multiplied with Matrix. + +This has the effect of scaling the drawing by (sx, sy) before transforming +the result with Matrix. + +#Param sx The amount to scale in x. ## +#Param sy The amount to scale in y. ## + +#Example +#Height 160 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkRect rect = { 10, 20, 60, 120 };
+ canvas->translate(20, 20);
+ canvas->drawRect(rect, paint);
+ canvas->scale(2, .5f);
+ paint.setColor(SK_ColorGRAY);
+ canvas->drawRect(rect, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void rotate(SkScalar degrees) + +Rotate Matrix by degrees. Positive degrees rotates clockwise. + +Mathematically, replace Matrix with a rotation matrix +pre-multiplied with Matrix. + +This has the effect of rotating the drawing by degrees before transforming +the result with Matrix. + +#Param degrees The amount to rotate, in degrees. ## + +#Example +#Description +Draw clock hands at time 5:10. The hour hand and minute hand point up and +are rotated clockwise. +## +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->translate(128, 128);
+ canvas->drawCircle(0, 0, 60, paint);
+ canvas->save();
+ canvas->rotate(10 * 360 / 60); // 10 minutes of 60 scaled to 360 degrees
+ canvas->drawLine(0, 0, 0, -50, paint);
+ canvas->restore();
+ canvas->rotate((5 + 10.f/60) * 360 / 12); // 5 and 10/60 hours of 12 scaled to 360 degrees
+ canvas->drawLine(0, 0, 0, -30, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void rotate(SkScalar degrees, SkScalar px, SkScalar py) + +Rotate Matrix by degrees about a point at (px, py). Positive degrees rotates clockwise. + +Mathematically, construct a rotation matrix. Pre-multiply the rotation matrix by +a translation matrix, then replace Matrix with the resulting matrix +pre-multiplied with Matrix. + +This has the effect of rotating the drawing about a given point before transforming +the result with Matrix. + +#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. ## + +#Example +#Height 192 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setTextSize(96);
+ canvas->drawString("A1", 130, 100, paint);
+ canvas->rotate(180, 130, 100);
+ canvas->drawString("A1", 130, 100, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void skew(SkScalar sx, SkScalar sy) + +Skew Matrix 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 Matrix with a skew matrix +pre-multiplied with Matrix. + +Preconcat the current matrix with the specified skew. +#Param sx The amount to skew in x. ## +#Param sy The amount to skew in y. ## + +This has the effect of scaling the drawing by (sx, sy) before transforming +the result with Matrix. + +#Example + #Description + Black text mimics an oblique text style by using a negative skew in x that + shifts the geometry to the right as the y values decrease. + Red text uses a positive skew in y to shift the geometry down as the x values + increase. + Blue text combines x and y skew to rotate and scale. + ## + SkPaint paint;
+ paint.setTextSize(128);
+ canvas->translate(30, 130);
+ canvas->save();
+ canvas->skew(-.5, 0);
+ canvas->drawString("A1", 0, 0, paint);
+ canvas->restore();
+ canvas->save();
+ canvas->skew(0, .5);
+ paint.setColor(SK_ColorRED);
+ canvas->drawString("A1", 0, 0, paint);
+ canvas->restore();
+ canvas->skew(-.5, .5);
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawString("A1", 0, 0, paint); +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void concat(const SkMatrix& matrix) + +Replace Matrix with matrix pre-multiplied with Matrix. + +This has the effect of transforming the drawn geometry by matrix, before transforming +the result with Matrix. + +#Param matrix Pre-multiply with Matrix. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setTextSize(80);
+ paint.setTextScaleX(.3);
+ SkMatrix matrix;
+ SkRect rect[2] = {{ 10, 20, 90, 110 }, { 40, 130, 140, 180 }};
+ matrix.setRectToRect(rect[0], rect[1], SkMatrix::kFill_ScaleToFit);
+ canvas->drawRect(rect[0], paint);
+ canvas->drawRect(rect[1], paint);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawString("Here", rect[0].fLeft + 10, rect[0].fBottom - 10, paint);
+ canvas->concat(matrix);
+ canvas->drawString("There", rect[0].fLeft + 10, rect[0].fBottom - 10, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void setMatrix(const SkMatrix& matrix) + +Replace Matrix with matrix. +Unlike concat(), any prior matrix state is overwritten. + +#Param matrix Copied into Matrix. ## + +#Example +#Height 128 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ canvas->scale(4, 6);
+ canvas->drawString("truth", 2, 10, paint);
+ SkMatrix matrix;
+ matrix.setScale(2.8f, 6);
+ canvas->setMatrix(matrix);
+ canvas->drawString("consequences", 2, 20, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void resetMatrix() + +Sets Matrix to the identity matrix. +Any prior matrix state is overwritten. + +#Example +#Height 128 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ canvas->scale(4, 6);
+ canvas->drawString("truth", 2, 10, paint);
+ canvas->resetMatrix();
+ canvas->scale(2.8f, 6);
+ canvas->drawString("consequences", 2, 20, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method const SkMatrix& getTotalMatrix() const + +Returns Matrix. +This does not account for translation by Device or Surface. + +#Return Matrix on Canvas. ## + +#Example + SkDebugf("isIdentity %s\n", canvas->getTotalMatrix().isIdentity() ? "true" : "false");
+ #StdOut
+ isIdentity true
+ ##
+## + +#ToDo incomplete ## + +## + +#Topic Matrix ## + +# ------------------------------------------------------------------------------ +#Topic Clip + +Clip is built from a stack of clipping paths. Each Path in the +stack can be constructed from one or more Path_Contour elements. The +Path_Contour may be composed of any number of Path_Verb segments. Each +Path_Contour forms a closed area; Path_Fill_Type defines the area enclosed +by Path_Contour. + +Clip stack of Path elements successfully restrict the Path area. Each +Path is transformed by Matrix, then intersected with or subtracted from the +prior Clip to form the replacement Clip. Use SkClipOp::kDifference +to subtract Path from Clip; use SkClipOp::kIntersect to intersect Path +with Clip. + +A clipping Path may be anti-aliased; if Path, after transformation, is +composed of horizontal and vertical lines, clearing Anti-alias allows whole pixels +to either be inside or outside the clip. The fastest drawing has a aliased, +rectanglar clip. + +If clipping Path has Anti-alias set, clip may partially clip a pixel, requiring +that drawing blend partially with the destination along the edge. A rotated +rectangular anti-aliased clip looks smoother but draws slower. + +Clip can combine with Rect and Round_Rect primitives; like +Path, these are transformed by Matrix before they are combined with Clip. + +Clip can combine with Region. Region is assumed to be in Device coordinates +and is unaffected by Matrix. + +#Example +#Height 90 + #Description + Draw a red circle with an aliased clip and an anti-aliased clip. + Use an image filter to zoom into the pixels drawn. + The edge of the aliased clip fully draws pixels in the red circle. + The edge of the anti-aliased clip partially draws pixels in the red circle. + ## + SkPaint redPaint, scalePaint;
+ redPaint.setAntiAlias(true);
+ redPaint.setColor(SK_ColorRED);
+ canvas->save();
+ for (bool antialias : { false, true } ) {
+ canvas->save();
+ canvas->clipRect(SkRect::MakeWH(19.5f, 11.5f), antialias);
+ canvas->drawCircle(17, 11, 8, redPaint);
+ canvas->restore();
+ canvas->translate(16, 0);
+ }
+ canvas->restore();
+ SkMatrix matrix;
+ matrix.setScale(6, 6);
+ scalePaint.setImageFilter(
+ SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr));
+ SkCanvas::SaveLayerRec saveLayerRec(
+ nullptr, &scalePaint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
+ canvas->saveLayer(saveLayerRec);
+ canvas->restore(); +## + +#Method void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias) + +Replace Clip with the intersection or difference of Clip and rect, +with an aliased or anti-aliased clip edge. rect is transformed by Matrix +before it is combined with Clip. + +#Param rect Rectangle to combine with Clip. ## +#Param op Clip_Op to apply to Clip. ## +#Param doAntiAlias true if Clip is to be anti-aliased. ## + +#Example +#Height 128 +void draw(SkCanvas* canvas) {
+ canvas->rotate(10);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ for (auto alias: { false, true } ) {
+ canvas->save();
+ canvas->clipRect(SkRect::MakeWH(90, 80), SkClipOp::kIntersect, alias);
+ canvas->drawCircle(100, 60, 60, paint);
+ canvas->restore();
+ canvas->translate(80, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +#Method void clipRect(const SkRect& rect, SkClipOp op) + +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 Matrix +before it is combined with Clip. + +#Param rect Rectangle to combine with Clip. ## +#Param op Clip_Op to apply to Clip. ## + +#Example +#Height 192 +#Width 280 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ for (SkClipOp op: { SkClipOp::kIntersect, SkClipOp::kDifference } ) {
+ canvas->save();
+ canvas->clipRect(SkRect::MakeWH(90, 120), op, false);
+ canvas->drawCircle(100, 100, 60, paint);
+ canvas->restore();
+ canvas->translate(80, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +#Method void clipRect(const SkRect& rect, bool doAntiAlias = 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 Matrix +before it is combined with Clip. + +#Param rect Rectangle to combine with Clip. ## +#Param doAntiAlias true if Clip is to be anti-aliased. ## + +#Example +#Height 133 + #Description + A circle drawn in pieces looks uniform when drawn aliased. + The same circle pieces blend with pixels more than once when anti-aliased, + visible as a thin pair of lines through the right circle. + ## +void draw(SkCanvas* canvas) {
+ canvas->clear(SK_ColorWHITE);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(0x8055aaff);
+ SkRect clipRect = { 0, 0, 87.4f, 87.4f };
+ for (auto alias: { false, true } ) {
+ canvas->save();
+ canvas->clipRect(clipRect, SkClipOp::kIntersect, alias);
+ canvas->drawCircle(67, 67, 60, paint);
+ canvas->restore();
+ canvas->save();
+ canvas->clipRect(clipRect, SkClipOp::kDifference, alias);
+ canvas->drawCircle(67, 67, 60, paint);
+ canvas->restore();
+ canvas->translate(120, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +#Method void androidFramework_setDeviceClipRestriction(const SkIRect& rect) + +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). +The clip restriction is not recorded in pictures. + +#Private +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. ## + +## + +#Method void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias) + +Replace Clip with the intersection or difference of Clip and rrect, +with an aliased or anti-aliased clip edge. +rrect is transformed by Matrix +before it is combined with Clip. + +#Param rrect Round_Rect to combine with Clip. ## +#Param op Clip_Op to apply to Clip. ## +#Param doAntiAlias true if Clip is to be antialiased. ## + +#Example +#Height 128 +void draw(SkCanvas* canvas) {
+ canvas->clear(SK_ColorWHITE);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(0x8055aaff);
+ SkRRect oval;
+ oval.setOval({10, 20, 90, 100});
+ canvas->clipRRect(oval, SkClipOp::kIntersect, true);
+ canvas->drawCircle(70, 100, 60, paint);
+} +## + +#ToDo incomplete ## + +## + +#Method void clipRRect(const SkRRect& rrect, SkClipOp op) + +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 Matrix +before it is combined with Clip. + +#Param rrect Round_Rect to combine with Clip. ## +#Param op Clip_Op to apply to Clip. ## + +#Example +#Height 128 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setColor(0x8055aaff);
+ auto oval = SkRRect::MakeOval({10, 20, 90, 100});
+ canvas->clipRRect(oval, SkClipOp::kIntersect);
+ canvas->drawCircle(70, 100, 60, paint);
+} +## + +#ToDo incomplete ## + +## + +#Method void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) + +Replace Clip with the intersection of Clip and rrect, +with an aliased or anti-aliased clip edge. +rrect is transformed by Matrix +before it is combined with Clip. + +#Param rrect Round_Rect to combine with Clip. ## +#Param doAntiAlias true if Clip is to be antialiased. ## + +#Example +#Height 128 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ auto oval = SkRRect::MakeRectXY({10, 20, 90, 100}, 9, 13);
+ canvas->clipRRect(oval, true);
+ canvas->drawCircle(70, 100, 60, paint);
+} +## + +#ToDo incomplete ## + +## + +#Method void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias) + +Replace Clip with the intersection or difference of Clip and path, +with an aliased or anti-aliased clip edge. Path_Fill_Type 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 Matrix +before it is combined with Clip. + +#Param path Path to combine with Clip. ## +#Param op Clip_Op to apply to Clip. ## +#Param doAntiAlias true if Clip is to be antialiased. ## + +#Example +#Description +Top figure uses SkPath::kInverseWinding_FillType and SkClipOp::kDifference; +area outside clip is subtracted from circle. + +Bottom figure uses SkPath::kWinding_FillType and SkClipOp::kIntersect; +area inside clip is intersected with circle. +## +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPath path;
+ path.addRect({20, 30, 100, 110});
+ path.setFillType(SkPath::kInverseWinding_FillType);
+ canvas->save();
+ canvas->clipPath(path, SkClipOp::kDifference, false);
+ canvas->drawCircle(70, 100, 60, paint);
+ canvas->restore();
+ canvas->translate(100, 100);
+ path.setFillType(SkPath::kWinding_FillType);
+ canvas->clipPath(path, SkClipOp::kIntersect, false);
+ canvas->drawCircle(70, 100, 60, paint);
+} +## + +#ToDo incomplete ## + +## + +#Method void clipPath(const SkPath& path, SkClipOp op) + +Replace Clip with the intersection or difference of Clip and path. +Resulting Clip is aliased; pixels are fully contained by the clip. +Path_Fill_Type 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 Matrix +before it is combined with Clip. + +#Param path Path to combine with Clip. ## +#Param op Clip_Op to apply to Clip. ## + +#Example +#Description +Overlapping Rects form a clip. When clip's Path_Fill_Type is set to +SkPath::kWinding_FillType, the overlap is included. Set to +SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole. +## +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPath path;
+ path.addRect({20, 15, 100, 95});
+ path.addRect({50, 65, 130, 135});
+ path.setFillType(SkPath::kWinding_FillType);
+ canvas->save();
+ canvas->clipPath(path, SkClipOp::kIntersect);
+ canvas->drawCircle(70, 85, 60, paint);
+ canvas->restore();
+ canvas->translate(100, 100);
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ canvas->clipPath(path, SkClipOp::kIntersect);
+ canvas->drawCircle(70, 85, 60, paint);
+} +## + +#ToDo incomplete ## + +## + +#Method void clipPath(const SkPath& path, bool doAntiAlias = false) + +Replace Clip with the intersection of Clip and path. +Resulting Clip is aliased; pixels are fully contained by the clip. +Path_Fill_Type 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 Matrix +before it is combined with Clip. + +#Param path Path to combine with Clip. ## +#Param doAntiAlias true if Clip is to be antialiased. ## + +#Example +#Height 212 +#Description +Clip loops over itself covering its center twice. When clip's Path_Fill_Type +is set to SkPath::kWinding_FillType, the overlap is included. Set to +SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole. +## +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPath path;
+ SkPoint poly[] = {{20, 20}, { 80, 20}, { 80, 80}, {40, 80},
+ {40, 40}, {100, 40}, {100, 100}, {20, 100}};
+ path.addPoly(poly, SK_ARRAY_COUNT(poly), true);
+ path.setFillType(SkPath::kWinding_FillType);
+ canvas->save();
+ canvas->clipPath(path, SkClipOp::kIntersect);
+ canvas->drawCircle(50, 50, 45, paint);
+ canvas->restore();
+ canvas->translate(100, 100);
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ canvas->clipPath(path, SkClipOp::kIntersect);
+ canvas->drawCircle(50, 50, 45, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void setAllowSimplifyClip(bool allow) + +#Experimental +Only used for testing. +## + +Set to simplify clip stack using path ops. + +## + +# ------------------------------------------------------------------------------ + +#Method void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect) + +Replace Clip with the intersection or difference of Clip and Region deviceRgn. +Resulting Clip is aliased; pixels are fully contained by the clip. +deviceRgn is unaffected by Matrix. + +#Param deviceRgn Region to combine with Clip. ## +#Param op Clip_Op to apply to Clip. ## + +#Example +#Description
+ region is unaffected by canvas rotation; rect is affected by canvas rotation.
+ Both clips are aliased; this is unnoticable on Region clip because it
+ aligns to pixel boundaries.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkIRect iRect = {30, 40, 120, 130 };
+ SkRegion region(iRect);
+ canvas->rotate(10);
+ canvas->save();
+ canvas->clipRegion(region, SkClipOp::kIntersect);
+ canvas->drawCircle(50, 50, 45, paint);
+ canvas->restore();
+ canvas->translate(100, 100);
+ canvas->clipRect(SkRect::Make(iRect), SkClipOp::kIntersect);
+ canvas->drawCircle(50, 50, 45, paint);
+} +## + +#ToDo incomplete ## + +## + +#Method bool quickReject(const SkRect& rect) const + +Return true if Rect rect, transformed by Matrix, 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 Rect to compare with Clip. ## + +#Return true if rect, transformed by Matrix, does not intersect Clip. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkRect testRect = {30, 30, 120, 129 };
+ SkRect clipRect = {30, 130, 120, 230 };
+ canvas->save();
+ canvas->clipRect(clipRect);
+ SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false");
+ canvas->restore();
+ canvas->rotate(10);
+ canvas->clipRect(clipRect);
+ SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false");
+} + #StdOut + quickReject true
+ quickReject false + ## +## + +#ToDo incomplete ## + +## + +#Method bool quickReject(const SkPath& path) const + +Return true if path, transformed by Matrix, 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 Path to compare with Clip. ## + +#Return true if path, transformed by Matrix, does not intersect Clip. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPoint testPoints[] = {{30, 30}, {120, 30}, {120, 129} };
+ SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} };
+ SkPath testPath, clipPath;
+ testPath.addPoly(testPoints, SK_ARRAY_COUNT(testPoints), true);
+ clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
+ canvas->save();
+ canvas->clipPath(clipPath);
+ SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false");
+ canvas->restore();
+ canvas->rotate(10);
+ canvas->clipPath(clipPath);
+ SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false");
+ #StdOut + quickReject true
+ quickReject false + ## +} +## + +#ToDo incomplete ## + +## + +#Method SkRect getLocalClipBounds() const + +Return bounds of Clip, transformed by inverse of Matrix. If Clip is empty, +return SkRect::MakeEmpty, where all Rect sides equal zero. + +Rect returned is outset by one to account for partial pixel coverage if Clip +is anti-aliased. + +#Return bounds of Clip in local coordinates. ## + +#Example + #Description + Initial bounds is device bounds outset by 1 on all sides. + Clipped bounds is clipPath bounds outset by 1 on all sides. + Scaling the canvas by two in x and y scales the local bounds by 1/2 in x and y. + ## + SkCanvas local(256, 256);
+ canvas = &local;
+ SkRect bounds = canvas->getLocalClipBounds();
+ SkDebugf("left:%g top:%g right:%g bottom:%g\n",
+ bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+ SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} };
+ SkPath clipPath;
+ clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
+ canvas->clipPath(clipPath);
+ bounds = canvas->getLocalClipBounds();
+ SkDebugf("left:%g top:%g right:%g bottom:%g\n",
+ bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+ canvas->scale(2, 2);
+ bounds = canvas->getLocalClipBounds();
+ SkDebugf("left:%g top:%g right:%g bottom:%g\n",
+ bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+ #StdOut
+ left:-1 top:-1 right:257 bottom:257
+ left:29 top:129 right:121 bottom:231
+ left:14.5 top:64.5 right:60.5 bottom:115.5
+ ##
+## + +# local canvas in example works around bug in fiddle ## +#Bug 6524 ## + +## + +#Method bool getLocalClipBounds(SkRect* bounds) const + +Return bounds of Clip, transformed by inverse of Matrix. If Clip is empty, +return false, and set bounds to SkRect::MakeEmpty, where all Rect sides equal zero. + +bounds is outset by one to account for partial pixel coverage if Clip +is anti-aliased. + +#Param bounds Rect of Clip in local coordinates. ## + +#Return true if Clip bounds is not empty. ## + +#Example + void draw(SkCanvas* canvas) {
+ SkCanvas local(256, 256);
+ canvas = &local;
+ SkRect bounds;
+ SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds)
+ ? "false" : "true");
+ SkPath path;
+ canvas->clipPath(path);
+ SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds)
+ ? "false" : "true");
+ } + #StdOut + local bounds empty = false
+ local bounds empty = true + ## +## + +# local canvas in example works around bug in fiddle ## +#Bug 6524 ## + +## + +#Method SkIRect getDeviceClipBounds() const + +Return IRect bounds of Clip, unaffected by Matrix. If Clip is empty, +return SkRect::MakeEmpty, where all Rect sides equal zero. + +Unlike getLocalClipBounds, returned IRect is not outset. + +#Return bounds of Clip in Device coordinates. ## + +#Example +void draw(SkCanvas* canvas) {
+ #Description
+ Initial bounds is device bounds, not outset. + Clipped bounds is clipPath bounds, not outset. + Scaling the canvas by 1/2 in x and y scales the device bounds by 1/2 in x and y. + ##
+ SkCanvas device(256, 256);
+ canvas = &device;
+ SkIRect bounds = canvas->getDeviceClipBounds();
+ SkDebugf("left:%d top:%d right:%d bottom:%d\n",
+ bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+ SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} };
+ SkPath clipPath;
+ clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
+ canvas->save();
+ canvas->clipPath(clipPath);
+ bounds = canvas->getDeviceClipBounds();
+ SkDebugf("left:%d top:%d right:%d bottom:%d\n",
+ bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+ canvas->restore();
+ canvas->scale(1.f/2, 1.f/2);
+ canvas->clipPath(clipPath);
+ bounds = canvas->getDeviceClipBounds();
+ SkDebugf("left:%d top:%d right:%d bottom:%d\n",
+ bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+ #StdOut + left:0 top:0 right:256 bottom:256
+ left:30 top:130 right:120 bottom:230
+ left:15 top:65 right:60 bottom:115 + ## +} +## + +#ToDo some confusion on why with an identity Matrix local and device are different ## + +# device canvas in example works around bug in fiddle ## +#Bug 6524 ## + +## + +#Method bool getDeviceClipBounds(SkIRect* bounds) const + +Return IRect bounds of Clip, unaffected by Matrix. If Clip is empty, +return false, and set bounds to SkRect::MakeEmpty, where all Rect sides equal zero. + +Unlike getLocalClipBounds, bounds is not outset. + +#Param bounds Rect of Clip in device coordinates. ## + +#Return true if Clip bounds is not empty. ## + +#Example + void draw(SkCanvas* canvas) {
+ SkIRect bounds;
+ SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds)
+ ? "false" : "true");
+ SkPath path;
+ canvas->clipPath(path);
+ SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds)
+ ? "false" : "true");
+ } + #StdOut + device bounds empty = false
+ device bounds empty = true + ## +## + +#ToDo incomplete ## + +## + +#Topic Clip ## + +# ------------------------------------------------------------------------------ + +#Method void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver) + +Fill Clip with Color color. +mode determines how Color_ARGB is combined with destination. + +#Param color Unpremultiplied Color_ARGB. ## +#Param mode SkBlendMode used to combine source color and destination. ## + +#Example + canvas->drawColor(SK_ColorRED);
+ canvas->clipRect(SkRect::MakeWH(150, 150));
+ canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00), SkBlendMode::kPlus);
+ canvas->clipRect(SkRect::MakeWH(75, 75));
+ canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF), SkBlendMode::kPlus);
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void clear(SkColor 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 Color_ARGB. ## + +#Example +void draw(SkCanvas* canvas) {
+ canvas->save();
+ canvas->clipRect(SkRect::MakeWH(256, 128));
+ canvas->clear(SkColorSetARGB(0x80, 0xFF, 0x00, 0x00));
+ canvas->restore();
+ canvas->save();
+ canvas->clipRect(SkRect::MakeWH(150, 192));
+ canvas->clear(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00));
+ canvas->restore();
+ canvas->clipRect(SkRect::MakeWH(75, 256));
+ canvas->clear(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF));
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void discard() + +Make Canvas contents undefined. Subsequent calls that read Canvas pixels, +such as drawing with SkBlendMode, return undefined results. discard() does +not change Clip or Matrix. + +discard() may do nothing, depending on the implementation of Surface or Device +that created Canvas. + +discard() allows optimized performance on subsequent draws by removing +cached data associated with Surface or Device. +It is not necessary to call discard() once done with Canvas; +any cached data is deleted when owning Surface or Device is deleted. + +#ToDo example? not sure how to make this meaningful w/o more implementation detail ## + +#NoExample +## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPaint(const SkPaint& paint) + +Fill Clip with Paint paint. drawPaint is affected by Paint components +Rasterizer, Mask_Filter, Shader, Color_Filter, Image_Filter, and Blend_Mode; but not by +Path_Effect. + +# can Path_Effect in paint ever alter drawPaint? + +#Param paint Used to fill the canvas. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+ SkScalar pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
+ SkPaint paint;
+ paint.setShader(SkGradientShader::MakeSweep(256, 256, colors, pos, SK_ARRAY_COUNT(colors)));
+ canvas->drawPaint(paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Enum PointMode + +#Code + enum PointMode { + kPoints_PointMode, + kLines_PointMode, + kPolygon_PointMode + }; +## + +Selects if an array of points are drawn as discrete points, as lines, or as +an open polygon. + +#Const kPoints_PointMode 0 + Draw each point separately. +## + +#Const kLines_PointMode 1 + Draw each pair of points as a line segment. +## + +#Const kPolygon_PointMode 2 + Draw the array of points as a open polygon. +## + +#Example + #Description + The upper left corner shows three squares when drawn as points. + The upper right corner shows one line; when drawn as lines, two points are required per line. + The lower right corner shows two lines; when draw as polygon, no miter is drawn at the corner. + The lower left corner shows two lines with a miter when path contains polygon. + ## +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(10);
+ SkPoint points[] = {{64, 32}, {96, 96}, {32, 96}};
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 3, points, paint);
+ canvas->translate(128, 0);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 3, points, paint);
+ canvas->translate(0, 128);
+ canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, points, paint);
+ SkPath path;
+ path.addPoly(points, 3, false);
+ canvas->translate(-128, 0);
+ canvas->drawPath(path, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) + +Draw pts using Clip, Matrix and Paint paint. +count is the number of points; if count is less than one, drawPoints 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 Paint_Stroke_Cap. +If paint is set to SkPaint::kRound_Cap, each point draws a circle of diameter Paint_Stroke_Width. +If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, +each point draws a square of width and height Paint_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 Paint_Stroke_Cap and Paint_Stroke_Width. +Paint_Style is ignored, as if were set to SkPaint::kStroke_Style. + +drawPoints always draws each element one at a time; drawPoints is not affected by +Paint_Stroke_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 The number of points in the array. ## +#Param pts Array of points to draw. ## +#Param paint Stroke, blend, color, and so on, used to draw. ## + +#Example +#Height 200 + #Description + #List + # The first column draws points. ## + # The second column draws points as lines. ## + # The third column draws points as a polygon. ## + # The fourth column draws points as a polygonal path. ## + # The first row uses a round cap and round join. ## + # The second row uses a square cap and a miter join. ## + # The third row uses a butt cap and a bevel join. ## + ## + The transparent color makes multiple line draws visible; + the path is drawn all at once. + ## +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(10);
+ paint.setColor(0x80349a45);
+ const SkPoint points[] = {{32, 16}, {48, 48}, {16, 32}};
+ const SkPaint::Join join[] = { SkPaint::kRound_Join,
+ SkPaint::kMiter_Join,
+ SkPaint::kBevel_Join };
+ int joinIndex = 0;
+ SkPath path;
+ path.addPoly(points, 3, false);
+ for (const auto cap : { SkPaint::kRound_Cap, SkPaint::kSquare_Cap, SkPaint::kButt_Cap } ) {
+ paint.setStrokeCap(cap);
+ paint.setStrokeJoin(join[joinIndex++]);
+ for (const auto mode : { SkCanvas::kPoints_PointMode,
+ SkCanvas::kLines_PointMode,
+ SkCanvas::kPolygon_PointMode } ) {
+ canvas->drawPoints(mode, 3, points, paint);
+ canvas->translate(64, 0);
+ }
+ canvas->drawPath(path, paint);
+ canvas->translate(-192, 64);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) + +Draw point at (x, y) using Clip, Matrix and Paint paint. + +The shape of point drawn depends on paint Paint_Stroke_Cap. +If paint is set to SkPaint::kRound_Cap, draw a circle of diameter Paint_Stroke_Width. +If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, +draw a square of width and height Paint_Stroke_Width. +Paint_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. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(0x80349a45);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(100);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+ canvas->scale(1, 1.2f);
+ canvas->drawPoint(64, 96, paint);
+ canvas->scale(.6f, .8f);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawPoint(106, 120, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) + +Draw line segment from (x0, y0) to (x1, y1) using Clip, Matrix, and Paint paint. +In paint: Paint_Stroke_Width describes the line thickness; Paint_Stroke_Cap draws the end rounded or square; +Paint_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. ## + +#Example + SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(0xFF9a67be);
+ paint.setStrokeWidth(20);
+ canvas->skew(1, 0);
+ canvas->drawLine(32, 96, 32, 160, paint);
+ canvas->skew(-2, 0);
+ canvas->drawLine(288, 96, 288, 160, paint);
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawRect(const SkRect& rect, const SkPaint& paint) + +Draw Rect rect using Clip, Matrix, and Paint paint. +In paint: Paint_Style determines if rectangle is stroked or filled; +if stroked, Paint_Stroke_Width describes the line thickness, and +Paint_Stroke_Join draws the corners rounded or square. + +#Param rect The rectangle to be drawn. ## +#Param paint Stroke or fill, blend, color, and so on, used to draw. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPoint rectPts[] = { {64, 48}, {192, 160} };
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(20);
+ paint.setStrokeJoin(SkPaint::kRound_Join);
+ SkMatrix rotator;
+ rotator.setRotate(30, 128, 128);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) {
+ paint.setColor(color);
+ SkRect rect;
+ rect.set(rectPts[0], rectPts[1]);
+ canvas->drawRect(rect, paint);
+ rotator.mapPoints(rectPts, 2);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawIRect(const SkIRect& rect, const SkPaint& paint) + +Draw IRect rect using Clip, Matrix, and Paint paint. +In paint: Paint_Style determines if rectangle is stroked or filled; +if stroked, Paint_Stroke_Width describes the line thickness, and +Paint_Stroke_Join draws the corners rounded or square. + +#Param rect The rectangle to be drawn. ## +#Param paint Stroke or fill, blend, color, and so on, used to draw. ## + +#Example + SkIRect rect = { 64, 48, 192, 160 };
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(20);
+ paint.setStrokeJoin(SkPaint::kRound_Join);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) {
+ paint.setColor(color);
+ canvas->drawIRect(rect, paint);
+ canvas->rotate(30, 128, 128);
+ }
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawRegion(const SkRegion& region, const SkPaint& paint) + +Draw Region region using Clip, Matrix, and Paint paint. +In paint: Paint_Style determines if rectangle is stroked or filled; +if stroked, Paint_Stroke_Width describes the line thickness, and +Paint_Stroke_Join draws the corners rounded or square. + +#Param region The region to be drawn. ## +#Param paint Paint stroke or fill, blend, color, and so on, used to draw. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkRegion region;
+ region.op( 10, 10, 50, 50, SkRegion::kUnion_Op);
+ region.op( 10, 50, 90, 90, SkRegion::kUnion_Op);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(20);
+ paint.setStrokeJoin(SkPaint::kRound_Join);
+ canvas->drawRegion(region, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawOval(const SkRect& oval, const SkPaint& paint) + +Draw Oval oval using Clip, Matrix, and Paint. +In paint: Paint_Style determines if Oval is stroked or filled; +if stroked, Paint_Stroke_Width describes the line thickness. + +#Param oval Rect bounds of Oval. ## +#Param paint Paint stroke or fill, blend, color, and so on, used to draw. ## + +#Example +void draw(SkCanvas* canvas) {
+ canvas->clear(0xFF3f5f9f);
+ SkColor kColor1 = SkColorSetARGB(0xff, 0xff, 0x7f, 0);
+ SkColor g1Colors[] = { kColor1, SkColorSetA(kColor1, 0x20) };
+ SkPoint g1Points[] = { { 0, 0 }, { 0, 100 } };
+ SkScalar pos[] = { 0.2f, 1.0f };
+ SkRect bounds = SkRect::MakeWH(80, 70);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setShader(SkGradientShader::MakeLinear(g1Points, g1Colors, pos, SK_ARRAY_COUNT(g1Colors),
+ SkShader::kClamp_TileMode));
+ canvas->drawOval(bounds , paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawRRect(const SkRRect& rrect, const SkPaint& paint) + +Draw Round_Rect rrect using Clip, Matrix, and Paint paint. +In paint: Paint_Style determines if rrect is stroked or filled; +if stroked, Paint_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 Round_Rect with up to eight corner radii to draw. ## +#Param paint Paint stroke or fill, blend, color, and so on, used to draw. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkRect outer = {30, 40, 210, 220};
+ SkRect radii = {30, 50, 70, 90 };
+ SkRRect rRect;
+ rRect.setNinePatch(outer, radii.fLeft, radii.fTop, radii.fRight, radii.fBottom);
+ canvas->drawRRect(rRect, paint);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawLine(outer.fLeft + radii.fLeft, outer.fTop,
+ outer.fLeft + radii.fLeft, outer.fBottom, paint);
+ canvas->drawLine(outer.fRight - radii.fRight, outer.fTop,
+ outer.fRight - radii.fRight, outer.fBottom, paint);
+ canvas->drawLine(outer.fLeft, outer.fTop + radii.fTop,
+ outer.fRight, outer.fTop + radii.fTop, paint);
+ canvas->drawLine(outer.fLeft, outer.fBottom - radii.fBottom,
+ outer.fRight, outer.fBottom - radii.fBottom, paint);
+}
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) + +Draw Round_Rect outer and inner +using Clip, Matrix, and Paint paint. +outer must contain inner or the drawing is undefined. +In paint: Paint_Style determines if rrect is stroked or filled; +if stroked, Paint_Stroke_Width describes the line thickness. +If stroked and Round_Rect corner has zero length radii, Paint_Stroke_Join can draw +corners rounded or square. + +GPU-backed platforms take advantage of drawDRRect since both outer and inner are +concave and outer contains inner. These platforms may not be able to draw +Path built with identical data as fast. + +#Param outer Round_Rect outer bounds to draw. ## +#Param inner Round_Rect inner bounds to draw. ## +#Param paint Paint stroke or fill, blend, color, and so on, used to draw. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200});
+ SkRRect inner = SkRRect::MakeOval({60, 70, 170, 160});
+ SkPaint paint;
+ canvas->drawDRRect(outer, inner, paint);
+} +## + +#Example +#Description + Outer Rect has no corner radii, but stroke join is rounded. + Inner Round_Rect has corner radii; outset stroke increases radii of corners. + Stroke join does not affect inner Round_Rect since it has no sharp corners. +## +void draw(SkCanvas* canvas) {
+ SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200});
+ SkRRect inner = SkRRect::MakeRectXY({60, 70, 170, 160}, 10, 10);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(20);
+ paint.setStrokeJoin(SkPaint::kRound_Join);
+ canvas->drawDRRect(outer, inner, paint);
+ paint.setStrokeWidth(1);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawDRRect(outer, inner, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) + +Draw Circle at (cx, cy) with radius using Clip, Matrix, and Paint paint. +If radius is zero or less, nothing is drawn. +In paint: Paint_Style determines if Circle is stroked or filled; +if stroked, Paint_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 Paint stroke or fill, blend, color, and so on, used to draw. ## + +#Example + void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas->drawCircle(128, 128, 90, paint);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawCircle(86, 86, 20, paint);
+ canvas->drawCircle(160, 76, 20, paint);
+ canvas->drawCircle(140, 150, 35, paint);
+ }
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint) + +Draw Arc using Clip, Matrix, and Paint 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 Rect oval is empty or sweepAngle is zero, nothing is drawn. + +#Param oval Rect 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 Paint stroke or fill, blend, color, and so on, used to draw. ## + +#Example + void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkRect oval = { 4, 4, 60, 60};
+ for (auto useCenter : { false, true } ) {
+ for (auto style : { SkPaint::kFill_Style, SkPaint::kStroke_Style } ) {
+ paint.setStyle(style);
+ for (auto degrees : { 45, 90, 180, 360} ) {
+ canvas->drawArc(oval, 0, degrees , useCenter, paint);
+ canvas->translate(64, 0);
+ }
+ canvas->translate(-256, 64);
+ }
+ }
+ } +## + +#Example +#Height 64 + void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(4);
+ SkRect oval = { 4, 4, 60, 60};
+ float intervals[] = { 5, 5 };
+ paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f));
+ for (auto degrees : { 270, 360, 540, 720 } ) {
+ canvas->drawArc(oval, 0, degrees, false, paint);
+ canvas->translate(64, 0);
+ }
+ } +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint) + +Draw Round_Rect bounded by Rect rect, with corner radii (rx, ry) using Clip, Matrix, +and Paint paint. +In paint: Paint_Style determines if Round_Rect is stroked or filled; +if stroked, Paint_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, Round_Rect is drawn as Rect and if stroked is affected by Paint_Stroke_Join. + +#Param rect Rect bounds of Round_Rect to draw. ## +#Param rx Semiaxis length in x of oval describing rounded corners. ## +#Param ry Semiaxis length in y of oval describing rounded corners. ## +#Param paint Stroke, blend, color, and so on, used to draw. ## + +#Example +#Description + Top row has a zero radius a generates a rectangle. + Second row radii sum to less than sides. + Third row radii sum equals sides. + Fourth row radii sum exceeds sides; radii are scaled to fit. +## + void draw(SkCanvas* canvas) {
+ SkVector radii[] = { {0, 20}, {10, 10}, {10, 20}, {10, 40} };
+ SkPaint paint;
+ paint.setStrokeWidth(15);
+ paint.setStrokeJoin(SkPaint::kRound_Join);
+ paint.setAntiAlias(true);
+ for (auto style : { SkPaint::kStroke_Style, SkPaint::kFill_Style } ) {
+ paint.setStyle(style );
+ for (size_t i = 0; i < SK_ARRAY_COUNT(radii); ++i) {
+ canvas->drawRoundRect({10, 10, 60, 40}, radii[i].fX, radii[i].fY, paint);
+ canvas->translate(0, 60);
+ }
+ canvas->translate(80, -240);
+ }
+ } +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPath(const SkPath& path, const SkPaint& paint) + +Draw Path path using Clip, Matrix, and Paint paint. +Path contains an array of Path_Contour, each of which may be open or closed. + +In paint: Paint_Style determines if Round_Rect is stroked or filled: +if filled, Path_Fill_Type determines whether Path_Contour describes inside or outside of fill; +if stroked, Paint_Stroke_Width describes the line thickness, Paint_Stroke_Cap describes line ends, +and Paint_Stroke_Join describes how corners are drawn. + +#Param path Path to draw. ## +#Param paint Stroke, blend, color, and so on, used to draw. ## + +#Example +#Description + Top rows draw stroked path with combinations of joins and caps. The open contour + is affected by caps; the closed contour is affected by joins. + Bottom row draws fill the same for open and closed contour. + First bottom column shows winding fills overlap. + Second bottom column shows even odd fills exclude overlap. + Third bottom column shows inverse winding fills area outside both contours. +## +void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.moveTo(20, 20);
+ path.quadTo(60, 20, 60, 60);
+ path.close();
+ path.moveTo(60, 20);
+ path.quadTo(60, 60, 20, 60);
+ SkPaint paint;
+ paint.setStrokeWidth(10);
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ for (auto join: { SkPaint::kBevel_Join, SkPaint::kRound_Join, SkPaint::kMiter_Join } ) {
+ paint.setStrokeJoin(join);
+ for (auto cap: { SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap } ) {
+ paint.setStrokeCap(cap);
+ canvas->drawPath(path, paint);
+ canvas->translate(80, 0);
+ }
+ canvas->translate(-240, 60);
+ }
+ paint.setStyle(SkPaint::kFill_Style);
+ for (auto fill : { SkPath::kWinding_FillType,
+ SkPath::kEvenOdd_FillType,
+ SkPath::kInverseWinding_FillType } ) {
+ path.setFillType(fill);
+ canvas->save();
+ canvas->clipRect({0, 10, 80, 70});
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ canvas->translate(80, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ +#Topic Draw_Image + +drawImage, drawImageRect, and drawImageNine can be called with a bare pointer or a smart pointer as a convenience. +The pairs of calls are otherwise identical. + + +#Method void drawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint = NULL) + +Draw Image image, with its top-left corner at (left, top), +using Clip, Matrix, and optional Paint paint. + +If paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader 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 Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## + +#Example +#Height 64 +#Image 4 +void draw(SkCanvas* canvas) {
+ // sk_sp<SkImage> image;
+ SkImage* imagePtr = image.get();
+ canvas->drawImage(imagePtr, 0, 0);
+ SkPaint paint;
+ canvas->drawImage(imagePtr, 80, 0, &paint);
+ paint.setAlpha(0x80);
+ canvas->drawImage(imagePtr, 160, 0, &paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top, + const SkPaint* paint = NULL) + +Draw Image image, with its top-left corner at (left, top), +using Clip, Matrix, and optional Paint paint. + +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader 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 Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## + +#Example +#Height 64 +#Image 4 +void draw(SkCanvas* canvas) {
+ // sk_sp<SkImage> image;
+ canvas->drawImage(image, 0, 0);
+ SkPaint paint;
+ canvas->drawImage(image, 80, 0, &paint);
+ paint.setAlpha(0x80);
+ canvas->drawImage(image, 160, 0, &paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Enum SrcRectConstraint + +#Code + enum SrcRectConstraint { + kStrict_SrcRectConstraint, + kFast_SrcRectConstraint, + }; +## + +SrcRectConstraint controls the behavior at the edge of the Rect src, provided to drawImageRect, +trading off speed for precision. + +Image_Filter in Paint may sample multiple pixels in the image. +Rect src restricts the bounds of pixels that may be read. Image_Filter may slow +down if it cannot read outside the bounds, when sampling near the edge of Rect src. +SrcRectConstraint specifies whether an Image_Filter is allowed to read pixels +outside Rect src. + +#Const kStrict_SrcRectConstraint + Requires Image_Filter to respect Rect src, + sampling only inside of its bounds, possibly with a performance penalty. +## + +#Const kFast_SrcRectConstraint + Permits Image_Filter to sample outside of Rect src + by half the width of Image_Filter, permitting it to run faster but with + error at the image edges. +## + +#Example +#Height 64 +#Description + redBorder contains a black and white checkerboard bordered by red. + redBorder is drawn scaled by 16 on the left. + The middle and right bitmaps are filtered checkboards. + Drawing the checkerboard with kStrict_SrcRectConstraint shows only a blur of black and white. + Drawing the checkerboard with kFast_SrcRectConstraint allows red to bleed in the corners. +## +void draw(SkCanvas* canvas) {
+ SkBitmap redBorder;
+ redBorder.allocPixels(SkImageInfo::MakeN32Premul(4, 4));
+ SkCanvas checkRed(redBorder);
+ checkRed.clear(SK_ColorRED);
+ uint32_t checkers[][2] = { { SK_ColorBLACK, SK_ColorWHITE },
+ { SK_ColorWHITE, SK_ColorBLACK } };
+ checkRed.writePixels(
+ SkImageInfo::MakeN32Premul(2, 2), (void*) checkers, sizeof(checkers[0]), 1, 1);
+ canvas->scale(16, 16);
+ canvas->drawBitmap(redBorder, 0, 0, nullptr);
+ canvas->resetMatrix();
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder);
+ SkPaint lowPaint;
+ lowPaint.setFilterQuality(kLow_SkFilterQuality);
+ for (auto constraint : { SkCanvas::kStrict_SrcRectConstraint,
+ SkCanvas::kFast_SrcRectConstraint } ) {
+ canvas->translate(80, 0);
+ canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3),
+ SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst, + const SkPaint* paint, + SrcRectConstraint constraint = kStrict_SrcRectConstraint) + +Draw Rect src of Image image, scaled and translated to fill Rect dst. +Additionally transform draw using Clip, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader 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 Paint Filter_Quality to sample within src; +set to kFast_SrcRectConstraint allows sampling outside to improve performance. + +#Param image Image containing pixels, dimensions, and format. ## +#Param src Source Rect of image to draw from. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## +#Param constraint Filter strictly within src or draw faster. ## + +#Example +#Height 64 +#Description + The left bitmap draws with Paint default kNone_SkFilterQuality, and stays within + its bounds; there's no bleeding with kFast_SrcRectConstraint. + the middle and right bitmaps draw with kLow_SkFilterQuality; with + kStrict_SrcRectConstraint, the filter remains within the checkerboard, and + with kFast_SrcRectConstraint red bleeds on the edges. +## +void draw(SkCanvas* canvas) {
+ uint32_t pixels[][4] = {
+ { 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 },
+ { 0xFFFF0000, 0xFF000000, 0xFFFFFFFF, 0xFFFF0000 },
+ { 0xFFFF0000, 0xFFFFFFFF, 0xFF000000, 0xFFFF0000 },
+ { 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 } };
+ SkBitmap redBorder;
+ redBorder.installPixels(SkImageInfo::MakeN32Premul(4, 4),
+ (void*) pixels, sizeof(pixels[0]));
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder);
+ SkPaint lowPaint;
+ for (auto constraint : {
+ SkCanvas::kFast_SrcRectConstraint,
+ SkCanvas::kStrict_SrcRectConstraint,
+ SkCanvas::kFast_SrcRectConstraint } ) {
+ canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3),
+ SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint);
+ lowPaint.setFilterQuality(kLow_SkFilterQuality);
+ canvas->translate(80, 0);
+ }
+}
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) + +Draw IRect isrc of Image image, scaled and translated to fill Rect dst. +Note that isrc is on integer pixel boundaries; dst may include fractional boundaries. +Additionally transform draw using Clip, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader 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 Paint Filter_Quality to sample within src; +set to kFast_SrcRectConstraint allows sampling outside to improve performance. + +#Param image Image containing pixels, dimensions, and format. ## +#Param isrc Source IRect of image to draw from. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## +#Param constraint Filter strictly within src or draw faster. ## + +#Example +#Image 4 +void draw(SkCanvas* canvas) {
+ // sk_sp<SkImage> image;
+ for (auto i : { 1, 2, 4, 8 } ) {
+ canvas->drawImageRect(image.get(), SkIRect::MakeLTRB(0, 0, 100, 100),
+ SkRect::MakeXYWH(i * 20, i * 20, i * 20, i * 20), nullptr);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint, + SrcRectConstraint constraint = kStrict_SrcRectConstraint) + +Draw Image image, scaled and translated to fill Rect dst, +using Clip, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader made from +SkImage::makeShader with SkShader::kClamp_TileMode set replicates the image's edge +color when it samples outside of its bounds. +Use constaint to choose kStrict_SrcRectConstraint or kFast_SrcRectConstraint. + +#Param image Image containing pixels, dimensions, and format. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## +#Param constraint Filter strictly within src or draw faster. ## + +#Example +#Image 4 +void draw(SkCanvas* canvas) {
+ // sk_sp<SkImage> image;
+ for (auto i : { 20, 40, 80, 160 } ) {
+ canvas->drawImageRect(image.get(), SkRect::MakeXYWH(i, i, i, i), nullptr);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst, + const SkPaint* paint, + SrcRectConstraint constraint = kStrict_SrcRectConstraint) + +Draw Rect src of Image image, scaled and translated to fill Rect dst. +Additionally transform draw using Clip, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader 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 Paint Filter_Quality to sample within src; +set to kFast_SrcRectConstraint allows sampling outside to improve performance. + +#Param image Image containing pixels, dimensions, and format. ## +#Param src Source Rect of image to draw from. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## +#Param constraint Filter strictly within src or draw faster. ## + +#Example +#Height 64 +#Description + Canvas scales and translates; transformation from src to dst also scales. + The two matrices are concatenated to create the final transformation. +## +void draw(SkCanvas* canvas) {
+ uint32_t pixels[][2] = { { SK_ColorBLACK, SK_ColorWHITE },
+ { SK_ColorWHITE, SK_ColorBLACK } };
+ SkBitmap bitmap;
+ bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
+ (void*) pixels, sizeof(pixels[0]));
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ SkPaint paint;
+ canvas->scale(4, 4);
+ for (auto alpha : { 50, 100, 150, 255 } ) {
+ paint.setAlpha(alpha);
+ canvas->drawImageRect(image, SkRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint);
+ canvas->translate(8, 0);
+ }
+}
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawImageRect(const sk_sp<SkImage>& image, const SkIRect& isrc, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) + +Draw IRect isrc of Image image, scaled and translated to fill Rect dst. +Note that isrc is on integer pixel boundaries; dst may include fractional boundaries. +Additionally transform draw using Clip, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader made from +SkShader::MakeBitmapShader with SkShader::kClamp_TileMode set replicates the image's edge +color when it samples outside of its bounds. +cons set to kStrict_SrcRectConstraint limits Paint Filter_Quality to sample within src; +set to kFast_SrcRectConstraint allows sampling outside to improve performance. + +#Param image Image containing pixels, dimensions, and format. ## +#Param isrc Source IRect of image to draw from. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## +#Param constraint Filter strictly within src or draw faster. ## + +#Example +#Height 64 +void draw(SkCanvas* canvas) {
+ uint32_t pixels[][2] = { { 0x00000000, 0x55555555},
+ { 0xAAAAAAAA, 0xFFFFFFFF} };
+ SkBitmap bitmap;
+ bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
+ (void*) pixels, sizeof(pixels[0]));
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ SkPaint paint;
+ canvas->scale(4, 4);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
+ paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
+ canvas->drawImageRect(image, SkIRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint);
+ canvas->translate(8, 0);
+ }
+} +## + +#ToDo incomplete ## +## + +# ------------------------------------------------------------------------------ + +#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& dst, const SkPaint* paint, + SrcRectConstraint constraint = kStrict_SrcRectConstraint) + +Draw Image image, scaled and translated to fill Rect dst, +using Clip, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader 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 Paint Filter_Quality to sample within src; +set to kFast_SrcRectConstraint allows sampling outside to improve performance. + +#Param image Image containing pixels, dimensions, and format. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## +#Param constraint Filter strictly within src or draw faster. ## + +#Example +#Height 64 +void draw(SkCanvas* canvas) {
+ uint32_t pixels[][2] = { { 0x00000000, 0x55550000},
+ { 0xAAAA0000, 0xFFFF0000} };
+ SkBitmap bitmap;
+ bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
+ (void*) pixels, sizeof(pixels[0]));
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ SkPaint paint;
+ canvas->scale(4, 4);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
+ paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
+ canvas->drawImageRect(image, SkRect::MakeWH(8, 8), &paint);
+ canvas->translate(8, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, + const SkPaint* paint = nullptr) + +Draw Image image stretched differentially to fit into Rect dst. +IRect center divides the image into nine sections: four sides, four corners, and the center. +corners are unscaled 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, Matrix, and optional Paint paint. +If paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader made from +SkShader::MakeBitmapShader with SkShader::kClamp_TileMode set replicates the image's edge +color when it samples outside of its bounds. + +#Param image Image containing pixels, dimensions, and format. ## +#Param center IRect edge of image corners and sides. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## + +#Example +#Height 128 +#Description + The leftmost image is smaller than center; only corners are drawn, all scaled to fit. + The second image equals the size of center; only corners are drawn, unscaled. + The remaining images are larger than center. All corners draw unscaled. The sides + and center are scaled if needed to take up the remaining space. +## +void draw(SkCanvas* canvas) {
+ SkIRect center = { 20, 10, 50, 40 };
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
+ SkCanvas bitCanvas(bitmap);
+ SkPaint paint;
+ SkColor gray = 0xFF000000;
+ int left = 0;
+ for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
+ int top = 0;
+ for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
+ paint.setColor(gray);
+ bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
+ gray += 0x001f1f1f;
+ top = bottom;
+ }
+ left = right;
+ }
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ SkImage* imagePtr = image.get();
+ for (auto dest: { 20, 30, 40, 60, 90 } ) {
+ canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr);
+ canvas->translate(dest + 4, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawImageNine(const sk_sp<SkImage>& image, const SkIRect& center, const SkRect& dst, + const SkPaint* paint = nullptr) + +Draw Image image stretched differentially to fit into Rect dst. +IRect center divides the image into nine sections: four sides, four corners, and the center. +corners are unscaled 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, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader made from +SkShader::MakeBitmapShader with SkShader::kClamp_TileMode set replicates the image's edge +color when it samples outside of its bounds. + +#Param image Image containing pixels, dimensions, and format. ## +#Param center IRect edge of image corners and sides. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## + +#Example +#Height 128 +#Description + The two leftmost images has four corners and sides to the left and right of center. + The leftmost image scales the width of corners proportionately to fit. + The third and fourth image corners are unscaled; the sides and center are scaled to + fill the remaining space. + The rightmost image has four corners scaled vertically to fit, and uses sides above + and below center to fill the remaining space. +## +void draw(SkCanvas* canvas) {
+ SkIRect center = { 20, 10, 50, 40 };
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
+ SkCanvas bitCanvas(bitmap);
+ SkPaint paint;
+ SkColor gray = 0xFF000000;
+ int left = 0;
+ for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
+ int top = 0;
+ for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
+ paint.setColor(gray);
+ bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
+ gray += 0x001f1f1f;
+ top = bottom;
+ }
+ left = right;
+ }
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ for (auto dest: { 20, 30, 40, 60, 90 } ) {
+ canvas->drawImageNine(image, center, SkRect::MakeWH(dest, 110 - dest), nullptr);
+ canvas->translate(dest + 4, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, + const SkPaint* paint = NULL) + +Draw Bitmap bitmap, with its top-left corner at (left, top), +using Clip, Matrix, and optional Paint paint. +If paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If bitmap is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from bitmap bounds. If generated mask extends +beyond bitmap bounds, replicate bitmap edge colors, just as Shader made from +SkShader::MakeBitmapShader with SkShader::kClamp_TileMode set replicates the bitmap's edge +color when it samples outside of its bounds. + +#Param bitmap Bitmap containing pixels, dimensions, and format. ## +#Param left Left side of bitmap. ## +#Param top Top side of bitmap. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## + +#Example +#Height 64 +void draw(SkCanvas* canvas) {
+ uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00},
+ { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
+ { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00},
+ { 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF},
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00},
+ { 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00},
+ { 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF} };
+ SkBitmap bitmap;
+ bitmap.installPixels(SkImageInfo::MakeA8(8, 8),
+ (void*) pixels, sizeof(pixels[0]));
+ SkPaint paint;
+ canvas->scale(4, 4);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) {
+ paint.setColor(color);
+ canvas->drawBitmap(bitmap, 0, 0, &paint);
+ canvas->translate(12, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) + +Draw Rect src of Bitmap bitmap, scaled and translated to fill Rect dst. +Additionally transform draw using Clip, Matrix, and optional Paint paint. +If paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If bitmap is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from bitmap bounds. If generated mask extends +beyond bitmap bounds, replicate bitmap edge colors, just as Shader 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 Paint Filter_Quality to sample within src; +set to kFast_SrcRectConstraint allows sampling outside to improve performance. + +#Param bitmap Bitmap containing pixels, dimensions, and format. ## +#Param src Source Rect of image to draw from. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## +#Param constraint Filter strictly within src or draw faster. ## + +#Example +#Height 64 +void draw(SkCanvas* canvas) {
+ uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00},
+ { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
+ { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00},
+ { 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF},
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00},
+ { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
+ { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00} };
+ SkBitmap bitmap;
+ bitmap.installPixels(SkImageInfo::MakeA8(8, 8),
+ (void*) pixels, sizeof(pixels[0]));
+ SkPaint paint;
+ paint.setMaskFilter(SkBlurMaskFilter::Make(kSolid_SkBlurStyle, 6));
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) {
+ paint.setColor(color);
+ canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint);
+ canvas->translate(48, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) + +Draw IRect isrc of Bitmap bitmap, scaled and translated to fill Rect dst. +Note that isrc is on integer pixel boundaries; dst may include fractional boundaries. +Additionally transform draw using Clip, Matrix, and optional Paint paint. +If paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If bitmap is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from bitmap bounds. If generated mask extends +beyond bitmap bounds, replicate bitmap edge colors, just as Shader 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 Paint Filter_Quality to sample within src; +set to kFast_SrcRectConstraint allows sampling outside to improve performance. + +#Param bitmap Bitmap containing pixels, dimensions, and format. ## +#Param isrc Source IRect of image to draw from. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## +#Param constraint Filter strictly within src or draw faster. ## + +#Example +#Height 64 +void draw(SkCanvas* canvas) {
+ uint8_t pixels[][8] = { { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
+ { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
+ { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF},
+ { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF},
+ { 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF},
+ { 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF},
+ { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
+ { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00} };
+ SkBitmap bitmap;
+ bitmap.installPixels(SkImageInfo::MakeA8(8, 8),
+ (void*) pixels, sizeof(pixels[0]));
+ SkPaint paint;
+ paint.setFilterQuality(kHigh_SkFilterQuality);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00, 0xFF7f007f} ) {
+ paint.setColor(color);
+ canvas->drawBitmapRect(bitmap, SkIRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint);
+ canvas->translate(48.25f, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint, + SrcRectConstraint constraint = kStrict_SrcRectConstraint) + +Draw Bitmap bitmap, scaled and translated to fill Rect dst. +Note that isrc is on integer pixel boundaries; dst may include fractional boundaries. +Additionally transform draw using Clip, Matrix, and optional Paint paint. +If paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If bitmap is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from bitmap bounds. If generated mask extends +beyond bitmap bounds, replicate bitmap edge colors, just as Shader 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 Paint Filter_Quality to sample within src; +set to kFast_SrcRectConstraint allows sampling outside to improve performance. + +#Param bitmap Bitmap containing pixels, dimensions, and format. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## +#Param constraint Filter strictly within src or draw faster. ## + +#Example +#Height 64 +void draw(SkCanvas* canvas) {
+ uint32_t pixels[][2] = { { 0x00000000, 0x55550000},
+ { 0xAAAA0000, 0xFFFF0000} };
+ SkBitmap bitmap;
+ bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
+ (void*) pixels, sizeof(pixels[0]));
+ SkPaint paint;
+ canvas->scale(4, 4);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
+ paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
+ canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), &paint);
+ canvas->translate(8, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, + const SkPaint* paint = NULL) + +Draw Bitmap bitmap stretched differentially to fit into Rect dst. +IRect center divides the bitmap into nine sections: four sides, four corners, and the center. +corners are unscaled 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, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If bitmap is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from bitmap bounds. If generated mask extends +beyond bitmap bounds, replicate bitmap edge colors, just as Shader made from +SkShader::MakeBitmapShader with SkShader::kClamp_TileMode set replicates the bitmap's edge +color when it samples outside of its bounds. + +#Param bitmap Bitmap containing pixels, dimensions, and format. ## +#Param center IRect edge of image corners and sides. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## + +#Example +#Height 128 +#Description + The two leftmost bitmap draws has four corners and sides to the left and right of center. + The leftmost bitmap draw scales the width of corners proportionately to fit. + The third and fourth draw corners are unscaled; the sides and center are scaled to + fill the remaining space. + The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above + and below center to fill the remaining space. +## +void draw(SkCanvas* canvas) {
+ SkIRect center = { 20, 10, 50, 40 };
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
+ SkCanvas bitCanvas(bitmap);
+ SkPaint paint;
+ SkColor gray = 0xFF000000;
+ int left = 0;
+ for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
+ int top = 0;
+ for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
+ paint.setColor(gray);
+ bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
+ gray += 0x001f1f1f;
+ top = bottom;
+ }
+ left = right;
+ }
+ for (auto dest: { 20, 30, 40, 60, 90 } ) {
+ canvas->drawBitmapNine(bitmap, center, SkRect::MakeWH(dest, 110 - dest), nullptr);
+ canvas->translate(dest + 4, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ +#Struct Lattice + + Lattice divides Bitmap or Image into a rectangular grid. + Grid entries on even columns and even rows are fixed; these entries are + always drawn at their original size if the destination is large enough. + If the destination side is too small to hold the fixed entries, all fixed + entries are proportionately scaled down to fit. + The grid entries not on even columns and rows are scaled to fit the + remaining space, if any. + +#Code + struct Lattice { + enum Flags {... + + const int* fXDivs; + const int* fYDivs; + const Flags* fFlags; + int fXCount; + int fYCount; + const SkIRect* fBounds; + }; +## + + #Enum Flags + #Code + enum Flags : uint8_t { + kTransparent_Flags = 1 << 0, + }; + ## + + Optional setting per rectangular grid entry to make it transparent. + + #Const kTransparent_Flags 1 + Set to skip lattice rectangle by making it transparent. + ## + ## + + #Member const int* fXDivs + 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. + ## + + #Member const int* fYDivs + 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. + ## + + #Member const Flags* fFlags + 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. + ## + + #Member int fXCount + Number of entries in fXDivs array; one less than the number of horizontal divisions. + ## + + #Member int fYCount + Number of entries in fYDivs array; one less than the number of vertical divisions. + ## + + #Member const SkIRect* fBounds + Optional subset IRect source to draw from. + If nullptr, source bounds is dimensions of Bitmap or Image. + ## + +#Struct Lattice ## + +#Method void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst, + const SkPaint* paint = nullptr) + +Draw Bitmap bitmap stretched differentially to fit into Rect 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, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If bitmap is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from bitmap bounds. If generated mask extends +beyond bitmap bounds, replicate bitmap edge colors, just as Shader made from +SkShader::MakeBitmapShader with SkShader::kClamp_TileMode set replicates the bitmap's edge +color when it samples outside of its bounds. + +#Param bitmap Bitmap containing pixels, dimensions, and format. ## +#Param lattice Division of bitmap into fixed and variable rectangles. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## + +#Example +#Height 128 +#Description + The two leftmost bitmap draws has four corners and sides to the left and right of center. + The leftmost bitmap draw scales the width of corners proportionately to fit. + The third and fourth draw corners are unscaled; the sides are scaled to + fill the remaining space; the center is transparent. + The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above + and below center to fill the remaining space. +## +void draw(SkCanvas* canvas) {
+ SkIRect center = { 20, 10, 50, 40 };
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
+ SkCanvas bitCanvas(bitmap);
+ SkPaint paint;
+ SkColor gray = 0xFF000000;
+ int left = 0;
+ for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
+ int top = 0;
+ for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
+ paint.setColor(gray);
+ bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
+ gray += 0x001f1f1f;
+ top = bottom;
+ }
+ left = right;
+ }
+ const int xDivs[] = { center.fLeft, center.fRight };
+ const int yDivs[] = { center.fTop, center.fBottom };
+ SkCanvas::Lattice::Flags flags[3][3];
+ memset(flags, 0, sizeof(flags));
+ flags[1][1] = SkCanvas::Lattice::kTransparent_Flags;
+ SkCanvas::Lattice lattice = { xDivs, yDivs, flags[0], SK_ARRAY_COUNT(xDivs),
+ SK_ARRAY_COUNT(yDivs), nullptr };
+ for (auto dest: { 20, 30, 40, 60, 90 } ) {
+ canvas->drawBitmapLattice(bitmap, lattice , SkRect::MakeWH(dest, 110 - dest), nullptr);
+ canvas->translate(dest + 4, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, + const SkPaint* paint = nullptr) + +Draw Image image stretched differentially to fit into Rect dst. + +Lattice lattice divides image into a rectangular grid. +Each intersection of an even-numbered row and column is fixed; like the corners +of drawImageNine, 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, Matrix, and optional Paint paint. +If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode, and Draw_Looper. +If image is kAlpha_8_SkColorType, apply Shader. +if paint contains Mask_Filter, generate mask from image bounds. If generated mask extends +beyond image bounds, replicate image edge colors, just as Shader made from +SkShader::MakeBitmapShader with SkShader::kClamp_TileMode set replicates the image's edge +color when it samples outside of its bounds. + +#Param image Image containing pixels, dimensions, and format. ## +#Param lattice Division of bitmap into fixed and variable rectangles. ## +#Param dst Destination Rect of image to draw to. ## +#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, and so on; or nullptr. ## + +#Example +#Height 128 +#Description + The leftmost image is smaller than center; only corners are drawn, all scaled to fit. + The second image equals the size of center; only corners are drawn, unscaled. + The remaining images are larger than center. All corners draw unscaled. The sides + are scaled if needed to take up the remaining space; the center is transparent. +## +void draw(SkCanvas* canvas) {
+ SkIRect center = { 20, 10, 50, 40 };
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
+ SkCanvas bitCanvas(bitmap);
+ SkPaint paint;
+ SkColor gray = 0xFF000000;
+ int left = 0;
+ for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
+ int top = 0;
+ for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
+ paint.setColor(gray);
+ bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
+ gray += 0x001f1f1f;
+ top = bottom;
+ }
+ left = right;
+ }
+ const int xDivs[] = { center.fLeft, center.fRight };
+ const int yDivs[] = { center.fTop, center.fBottom };
+ SkCanvas::Lattice::Flags flags[3][3];
+ memset(flags, 0, sizeof(flags));
+ flags[1][1] = SkCanvas::Lattice::kTransparent_Flags;
+ SkCanvas::Lattice lattice = { xDivs, yDivs, flags[0], SK_ARRAY_COUNT(xDivs),
+ SK_ARRAY_COUNT(yDivs), nullptr };
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ SkImage* imagePtr = image.get();
+ for (auto dest: { 20, 30, 40, 60, 90 } ) {
+ canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr);
+ canvas->translate(dest + 4, 0);
+ }
+} +## + +#ToDo incomplete ## + +## + +#Topic Draw_Image ## + +# ------------------------------------------------------------------------------ + +#Method void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint& paint) + +Draw text, with origin at (x, y), using Clip, Matrix, and Paint paint. +text's meaning depends on Paint_Text_Encoding; by default, text encoding is UTF-8. +x and y meaning depends on Paint_Text_Align and Paint_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 Matrix and Paint_Text_Size. + +All elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; apply to text. By default, drawText 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. ## + +#Example +#Height 200 +#Description + The same text is drawn varying Paint_Text_Size and varying + Matrix. +## +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ float textSizes[] = { 12, 18, 24, 36 };
+ for (auto size: textSizes ) {
+ paint.setTextSize(size);
+ canvas->drawText("Aa", 2, 10, 20, paint);
+ canvas->translate(0, size * 2);
+ }
+ paint.reset();
+ paint.setAntiAlias(true);
+ float yPos = 20;
+ for (auto size: textSizes ) {
+ float scale = size / 12.f;
+ canvas->resetMatrix();
+ canvas->translate(100, 0);
+ canvas->scale(scale, scale);
+ canvas->drawText("Aa", 2, 10 / scale, yPos / scale, paint);
+ yPos += size * 2;
+ }
+}
+## + +#ToDo incomplete ## + +## + +#Method void drawString(const char* string, SkScalar x, SkScalar y, const SkPaint& paint) + +Draw null terminated string, with origin at (x, y), using Clip, Matrix, and Paint paint. +string's meaning depends on Paint_Text_Encoding; by default, string encoding is UTF-8. +Other values of Paint_Text_Encoding are unlikely to produce the desired results, since +zero bytes may be embedded in the string. +x and y meaning depends on Paint_Text_Align and Paint_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 Matrix and Paint_Text_Size. + +All elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; apply to string. By default, drawString 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. ## + +#Example + SkPaint paint; + canvas->drawString("a small hello", 20, 20, paint); +## + +#SeeAlso drawText + +## + +#Method void drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) + +Draw null terminated string, with origin at (x, y), using Clip, Matrix, and Paint paint. +string's meaning depends on Paint_Text_Encoding; by default, string encoding is UTF-8. +Other values of Paint_Text_Encoding are unlikely to produce the desired results, since +zero bytes may be embedded in the string. +x and y meaning depends on Paint_Text_Align and Paint_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 Matrix and Paint_Text_Size. + +All elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; apply to string. By default, drawString 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. ## + +#Example + SkPaint paint; + SkString string("a small hello"); + canvas->drawString(string, 20, 20, paint); +## + +#SeeAlso drawText + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint& paint) + +Draw each glyph in text with the origin in pos array, using Clip, Matrix, and Paint paint. +The number of entries in pos array must match the number of glyphs described by byteLength of text. +text's meaning depends on Paint_Text_Encoding; by default, text encoding is UTF-8. +pos elements' meaning depends on Paint_Text_Align and Paint_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 Matrix and Paint_Text_Size. + +All elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; apply to text. By default, drawPosText draws filled 12 point black +glyphs. + +Layout engines such as Harfbuzz typically use drawPosText to 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. ## + +#Example +#Height 120 +void draw(SkCanvas* canvas) {
+ const char hello[] = "HeLLo!";
+ const SkPoint pos[] = { {40, 100}, {82, 95}, {115, 110}, {130, 95}, {145, 85},
+ {172, 100} };
+ SkPaint paint;
+ paint.setTextSize(60);
+ canvas->drawPosText(hello, strlen(hello), pos, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) + +Draw each glyph in text with its (x, y) origin composed from xpos array and constY, using Clip, Matrix, and Paint paint. +The number of entries in xpos array must match the number of glyphs described by byteLength of text. +text's meaning depends on Paint_Text_Encoding; by default, text encoding is UTF-8. +pos elements' meaning depends on Paint_Text_Align and Paint_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 Matrix and Paint_Text_Size. + +All elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; apply to text. By default, drawPosTextH draws filled 12 point black +glyphs. + +Layout engines such as Harfbuzz typically use drawPosTextH to 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. ## + +#Example +#Height 40 + void draw(SkCanvas* canvas) {
+ SkScalar xpos[] = { 20, 40, 80, 160 };
+ SkPaint paint;
+ canvas->drawPosTextH("XXXX", 4, xpos, 20, paint);
+ }
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawTextOnPathHV(const void* text, size_t byteLength, const SkPath& path, SkScalar hOffset, + SkScalar vOffset, const SkPaint& paint) + +Draw text on Path path, using Clip, Matrix, and Paint 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 Paint_Text_Encoding; by default, text encoding is UTF-8. +Origin meaning depends on Paint_Text_Align and Paint_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 Matrix and Paint_Text_Size. + +All elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; apply to text. By default, drawTextOnPathHV draws filled 12 point black +glyphs. + +#Param text Character code points or glyphs drawn. ## +#Param byteLength Byte length of text array. ## +#Param path Path 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. ## + +#Example + void draw(SkCanvas* canvas) {
+ const char aero[] = "correo a" "\xC3" "\xA9" "reo";
+ const size_t len = sizeof(aero) - 1;
+ SkPath path;
+ path.addOval({43-26, 43-26, 43+26, 43+26}, SkPath::kCW_Direction, 3);
+ SkPaint paint;
+ paint.setTextSize(24);
+ for (auto offset : { 0, 10, 20 } ) {
+ canvas->drawTextOnPathHV(aero, len, path, 0, -offset, paint);
+ canvas->translate(70 + offset, 70 + offset);
+ }
+ }
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, + const SkMatrix* matrix, const SkPaint& paint) + +Draw text on Path path, using Clip, Matrix, and Paint 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 Paint_Text_Encoding; by default, text encoding is UTF-8. +Origin meaning depends on Paint_Text_Align and Paint_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 Matrix and Paint_Text_Size. + +All elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; apply to text. By default, drawTextOnPath draws filled 12 point black +glyphs. + +#Param text Character code points or glyphs drawn. ## +#Param byteLength Byte length of text array. ## +#Param path Path providing text baseline. ## +#Param matrix Optional transform of glyphs before mapping to path; or nullptr. ## +#Param paint Text size, blend, color, and so on, used to draw. ## + +#Example + void draw(SkCanvas* canvas) {
+ const char roller[] = "rollercoaster";
+ const size_t len = sizeof(roller) - 1;
+ SkPath path;
+ path.cubicTo(40, -80, 120, 80, 160, -40);
+ SkPaint paint;
+ paint.setTextSize(32);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkMatrix matrix;
+ matrix.setIdentity();
+ for (int i = 0; i < 3; ++i) {
+ canvas->translate(25, 60);
+ canvas->drawPath(path, paint);
+ canvas->drawTextOnPath(roller, len, path, &matrix, paint);
+ matrix.preTranslate(0, 10);
+ }
+ }
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], + const SkRect* cullRect, const SkPaint& paint) + +Draw text, transforming each glyph by the corresponding SkRSXform, +using Clip, Matrix, and Paint paint. +RSXform array specifies a separate square scale, rotation, and translation for +each glyph. +Optional Rect cullRect is a conservative bounds of text, +taking into account RSXform and paint. If cullrect is outside of Clip, canvas can +skip drawing. + +All elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; apply to text. By default, drawTextRSXform draws filled 12 point black +glyphs. + +#Param text Character code points or glyphs drawn. ## +#Param byteLength Byte length of text array. ## +#Param xform RSXform rotates, scales, and translates each glyph individually. ## +#Param cullRect Rect bounds of text for efficient clipping; or nullptr. ## +#Param paint Text size, blend, color, and so on, used to draw. ## + +#Example +void draw(SkCanvas* canvas) {
+ const int iterations = 26;
+ SkRSXform transforms[iterations];
+ char alphabet[iterations];
+ SkScalar angle = 0;
+ SkScalar scale = 1;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(transforms); ++i) {
+ const SkScalar s = SkScalarSin(angle) * scale;
+ const SkScalar c = SkScalarCos(angle) * scale;
+ transforms[i] = SkRSXform::Make(-c, -s, -s * 16, c * 16);
+ angle += .45;
+ scale += .2;
+ alphabet[i] = 'A' + i;
+ }
+ SkPaint paint;
+ paint.setTextAlign(SkPaint::kCenter_Align);
+ canvas->translate(110, 138);
+ canvas->drawTextRSXform(alphabet, sizeof(alphabet), transforms, nullptr, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) + +Draw Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint. +blob contains glyphs, their positions, and paint attributes specific to text: +Typeface, Paint_Text_Size, Paint_Text_Scale_X, Paint_Text_Skew_X, Paint_Text_Align, +Paint_Hinting, Anti-alias, Paint_Fake_Bold, Font_Embedded_Bitmaps, Full_Hinting_Spacing, +LCD_Text, Linear_Text, Subpixel_Text, and Paint_Vertical_Text. + +Elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; 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. ## + +#Example +#Height 120 + void draw(SkCanvas* canvas) {
+ SkTextBlobBuilder textBlobBuilder;
+ const char bunny[] = "/(^x^)\\";
+ const int len = sizeof(bunny) - 1;
+ uint16_t glyphs[len];
+ SkPaint paint;
+ paint.textToGlyphs(bunny, len, glyphs);
+ int runs[] = { 3, 1, 3 };
+ SkPoint textPos = { 20, 100 };
+ int glyphIndex = 0;
+ for (auto runLen : runs) {
+ paint.setTextSize(1 == runLen ? 20 : 50);
+ const SkTextBlobBuilder::RunBuffer& run =
+ textBlobBuilder.allocRun(paint, runLen, textPos.fX, textPos.fY);
+ memcpy(run.glyphs, &glyphs[glyphIndex], sizeof(glyphs[0]) * runLen);
+ textPos.fX += paint.measureText(&bunny[glyphIndex], runLen, nullptr);
+ glyphIndex += runLen;
+ }
+ sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
+ paint.reset();
+ canvas->drawTextBlob(blob.get(), 0, 0, paint);
+ } +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawTextBlob(const sk_sp<SkTextBlob>& blob, SkScalar x, SkScalar y, const SkPaint& paint) + +Draw Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint. +blob contains glyphs, their positions, and paint attributes specific to text: +Typeface, Paint_Text_Size, Paint_Text_Scale_X, Paint_Text_Skew_X, Paint_Text_Align, +Paint_Hinting, Anti-alias, Paint_Fake_Bold, Font_Embedded_Bitmaps, Full_Hinting_Spacing, +LCD_Text, Linear_Text, Subpixel_Text, and Paint_Vertical_Text. + +Elements of paint: Path_Effect, Rasterizer, Mask_Filter, Shader, Color_Filter, +Image_Filter, and Draw_Looper; 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. ## + +#Example +#Height 120 +#Description +Paint attributes unrelated to text, like color, have no effect on paint in allocated Text_Blob. +Paint attributes related to text, like text size, have no effect on paint passed to drawTextBlob. +## + void draw(SkCanvas* canvas) {
+ SkTextBlobBuilder textBlobBuilder;
+ SkPaint paint;
+ paint.setTextSize(50);
+ paint.setColor(SK_ColorRED);
+ const SkTextBlobBuilder::RunBuffer& run =
+ textBlobBuilder.allocRun(paint, 1, 20, 100);
+ run.glyphs[0] = 20;
+ sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
+ paint.setTextSize(10);
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawTextBlob(blob.get(), 0, 0, paint);
+ }
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPicture(const SkPicture* picture) + +Draw Picture picture, using Clip and Matrix. +Clip and Matrix 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. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
+ SkPaint paint;
+ paint.setColor(color);
+ recordingCanvas->drawRect({10, 10, 30, 40}, paint);
+ recordingCanvas->translate(10, 10);
+ recordingCanvas->scale(1.2f, 1.4f);
+ }
+ sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
+ const SkPicture* playbackPtr = playback.get();
+ canvas->drawPicture(playback);
+ canvas->scale(2, 2);
+ canvas->translate(50, 0);
+ canvas->drawPicture(playback);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPicture(const sk_sp<SkPicture>& picture) + +Draw Picture picture, using Clip and Matrix. +Clip and Matrix 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. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
+ SkPaint paint;
+ paint.setColor(color);
+ recordingCanvas->drawRect({10, 10, 30, 40}, paint);
+ recordingCanvas->translate(10, 10);
+ recordingCanvas->scale(1.2f, 1.4f);
+ }
+ sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
+ canvas->drawPicture(playback);
+ canvas->scale(2, 2);
+ canvas->translate(50, 0);
+ canvas->drawPicture(playback);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) + +Draw Picture picture, using Clip and Matrix; +transforming picture with Matrix matrix, if provided; +and use Paint paint Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode, 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 Optional Matrix to rotate, scale, translate, and so on; or nullptr. ## +#Param paint Optional Paint to apply transparency, filtering, and so on; or nullptr. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
+ paint.setColor(color);
+ recordingCanvas->drawRect({10, 10, 30, 40}, paint);
+ recordingCanvas->translate(10, 10);
+ recordingCanvas->scale(1.2f, 1.4f);
+ }
+ sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
+ const SkPicture* playbackPtr = playback.get();
+ SkMatrix matrix;
+ matrix.reset();
+ for (auto alpha : { 70, 140, 210 } ) {
+ paint.setAlpha(alpha);
+ canvas->drawPicture(playbackPtr, &matrix, &paint);
+ matrix.preTranslate(70, 70);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPicture(const sk_sp<SkPicture>& picture, const SkMatrix* matrix, const SkPaint* paint) + +Draw Picture picture, using Clip and Matrix; +transforming picture with Matrix matrix, if provided; +and use Paint paint Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode, 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 Optional Matrix to rotate, scale, translate, and so on; or nullptr. ## +#Param paint Optional Paint to apply transparency, filtering, and so on; or nullptr. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
+ for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
+ paint.setColor(color);
+ recordingCanvas->drawRect({10, 10, 30, 40}, paint);
+ recordingCanvas->translate(10, 10);
+ recordingCanvas->scale(1.2f, 1.4f);
+ }
+ sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
+ SkMatrix matrix;
+ matrix.reset();
+ for (auto alpha : { 70, 140, 210 } ) {
+ paint.setAlpha(alpha);
+ canvas->drawPicture(playback, &matrix, &paint);
+ matrix.preTranslate(70, 70);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) + +Draw Vertices vertices, a triangle mesh, using Clip and Matrix. +If Vertices_Texs and Vertices_Colors are defined in vertices, and Paint paint contains Shader, +Blend_Mode mode combines Vertices_Colors with Shader. + +#Param vertices The triangle mesh to draw. ## +#Param mode Combines Vertices_Colors with Shader, if both are present. ## +#Param paint Specifies the Shader, used as Vertices texture, if present. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
+ SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
+ auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
+ SK_ARRAY_COUNT(points), points, nullptr, colors);
+ canvas->drawVertices(vertices.get(), SkBlendMode::kSrc, paint);
+}
+## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, const SkPaint& paint) + +Draw Vertices vertices, a triangle mesh, using Clip and Matrix. +If Vertices_Texs and Vertices_Colors are defined in vertices, and Paint paint contains Shader, +Blend_Mode mode combines Vertices_Colors with Shader. + +#Param vertices The triangle mesh to draw. ## +#Param mode Combines Vertices_Colors with Shader, if both are present. ## +#Param paint Specifies the Shader, used as Vertices texture, if present. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
+ SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };
+ SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
+ paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
+ SkShader::kClamp_TileMode));
+ auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
+ SK_ARRAY_COUNT(points), points, texs, colors);
+ canvas->drawVertices(vertices.get(), SkBlendMode::kDarken, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint) + +Draw a cubic Coons patch: the interpolation of four cubics with shared corners, +associating a color, and optionally a texture coordinate, with each corner. + +#ToDo can patch use image filter? ## + +The Coons patch uses Clip and Matrix, Paint paint's Shader, Color_Filter, Color_Alpha, +Image_Filter, and Blend_Mode. If Shader is provided it is treated as the Coons +patch texture; Blend_Mode mode combines Color colors and Shader if both are provided. + +#Param cubics Point array cubics specifying the four cubics starting at the top left corner, +in clockwise order, sharing every fourth point. The last cubic ends at the first point. ## +#Param colors Color array color associating colors with corners in top left, top right, bottom right, +bottom left order. ## +#Param texCoords Point array texCoords mapping Shader as texture to corners in same order, if paint +contains Shader; or nullptr. ## +#Param mode Blend_Mode for colors and Shader if present. ## +#Param paint Shader, Color_Filter, Blend_Mode, used to draw. ## + +#Example +#Image 5 +void draw(SkCanvas* canvas) {
+ // SkBitmap source = cmbkygk;
+ SkPaint paint;
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setAntiAlias(true);
+ SkPoint cubics[] = { { 3, 1 }, { 4, 2 }, { 5, 1 }, { 7, 3 },
+ /* { 7, 3 }, */ { 6, 4 }, { 7, 5 }, { 5, 7 },
+ /* { 5, 7 }, */ { 4, 6 }, { 3, 7 }, { 1, 5 },
+ /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
+ SkColor colors[] = { 0xbfff0000, 0xbf0000ff, 0xbfff00ff, 0xbf00ffff };
+ SkPoint texCoords[] = { { -30, -30 }, { 162, -30}, { 162, 162}, { -30, 162} };
+ paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode, nullptr));
+ canvas->scale(15, 15);
+ for (auto blend : { SkBlendMode::kSrcOver, SkBlendMode::kModulate, SkBlendMode::kXor } ) {
+ canvas->drawPatch(cubics, colors, texCoords, blend, paint);
+ canvas->translate(4, 4);
+ }
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], const SkPaint& paint) + +Draw a cubic Coons patch: the interpolation of four cubics with shared corners, +associating a color, a texture coordinate, or both, with each corner. + +The Coons patch uses Clip and Matrix, Paint paint's Shader, Color_Filter, Color_Alpha, +Image_Filter, (?) and Blend_Mode. If Shader is provided it is treated as the Coons +patch texture. + +#Param cubics Point array cubics specifying the four cubics starting at the top left corner, +in clockwise order, sharing every fourth point. The last cubic ends at the first point. ## +#Param colors Color array color associating colors with corners in top left, top right, bottom right, +bottom left order; or nullptr. ## +#Param texCoords Point array texCoords mapping Shader as texture to corners in same order, if paint +contains Shader; or nullptr. ## +#Param paint Shader, Color_Filter, Blend_Mode, used to draw. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPoint cubics[] = { { 3, 1 }, { 4, 2 }, { 5, 1 }, { 7, 3 },
+ /* { 7, 3 }, */ { 6, 4 }, { 7, 5 }, { 5, 7 },
+ /* { 5, 7 }, */ { 4, 6 }, { 3, 7 }, { 1, 5 },
+ /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
+ SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
+ canvas->scale(30, 30);
+ canvas->drawPatch(cubics, colors, nullptr, paint);
+ SkPoint text[] = { {3,0.9f}, {4,2.5f}, {5,0.9f}, {7.5f,3.2f}, {5.5f,4.2f},
+ {7.5f,5.2f}, {5,7.5f}, {4,5.9f}, {3,7.5f}, {0.5f,5.2f}, {2.5f,4.2f},
+ {0.5f,3.2f} };
+ paint.setTextSize(18.f / 30);
+ paint.setTextAlign(SkPaint::kCenter_Align);
+ for (int i = 0; i< 10; ++i) {
+ char digit = '0' + i;
+ canvas->drawText(&digit, 1, text[i].fX, text[i].fY, paint);
+ }
+ canvas->drawString("10", text[10].fX, text[10].fY, paint);
+ canvas->drawString("11", text[11].fX, text[11].fY, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawPoints(SkCanvas::kPolygon_PointMode, 12, cubics, paint);
+ canvas->drawLine(cubics[11].fX, cubics[11].fY, cubics[0].fX, cubics[0].fY, paint);
+} +## + +#Example +#Image 6 +void draw(SkCanvas* canvas) {
+ // SkBitmap source = checkerboard;
+ SkPaint paint;
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setAntiAlias(true);
+ SkPoint cubics[] = { { 3, 1 }, { 4, 2 }, { 5, 1 }, { 7, 3 },
+ /* { 7, 3 }, */ { 6, 4 }, { 7, 5 }, { 5, 7 },
+ /* { 5, 7 }, */ { 4, 6 }, { 3, 7 }, { 1, 5 },
+ /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
+ SkPoint texCoords[] = { { 0, 0 }, { 0, 62}, { 62, 62}, { 62, 0 } };
+ paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode, nullptr));
+ canvas->scale(30, 30);
+ canvas->drawPatch(cubics, nullptr, texCoords, paint);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method 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, Matrix, and optional Paint paint. +paint uses Anti-alias, Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode to draw, if present. +For each entry in the array, Rect tex locates sprite in atlas, and RSXform xform transforms it +into destination space. +xform, text, and colors if present, must contain count entries. +Optional colors is applied for each sprite using Blend_Mode. +Optional cullRect is a conservative bounds of all transformed sprites. +If cullrect is outside of Clip, canvas can skip drawing. + +#Param atlas Image containing sprites. ## +#Param xform RSXform mappings for sprites in atlas. ## +#Param tex Rect locations of sprites in atlas. ## +#Param colors Color, one per sprite, blended with sprite using Blend_Mode; or nullptr. ## +#Param count Number of sprites to draw. ## +#Param mode Blend_Mode combining colors and sprites. ## +#Param cullRect Rect bounds of transformed sprites for efficient clipping; or nullptr. ## +#Param paint Paint Color_Filter, Image_Filter, Blend_Mode, and so on; or nullptr. ## + +#Example +#Image 3 +void draw(SkCanvas* canvas) {
+ // SkBitmap source = mandrill;
+ SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
+ SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
+ SkColor colors[] = { 0x7f55aa00, 0x7f3333bf };
+ const SkImage* imagePtr = image.get();
+ canvas->drawAtlas(imagePtr, xforms, tex, colors, 2, SkBlendMode::kSrcOver, nullptr, nullptr);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawAtlas(const sk_sp<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, Matrix, and optional Paint paint. +paint uses Anti-alias, Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode to draw, if present. +For each entry in the array, Rect tex locates sprite in atlas, and RSXform xform transforms it +into destination space. +xform, text, and colors if present, must contain count entries. +Optional colors is applied for each sprite using Blend_Mode. +Optional cullRect is a conservative bounds of all transformed sprites. +If cullrect is outside of Clip, canvas can skip drawing. + +#Param atlas Image containing sprites. ## +#Param xform RSXform mappings for sprites in atlas. ## +#Param tex Rect locations of sprites in atlas. ## +#Param colors Color, one per sprite, blended with sprite using Blend_Mode; or nullptr. ## +#Param count Number of sprites to draw. ## +#Param mode Blend_Mode combining colors and sprites. ## +#Param cullRect Rect bounds of transformed sprites for efficient clipping; or nullptr. ## +#Param paint Paint Color_Filter, Image_Filter, Blend_Mode, and so on; or nullptr. ## + +#Example +#Image 3 +void draw(SkCanvas* canvas) {
+ // SkBitmap source = mandrill;
+ SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
+ SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
+ SkColor colors[] = { 0x7f55aa00, 0x7f3333bf };
+ SkPaint paint;
+ paint.setAlpha(127);
+ canvas->drawAtlas(image, xforms, tex, colors, 2, SkBlendMode::kPlus, nullptr, &paint);
+} +## + +#ToDo bug in example on cpu side, gpu looks ok ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count, + const SkRect* cullRect, const SkPaint* paint) + +Draw a set of sprites from atlas, using Clip, Matrix, and optional Paint paint. +paint uses Anti-alias, Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode to draw, if present. +For each entry in the array, Rect tex locates sprite in atlas, and RSXform 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 Image containing sprites. ## +#Param xform RSXform mappings for sprites in atlas. ## +#Param tex Rect locations of sprites in atlas. ## +#Param count Number of sprites to draw. ## +#Param cullRect Rect bounds of transformed sprites for efficient clipping; or nullptr. ## +#Param paint Paint Color_Filter, Image_Filter, Blend_Mode, and so on; or nullptr. ## + +#Example +#Image 3 +void draw(SkCanvas* canvas) {
+ // sk_sp<SkImage> image = mandrill;
+ SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
+ SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
+ const SkImage* imagePtr = image.get();
+ canvas->drawAtlas(imagePtr, xforms, tex, 2, nullptr, nullptr);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[], + int count, const SkRect* cullRect, const SkPaint* paint) + +Draw a set of sprites from atlas, using Clip, Matrix, and optional Paint paint. +paint uses Anti-alias, Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode to draw, if present. +For each entry in the array, Rect tex locates sprite in atlas, and RSXform 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 Image containing sprites. ## +#Param xform RSXform mappings for sprites in atlas. ## +#Param tex Rect locations of sprites in atlas. ## +#Param count Number of sprites to draw. ## +#Param cullRect Rect bounds of transformed sprites for efficient clipping; or nullptr. ## +#Param paint Paint Color_Filter, Image_Filter, Blend_Mode, and so on; or nullptr. ## + +#Example +#Image 3 +void draw(SkCanvas* canvas) {
+ // sk_sp<SkImage> image = mandrill;
+ SkRSXform xforms[] = { { 1, 0, 0, 0 }, {0, 1, 300, 100 } };
+ SkRect tex[] = { { 0, 0, 200, 200 }, { 200, 0, 400, 200 } };
+ canvas->drawAtlas(image, xforms, tex, 2, nullptr, nullptr);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = NULL) + +Draw Drawable drawable using Clip and Matrix, concatenated with +optional matrix. + +If Canvas 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; or nullptr. ## + +#Example +#Height 100 +#Function +struct MyDrawable : public SkDrawable {
+ SkRect onGetBounds() override { return SkRect::MakeWH(50, 100); }
+
+ void onDraw(SkCanvas* canvas) override {
+ SkPath path;
+ path.conicTo(10, 90, 50, 90, 0.9f);
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawRect(path.getBounds(), paint);
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawPath(path, paint);
+ }
+};
+
+#Function ##
+void draw(SkCanvas* canvas) {
+ sk_sp<SkDrawable> drawable(new MyDrawable);
+ SkMatrix matrix;
+ matrix.setTranslate(10, 10);
+ canvas->drawDrawable(drawable.get(), &matrix);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y) + +Draw Drawable drawable using Clip and Matrix, offset by (x, y). + +If Canvas 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 Canvas writable pixels in x. ## +#Param y Offset into Canvas writable pixels in y. ## + +#Example +#Height 100 +#Function +struct MyDrawable : public SkDrawable {
+ SkRect onGetBounds() override { return SkRect::MakeWH(50, 100); }
+
+ void onDraw(SkCanvas* canvas) override {
+ SkPath path;
+ path.conicTo(10, 90, 50, 90, 0.9f);
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawRect(path.getBounds(), paint);
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawPath(path, paint);
+ }
+};
+
+#Function ##
+void draw(SkCanvas* canvas) {
+ sk_sp<SkDrawable> drawable(new MyDrawable);
+ canvas->drawDrawable(drawable.get(), 10, 10);
+} +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawAnnotation(const SkRect& rect, const char key[], SkData* value) + +Associate Rect on Canvas 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 Rect extent of canvas to annotate. ## +#Param key String used for lookup. ## +#Param value Data holding value stored in annotation. ## + +#Example + #Height 1 + const char text[] = "Click this link!"; + SkRect bounds; + SkPaint paint; + paint.setTextSize(40); + (void)paint.measureText(text, strlen(text), &bounds); + const char url[] = "https://www.google.com/"; + sk_sp<SkData> urlData(SkData::MakeWithCString(url)); + canvas->drawAnnotation(bounds, "url_key", urlData.get()); +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method void drawAnnotation(const SkRect& rect, const char key[], const sk_sp<SkData>& value) + +Associate Rect on Canvas 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 Rect extent of canvas to annotate. ## +#Param key String used for lookup. ## +#Param value Data holding value stored in annotation. ## + +#Example +#Height 1 + const char text[] = "Click this link!"; + SkRect bounds; + SkPaint paint; + paint.setTextSize(40); + (void)paint.measureText(text, strlen(text), &bounds); + const char url[] = "https://www.google.com/"; + sk_sp<SkData> urlData(SkData::MakeWithCString(url)); + canvas->drawAnnotation(bounds, "url_key", urlData.get()); +## + +#ToDo incomplete ## + +## + +#Method SkDrawFilter* getDrawFilter() const + +Legacy call to be deprecated. + +#Deprecated +## + +## + +#Method virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter) + +Legacy call to be deprecated. + +#Deprecated +## + +## + +# ------------------------------------------------------------------------------ + +#Method virtual bool isClipEmpty() const + +Returns true if Clip is empty; that is, nothing will draw. + +isClipEmpty 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. ## + +#Example + void draw(SkCanvas* canvas) {
+ SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not");
+ SkPath path;
+ canvas->clipPath(path);
+ SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not");
+ } + #StdOut + clip is not empty
+ clip is empty + ## +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Method virtual bool isClipRect() const + +Returns true if Clip is Rect and not empty. +Returns false if the clip is empty, or if it is not Rect. + +#Return true if Clip is Rect and not empty. ## + +#Example + void draw(SkCanvas* canvas) {
+ SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not");
+ canvas->clipRect({0, 0, 0, 0});
+ SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not");
+ } + #StdOut + clip is rect
+ clip is not rect + ## +## + +#ToDo incomplete ## + +## + +#Class SkCanvas ## +#Topic Canvas ## diff --git a/docs/SkPaint.bmh b/docs/SkPaint.bmh new file mode 100644 index 0000000000..4adb6dadcf --- /dev/null +++ b/docs/SkPaint.bmh @@ -0,0 +1,5280 @@ +#Topic Paint + +Paint controls options applied when drawing and measuring. Paint collects all +options outside of the Canvas_Clip and Canvas_Matrix. + +Various options apply to text, strokes and fills, and images. + +Some options may not be implemented on all platforms; in these cases, setting +the option has no effect. Some options are conveniences that duplicate Canvas +functionality; for instance, text size is identical to matrix scale. + +Paint options are rarely exclusive; each option modifies a stage of the drawing +pipeline and multiple pipeline stages may be affected by a single Paint. + +Paint collects effects and filters that describe single-pass and multiple-pass +algorithms that alter the drawing geometry, color, and transparency. For instance, +Paint does not directly implement dashing or blur, but contains the objects that do so. + +The objects contained by Paint are opaque, and cannot be edited outside of the Paint +to affect it. The implementation is free to defer computations associated with the +Paint, or ignore them altogether. For instance, some GPU implementations draw all +Path geometries with anti-aliasing, regardless of SkPaint::kAntiAlias_Flag setting. + +Paint 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 +Shader attached to Paint. + +#Class SkPaint + +#Topic Overview + +#Subtopic Subtopics +#ToDo not all methods are in topics ## +#ToDo subtopics are not in topics ## +#Table +#Legend +# topics # description ## +#Legend ## +# Initializers # Constructors and initialization. ## +# Destructor # Paint termination. ## +# Management # Paint copying, moving, comparing. ## +# Hinting # Glyph outline adjustment. ## +# Flags # Attributes represented by single bits. ## +# Anti-alias # Approximating coverage with transparency. ## +# Dither # Distributing color error. ## +# Device_Text # Increase precision of glyph position. ## +# Font_Embedded_Bitmaps # Custom-sized bitmap glyphs. ## +# Automatic_Hinting # Always adjust glyph paths. ## +# Vertical_Text # Orient text from top to bottom. ## +# Fake_Bold # Approximate font styles. ## +# Full_Hinting_Spacing # Glyph spacing affected by hinting. ## +# Filter_Quality_Methods # Get and set Filter_Quality. ## +# Color_Methods # Get and set Color. ## +# Style # Geometry filling, stroking. ## +# Stroke_Width # Thickness perpendicular to geometry. ## +# Miter_Limit # Maximum length of stroked corners. ## +# Stroke_Cap # Decorations at ends of open strokes. ## +# Stroke_Join # Decoration at corners of strokes. ## +# Fill_Path # Make Path from Path_Effect, stroking. ## +# Shader_Methods # Get and set Shader. ## +# Color_Filter_Methods # Get and set Color_Filter. ## +# Blend_Mode_Methods # Get and set Blend_Mode. ## +# Path_Effect_Methods # Get and set Path_Effect. ## +# Mask_Filter_Methods # Get and set Mask_Filter. ## +# Typeface_Methods # Get and set Typeface. ## +# Rasterizer_Methods # Get and set Rasterizer. ## +# Image_Filter_Methods # Get and set Image_Filter. ## +# Draw_Looper_Methods # Get and set Draw_Looper. ## +# Text_Align # Text placement relative to position. ## +# Text_Size # Overall height in points. ## +# Text_Scale_X # Text horizontal scale. ## +# Text_Skew_X # Text horizontal slant. ## +# Text_Encoding # Text encoded as characters or glyphs. ## +# Font_Metrics # Common glyph dimensions. ## +# Measure_Text # Width, height, bounds of text. ## +# Text_Path # Geometry of glyphs. ## +# Text_Intercepts # Advanced underline, strike through. ## +# Fast_Bounds # Appproxiate area required by Paint. ## +#Table ## +#Subtopic ## + +#Subtopic Constants +#Table +#Legend +# constants # description ## +#Legend ## +# Align # Glyph locations relative to text position. ## +# Cap # Start and end geometry on stroked shapes. ## +# Flags # Values described by bits and masks. ## +# FontMetrics::FontMetricsFlags # Valid Font_Metrics. ## +# Hinting # Level of glyph outline adjustment. ## +# Join # Corner geometry on stroked shapes. ## +# Style # Stroke, fill, or both. ## +# TextEncoding # Character or glyph encoding size. ## +#Table ## +#Subtopic ## + +#Subtopic Structs +#Table +#Legend +# struct # description ## +#Legend ## +# FontMetrics # Typeface values. ## +#Table ## +#Subtopic ## + +#Subtopic Constructors +#Table +#Legend +# # description ## +#Legend ## +# SkPaint() # Constructs with default values. ## +# SkPaint(const SkPaint& paint) # Makes a shallow copy. ## +# SkPaint(SkPaint&& paint) # Moves paint without copying it. ## +# ~SkPaint() # Decreases Reference_Count of owned objects. ## +#Table ## +#Subtopic ## + +#Subtopic Operators +#Table +#Legend +# operator # description ## +#Legend ## +# operator=(const SkPaint& paint) # Makes a shallow copy. ## +# operator=(SkPaint&& paint) # Moves paint without copying it. ## +# operator==(const SkPaint& a, const SkPaint& b) # Compares paints for equality. ## +# operator!=(const SkPaint& a, const SkPaint& b) # Compares paints for inequality. ## +#Table ## +#Subtopic ## + +#Subtopic Member_Functions +#Table +#Legend +# function # description ## +#Legend ## +# breakText # Returns text that fits in a width. ## +# canComputeFastBounds # Returns true if settings allow for fast bounds computation. ## +# computeFastBounds # Returns fill bounds for quick reject tests. ## +# computeFastStrokeBounds # Returns stroke bounds for quick reject tests. ## +# containsText # Returns if all text corresponds to glyphs. ## +# countText # Returns number of glyphs in text. ## +# doComputeFastBounds # Returns bounds for quick reject tests. ## +# flatten() # Serializes into a buffer. ## +# getAlpha # Returns Color_Alpha, color opacity. ## +# getBlendMode # Returns Blend_Mode, how colors combine with dest. ## +# getColor # Returns Color_Alpha and Color_RGB, one drawing color. ## +# getColorFilter # Returns Color_Filter, how colors are altered. ## +# getDrawLooper # Returns Draw_Looper, multiple layers. ## +# getFillPath # Returns fill path equivalent to stroke. ## +# getFilterQuality # Returns Filter_Quality, image filtering level. ## +# getFlags # Returns Flags stored in a bit field. ## +# getFontBounds # Returns union all glyph bounds. ## +# getFontMetrics # Returns Typeface metrics scaled by text size. ## +# getFontSpacing # Returns recommended spacing between lines. ## +# getHash # Returns a shallow hash for equality checks. ## +# getHinting # Returns Hinting, glyph outline adjustment level. ## +# getImageFilter # Returns Image_Filter, alter pixels; blur. ## +# getMaskFilter # Returns Mask_Filter, alterations to Mask_Alpha. ## +# getPathEffect # Returns Path_Effect, modifications to path geometry; dashing. ## +# getPosTextPath # Returns Path equivalent to positioned text. ## +# getPosTextIntercepts # Returns where lines intersect positioned text; underlines. ## +# getPosTextHIntercepts # Returns where lines intersect horizontally positioned text; underlines. ## +# getRasterizer # Returns Rasterizer, Mask_Alpha generation from Path. ## +# getShader # Returns Shader, multiple drawing colors; gradients. ## +# getStrokeCap # Returns Cap, the area drawn at path ends. ## +# getStrokeJoin # Returns Join, geometry on path corners. ## +# getStrokeMiter # Returns Miter_Limit, angles with sharp corners. ## +# getStrokeWidth # Returns thickness of the stroke. ## +# getStyle # Returns Style: stroke, fill, or both. ## +# getTextAlign # Returns Align: left, center, or right. ## +# getTextBlobIntercepts # Returns where lines intersect Text_Blob; underlines. ## +# getTextEncoding # Returns character or glyph encoding size. ## +# getTextIntercepts # Returns where lines intersect text; underlines. ## +# getTextPath # Returns Path equivalent to text. ## +# getTextScaleX # Returns the text horizontal scale; condensed text. ## +# getTextSkewX # Returns the text horizontal skew; oblique text. ## +# getTextSize # Returns text size in points. ## +# getTextWidths # Returns advance and bounds for each glyph in text. ## +# getTypeface # Returns Typeface, font description. ## +# glyphsToUnichars # Converts glyphs into text. ## +# isAntiAlias # Returns true if Anti-alias is set. ## +# isAutohinted # Returns true if glyphs are always hinted. ## +# isDevKernText # Returns true if Full_Hinting_Spacing is set. ## +# isDither # Returns true if Dither is set. ## +# isEmbeddedBitmapText # Returns true if Font_Embedded_Bitmaps is set. ## +# isFakeBoldText # Returns true if Fake_Bold is set. ## +# isLCDRenderText # Returns true if LCD_Text is set. ## +# isSrcOver # Returns true if Blend_Mode is SkBlendMode::kSrcOver. ## +# isSubpixelText # Returns true if Subpixel_Text is set. ## +# isVerticalText # Returns true if Vertical_Text is set. ## +# measureText # Returns advance width and bounds of text. ## +# nothingToDraw # Returns true if Paint prevents all drawing. ## +# refColorFilter # References Color_Filter, how colors are altered. ## +# refDrawLooper # References Draw_Looper, multiple layers. ## +# refImageFilter # References Image_Filter, alter pixels; blur. ## +# refMaskFilter # References Mask_Filter, alterations to Mask_Alpha. ## +# refPathEffect # References Path_Effect, modifications to path geometry; dashing. ## +# refRasterizer # References Rasterizer, mask generation from path. ## +# refShader # References Shader, multiple drawing colors; gradients. ## +# refTypeface # References Typeface, font description. ## +# reset() # Sets to default values. ## +# setAlpha # Sets Color_Alpha, color opacity. ## +# setAntiAlias # Sets or clears Anti-alias. ## +# setARGB # Sets color by component. ## +# setAutohinted # Sets glyphs to always be hinted. ## +# setBlendMode # Sets Blend_Mode, how colors combine with destination. ## +# setColor # Sets Color_Alpha and Color_RGB, one drawing color. ## +# setColorFilter # Sets Color_Filter, alters color. ## +# setDevKernText # Sets or clears Full_Hinting_Spacing. ## +# setDither # Sets or clears Dither. ## +# setDrawLooper # Sets Draw_Looper, multiple layers. ## +# setEmbeddedBitmapText # Sets or clears Font_Embedded_Bitmaps. ## +# setFakeBoldText # Sets or clears Fake_Bold. ## +# setFilterQuality # Sets Filter_Quality, the image filtering level. ## +# setFlags # Sets multiple Flags in a bit field. ## +# setHinting # Sets Hinting, glyph outline adjustment level. ## +# setLCDRenderText # Sets or clears LCD_Text. ## +# setMaskFilter # Sets Mask_Filter, alterations to Mask_Alpha. ## +# setPathEffect # Sets Path_Effect, modifications to path geometry; dashing. ## +# setRasterizer # Sets Rasterizer, Mask_Alpha generation from Path. ## +# setImageFilter # Sets Image_Filter, alter pixels; blur. ## +# setShader # Sets Shader, multiple drawing colors; gradients. ## +# setStrokeCap # Sets Cap, the area drawn at path ends. ## +# setStrokeJoin # Sets Join, geometry on path corners. ## +# setStrokeMiter # Sets Miter_Limit, angles with sharp corners. ## +# setStrokeWidth # Sets thickness of the stroke. ## +# setStyle # Sets Style: stroke, fill, or both. ## +# setSubpixelText # Sets or clears Subpixel_Text. ## +# setTextAlign # Sets Align: left, center, or right. ## +# setTextEncoding # Sets character or glyph encoding size. ## +# setTextScaleX # Sets the text horizontal scale; condensed text. ## +# setTextSkewX # Sets the text horizontal skew; oblique text. ## +# setTextSize # Sets text size in points. ## +# setTypeface # Sets Typeface, font description. ## +# setVerticalText # Sets or clears Vertical_Text. ## +# textToGlyphs # Converts text into glyph indices. ## +# toString # Converts Paint to machine parsable form (Developer_Mode) ## +# unflatten() # Populates from a serialized stream. ## +#Table ## +#Subtopic ## + +#Topic Overview ## + +# ------------------------------------------------------------------------------ +#Topic Initializers + +#Method SkPaint() + +Constructs Paint with default values. + +#Table +#Legend +# attribute # default value ## +#Legend ## +# Anti-alias # false ## +# Blend_Mode # SkBlendMode::kSrcOver ## +# Color # SK_ColorBLACK ## +# Color_Alpha # 255 ## +# Color_Filter # nullptr ## +# Dither # false ## +# Draw_Looper # nullptr ## +# Fake_Bold # false ## +# Filter_Quality # kNone_SkFilterQuality ## +# Font_Embedded_Bitmaps # false ## +# Automatic_Hinting # false ## +# Full_Hinting_Spacing # false ## +# Hinting # kNormal_Hinting ## +# Image_Filter # nullptr ## +# LCD_Text # false ## +# Linear_Text # false ## +# Miter_Limit # 4 ## +# Mask_Filter # nullptr ## +# Path_Effect # nullptr ## +# Rasterizer # nullptr ## +# Shader # nullptr ## +# Style # kFill_Style ## +# Text_Align # kLeft_Align ## +# Text_Encoding # kUTF8_TextEncoding ## +# Text_Scale_X # 1 ## +# Text_Size # 12 ## +# Text_Skew_X # 0 ## +# Typeface # nullptr ## +# Stroke_Cap # kButt_Cap ## +# Stroke_Join # kMiter_Join ## +# Stroke_Width # 0 ## +# Subpixel_Text # false ## +# Vertical_Text # false ## +#Table ## + +The flags, text size, hinting, and miter limit may be overridden at compile time by defining +paint default values. The overrides may be included in SkUserConfig.h or predefined by the +build system. + +#Return default initialized Paint ## + +#Example +#ToDo mark this as no output ## +#Height 1 +###$ $ redefine markup character so preprocessor commands appear normally +#ifndef SkUserConfig_DEFINED +#define SkUserConfig_DEFINED + +#define SkPaintDefaults_Flags 0x01 // always enable antialiasing +#define SkPaintDefaults_TextSize 24.f // double default font size +#define SkPaintDefaults_Hinting 3 // use full hinting +#define SkPaintDefaults_MiterLimit 10.f // use HTML Canvas miter limit setting + +#endif +$$$# # restore original markup character +## + + +## + +#Method SkPaint(const SkPaint& paint) + +Makes a shallow copy of Paint. Typeface, Path_Effect, Shader, +Mask_Filter, Color_Filter, Rasterizer, Draw_Looper, and Image_Filter are shared +between the original paint and the copy. These objects' Reference_Count are increased. + +The referenced objects Path_Effect, Shader, Mask_Filter, Color_Filter, Rasterizer, +Draw_Looper, and Image_Filter cannot be modified after they are created. +This prevents objects with Reference_Count from being modified once Paint refers to them. + +#Param paint original to copy ## + +#Return shallow copy of paint ## + +#Example +#ToDo why is this double-spaced on Fiddle? ## + SkPaint paint1; + paint1.setColor(SK_ColorRED); + SkPaint paint2(paint1); + paint2.setColor(SK_ColorBLUE); + SkDebugf("SK_ColorRED %c= paint1.getColor()\n", SK_ColorRED == paint1.getColor() ? '=' : '!'); + SkDebugf("SK_ColorBLUE %c= paint2.getColor()\n", SK_ColorBLUE == paint2.getColor() ? '=' : '!'); + + #StdOut + SK_ColorRED == paint1.getColor() + SK_ColorBLUE == paint2.getColor() + ## +## + +## + +#Method SkPaint(SkPaint&& paint) + + Implements a move constructor to avoid incrementing the reference counts + of objects referenced by the paint. + + After the call, paint is undefined, and can be safely destructed. + + #Param paint original to move ## + + #Return content of paint ## + + #Example + SkPaint paint; + float intervals[] = { 5, 5 }; + paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 2.5f)); + SkPaint dashed(std::move(paint)); + SkDebugf("path effect unique: %s\n", dashed.getPathEffect()->unique() ? "true" : "false"); + + #StdOut + path effect unique: true + ## + ## + +## + +# ------------------------------------------------------------------------------ + +#Method void reset() + +Sets all paint's contents to their initial values. This is equivalent to replacing +the paint with the result of SkPaint(). + +#Example + SkPaint paint1, paint2; + paint1.setColor(SK_ColorRED); + paint1.reset(); + SkDebugf("paint1 %c= paint2", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + ## +## + +## + +#Topic ## + +# ------------------------------------------------------------------------------ +#Topic Destructor + +#Method ~SkPaint() + +Decreases Paint Reference_Count of owned objects: Typeface, Path_Effect, Shader, +Mask_Filter, Color_Filter, Rasterizer, Draw_Looper, and Image_Filter. If the +objects' reference count goes to zero, they are deleted. + +#NoExample +## + +## + +## +# ------------------------------------------------------------------------------ +#Topic Management + +#Method SkPaint& operator=(const SkPaint& paint) + +Makes a shallow copy of Paint. Typeface, Path_Effect, Shader, +Mask_Filter, Color_Filter, Rasterizer, Draw_Looper, and Image_Filter are shared +between the original paint and the copy. The objects' Reference_Count are in the +prior destination are decreased by one, and the referenced objects are deleted if the +resulting count is zero. The objects' Reference_Count in the parameter paint are increased +by one. paint is unmodified. + +#Param paint original to copy ## + +#Return content of paint ## + +#Example + SkPaint paint1, paint2; + paint1.setColor(SK_ColorRED); + paint2 = paint1; + SkDebugf("SK_ColorRED %c= paint1.getColor()\n", SK_ColorRED == paint1.getColor() ? '=' : '!'); + SkDebugf("SK_ColorRED %c= paint2.getColor()\n", SK_ColorRED == paint2.getColor() ? '=' : '!'); + + #StdOut + SK_ColorRED == paint1.getColor() + SK_ColorRED == paint2.getColor() + ## +## + +## + +# ------------------------------------------------------------------------------ + +#Method SkPaint& operator=(SkPaint&& paint) + +Moves the paint to avoid incrementing the reference counts +of objects referenced by the paint parameter. The objects' Reference_Count are in the +prior destination are decreased by one, and the referenced objects are deleted if the +resulting count is zero. + +After the call, paint is undefined, and can be safely destructed. + + #Param paint original to move ## + + #Return content of paint ## + +#Example + SkPaint paint1, paint2; + paint1.setColor(SK_ColorRED); + paint2 = std::move(paint1); + SkDebugf("SK_ColorRED == paint2.getColor()\n", SK_ColorRED == paint2.getColor() ? '=' : '!'); + + #StdOut + SK_ColorRED == paint2.getColor() + ## +## + +## + +# ------------------------------------------------------------------------------ + +#Method bool operator==(const SkPaint& a, const SkPaint& b) + + Compares a and b, and returns true if a and b are equivalent. May return false + if Typeface, Path_Effect, Shader, Mask_Filter, Color_Filter, Rasterizer, + Draw_Looper, or Image_Filter have identical contents but different pointers. + + #Param a Paint to compare ## + #Param b Paint to compare ## + + #Return true if Paint pair are equivalent ## + + #Example + SkPaint paint1, paint2; + paint1.setColor(SK_ColorRED); + paint2.setColor(0xFFFF0000); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + float intervals[] = { 5, 5 }; + paint1.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f)); + paint2.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f)); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + paint1 != paint2 + ## + ## + +## + +# ------------------------------------------------------------------------------ + +#Method bool operator!=(const SkPaint& a, const SkPaint& b) + + Compares a and b, and returns true if a and b are not equivalent. May return true + if Typeface, Path_Effect, Shader, Mask_Filter, Color_Filter, Rasterizer, + Draw_Looper, or Image_Filter have identical contents but different pointers. + + #Param a Paint to compare ## + #Param b Paint to compare ## + + #Return true if Paint pair are not equivalent ## + +#Example + SkPaint paint1, paint2; + paint1.setColor(SK_ColorRED); + paint2.setColor(0xFFFF0000); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + SkDebugf("paint1 %c= paint2\n", paint1 != paint2 ? '!' : '='); + + #StdOut + paint1 == paint2 + paint1 == paint2 + ## +## + +## + +# ------------------------------------------------------------------------------ + +#Method uint32_t getHash() const + +Returns a hash generated from Paint values and pointers. +Identical hashes guarantee that the paints are +equivalent, but differing hashes do not guarantee that the paints have differing +contents. + +If operator==(const SkPaint& a, const SkPaint& b) returns true for two paints, +their hashes are also equal. + +The hash returned is platform and implementation specific. + +#Return a shallow hash ## + +#Example + SkPaint paint1, paint2; + paint1.setColor(SK_ColorRED); + paint2.setColor(0xFFFF0000); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + SkDebugf("paint1.getHash() %c= paint2.getHash()\n", + paint1.getHash() == paint2.getHash() ? '=' : '!'); + + #StdOut + paint1 == paint2 + paint1.getHash() == paint2.getHash() + ## +## + +## + +# ------------------------------------------------------------------------------ + +#Method void flatten(SkWriteBuffer& buffer) const + +Serializes Paint into a buffer. A companion unflatten() call +can reconstitute the paint at a later time. + +#Param buffer Write_Buffer receiving the flattened Paint data ## + +#Example + class PaintDumper : public SkWriteBuffer { + public: + bool isCrossProcess() const override { return false; }; + void writeByteArray(const void* data, size_t size) override {} + void writeBool(bool value) override {} + void writeScalar(SkScalar value) override {} + void writeScalarArray(const SkScalar* value, uint32_t count) override {} + void writeInt(int32_t value) override {} + void writeIntArray(const int32_t* value, uint32_t count) override {} + void writeUInt(uint32_t value) override {} + void writeString(const char* value) override {} + void writeFlattenable(const SkFlattenable* flattenable) override {} + void writeColorArray(const SkColor* color, uint32_t count) override {} + void writeColor4f(const SkColor4f& color) override {} + void writeColor4fArray(const SkColor4f* color, uint32_t count) override {} + void writePoint(const SkPoint& point) override {} + void writePointArray(const SkPoint* point, uint32_t count) override {} + void writeMatrix(const SkMatrix& matrix) override {} + void writeIRect(const SkIRect& rect) override {} + void writeRect(const SkRect& rect) override {} + void writeRegion(const SkRegion& region) override {} + void writePath(const SkPath& path) override {} + size_t writeStream(SkStream* stream, size_t length) override { return 0; } + void writeBitmap(const SkBitmap& bitmap) override {} + void writeImage(const SkImage*) override {} + void writeTypeface(SkTypeface* typeface) override {} + void writePaint(const SkPaint& paint) override {} + + void writeColor(SkColor color) override { + SkDebugf("color = 0x%08x\n", color); + } + } dumper; + + SkPaint paint; + paint.setColor(SK_ColorRED); + paint.flatten(dumper); + + #StdOut + color = 0xffff0000 + ## +## + +## + +# ------------------------------------------------------------------------------ + +#Method void unflatten(SkReadBuffer& buffer) + +Populates Paint, typically from a serialized stream, created by calling +flatten() at an earlier time. + +SkReadBuffer class is not public, so unflatten() cannot be meaningfully called +by the client. + +#Param buffer serialized data to unflatten ## + +# why is unflatten() public? +#Bug 6172 ## + +#NoExample +## + +#ToDo incomplete ## + +## + +#Topic Management ## + +# ------------------------------------------------------------------------------ +#Topic Hinting + +#Enum Hinting + +#Code + enum Hinting { + kNo_Hinting = 0, + kSlight_Hinting = 1, + kNormal_Hinting = 2, + kFull_Hinting = 3 + }; +## + +Hinting adjusts the glyph outlines so that the shape provides a uniform +look at a given point size on font engines that support it. Hinting may have a +muted effect or no effect at all depending on the platform. + +The four levels roughly control corresponding features on platforms that use FreeType +as the Font_Engine. + +#Const kNo_Hinting 0 + Leaves glyph outlines unchanged from their native representation. + With FreeType, this is equivalent to the FT_LOAD_NO_HINTING + bit-field constant supplied to FT_Load_Glyph, which indicates that the vector + outline being loaded should not be fitted to the pixel grid but simply scaled + to 26.6 fractional pixels. +## +#Const kSlight_Hinting 1 + Modifies glyph outlines minimally to improve constrast. + With FreeType, this is equivalent in spirit to the + FT_LOAD_TARGET_LIGHT value supplied to FT_Load_Glyph. It chooses a + lighter hinting algorithm for non-monochrome modes. + Generated glyphs may be fuzzy but better resemble their original shape. +## +#Const kNormal_Hinting 2 + Modifies glyph outlines to improve constrast. This is the default. + With FreeType, this supplies FT_LOAD_TARGET_NORMAL to FT_Load_Glyph,
+ choosing the default hinting algorithm, which is optimized for standard + gray-level rendering. +## +#Const kFull_Hinting 3 + Modifies glyph outlines for maxiumum constrast. With FreeType, this selects
+ FT_LOAD_TARGET_LCD or FT_LOAD_TARGET_LCD_V if kLCDRenderText_Flag is set.
+ FT_LOAD_TARGET_LCD is a variant of FT_LOAD_TARGET_NORMAL optimized for
+ horizontally decimated LCD displays; FT_LOAD_TARGET_LCD_V is a
+ variant of FT_LOAD_TARGET_NORMAL optimized for vertically decimated LCD displays. +## + +#Track +#File SkFontHost_mac.cpp:1777,1806 +#Time 2013-03-03 07:16:29 +0000 +#Bug 915 ## +On OS_X and iOS, hinting controls whether Core_Graphics dilates the font outlines +to account for LCD text. No hinting uses Core_Text gray scale output. +Normal hinting uses Core_Text LCD output. If kLCDRenderText_Flag is clear, +the LCD output is reduced to a single grayscale channel. +#Track ## + +On Windows with DirectWrite, Hinting has no effect. + +Hinting defaults to kNormal_Hinting. +Set SkPaintDefaults_Hinting at compile time to change the default setting. + +#ToDo add an illustration? linux running GM:typefacerendering is best for this + the hinting variations are every other character horizontally +#ToDo ## + +#Enum ## + +#Method Hinting getHinting() const + + Returns level of glyph outline adjustment. + + #Return one of: kNo_Hinting, kSlight_Hinting, kNormal_Hinting, kFull_Hinting ## + + #Example + SkPaint paint; + SkDebugf("SkPaint::kNormal_Hinting %c= paint.getHinting()\n", + SkPaint::kNormal_Hinting == paint.getHinting() ? '=' : ':'); + + #StdOut + SkPaint::kNormal_Hinting == paint.getHinting() + ## + ## +## + +#Method void setHinting(Hinting hintingLevel) + + Sets level of glyph outline adjustment. + Does not check for valid values of hintingLevel. + + #Table + #Legend + # Hinting # value # effect on generated glyph outlines ## + ## + # kNo_Hinting # 0 # leaves glyph outlines unchanged from their native representation ## + # kSlight_Hinting # 1 # modifies glyph outlines minimally to improve constrast ## + # kNormal_Hinting # 2 # modifies glyph outlines to improve constrast ## + # kFull_Hinting # 3 # modifies glyph outlines for maxiumum constrast ## + ## + + #Param hintingLevel one of: kNo_Hinting, kSlight_Hinting, kNormal_Hinting, kFull_Hinting ## + + #Example + SkPaint paint1, paint2; + paint2.setHinting(SkPaint::kNormal_Hinting); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : ':'); + + #StdOut + paint1 == paint2 + ## + ## +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Flags + +#Enum Flags + +#Code + enum Flags { + kAntiAlias_Flag = 0x01, + kDither_Flag = 0x04, + kFakeBoldText_Flag = 0x20, + kLinearText_Flag = 0x40, + kSubpixelText_Flag = 0x80, + kDevKernText_Flag = 0x100, + kLCDRenderText_Flag = 0x200, + kEmbeddedBitmapText_Flag = 0x400, + kAutoHinting_Flag = 0x800, + kVerticalText_Flag = 0x1000, + kGenA8FromLCD_Flag = 0x2000, + + kAllFlags = 0xFFFF, + }; + +## + +The bit values stored in Flags. +The default value for Flags, normally zero, can be changed at compile time +with a custom definition of SkPaintDefaults_Flags. +All flags can be read and written explicitly; Flags allows manipulating +multiple settings at once. + + #Const kAntiAlias_Flag 0x0001 + mask for setting Anti-alias + ## + #Const kDither_Flag 0x0004 + mask for setting Dither + ## + + #Const kFakeBoldText_Flag 0x0020 + mask for setting Fake_Bold + ## + #Const kLinearText_Flag 0x0040 + mask for setting Linear_Text + ## + #Const kSubpixelText_Flag 0x0080 + mask for setting Subpixel_Text + ## + #Const kDevKernText_Flag 0x0100 + mask for setting Full_Hinting_Spacing + ## + #Const kLCDRenderText_Flag 0x0200 + mask for setting LCD_Text + ## + #Const kEmbeddedBitmapText_Flag 0x0400 + mask for setting Font_Embedded_Bitmaps + ## + #Const kAutoHinting_Flag 0x0800 + mask for setting Automatic_Hinting + ## + #Const kVerticalText_Flag 0x1000 + mask for setting Vertical_Text + ## + #Const kGenA8FromLCD_Flag 0x2000 + #Private + Hack for GDI -- do not use if you can help it + ## + not intended for public use + ## + #Const kAllFlags 0xFFFF + mask of all Flags, including private flags and flags reserved for future use + ## + +Flags default to all flags clear, disabling the associated feature. + +#Enum ## + +#Enum ReserveFlags + +#Private +To be deprecated; only valid for Android framework. +## + +#Code + enum ReserveFlags { + kUnderlineText_ReserveFlag = 0x08, + kStrikeThruText_ReserveFlag = 0x10, + }; +## + + #Const kUnderlineText_ReserveFlag 0x0008 + mask for underline text + ## + #Const kStrikeThruText_ReserveFlag 0x0010 + mask for strike-thru text + ## + +#ToDo incomplete ## + +#Enum ## + +#Method uint32_t getFlags() const + +Returns paint settings described by Flags. Each setting uses one +bit, and can be tested with Flags members. + +#Return zero, one, or more bits described by Flags ## + +#Example + SkPaint paint; + paint.setAntiAlias(true); + SkDebugf("(SkPaint::kAntiAlias_Flag & paint.getFlags()) %c= 0\n", + SkPaint::kAntiAlias_Flag & paint.getFlags() ? '!' : '='); + + #StdOut + (SkPaint::kAntiAlias_Flag & paint.getFlags()) != 0 + ## +## + +## + +#Method void setFlags(uint32_t flags) + +Replaces Flags with flags, the union of the Flags members. +All Flags members may be cleared, or one or more may be set. + +#Param flags union of Flags for Paint ## + +#Example + SkPaint paint; + paint.setFlags((uint32_t) (SkPaint::kAntiAlias_Flag | SkPaint::kDither_Flag)); + SkDebugf("paint.isAntiAlias()\n", paint.isAntiAlias() ? '!' : '='); + SkDebugf("paint.isDither()\n", paint.isDither() ? '!' : '='); + + #StdOut + paint.isAntiAlias() + paint.isDither() + ## +## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Anti-alias +#Alias Anti-alias # permit hyphen in topic name, should probably not substitute hyphen with _ + +Anti-alias drawing approximates partial pixel coverage with transparency. +If kAntiAlias_Flag is clear, pixel centers contained by the shape edge are drawn opaque. +If kAntiAlias_Flag is set, pixels are drawn with Color_Alpha equal to their coverage. + +The rule for aliased pixels is inconsistent across platforms. A shape edge +passing through the pixel center may, but is not required to, draw the pixel. + +Raster_Engine draws aliased pixels whose centers are on or to the right of the start of an +active Path edge, and whose center is to the left of the end of the active Path edge. + +#ToDo add illustration of raster pixels ## + +A platform may only support anti-aliased drawing. Some GPU-backed platforms use +supersampling to anti-alias all drawing, and have no mechanism to selectively +alias. + +The amount of coverage computed for anti-aliased pixels also varies across platforms. + +Anti-alias is disabled by default. +Anti-alias can be enabled by default by setting SkPaintDefaults_Flags to kAntiAlias_Flag +at compile time. + + #Example + #Width 512 + #Description + A red line is drawn with transparency on the edges to make it look smoother. + A blue line draws only where the pixel centers are contained. + The lines are drawn into an offscreen bitmap, then drawn magified to make the + aliasing easier to see. + ## + + void draw(SkCanvas* canvas) { + SkBitmap bitmap; + bitmap.allocN32Pixels(50, 50); + SkCanvas offscreen(bitmap); + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(10); + for (bool antialias : { false, true }) { + paint.setColor(antialias ? SK_ColorRED : SK_ColorBLUE); + paint.setAntiAlias(antialias); + bitmap.eraseColor(0); + offscreen.drawLine(5, 5, 15, 30, paint); + canvas->drawLine(5, 5, 15, 30, paint); + canvas->save(); + canvas->scale(10, 10); + canvas->drawBitmap(bitmap, antialias ? 12 : 0, 0); + canvas->restore(); + canvas->translate(15, 0); + } + } + ## + +#Method bool isAntiAlias() const + + If true, pixels on the active edges of Path may be drawn with partial transparency. + + Equivalent to getFlags masked with kAntiAlias_Flag. + + #Return kAntiAlias_Flag state ## + + #Example + SkPaint paint; + SkDebugf("paint.isAntiAlias() %c= !!(paint.getFlags() & SkPaint::kAntiAlias_Flag)\n", + paint.isAntiAlias() == !!(paint.getFlags() & SkPaint::kAntiAlias_Flag) ? '=' : '!'); + paint.setAntiAlias(true); + SkDebugf("paint.isAntiAlias() %c= !!(paint.getFlags() & SkPaint::kAntiAlias_Flag)\n", + paint.isAntiAlias() == !!(paint.getFlags() & SkPaint::kAntiAlias_Flag) ? '=' : '!'); + + #StdOut + paint.isAntiAlias() == !!(paint.getFlags() & SkPaint::kAntiAlias_Flag) + paint.isAntiAlias() == !!(paint.getFlags() & SkPaint::kAntiAlias_Flag) + ## + ## +## + +#Method void setAntiAlias(bool aa) + + Requests, but does not require, that Path edge pixels draw opaque or with + partial transparency. + + Sets kAntiAlias_Flag if aa is true. + Clears kAntiAlias_Flag if aa is false. + + #Param aa setting for kAntiAlias_Flag ## + + #Example + SkPaint paint1, paint2; + paint1.setAntiAlias(true); + paint2.setFlags(paint2.getFlags() | SkPaint::kAntiAlias_Flag); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + ## + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Dither + +Dither increases fidelity by adjusting the color of adjcent pixels. +This can help to smooth color transitions and reducing banding in gradients. +Dithering lessens visible banding from kRGB_565_SkColorType +and kRGBA_8888_SkColorType gradients, +and improves rendering into a kRGB_565_SkColorType Surface. + +Dithering is always enabled for linear gradients drawing into +kRGB_565_SkColorType Surface and kRGBA_8888_SkColorType Surface. +Dither cannot be enabled for kAlpha_8_SkColorType Surface and +kRGBA_F16_SkColorType Surface. + +Dither is disabled by default. +Dither can be enabled by default by setting SkPaintDefaults_Flags to kDither_Flag +at compile time. + +Some platform implementations may ignore dithering. Set + +#Define SK_IGNORE_GPU_DITHER + +to ignore Dither on GPU_Surface. + +#Example +#Description +Dithering in the bottom half more closely approximates the requested color by +alternating nearby colors from pixel to pixel. +## +void draw(SkCanvas* canvas) { + SkBitmap bm16; + bm16.allocPixels(SkImageInfo::Make(32, 32, kRGB_565_SkColorType, kOpaque_SkAlphaType)); + SkCanvas c16(bm16); + SkPaint colorPaint; + for (auto dither : { false, true } ) { + colorPaint.setDither(dither); + for (auto colors : { 0xFF333333, 0xFF666666, 0xFF999999, 0xFFCCCCCC } ) { + for (auto mask : { 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFFFFFFFF } ) { + colorPaint.setColor(colors & mask); + c16.drawRect({0, 0, 8, 4}, colorPaint); + c16.translate(8, 0); + } + c16.translate(-32, 4); + } + } + canvas->scale(8, 8); + canvas->drawBitmap(bm16, 0, 0); +} +## + +#Example +#Description +Dithering introduces subtle adjustments to color to smooth gradients. +Drawing the gradient repeatedly with SkBlendMode::kPlus exaggerates the +dither, making it easier to see. +## +void draw(SkCanvas* canvas) { + canvas->clear(0); + SkBitmap bm32; + bm32.allocPixels(SkImageInfo::Make(20, 10, kN32_SkColorType, kPremul_SkAlphaType)); + SkCanvas c32(bm32); + SkPoint points[] = {{0, 0}, {20, 0}}; + SkColor colors[] = {0xFF334455, 0xFF662211 }; + SkPaint paint; + paint.setShader(SkGradientShader::MakeLinear( + points, colors, nullptr, SK_ARRAY_COUNT(colors), + SkShader::kClamp_TileMode, 0, nullptr)); + paint.setDither(true); + c32.drawPaint(paint); + canvas->scale(12, 12); + canvas->drawBitmap(bm32, 0, 0); + paint.setBlendMode(SkBlendMode::kPlus); + canvas->drawBitmap(bm32, 0, 11, &paint); + canvas->drawBitmap(bm32, 0, 11, &paint); + canvas->drawBitmap(bm32, 0, 11, &paint); +} +## + +#Method bool isDither() const + + If true, color error may be distributed to smooth color transition. + + Equivalent to getFlags masked with kDither_Flag. + + #Return kDither_Flag state ## + + #Example + SkPaint paint; + SkDebugf("paint.isDither() %c= !!(paint.getFlags() & SkPaint::kDither_Flag)\n", + paint.isDither() == !!(paint.getFlags() & SkPaint::kDither_Flag) ? '=' : '!'); + paint.setDither(true); + SkDebugf("paint.isDither() %c= !!(paint.getFlags() & SkPaint::kDither_Flag)\n", + paint.isDither() == !!(paint.getFlags() & SkPaint::kDither_Flag) ? '=' : '!'); + + #StdOut + paint.isDither() == !!(paint.getFlags() & SkPaint::kDither_Flag) + paint.isDither() == !!(paint.getFlags() & SkPaint::kDither_Flag) + ## + ## + +## + +#Method void setDither(bool dither) + + Requests, but does not require, to distribute color error. + + Sets kDither_Flag if dither is true. + Clears kDither_Flag if dither is false. + + #Param dither setting for kDither_Flag ## + + #Example + SkPaint paint1, paint2; + paint1.setDither(true); + paint2.setFlags(paint2.getFlags() | SkPaint::kDither_Flag); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + ## + ## + + #SeeAlso kRGB_565_SkColorType + +## + +#SeeAlso Gradient Color_RGB-565 + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Device_Text + +LCD_Text and Subpixel_Text increase the precision of glyph position. + +When set, Flags kLCDRenderText_Flag takes advantage of the organization of Color_RGB stripes that +create a color, and relies +on the small size of the stripe and visual perception to make the color fringing inperceptible. +LCD_Text can be enabled on devices that orient stripes horizontally or vertically, and that order +the color components as Color_RGB or Color_RBG. + +Flags kSubpixelText_Flag uses the pixel transparency to represent a fractional offset. +As the opaqueness +of the color increases, the edge of the glyph appears to move towards the outside of the pixel. + +Either or both techniques can be enabled. +kLCDRenderText_Flag and kSubpixelText_Flag are clear by default. +LCD_Text or Subpixel_Text can be enabled by default by setting SkPaintDefaults_Flags to +kLCDRenderText_Flag or kSubpixelText_Flag (or both) at compile time. + +#Example + #Description + Four commas are drawn normally and with combinations of LCD_Text and Subpixel_Text. + When Subpixel_Text is disabled, the comma glyphs are indentical, but not evenly spaced. + When Subpixel_Text is enabled, the comma glyphs are unique, but appear evenly spaced. + ## + + SkBitmap bitmap; + bitmap.allocN32Pixels(24, 33); + SkCanvas offscreen(bitmap); + offscreen.clear(SK_ColorWHITE); + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(20); + for (bool lcd : { false, true }) { + paint.setLCDRenderText(lcd); + for (bool subpixel : { false, true }) { + paint.setSubpixelText(subpixel); + offscreen.drawString(",,,,", 0, 4, paint); + offscreen.translate(0, 7); + } + } + canvas->drawBitmap(bitmap, 4, 12); + canvas->scale(9, 9); + canvas->drawBitmap(bitmap, 4, -1); +## + +#Subtopic Linear_Text +#Alias Linear_Text # makes this a top level name, since it is under subtopic Device_Text + +Linear_Text selects whether text is rendered as a Glyph or as a Path. +If kLinearText_Flag is set, it has the same effect as setting Hinting to kNormal_Hinting. +If kLinearText_Flag is clear, it's the same as setting Hinting to kNo_Hinting. + +#Method bool isLinearText() const + + If true, text is converted to Path before drawing and measuring. + + Equivalent to getFlags masked with kLinearText_Flag. + + #Return kLinearText_Flag state ## + + #Example + #Height 128 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + const char testStr[] = "xxxx xxxx"; + for (auto linearText : { false, true } ) { + paint.setLinearText(linearText); + paint.setTextSize(24); + canvas->drawString(paint.isLinearText() ? "linear" : "hinted", 128, 30, paint); + for (SkScalar textSize = 8; textSize < 30; textSize *= 1.22f) { + paint.setTextSize(textSize); + canvas->translate(0, textSize); + canvas->drawString(testStr, 10, 0, paint); + } + } + } + ## + + #SeeAlso setLinearText Hinting +## + +#Method void setLinearText(bool linearText) + + If true, text is converted to Path before drawing and measuring. + By default, kLinearText_Flag is clear. + + Sets kLinearText_Flag if linearText is true. + Clears kLinearText_Flag if linearText is false. + + #Param linearText setting for kLinearText_Flag ## + + #Example + #Height 128 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + const char testStr[] = "abcd efgh"; + for (int textSize : { 12, 24 } ) { + paint.setTextSize(textSize); + for (auto linearText : { false, true } ) { + paint.setLinearText(linearText); + SkString width; + width.appendScalar(paint.measureText(testStr, SK_ARRAY_COUNT(testStr), nullptr)); + canvas->translate(0, textSize + 4); + canvas->drawString(testStr, 10, 0, paint); + canvas->drawString(width, 128, 0, paint); + } + } + } + ## + + #SeeAlso isLinearText Hinting +## + +#Subtopic ## + +#Subtopic Subpixel_Text +#Alias Subpixel_Text # makes this a top level name, since it is under subtopic Device_Text + +Flags kSubpixelText_Flag uses the pixel transparency to represent a fractional offset. +As the opaqueness +of the color increases, the edge of the glyph appears to move towards the outside of the pixel. + +#Method bool isSubpixelText() const + + If true, glyphs at different sub-pixel positions may differ on pixel edge coverage. + + Equivalent to getFlags masked with kSubpixelText_Flag. + + #Return kSubpixelText_Flag state ## + + #Example +SkPaint paint; +SkDebugf("paint.isSubpixelText() %c= !!(paint.getFlags() & SkPaint::kSubpixelText_Flag)\n", + paint.isSubpixelText() == !!(paint.getFlags() & SkPaint::kSubpixelText_Flag) ? '=' : '!'); +paint.setSubpixelText(true); +SkDebugf("paint.isSubpixelText() %c= !!(paint.getFlags() & SkPaint::kSubpixelText_Flag)\n", + paint.isSubpixelText() == !!(paint.getFlags() & SkPaint::kSubpixelText_Flag) ? '=' : '!'); + + #StdOut + paint.isSubpixelText() == !!(paint.getFlags() & SkPaint::kSubpixelText_Flag) + paint.isSubpixelText() == !!(paint.getFlags() & SkPaint::kSubpixelText_Flag) + ## + ## + +## + +#Method void setSubpixelText(bool subpixelText) + + Requests, but does not require, that glyphs respect sub-pixel positioning. + + Sets kSubpixelText_Flag if subpixelText is true. + Clears kSubpixelText_Flag if subpixelText is false. + + #Param subpixelText setting for kSubpixelText_Flag ## + + #Example + SkPaint paint1, paint2; + paint1.setSubpixelText(true); + paint2.setFlags(paint2.getFlags() | SkPaint::kSubpixelText_Flag); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + ## + ## + +## + +#Subtopic ## + +#Subtopic LCD_Text +#Alias LCD_Text # makes this a top level name, since it is under subtopic Device_Text + +When set, Flags kLCDRenderText_Flag takes advantage of the organization of Color_RGB stripes that +create a color, and relies +on the small size of the stripe and visual perception to make the color fringing inperceptible. +LCD_Text can be enabled on devices that orient stripes horizontally or vertically, and that order +the color components as Color_RGB or Color_RBG. + +#Method bool isLCDRenderText() const + + If true, glyphs may use LCD striping to improve glyph edges. + + Returns true if Flags kLCDRenderText_Flag is set. + + #Return kLCDRenderText_Flag state ## + + #Example +SkPaint paint; +SkDebugf("paint.isLCDRenderText() %c= !!(paint.getFlags() & SkPaint::kLCDRenderText_Flag)\n", + paint.isLCDRenderText() == !!(paint.getFlags() & SkPaint::kLCDRenderText_Flag) ? '=' : '!'); +paint.setLCDRenderText(true); +SkDebugf("paint.isLCDRenderText() %c= !!(paint.getFlags() & SkPaint::kLCDRenderText_Flag)\n", + paint.isLCDRenderText() == !!(paint.getFlags() & SkPaint::kLCDRenderText_Flag) ? '=' : '!'); + + #StdOut + paint.isLCDRenderText() == !!(paint.getFlags() & SkPaint::kLCDRenderText_Flag) + paint.isLCDRenderText() == !!(paint.getFlags() & SkPaint::kLCDRenderText_Flag) + ## + ## + +## + +#Method void setLCDRenderText(bool lcdText) + + Requests, but does not require, that glyphs use LCD striping for glyph edges. + + Sets kLCDRenderText_Flag if lcdText is true. + Clears kLCDRenderText_Flag if lcdText is false. + + #Param lcdText setting for kLCDRenderText_Flag ## + + #Example + SkPaint paint1, paint2; + paint1.setLCDRenderText(true); + paint2.setFlags(paint2.getFlags() | SkPaint::kLCDRenderText_Flag); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + ## + ## + + +## + +#Subtopic ## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Font_Embedded_Bitmaps +#Alias Font_Embedded_Bitmaps # long-winded enough, alias so I don't type Paint_Font_... + +Font_Embedded_Bitmaps allows selecting custom-sized bitmap glyphs. +Flags kEmbeddedBitmapText_Flag when set chooses an embedded bitmap glyph over an outline contained +in a font if the platform supports this option. + +FreeType selects the bitmap glyph if available when kEmbeddedBitmapText_Flag is set, and selects +the outline glyph if kEmbeddedBitmapText_Flag is clear. +Windows may select the bitmap glyph but is not required to do so. +OS_X and iOS do not support this option. + +Font_Embedded_Bitmaps is disabled by default. +Font_Embedded_Bitmaps can be enabled by default by setting SkPaintDefaults_Flags to +kEmbeddedBitmapText_Flag at compile time. + +#Example + #ToDo image will only output on Ubuntu ... how to handle that in fiddle? ## + #Platform !fiddle + #Description + The hintgasp TrueType font in the Skia resources/fonts directory includes an embedded + bitmap glyph at odd font sizes. This example works on platforms that use FreeType + as their Font_Engine. + Windows may, but is not required to, return a bitmap glyph if kEmbeddedBitmapText_Flag is set. + ## + #Image embeddedbitmap.png + + SkBitmap bitmap; + bitmap.allocN32Pixels(30, 15); + bitmap.eraseColor(0); + SkCanvas offscreen(bitmap); + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(13); + paint.setTypeface(MakeResourceAsTypeface("/fonts/hintgasp.ttf")); + for (bool embedded : { false, true}) { + paint.setEmbeddedBitmapText(embedded); + offscreen.drawString("A", embedded ? 5 : 15, 15, paint); + } + canvas->drawBitmap(bitmap, 0, 0); + canvas->scale(10, 10); + canvas->drawBitmap(bitmap, -2, 1); +## + +#Method bool isEmbeddedBitmapText() const + + If true, Font_Engine may return glyphs from font bitmaps instead of from outlines. + + Equivalent to getFlags masked with kEmbeddedBitmapText_Flag. + + #Return kEmbeddedBitmapText_Flag state ## + + #Example + SkPaint paint; + SkDebugf("paint.isEmbeddedBitmapText() %c=" + " !!(paint.getFlags() & SkPaint::kEmbeddedBitmapText_Flag)\n", + paint.isEmbeddedBitmapText() == + !!(paint.getFlags() & SkPaint::kEmbeddedBitmapText_Flag) ? '=' : '!'); + paint.setEmbeddedBitmapText(true); + SkDebugf("paint.isEmbeddedBitmapText() %c=" + " !!(paint.getFlags() & SkPaint::kEmbeddedBitmapText_Flag)\n", + paint.isEmbeddedBitmapText() == + !!(paint.getFlags() & SkPaint::kEmbeddedBitmapText_Flag) ? '=' : '!'); + + #StdOut + paint.isEmbeddedBitmapText() == !!(paint.getFlags() & SkPaint::kEmbeddedBitmapText_Flag) + paint.isEmbeddedBitmapText() == !!(paint.getFlags() & SkPaint::kEmbeddedBitmapText_Flag) + ## + ## + +## + +#Method void setEmbeddedBitmapText(bool useEmbeddedBitmapText) + + Requests, but does not require, to use bitmaps in fonts instead of outlines. + + Sets kEmbeddedBitmapText_Flag if useEmbeddedBitmapText is true. + Clears kEmbeddedBitmapText_Flag if useEmbeddedBitmapText is false. + + #Param useEmbeddedBitmapText setting for kEmbeddedBitmapText_Flag ## + + #Example + SkPaint paint1, paint2; + paint1.setEmbeddedBitmapText(true); + paint2.setFlags(paint2.getFlags() | SkPaint::kEmbeddedBitmapText_Flag); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + ## + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Automatic_Hinting +#Substitute auto-hinting + +If Hinting is set to kNormal_Hinting or kFull_Hinting, Automatic_Hinting +instructs the Font_Manager to always hint Glyphs. +Automatic_Hinting has no effect if Hinting is set to kNo_Hinting or +kSlight_Hinting. + +Automatic_Hinting only affects platforms that use FreeType as the Font_Manager. + +#Method bool isAutohinted() const + + If true, and if Hinting is set to kNormal_Hinting or kFull_Hinting, and if + platform uses FreeType as the Font_Manager, instruct the Font_Manager to always hint + Glyphs. + + Equivalent to getFlags masked with kAutoHinting_Flag. + + #Return kAutoHinting_Flag state ## + + #Example + SkPaint paint; + for (auto forceAutoHinting : { false, true} ) { + paint.setAutohinted(forceAutoHinting); + SkDebugf("paint.isAutohinted() %c=" + " !!(paint.getFlags() & SkPaint::kAutoHinting_Flag)\n", + paint.isAutohinted() == + !!(paint.getFlags() & SkPaint::kAutoHinting_Flag) ? '=' : '!'); + } + #StdOut + paint.isAutohinted() == !!(paint.getFlags() & SkPaint::kAutoHinting_Flag) + paint.isAutohinted() == !!(paint.getFlags() & SkPaint::kAutoHinting_Flag) + ## + ## + + #SeeAlso setAutohinted Hinting + +## + +#Method void setAutohinted(bool useAutohinter) + + If Hinting is set to kNormal_Hinting or kFull_Hinting and useAutohinter is set, + instruct the Font_Manager to always hint Glyphs. + Automatic_Hinting has no effect if Hinting is set to kNo_Hinting or + kSlight_Hinting. + + setAutohinted only affects platforms that use FreeType as the Font_Manager. + + Sets kAutoHinting_Flag if useAutohinter is true. + Clears kAutoHinting_Flag if useAutohinter is false. + + #Param useAutohinter setting for kAutoHinting_Flag ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + const char testStr[] = "xxxx xxxx"; + for (auto forceAutoHinting : { false, true} ) { + paint.setAutohinted(forceAutoHinting); + paint.setTextSize(24); + canvas->drawString(paint.isAutohinted() ? "auto-hinted" : "default", 108, 30, paint); + for (SkScalar textSize = 8; textSize < 30; textSize *= 1.22f) { + paint.setTextSize(textSize); + canvas->translate(0, textSize); + canvas->drawString(testStr, 10, 0, paint); + } + } + } + ## + + #SeeAlso isAutohinted Hinting + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Vertical_Text + +Text may be drawn by positioning each glyph, or by positioning the first glyph and +using Font_Advance to position subsequent glyphs. By default, each successive glyph +is positioned to the right of the preceeding glyph. Vertical_Text sets successive +glyphs to position below the preceeding glyph. + +Skia can translate text character codes as a series of glyphs, but does not implement +font substitution, +textual substitution, line layout, or contextual spacing like kerning pairs. Use +a text shaping engine like #A HarfBuzz # http://harfbuzz.org/ ## to translate text runs +into glyph series. + +Vertical_Text is clear if text is drawn left to right or set if drawn from top to bottom. + +Flags kVerticalText_Flag if clear draws text left to right. +Flags kVerticalText_Flag if set draws text top to bottom. + +Vertical_Text is clear by default. +Vertical_Text can be set by default by setting SkPaintDefaults_Flags to +kVerticalText_Flag at compile time. + +#Example + +void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(50); + for (bool vertical : { false, true } ) { + paint.setVerticalText(vertical); + canvas->drawString("aAlL", 25, 50, paint); + } +} + +## + +#Method bool isVerticalText() const + + If true, glyphs are drawn top to bottom instead of left to right. + + Equivalent to getFlags masked with kVerticalText_Flag. + + #Return kVerticalText_Flag state ## + + #Example + SkPaint paint; + SkDebugf("paint.isVerticalText() %c= !!(paint.getFlags() & SkPaint::kVerticalText_Flag)\n", + paint.isVerticalText() == !!(paint.getFlags() & SkPaint::kVerticalText_Flag) ? '=' : '!'); + paint.setVerticalText(true); + SkDebugf("paint.isVerticalText() %c= !!(paint.getFlags() & SkPaint::kVerticalText_Flag)\n", + paint.isVerticalText() == !!(paint.getFlags() & SkPaint::kVerticalText_Flag) ? '=' : '!'); + + #StdOut + paint.isVerticalText() == !!(paint.getFlags() & SkPaint::kVerticalText_Flag) + paint.isVerticalText() == !!(paint.getFlags() & SkPaint::kVerticalText_Flag) + ## + ## + +## + +#Method void setVerticalText(bool verticalText) + + If true, text advance positions the next glyph below the previous glyph instead of to the + right of previous glyph. + + Sets kVerticalText_Flag if vertical is true. + Clears kVerticalText_Flag if vertical is false. + + #Param verticalText setting for kVerticalText_Flag ## + + #Example + SkPaint paint1, paint2; + paint1.setVerticalText(true); + paint2.setFlags(paint2.getFlags() | SkPaint::kVerticalText_Flag); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + ## + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ + +#Topic Fake_Bold + +Fake_Bold approximates the bold font style accompanying a normal font when a bold font face +is not available. Skia does not provide font substitution; it is up to the client to find the +bold font face using the platform's Font_Manager. + +Use Text_Skew_X to approximate an italic font style when the italic font face +is not available. + +A FreeType-based port may define SK_USE_FREETYPE_EMBOLDEN at compile time to direct +the font engine to create the bold glyphs. Otherwise, the extra bold is computed +by increasing the stroke width and setting the Style to kStrokeAndFill_Style as needed. + +Fake_Bold is disabled by default. + +#Example +#Height 128 +void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(40); + canvas->drawString("OjYy_-", 10, 35, paint); + paint.setFakeBoldText(true); + canvas->drawString("OjYy_-", 10, 75, paint); + // create a custom fake bold by varying the stroke width + paint.setFakeBoldText(false); + paint.setStyle(SkPaint::kStrokeAndFill_Style); + paint.setStrokeWidth(40.f / 48); + canvas->drawString("OjYy_-", 10, 115, paint); +} +## + +#Method bool isFakeBoldText() const + + If true, approximate bold by increasing the stroke width when creating glyph bitmaps + from outlines. + + Equivalent to getFlags masked with kFakeBoldText_Flag. + + #Return kFakeBoldText_Flag state ## + + #Example + SkPaint paint; + SkDebugf("paint.isFakeBoldText() %c= !!(paint.getFlags() & SkPaint::kFakeBoldText_Flag)\n", + paint.isFakeBoldText() == !!(paint.getFlags() & SkPaint::kFakeBoldText_Flag) ? '=' : '!'); + paint.setFakeBoldText(true); + SkDebugf("paint.isFakeBoldText() %c= !!(paint.getFlags() & SkPaint::kFakeBoldText_Flag)\n", + paint.isFakeBoldText() == !!(paint.getFlags() & SkPaint::kFakeBoldText_Flag) ? '=' : '!'); + + #StdOut + paint.isFakeBoldText() == !!(paint.getFlags() & SkPaint::kFakeBoldText_Flag) + paint.isFakeBoldText() == !!(paint.getFlags() & SkPaint::kFakeBoldText_Flag) + ## + ## + +## + +#Method void setFakeBoldText(bool fakeBoldText) + + Use increased stroke width when creating glyph bitmaps to approximate bolding. + + Sets kFakeBoldText_Flag if fakeBoldText is true. + Clears kFakeBoldText_Flag if fakeBoldText is false. + + #Param fakeBoldText setting for kFakeBoldText_Flag ## + + #Example + SkPaint paint1, paint2; + paint1.setFakeBoldText(true); + paint2.setFlags(paint2.getFlags() | SkPaint::kFakeBoldText_Flag); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + ## + ## + +## + +#Topic ## + +# ------------------------------------------------------------------------------ +#Topic Full_Hinting_Spacing +#Alias Full_Hinting_Spacing # long winded enough -- maybe things with two underscores auto-aliased? + +Full_Hinting_Spacing adjusts the character spacing by the difference of the +hinted and unhinted left and right side bearings, +if Hinting is set to kFull_Hinting. Full_Hinting_Spacing only +applies to platforms that use FreeType as their Font_Engine. + +Full_Hinting_Spacing is not related to text kerning, where the space between +a specific pair of characters is adjusted using data in the font's kerning tables. + +#Method bool isDevKernText() const + + Returns if character spacing may be adjusted by the hinting difference. + + Equivalent to getFlags masked with kDevKernText_Flag. + + #Return kDevKernText_Flag state ## + + #Example + SkPaint paint; + SkDebugf("paint.isDevKernText() %c= !!(paint.getFlags() & SkPaint::kDevKernText_Flag)\n", + paint.isDevKernText() == !!(paint.getFlags() & SkPaint::kDevKernText_Flag) ? '=' : '!'); + paint.setDevKernText(true); + SkDebugf("paint.isDevKernText() %c= !!(paint.getFlags() & SkPaint::kDevKernText_Flag)\n", + paint.isDevKernText() == !!(paint.getFlags() & SkPaint::kDevKernText_Flag) ? '=' : '!'); + ## + +## + +#Method void setDevKernText(bool devKernText) + + Requests, but does not require, to use hinting to adjust glyph spacing. + + Sets kDevKernText_Flag if devKernText is true. + Clears kDevKernText_Flag if devKernText is false. + + #Param devKernText setting for devKernText ## + + #Example + SkPaint paint1, paint2; + paint1.setDevKernText(true); + paint2.setFlags(paint2.getFlags() | SkPaint::kDevKernText_Flag); + SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); + + #StdOut + paint1 == paint2 + ## + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Filter_Quality_Methods + +Filter_Quality trades speed for image filtering when the image is scaled. +A lower Filter_Quality draws faster, but has less fidelity. +A higher Filter_Quality draws slower, but looks better. +If the image is unscaled, the Filter_Quality choice will not result in a noticable +difference. + +Filter_Quality is used in Paint passed as a parameter to +#List +# SkCanvas::drawBitmap ## +# SkCanvas::drawBitmapRect ## +# SkCanvas::drawImage ## +# SkCanvas::drawImageRect ## + #ToDo probably more... ## +#List ## +and when Paint has a Shader specialization that uses Image or Bitmap. + +Filter_Quality is kNone_SkFilterQuality by default. + +#Example +#Image 3 +void draw(SkCanvas* canvas) { + SkPaint paint; + canvas->scale(.2f, .2f); + for (SkFilterQuality q : { kNone_SkFilterQuality, kLow_SkFilterQuality, + kMedium_SkFilterQuality, kHigh_SkFilterQuality } ) { + paint.setFilterQuality(q); + canvas->drawImage(image.get(), 0, 0, &paint); + canvas->translate(550, 0); + if (kLow_SkFilterQuality == q) canvas->translate(-1100, 550); + } +} +## + +#Method SkFilterQuality getFilterQuality() const + +Returns Filter_Quality, the image filtering level. A lower setting +draws faster; a higher setting looks better when the image is scaled. + +#Return one of: kNone_SkFilterQuality, kLow_SkFilterQuality, + kMedium_SkFilterQuality, kHigh_SkFilterQuality +#Return ## + +#Example + SkPaint paint; + SkDebugf("kNone_SkFilterQuality %c= paint.getFilterQuality()\n", + kNone_SkFilterQuality == paint.getFilterQuality() ? '=' : '!'); + + #StdOut + kNone_SkFilterQuality == paint.getFilterQuality() + ## +## + +## + + +#Method void setFilterQuality(SkFilterQuality quality) + +Sets Filter_Quality, the image filtering level. A lower setting +draws faster; a higher setting looks better when the image is scaled. +setFilterQuality does not check to see if quality is valid. + +#Param quality one of: kNone_SkFilterQuality, kLow_SkFilterQuality, + kMedium_SkFilterQuality, kHigh_SkFilterQuality +## + +#Example + SkPaint paint; + paint.setFilterQuality(kHigh_SkFilterQuality); + SkDebugf("kHigh_SkFilterQuality %c= paint.getFilterQuality()\n", + kHigh_SkFilterQuality == paint.getFilterQuality() ? '=' : '!'); + + #StdOut + kHigh_SkFilterQuality == paint.getFilterQuality() + ## +## + +#SeeAlso SkFilterQuality Image_Scaling + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Color_Methods + +Color specifies the Color_RGB_Red, Color_RGB_Blue, Color_RGB_Green, and Color_Alpha values used to draw a filled +or stroked shape in a +32-bit value. Each component occupies 8-bits, ranging from zero: no contribution; +to 255: full intensity. All values in any combination are valid. + +Color is not premultiplied; +Color_Alpha sets the transparency independent of Color_RGB: Color_RGB_Red, Color_RGB_Blue, and Color_RGB_Green. + +The bit positions of Color_Alpha and Color_RGB are independent of the bit positions +on the output device, which may have more or fewer bits, and may have a different arrangement. + +#Table +#Legend +# bit positions # Color_Alpha # Color_RGB_Red # Color_RGB_Blue # Color_RGB_Green ## +#Legend ## +# # 31 - 24 # 23 - 16 # 15 - 8 # 7 - 0 ## +#Table ## + +#Example +#Height 128 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setColor(0x8000FF00); // transparent green + canvas->drawCircle(50, 50, 40, paint); + paint.setARGB(128, 255, 0, 0); // transparent red + canvas->drawCircle(80, 50, 40, paint); + paint.setColor(SK_ColorBLUE); + paint.setAlpha(0x80); + canvas->drawCircle(65, 65, 40, paint); + } +## + +#Method SkColor getColor() const + + Retrieves Color_Alpha and Color_RGB, unpremultiplied, packed into 32 bits. + Use helpers SkColorGetA, SkColorGetR, SkColorGetG, and SkColorGetB to extract + a color component. + + #Return Unpremultiplied Color_ARGB ## + + #Example + SkPaint paint; + paint.setColor(SK_ColorYELLOW); + SkColor y = paint.getColor(); + SkDebugf("Yellow is %d%% red, %d%% green, and %d%% blue.\n", (int) (SkColorGetR(y) / 2.55f), + (int) (SkColorGetG(y) / 2.55f), (int) (SkColorGetB(y) / 2.55f)); + + #StdOut + Yellow is 100% red, 100% green, and 0% blue. + ## + ## + + #SeeAlso SkColor + +## + +#Method void setColor(SkColor color) + + Sets Color_Alpha and Color_RGB used when stroking and filling. The color is a 32-bit value, + unpremutiplied, packing 8-bit components for Color_Alpha, Color_RGB_Red, Color_RGB_Blue, and Color_RGB_Green. + + #Param color Unpremultiplied Color_ARGB ## + + #Example + SkPaint green1, green2; + unsigned a = 255; + unsigned r = 0; + unsigned g = 255; + unsigned b = 0; + green1.setColor((a << 24) + (r << 16) + (g << 8) + (b << 0)); + green2.setColor(0xFF00FF00); + SkDebugf("green1 %c= green2\n", green1 == green2 ? '=' : '!'); + + #StdOut + green1 == green2 + ## + ## + + #SeeAlso SkColor setARGB SkColorSetARGB + +## + +#Subtopic Alpha_Methods + +Color_Alpha sets the transparency independent of Color_RGB: Color_RGB_Red, Color_RGB_Blue, and Color_RGB_Green. + +#Method uint8_t getAlpha() const + + Retrieves Color_Alpha from the Color used when stroking and filling. + + #Return Color_Alpha ranging from zero, fully transparent, to 255, fully opaque ## + + #Example + SkPaint paint; + SkDebugf("255 %c= paint.getAlpha()\n", 255 == paint.getAlpha() ? '=' : '!'); + + #StdOut + 255 == paint.getAlpha() + ## + ## + +## + +#Method void setAlpha(U8CPU a) + + Replaces Color_Alpha, leaving Color_RGB + unchanged. An out of range value triggers an assert in the debug + build. a is a value from zero to 255. + a set to zero makes Color fully transparent; a set to 255 makes Color + fully opaque. + + #Param a Color_Alpha component of Color ## + + #Example + SkPaint paint; + paint.setColor(0x00112233); + paint.setAlpha(0x44); + SkDebugf("0x44112233 %c= paint.getColor()\n", 0x44112233 == paint.getColor() ? '=' : '!'); + + #StdOut + 0x44112233 == paint.getColor() + ## + ## + +## + +#Subtopic ## + +#Method void setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) + + Sets Color used when drawing solid fills. The color components range from 0 to 255. + The color is unpremultiplied; + Color_Alpha sets the transparency independent of Color_RGB. + + #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) ## + + #Example + SkPaint transRed1, transRed2; + transRed1.setARGB(255 / 2, 255, 0, 0); + transRed2.setColor(SkColorSetARGB(255 / 2, 255, 0, 0)); + SkDebugf("transRed1 %c= transRed2", transRed1 == transRed2 ? '=' : '!'); + + #StdOut + transRed1 == transRed2 + ## + ## + + #SeeAlso setColor SkColorSetARGB + +## + +#Topic Color_Methods ## + +# ------------------------------------------------------------------------------ +#Topic Style + +Style specifies if the geometry is filled, stroked, or both filled and stroked. +Some shapes ignore Style and are always drawn filled or stroked. + +Set Style to kFill_Style to fill the shape. +The fill covers the area inside the geometry for most shapes. + +Set Style to kStroke_Style to stroke the shape. + +# ------------------------------------------------------------------------------ +#Subtopic Fill + +#ToDo write up whatever generalities make sense to describe filling ## + +#SeeAlso Path_Fill_Type +#Subtopic ## + +#Subtopic Stroke +The stroke covers the area described by following the shape's edge with a pen or brush of +Stroke_Width. The area covered where the shape starts and stops is described by Stroke_Cap. +The area covered where the shape turns a corner is described by Stroke_Join. +The stroke is centered on the shape; it extends equally on either side of the shape's edge. + +As Stroke_Width gets smaller, the drawn path frame is thinner. Stroke_Width less than one +may have gaps, and if kAntiAlias_Flag is set, Color_Alpha will increase to visually decrease coverage. +#Subtopic ## + +#Subtopic Hairline +#Alias Hairline # maybe should be Stroke_Hairline ? + +Stroke_Width of zero has a special meaning and switches drawing to use Hairline. +Hairline draws the thinnest continuous frame. If kAntiAlias_Flag is clear, adjacent pixels +flow horizontally, vertically,or diagonally. + +#ToDo what is the description of anti-aliased hairlines? ## + +Path drawing with Hairline may hit the same pixel more than once. For instance, Path containing +two lines in one Path_Contour will draw the corner point once, but may both lines may draw the adjacent +pixel. If kAntiAlias_Flag is set, transparency is applied twice, resulting in a darker pixel. Some +GPU-backed implementations apply transparency at a later drawing stage, avoiding double hit pixels +while stroking. + +#Subtopic ## + +#Enum Style + +#Code + enum Style { + kFill_Style, + kStroke_Style, + kStrokeAndFill_Style, + }; +## + +Set Style to fill, stroke, or both fill and stroke geometry. +The stroke and fill +share all paint attributes; for instance, they are drawn with the same color. + +Use kStrokeAndFill_Style to avoid hitting the same pixels twice with a stroke draw and +a fill draw. + +#Const kFill_Style 0 + Set to fill geometry. + Applies to Rect, Region, Round_Rect, Circle, Oval, Path, and Text. + Bitmap, Image, Patch, Region, Sprite, and Vertices are painted as if + kFill_Style is set, and ignore the set Style. + The Path_Fill_Type specifies additional rules to fill the area outside the path edge, + and to create an unfilled hole inside the shape. + Style is set to kFill_Style by default. +## + +#Const kStroke_Style 1 + Set to stroke geometry. + Applies to Rect, Region, Round_Rect, Arc, Circle, Oval, + Path, and Text. + Arc, Line, Point, and Point_Array are always drawn as if kStroke_Style is set, + and ignore the set Style. + The stroke construction is unaffected by the Path_Fill_Type. +## + +#Const kStrokeAndFill_Style 2 + Set to stroke and fill geometry. + Applies to Rect, Region, Round_Rect, Circle, Oval, Path, and Text. + Path is treated as if it is set to SkPath::kWinding_FillType, + and the set Path_Fill_Type is ignored. +## + +#Enum ## + +#Enum + +#Code + enum { + kStyleCount = kStrokeAndFill_Style + 1 + }; +## + +#Const kStyleCount 3 +The number of different Style values defined. +May be used to verify that Style is a legal value. +## + +#Enum ## + +#Method Style getStyle() const + + Whether the geometry is filled, stroked, or filled and stroked. + + #Return one of:kFill_Style, kStroke_Style, kStrokeAndFill_Style ## + + #Example + SkPaint paint; + SkDebugf("SkPaint::kFill_Style %c= paint.getStyle()\n", + SkPaint::kFill_Style == paint.getStyle() ? '=' : '!'); + + #StdOut + SkPaint::kFill_Style == paint.getStyle() + ## + ## + +#SeeAlso Style setStyle +## + +#Method void setStyle(Style style) + + Sets whether the geometry is filled, stroked, or filled and stroked. + Has no effect if style is not a legal Style value. + + #Param style one of: kFill_Style, kStroke_Style, kStrokeAndFill_Style + ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setStrokeWidth(5); + SkRegion region; + region.op(140, 10, 160, 30, SkRegion::kUnion_Op); + region.op(170, 40, 190, 60, SkRegion::kUnion_Op); + SkBitmap bitmap; + bitmap.setInfo(SkImageInfo::MakeA8(50, 50), 50); + uint8_t pixels[50][50]; + for (int x = 0; x < 50; ++x) { + for (int y = 0; y < 50; ++y) { + pixels[y][x] = (x + y) % 5 ? 0xFF : 0x00; + } + } + bitmap.setPixels(pixels); + for (auto style : { SkPaint::kFill_Style, + SkPaint::kStroke_Style, + SkPaint::kStrokeAndFill_Style }) { + paint.setStyle(style); + canvas->drawLine(10, 10, 60, 60, paint); + canvas->drawRect({80, 10, 130, 60}, paint); + canvas->drawRegion(region, paint); + canvas->drawBitmap(bitmap, 200, 10, &paint); + canvas->translate(0, 80); + } + } + ## + +#SeeAlso Style getStyle +## + +#SeeAlso Path_Fill_Type Path_Effect Style_Fill Style_Stroke +#Topic Style ## + +# ------------------------------------------------------------------------------ +#Topic Stroke_Width + +Stroke_Width sets the width for stroking. The width is the thickness +of the stroke perpendicular to the path's direction when the paint's style is +set to kStroke_Style or kStrokeAndFill_Style. + +When width is greater than zero, the stroke encompasses as many pixels partially +or fully as needed. When the width equals zero, the paint enables hairlines; +the stroke is always one pixel wide. + +The stroke's dimensions are scaled by the canvas matrix, but Hairline stroke +remains one pixel wide regardless of scaling. + +The default width for the paint is zero. + +#Example +#Height 170 + #Platform raster gpu + #Description + The pixels hit to represent thin lines vary with the angle of the + line and the platform's implementation. + ## + void draw(SkCanvas* canvas) { + SkPaint paint; + for (bool antialias : { false, true }) { + paint.setAntiAlias(antialias); + for (int width = 0; width <= 4; ++width) { + SkScalar offset = antialias * 100 + width * 20; + paint.setStrokeWidth(width * 0.25f); + canvas->drawLine(10 + offset, 10, 20 + offset, 60, paint); + canvas->drawLine(10 + offset, 110, 60 + offset, 160, paint); + } + } + } +## + +#Method SkScalar getStrokeWidth() const + + Returns the thickness of the pen used by Paint to + outline the shape. + + #Return zero for Hairline, greater than zero for pen thickness ## + + #Example + SkPaint paint; + SkDebugf("0 %c= paint.getStrokeWidth()\n", 0 == paint.getStrokeWidth() ? '=' : '!'); + + #StdOut + 0 == paint.getStrokeWidth() + ## + ## + +## + +#Method void setStrokeWidth(SkScalar width) + + Sets the thickness of the pen used by the paint to + outline the shape. + Has no effect if width is less than zero. + + #Param width zero thickness for Hairline; greater than zero for pen thickness + ## + + #Example + SkPaint paint; + paint.setStrokeWidth(5); + paint.setStrokeWidth(-1); + SkDebugf("5 %c= paint.getStrokeWidth()\n", 5 == paint.getStrokeWidth() ? '=' : '!'); + + #StdOut + 5 == paint.getStrokeWidth() + ## + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Miter_Limit + +Miter_Limit specifies the maximum miter length, +relative to the stroke width. + +Miter_Limit is used when the Stroke_Join +is set to kMiter_Join, and the Style is either kStroke_Style +or kStrokeAndFill_Style. + +If the miter at a corner exceeds this limit, kMiter_Join +is replaced with kBevel_Join. + +Miter_Limit can be computed from the corner angle: + +#Formula + miter limit = 1 / sin ( angle / 2 ) +#Formula ## + +Miter_Limit default value is 4. +The default may be changed at compile time by setting SkPaintDefaults_MiterLimit +in SkUserConfig.h or as a define supplied by the build environment. + +Here are some miter limits and the angles that triggers them. +#Table +#Legend + # miter limit # angle in degrees ## +#Legend ## + # 10 # 11.48 ## + # 9 # 12.76 ## + # 8 # 14.36 ## + # 7 # 16.43 ## + # 6 # 19.19 ## + # 5 # 23.07 ## + # 4 # 28.96 ## + # 3 # 38.94 ## + # 2 # 60 ## + # 1 # 180 ## +#Table ## + +#Example + #Height 170 + #Width 384 + #Description + This example draws a stroked corner and the miter length beneath. + When the miter limit is decreased slightly, the miter join is replaced + by a bevel join. + ## + void draw(SkCanvas* canvas) { + SkPoint pts[] = {{ 10, 50 }, { 110, 80 }, { 10, 110 }}; + SkVector v[] = { pts[0] - pts[1], pts[2] - pts[1] }; + SkScalar angle1 = SkScalarATan2(v[0].fY, v[0].fX); + SkScalar angle2 = SkScalarATan2(v[1].fY, v[1].fX); + const SkScalar strokeWidth = 20; + SkScalar miterLimit = 1 / SkScalarSin((angle2 - angle1) / 2); + SkScalar miterLength = strokeWidth * miterLimit; + SkPath path; + path.moveTo(pts[0]); + path.lineTo(pts[1]); + path.lineTo(pts[2]); + SkPaint paint; // set to default kMiter_Join + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeMiter(miterLimit); + paint.setStrokeWidth(strokeWidth); + canvas->drawPath(path, paint); + paint.setStrokeWidth(1); + canvas->drawLine(pts[1].fX - miterLength / 2, pts[1].fY + 50, + pts[1].fX + miterLength / 2, pts[1].fY + 50, paint); + canvas->translate(200, 0); + miterLimit *= 0.99f; + paint.setStrokeMiter(miterLimit); + paint.setStrokeWidth(strokeWidth); + canvas->drawPath(path, paint); + paint.setStrokeWidth(1); + canvas->drawLine(pts[1].fX - miterLength / 2, pts[1].fY + 50, + pts[1].fX + miterLength / 2, pts[1].fY + 50, paint); + } +## + +#Method SkScalar getStrokeMiter() const + + The limit at which a sharp corner is drawn beveled. + + #Return zero and greater Miter_Limit ## + + #Example + SkPaint paint; + SkDebugf("default miter limit == %g\n", paint.getStrokeMiter()); + + #StdOut + default miter limit == 4 + ## + ## + + #SeeAlso Miter_Limit setStrokeMiter Join + +## + +#Method void setStrokeMiter(SkScalar miter) + + The limit at which a sharp corner is drawn beveled. + Valid values are zero and greater. + Has no effect if miter is less than zero. + + #Param miter zero and greater Miter_Limit + ## + + #Example + SkPaint paint; + paint.setStrokeMiter(8); + paint.setStrokeMiter(-1); + SkDebugf("default miter limit == %g\n", paint.getStrokeMiter()); + + #StdOut + default miter limit == 8 + ## + ## + + #SeeAlso Miter_Limit getStrokeMiter Join + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Stroke_Cap + +#Enum Cap + +#Code + enum Cap { + kButt_Cap, + kRound_Cap, + kSquare_Cap, + + kLast_Cap = kSquare_Cap, + kDefault_Cap = kButt_Cap + }; + static constexpr int kCapCount = kLast_Cap + 1; +## + +Stroke_Cap draws at the beginning and end of an open Path_Contour. + + #Const kButt_Cap 0 + Does not extend the stroke past the beginning or the end. + ## + #Const kRound_Cap 1 + Adds a circle with a diameter equal to Stroke_Width at the beginning + and end. + ## + #Const kSquare_Cap 2 + Adds a square with sides equal to Stroke_Width at the beginning + and end. The square sides are parallel to the initial and final direction + of the stroke. + ## + #Const kLast_Cap 2 + Equivalent to the largest value for Stroke_Cap. + ## + #Const kDefault_Cap 0 + Equivalent to kButt_Cap. + Stroke_Cap is set to kButt_Cap by default. + ## + + #Const kCapCount 3 + The number of different Stroke_Cap values defined. + May be used to verify that Stroke_Cap is a legal value. + ## +#Enum ## + +Stroke describes the area covered by a pen of Stroke_Width as it +follows the Path_Contour, moving parallel to the contours's direction. + +If the Path_Contour is not terminated by SkPath::kClose_Verb, the contour has a +visible beginning and end. + +Path_Contour may start and end at the same point; defining Zero_Length_Contour. + +kButt_Cap and Zero_Length_Contour is not drawn. +kRound_Cap and Zero_Length_Contour draws a circle of diameter Stroke_Width +at the contour point. +kSquare_Cap and Zero_Length_Contour draws an upright square with a side of +Stroke_Width at the contour point. + +Stroke_Cap is kButt_Cap by default. + +#Example + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(20); + SkPath path; + path.moveTo(30, 30); + path.lineTo(30, 30); + path.moveTo(70, 30); + path.lineTo(90, 40); + for (SkPaint::Cap c : { SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap } ) { + paint.setStrokeCap(c); + canvas->drawPath(path, paint); + canvas->translate(0, 70); + } +## + +#Method Cap getStrokeCap() const + + The geometry drawn at the beginning and end of strokes. + + #Return one of: kButt_Cap, kRound_Cap, kSquare_Cap ## + + #Example + SkPaint paint; + SkDebugf("kButt_Cap %c= default stroke cap\n", + SkPaint::kButt_Cap == paint.getStrokeCap() ? '=' : '!'); + + #StdOut + kButt_Cap == default stroke cap + ## + ## + + #SeeAlso Stroke_Cap setStrokeCap +## + +#Method void setStrokeCap(Cap cap) + + The geometry drawn at the beginning and end of strokes. + + #Param cap one of: kButt_Cap, kRound_Cap, kSquare_Cap; + has no effect if cap is not valid + ## + + #Example + SkPaint paint; + paint.setStrokeCap(SkPaint::kRound_Cap); + paint.setStrokeCap((SkPaint::Cap) SkPaint::kCapCount); + SkDebugf("kRound_Cap %c= paint.getStrokeCap()\n", + SkPaint::kRound_Cap == paint.getStrokeCap() ? '=' : '!'); + + #StdOut + kRound_Cap == paint.getStrokeCap() + ## + ## + + #SeeAlso Stroke_Cap getStrokeCap +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Stroke_Join + +Stroke_Join draws at the sharp corners of an open or closed Path_Contour. + +Stroke describes the area covered by a pen of Stroke_Width as it +follows the Path_Contour, moving parallel to the contours's direction. + +If the contour direction changes abruptly, because the tangent direction leading +to the end of a curve within the contour does not match the tangent direction of +the following curve, the pair of curves meet at Stroke_Join. + +#Example + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(20); + SkPath path; + path.moveTo(30, 30); + path.lineTo(40, 50); + path.conicTo(70, 30, 100, 30, .707f); + for (SkPaint::Join j : { SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join } ) { + paint.setStrokeJoin(j); + canvas->drawPath(path, paint); + canvas->translate(0, 70); + } +## + +#Enum Join +#Code + enum Join { + kMiter_Join, + kRound_Join, + kBevel_Join, + + kLast_Join = kBevel_Join, + kDefault_Join = kMiter_Join + }; + static constexpr int kJoinCount = kLast_Join + 1; +## + +Join specifies how corners are drawn when a shape is stroked. The paint's Join setting +affects the four corners of a stroked rectangle, and the connected segments in a +stroked path. + +Choose miter join to draw sharp corners. Choose round join to draw a circle with a +radius equal to the stroke width on top of the corner. Choose bevel join to minimally +connect the thick strokes. + +The fill path constructed to describe the stroked path respects the join setting but may +not contain the actual join. For instance, a fill path constructed with round joins does +not necessarily include circles at each connected segment. + +#Const kMiter_Join 0 + Extends the outside corner to the extent allowed by Miter_Limit. + If the extension exceeds Miter_Limit, kBevel_Join is used instead. +## + +#Const kRound_Join 1 + Adds a circle with a diameter of Stroke_Width at the sharp corner. +## + +#Const kBevel_Join 2 + Connects the outside edges of the sharp corner. +## + +#Const kLast_Join 2 + Equivalent to the largest value for Stroke_Join. +## + +#Const kDefault_Join 1 + Equivalent to kMiter_Join. + Stroke_Join is set to kMiter_Join by default. +## + +#Const kJoinCount 3 + The number of different Stroke_Join values defined. + May be used to verify that Stroke_Join is a legal value. +## + +#Example +#Width 462 +void draw(SkCanvas* canvas) { + SkPath path; + path.moveTo(10, 50); + path.quadTo(35, 110, 60, 210); + path.quadTo(105, 110, 130, 10); + SkPaint paint; // set to default kMiter_Join + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(20); + canvas->drawPath(path, paint); + canvas->translate(150, 0); + paint.setStrokeJoin(SkPaint::kBevel_Join); + canvas->drawPath(path, paint); + canvas->translate(150, 0); + paint.setStrokeJoin(SkPaint::kRound_Join); + canvas->drawPath(path, paint); +} +## + +#SeeAlso setStrokeJoin getStrokeJoin setStrokeMiter getStrokeMiter + +#Enum ## + +#Method Join getStrokeJoin() const + + The geometry drawn at the corners of strokes. + + #Return one of: kMiter_Join, kRound_Join, kBevel_Join ## + + #Example + SkPaint paint; + SkDebugf("kMiter_Join %c= default stroke join\n", + SkPaint::kMiter_Join == paint.getStrokeJoin() ? '=' : '!'); + + #StdOut + kMiter_Join == default stroke join + ## + ## + + #SeeAlso Stroke_Join setStrokeJoin +## + +#Method void setStrokeJoin(Join join) + + The geometry drawn at the corners of strokes. + + #Param join one of: kMiter_Join, kRound_Join, kBevel_Join; + otherwise, setStrokeJoin has no effect + ## + + #Example + SkPaint paint; + paint.setStrokeJoin(SkPaint::kMiter_Join); + paint.setStrokeJoin((SkPaint::Join) SkPaint::kJoinCount); + SkDebugf("kMiter_Join %c= paint.getStrokeJoin()\n", + SkPaint::kMiter_Join == paint.getStrokeJoin() ? '=' : '!'); + + #StdOut + kMiter_Join == paint.getStrokeJoin() + ## + ## + + #SeeAlso Stroke_Join getStrokeJoin +## + +#SeeAlso Miter_Limit + +#Topic Stroke_Join ## +# ------------------------------------------------------------------------------ +#Topic Fill_Path + +Fill_Path creates a Path by applying the Path_Effect, followed by the Style_Stroke. + +If Paint contains Path_Effect, Path_Effect operates on the source Path; the result +replaces the destination Path. Otherwise, the source Path is replaces the +destination Path. + +Fill Path can request the Path_Effect to restrict to a culling rectangle, but +the Path_Effect is not required to do so. + +If Style is kStroke_Style or kStrokeAndFill_Style, +and Stroke_Width is greater than zero, the Stroke_Width, Stroke_Cap, Stroke_Join, +and Miter_Limit operate on the destination Path, replacing it. + +Fill Path can specify the precision used by Stroke_Width to approximate the stroke geometry. + +If the Style is kStroke_Style and the Stroke_Width is zero, getFillPath +returns false since Hairline has no filled equivalent. + +#Method bool getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect, + SkScalar resScale = 1) const + + The filled equivalent of the stroked path. + + #Param src Path read to create a filled version ## + #Param dst resulting Path; may be the same as src, but may not be nullptr ## + #Param cullRect optional limit passed to Path_Effect ## + #Param resScale if > 1, increase precision, else if (0 < res < 1) reduce precision + to favor speed and size + ## + #Return true if the path represents Style_Fill, or false if it represents Hairline ## + + #Example + #Height 192 + #Description + A very small quad stroke is turned into a filled path with increasing levels of precision. + At the lowest precision, the quad stroke is approximated by a rectangle. + At the highest precision, the filled path has high fidelity compared to the original stroke. + ## + void draw(SkCanvas* canvas) { + SkPaint strokePaint; + strokePaint.setAntiAlias(true); + strokePaint.setStyle(SkPaint::kStroke_Style); + strokePaint.setStrokeWidth(.1f); + SkPath strokePath; + strokePath.moveTo(.08f, .08f); + strokePath.quadTo(.09f, .08f, .17f, .17f); + SkPath fillPath; + SkPaint outlinePaint(strokePaint); + outlinePaint.setStrokeWidth(2); + SkMatrix scale = SkMatrix::MakeScale(300, 300); + for (SkScalar precision : { 0.01f, .1f, 1.f, 10.f, 100.f } ) { + strokePaint.getFillPath(strokePath, &fillPath, nullptr, precision); + fillPath.transform(scale); + canvas->drawPath(fillPath, outlinePaint); + canvas->translate(60, 0); + if (1.f == precision) canvas->translate(-180, 100); + } + strokePath.transform(scale); + strokePaint.setStrokeWidth(30); + canvas->drawPath(strokePath, strokePaint); + } + ## + +## + +#Method bool getFillPath(const SkPath& src, SkPath* dst) const + + The filled equivalent of the stroked path. + + Replaces dst with the src path modified by Path_Effect and Style_Stroke. + Path_Effect, if any, is not culled. Stroke_Width is created with default precision. + + #Param src Path read to create a filled version ## + #Param dst resulting Path dst may be the same as src, but may not be nullptr ## + #Return true if the path represents Style_Fill, or false if it represents Hairline ## + + #Example + #Height 128 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(10); + SkPath strokePath; + strokePath.moveTo(20, 20); + strokePath.lineTo(100, 100); + canvas->drawPath(strokePath, paint); + SkPath fillPath; + paint.getFillPath(strokePath, &fillPath); + paint.setStrokeWidth(2); + canvas->translate(40, 0); + canvas->drawPath(fillPath, paint); + } + ## + +## + +#SeeAlso Style_Stroke Stroke_Width Path_Effect + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Shader_Methods + +Shader defines the colors used when drawing a shape. +Shader may be an image, a gradient, or a computed fill. +If Paint has no Shader, then Color fills the shape. + +Shader is modulated by Color_Alpha component of Color. +If Shader object defines only Color_Alpha, then Color modulated by Color_Alpha describes +the fill. + +The drawn transparency can be modified without altering Shader, by changing Color_Alpha. + +#Example +void draw(SkCanvas* canvas) { + SkPaint paint; + SkPoint center = { 50, 50 }; + SkScalar radius = 50; + const SkColor colors[] = { 0xFFFFFFFF, 0xFF000000 }; + paint.setShader(SkGradientShader::MakeRadial(center, radius, colors, + nullptr, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode)); + for (SkScalar a : { 0.3f, 0.6f, 1.0f } ) { + paint.setAlpha((int) (a * 255)); + canvas->drawCircle(center.fX, center.fY, radius, paint); + canvas->translate(70, 70); + } +} +## + +If Shader generates only Color_Alpha then all components of Color modulate the output. + +#Example +void draw(SkCanvas* canvas) { + SkPaint paint; + SkBitmap bitmap; + bitmap.setInfo(SkImageInfo::MakeA8(5, 1), 5); // bitmap only contains alpha + uint8_t pixels[5] = { 0x22, 0x55, 0x88, 0xBB, 0xFF }; + bitmap.setPixels(pixels); + paint.setShader(SkShader::MakeBitmapShader(bitmap, + SkShader::kMirror_TileMode, SkShader::kMirror_TileMode)); + for (SkColor c : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) { + paint.setColor(c); // all components in color affect shader + canvas->drawCircle(50, 50, 50, paint); + canvas->translate(70, 70); + } +} +## + +#Method SkShader* getShader() const + + Optional colors used when filling a path, such as a gradient. + + Does not alter Shader Reference_Count. + + #Return Shader if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("nullptr %c= shader\n", paint.getShader() ? '!' : '='); + paint.setShader(SkShader::MakeEmptyShader()); + SkDebugf("nullptr %c= shader\n", paint.getShader() ? '!' : '='); + } + + #StdOut + nullptr == shader + nullptr != shader + ## + ## + +## + +#Method sk_sp<SkShader> refShader() const + + Optional colors used when filling a path, such as a gradient. + + Increases Shader Reference_Count by one. + + #Return Shader if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint1, paint2; + paint1.setShader(SkShader::MakeEmptyShader()); + SkDebugf("shader unique: %s\n", paint1.getShader()->unique() ? "true" : "false"); + paint2.setShader(paint1.refShader()); + SkDebugf("shader unique: %s\n", paint1.getShader()->unique() ? "true" : "false"); + } + + #StdOut + shader unique: true + shader unique: false + ## + ## + +## + +#Method void setShader(sk_sp<SkShader> shader) + + Optional colors used when filling a path, such as a gradient. + + Sets Shader to shader, decrementing Reference_Count of the previous Shader. + Does not alter shader Reference_Count. + + #Param shader how geometry is filled with color; if nullptr, Color is used instead ## + + #Example + #Height 64 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setColor(SK_ColorBLUE); + paint.setShader(SkShader::MakeColorShader(SK_ColorRED)); + canvas->drawRect(SkRect::MakeWH(40, 40), paint); + paint.setShader(nullptr); + canvas->translate(50, 0); + canvas->drawRect(SkRect::MakeWH(40, 40), paint); + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Color_Filter_Methods + +Color_Filter alters the color used when drawing a shape. +Color_Filter may apply Blend_Mode, transform the color through a matrix, or composite multiple filters. +If Paint has no Color_Filter, the color is unaltered. + +The drawn transparency can be modified without altering Color_Filter, by changing Color_Alpha. + +#Example +#Height 128 +void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setColorFilter(SkColorMatrixFilter::MakeLightingFilter(0xFFFFFF, 0xFF0000)); + for (SkColor c : { SK_ColorBLACK, SK_ColorGREEN } ) { + paint.setColor(c); + canvas->drawRect(SkRect::MakeXYWH(10, 10, 50, 50), paint); + paint.setAlpha(0x80); + canvas->drawRect(SkRect::MakeXYWH(60, 60, 50, 50), paint); + canvas->translate(100, 0); + } +} +## + +#Method SkColorFilter* getColorFilter() const + + Returns Color_Filter if set, or nullptr. + Does not alter Color_Filter Reference_Count. + + #Return Color_Filter if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("nullptr %c= color filter\n", paint.getColorFilter() ? '!' : '='); + paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorLTGRAY, SkBlendMode::kSrcIn)); + SkDebugf("nullptr %c= color filter\n", paint.getColorFilter() ? '!' : '='); + } + + #StdOut + nullptr == color filter + nullptr != color filter + ## + ## +## + +#Method sk_sp<SkColorFilter> refColorFilter() const + + Returns Color_Filter if set, or nullptr. + Increases Color_Filter Reference_Count by one. + + #Return Color_Filter if set, or nullptr ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint1, paint2; + paint1.setColorFilter(SkColorFilter::MakeModeFilter(0xFFFF0000, SkBlendMode::kSrcATop)); + SkDebugf("color filter unique: %s\n", paint1.getColorFilter()->unique() ? "true" : "false"); + paint2.setColorFilter(paint1.refColorFilter()); + SkDebugf("color filter unique: %s\n", paint1.getColorFilter()->unique() ? "true" : "false"); + } + + #StdOut + color filter unique: true + color filter unique: false + ## + ## +## + +#Method void setColorFilter(sk_sp<SkColorFilter> colorFilter) + + Sets Color_Filter to filter, decrementing Reference_Count of the previous Color_Filter. + Pass nullptr to clear Color_Filter. + Does not alter filter Reference_Count. + + #Param colorFilter Color_Filter to apply to subsequent draw ## + + #Example + #Height 64 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorLTGRAY, SkBlendMode::kSrcIn)); + canvas->drawRect(SkRect::MakeWH(50, 50), paint); + paint.setColorFilter(nullptr); + canvas->translate(70, 0); + canvas->drawRect(SkRect::MakeWH(50, 50), paint); + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Blend_Mode_Methods + +Blend_Mode describes how Color combines with the destination color. +The default setting, SkBlendMode::kSrcOver, draws the source color +over the destination color. + +#Example +void draw(SkCanvas* canvas) { + SkPaint normal, blender; + normal.setColor(0xFF58a889); + blender.setColor(0xFF8958a8); + canvas->clear(0); + for (SkBlendMode m : { SkBlendMode::kSrcOver, SkBlendMode::kSrcIn, SkBlendMode::kSrcOut } ) { + normal.setBlendMode(SkBlendMode::kSrcOver); + canvas->drawOval(SkRect::MakeXYWH(30, 30, 30, 80), normal); + blender.setBlendMode(m); + canvas->drawOval(SkRect::MakeXYWH(10, 50, 80, 30), blender); + canvas->translate(70, 70); + } +} +## + +#SeeAlso Blend_Mode + +#Method SkBlendMode getBlendMode() const + + Returns Blend_Mode. + By default, getBlendMode returns SkBlendMode::kSrcOver. + + #Return mode used to combine source color with destination color ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("kSrcOver %c= getBlendMode\n", + SkBlendMode::kSrcOver == paint.getBlendMode() ? '=' : '!'); + paint.setBlendMode(SkBlendMode::kSrc); + SkDebugf("kSrcOver %c= getBlendMode\n", + SkBlendMode::kSrcOver == paint.getBlendMode() ? '=' : '!'); + } + + #StdOut + kSrcOver == getBlendMode + kSrcOver != getBlendMode + ## + ## + +## + +#Method bool isSrcOver() const + + Returns true if Blend_Mode is SkBlendMode::kSrcOver, the default. + + #Return true if Blend_Mode is SkBlendMode::kSrcOver ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("isSrcOver %c= true\n", paint.isSrcOver() ? '=' : '!'); + paint.setBlendMode(SkBlendMode::kSrc); + SkDebugf("isSrcOver %c= true\n", paint.isSrcOver() ? '=' : '!'); + } + + #StdOut + isSrcOver == true + isSrcOver != true + ## + ## + +## + +#Method void setBlendMode(SkBlendMode mode) + + Sets Blend_Mode to mode. + Does not check for valid input. + + #Param mode SkBlendMode used to combine source color and destination ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("isSrcOver %c= true\n", paint.isSrcOver() ? '=' : '!'); + paint.setBlendMode(SkBlendMode::kSrc); + SkDebugf("isSrcOver %c= true\n", paint.isSrcOver() ? '=' : '!'); + } + + #StdOut + isSrcOver == true + isSrcOver != true + ## + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Path_Effect_Methods + +Path_Effect modifies the path geometry before drawing it. +Path_Effect may implement dashing, custom fill effects and custom stroke effects. +If Paint has no Path_Effect, the path geometry is unaltered when filled or stroked. + +#Example +#Height 160 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(16); + SkScalar intervals[] = {30, 10}; + paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 1)); + canvas->drawRoundRect({20, 20, 120, 120}, 20, 20, paint); + } +## + +#SeeAlso Path_Effect + +#Method SkPathEffect* getPathEffect() const + + Returns Path_Effect if set, or nullptr. + Does not alter Path_Effect Reference_Count. + + #Return Path_Effect if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("nullptr %c= path effect\n", paint.getPathEffect() ? '!' : '='); + paint.setPathEffect(SkCornerPathEffect::Make(10)); + SkDebugf("nullptr %c= path effect\n", paint.getPathEffect() ? '!' : '='); + } + + #StdOut + nullptr == path effect + nullptr != path effect + ## + ## + +## + + +#Method sk_sp<SkPathEffect> refPathEffect() const + + Returns Path_Effect if set, or nullptr. + Increases Path_Effect Reference_Count by one. + + #Return Path_Effect if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint1, paint2; + paint1.setPathEffect(SkArcToPathEffect::Make(10)); + SkDebugf("path effect unique: %s\n", paint1.getPathEffect()->unique() ? "true" : "false"); + paint2.setPathEffect(paint1.refPathEffect()); + SkDebugf("path effect unique: %s\n", paint1.getPathEffect()->unique() ? "true" : "false"); + } + + #StdOut + path effect unique: true + path effect unique: false + ## + ## + +## + + +#Method void setPathEffect(sk_sp<SkPathEffect> pathEffect) + + Sets Path_Effect to pathEffect, + decrementing Reference_Count of the previous Path_Effect. + Pass nullptr to leave the path geometry unaltered. + Does not alter pathEffect Reference_Count. + + #Param pathEffect replace Path with a modification when drawn ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setPathEffect(SkDiscretePathEffect::Make(3, 5)); + canvas->drawRect(SkRect::MakeXYWH(40, 40, 175, 175), paint); + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Mask_Filter_Methods + +Mask_Filter uses Color_Alpha of the shape drawn to create Mask_Alpha. +Mask_Filter operates at a lower level than Rasterizer; Mask_Filter takes a Mask, +and returns a Mask. +Mask_Filter may change the geometry and transparency of the shape, such as creating a blur effect. +Set Mask_Filter to nullptr to prevent Mask_Filter from modifying the draw. + +#Example + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setMaskFilter(SkBlurMaskFilter::Make(kSolid_SkBlurStyle, 3)); + canvas->drawRect(SkRect::MakeXYWH(40, 40, 175, 175), paint); + } +## + +#Method SkMaskFilter* getMaskFilter() const + + Returns Mask_Filter if set, or nullptr. + Does not alter Mask_Filter Reference_Count. + + #Return Mask_Filter if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("nullptr %c= mask filter\n", paint.getMaskFilter() ? '!' : '='); + paint.setMaskFilter(SkBlurMaskFilter::Make(kOuter_SkBlurStyle, 3)); + SkDebugf("nullptr %c= mask filter\n", paint.getMaskFilter() ? '!' : '='); + } + + #StdOut + nullptr == mask filter + nullptr != mask filter + ## + ## + +## + +#Method sk_sp<SkMaskFilter> refMaskFilter() const + + Returns Mask_Filter if set, or nullptr. + Increases Mask_Filter Reference_Count by one. + + #Return Mask_Filter if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint1, paint2; + paint1.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 1)); + SkDebugf("mask filter unique: %s\n", paint1.getMaskFilter()->unique() ? "true" : "false"); + paint2.setMaskFilter(paint1.refMaskFilter()); + SkDebugf("mask filter unique: %s\n", paint1.getMaskFilter()->unique() ? "true" : "false"); + } + + #StdOut + mask filter unique: true + mask filter unique: false + ## + ## + +## + +#Method void setMaskFilter(sk_sp<SkMaskFilter> maskFilter) + + Sets Mask_Filter to maskFilter, + decrementing Reference_Count of the previous Mask_Filter. + Pass nullptr to clear Mask_Filter and leave Mask_Filter effect on Mask_Alpha unaltered. + Does not affect Rasterizer. + Does not alter maskFilter Reference_Count. + + #Param maskFilter modifies clipping mask generated from drawn geometry ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(10); + paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 10)); + canvas->drawRect(SkRect::MakeXYWH(40, 40, 175, 175), paint); + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Typeface_Methods + +Typeface identifies the font used when drawing and measuring text. +Typeface may be specified by name, from a file, or from a data stream. +The default Typeface defers to the platform-specific default font +implementation. + +#Example +#Height 100 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTypeface(SkTypeface::MakeDefault(SkTypeface::kBold)); + paint.setAntiAlias(true); + paint.setTextSize(36); + canvas->drawString("A Big Hello!", 10, 40, paint); + paint.setTypeface(nullptr); + paint.setFakeBoldText(true); + canvas->drawString("A Big Hello!", 10, 80, paint); + } +## + +#Method SkTypeface* getTypeface() const + + Returns Typeface if set, or nullptr. + Does not alter Typeface Reference_Count. + + #Return Typeface if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("nullptr %c= typeface\n", paint.getTypeface() ? '!' : '='); + paint.setTypeface(SkTypeface::MakeFromName("Times New Roman", SkFontStyle())); + SkDebugf("nullptr %c= typeface\n", paint.getTypeface() ? '!' : '='); + } + + #StdOut + nullptr == typeface + nullptr != typeface + ## + ## + +## + +#Method sk_sp<SkTypeface> refTypeface() const + + Increases Typeface Reference_Count by one. + + #Return Typeface if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint1, paint2; + paint1.setTypeface(SkTypeface::MakeFromName("Times New Roman", + SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width, + SkFontStyle::kItalic_Slant))); + SkDebugf("typeface1 %c= typeface2\n", + paint1.getTypeface() == paint2.getTypeface() ? '=' : '!'); + paint2.setTypeface(paint1.refTypeface()); + SkDebugf("typeface1 %c= typeface2\n", + paint1.getTypeface() == paint2.getTypeface() ? '=' : '!'); + } + + #StdOut + typeface1 != typeface2 + typeface1 == typeface2 + ## + ## + +## + +#Method void setTypeface(sk_sp<SkTypeface> typeface) + + Sets Typeface to typeface, + decrementing Reference_Count of the previous Typeface. + Pass nullptr to clear Typeface and use the default typeface. + Does not alter typeface Reference_Count. + + #Param typeface font and style used to draw text ## + + #Example + #Height 64 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTypeface(SkTypeface::MakeFromName("Courier New", SkFontStyle())); + canvas->drawString("Courier New", 10, 30, paint); + paint.setTypeface(nullptr); + canvas->drawString("default", 10, 50, paint); + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Rasterizer_Methods + +Rasterizer controls how shapes are converted to Mask_Alpha. +Rasterizer operates at a higher level than Mask_Filter; Rasterizer takes a Path, +and returns a Mask. +Rasterizer may change the geometry and transparency of the shape, such as +creating a shadow effect. Rasterizer forms the base of Rasterizer_Layer, which +creates effects like embossing and outlining. +Rasterizer applies to Rect, Region, Round_Rect, Arc, Circle, Oval, +Path, and Text. + +#Example +#Height 64 + void draw(SkCanvas* canvas) { + SkLayerRasterizer::Builder layerBuilder; + SkPaint paint; + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(1); + layerBuilder.addLayer(paint); + paint.setAlpha(0x10); + paint.setStyle(SkPaint::kFill_Style); + paint.setBlendMode(SkBlendMode::kSrc); + layerBuilder.addLayer(paint); + paint.reset(); + paint.setAntiAlias(true); + paint.setTextSize(50); + paint.setRasterizer(layerBuilder.detach()); + canvas->drawString("outline", 10, 50, paint); + } +## + +#Method SkRasterizer* getRasterizer() const + + Returns Rasterizer if set, or nullptr. + Does not alter Rasterizer Reference_Count. + + #Return Rasterizer if previously set, nullptr otherwise ## + + #Example + #Function + class DummyRasterizer : public SkRasterizer { + public: + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(DummyRasterizer) + }; + + sk_sp<SkFlattenable> DummyRasterizer::CreateProc(SkReadBuffer&) { + return sk_make_sp<DummyRasterizer>(); + } + + #Function ## + void draw(SkCanvas* canvas) { + SkPaint paint; + DummyRasterizer dummy; + SkDebugf("nullptr %c= rasterizer\n", paint.getRasterizer() ? '!' : '='); + paint.setRasterizer(sk_make_sp<DummyRasterizer>()); + SkDebugf("nullptr %c= rasterizer\n", paint.getRasterizer() ? '!' : '='); + } + + #StdOut + nullptr == rasterizer + nullptr != rasterizer + ## + ## + +## + +#Method sk_sp<SkRasterizer> refRasterizer() const + + Returns Rasterizer if set, or nullptr. + Increases Rasterizer Reference_Count by one. + + #Return Rasterizer if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkLayerRasterizer::Builder layerBuilder; + SkPaint paint1, paint2; + layerBuilder.addLayer(paint2); + paint1.setRasterizer(layerBuilder.detach()); + SkDebugf("rasterizer unique: %s\n", paint1.getRasterizer()->unique() ? "true" : "false"); + paint2.setRasterizer(paint1.refRasterizer()); + SkDebugf("rasterizer unique: %s\n", paint1.getRasterizer()->unique() ? "true" : "false"); + } + + #StdOut + rasterizer unique: true + rasterizer unique: false + ## + ## + +## + +#Method void setRasterizer(sk_sp<SkRasterizer> rasterizer) + + Sets Rasterizer to rasterizer, + decrementing Reference_Count of the previous Rasterizer. + Pass nullptr to clear Rasterizer and leave Rasterizer effect on Mask_Alpha unaltered. + Does not affect Mask_Filter. + Does not alter rasterizer Reference_Count. + + #Param rasterizer how geometry is converted to Mask_Alpha ## + + #Example + #Height 64 + SkLayerRasterizer::Builder layerBuilder; + SkPaint paint; + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(2); + layerBuilder.addLayer(paint); + paint.reset(); + paint.setAntiAlias(true); + paint.setTextSize(50); + paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 3)); + paint.setRasterizer(layerBuilder.detach()); + canvas->drawString("blurry out", 0, 50, paint); + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Image_Filter_Methods + +Image_Filter operates on the pixel representation of the shape, as modified by Paint +with Blend_Mode set to SkBlendMode::kSrcOver. Image_Filter creates a new bitmap, +which is drawn to the device using the set Blend_Mode. +Image_Filter is higher level than Mask_Filter; for instance, an Image_Filter +can operate on all channels of Color, while Mask_Filter generates Color_Alpha only. +Image_Filter operates independently of and can be used in combination with +Mask_Filter and Rasterizer. + +#Example + #ToDo explain why the two draws are so different ## + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(2); + SkRegion region; + region.op( 10, 10, 50, 50, SkRegion::kUnion_Op); + region.op( 10, 50, 90, 90, SkRegion::kUnion_Op); + paint.setImageFilter(SkImageFilter::MakeBlur(5.0f, 5.0f, nullptr)); + canvas->drawRegion(region, paint); + paint.setImageFilter(nullptr); + paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 5)); + canvas->translate(100, 100); + canvas->drawRegion(region, paint); + } +## + +#Method SkImageFilter* getImageFilter() const + + Returns Image_Filter if set, or nullptr. + Does not alter Image_Filter Reference_Count. + + #Return Image_Filter if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("nullptr %c= image filter\n", paint.getImageFilter() ? '!' : '='); + paint.setImageFilter(SkImageFilter::MakeBlur(kOuter_SkBlurStyle, 3, nullptr, nullptr)); + SkDebugf("nullptr %c= image filter\n", paint.getImageFilter() ? '!' : '='); + } + + #StdOut + nullptr == image filter + nullptr != image filter + ## + ## + +## + +#Method sk_sp<SkImageFilter> refImageFilter() const + + Returns Image_Filter if set, or nullptr. + Increases Image_Filter Reference_Count by one. + + #Return Image_Filter if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint1, paint2; + paint1.setImageFilter(SkOffsetImageFilter::Make(25, 25, nullptr)); + SkDebugf("image filter unique: %s\n", paint1.getImageFilter()->unique() ? "true" : "false"); + paint2.setImageFilter(paint1.refImageFilter()); + SkDebugf("image filter unique: %s\n", paint1.getImageFilter()->unique() ? "true" : "false"); + } + + #StdOut + image filter unique: true + image filter unique: false + ## + ## + +## + +#Method void setImageFilter(sk_sp<SkImageFilter> imageFilter) + + Sets Image_Filter to imageFilter, + decrementing Reference_Count of the previous Image_Filter. + Pass nullptr to clear Image_Filter, and remove Image_Filter effect + on drawing. + Does not affect Rasterizer or Mask_Filter. + Does not alter imageFilter Reference_Count. + + #Param imageFilter how Image is sampled when transformed ## + + #Example + #Height 160 + void draw(SkCanvas* canvas) { + SkBitmap bitmap; + bitmap.allocN32Pixels(100, 100); + SkCanvas offscreen(bitmap); + SkPaint paint; + paint.setAntiAlias(true); + paint.setColor(SK_ColorWHITE); + paint.setTextSize(96); + offscreen.clear(0); + offscreen.drawString("e", 20, 70, paint); + paint.setImageFilter( + SkLightingImageFilter::MakePointLitDiffuse(SkPoint3::Make(80, 100, 10), + SK_ColorWHITE, 1, 2, nullptr, nullptr)); + canvas->drawBitmap(bitmap, 0, 0, &paint); + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Draw_Looper_Methods + +Draw_Looper sets a modifier that communicates state from one Draw_Layer +to another to construct the draw. +Draw_Looper draws one or more times, modifying the canvas and paint each time. +Draw_Looper may be used to draw multiple colors or create a colored shadow. +Set Draw_Looper to nullptr to prevent Draw_Looper from modifying the draw. + +#Example +#Height 128 + void draw(SkCanvas* canvas) { + SkLayerDrawLooper::LayerInfo info; + info.fPaintBits = (SkLayerDrawLooper::BitFlags) SkLayerDrawLooper::kColorFilter_Bit; + info.fColorMode = SkBlendMode::kSrc; + SkLayerDrawLooper::Builder looperBuilder; + SkPaint* loopPaint = looperBuilder.addLayer(info); + loopPaint->setColor(SK_ColorRED); + info.fOffset.set(20, 20); + loopPaint = looperBuilder.addLayer(info); + loopPaint->setColor(SK_ColorBLUE); + SkPaint paint; + paint.setDrawLooper(looperBuilder.detach()); + canvas->drawCircle(50, 50, 50, paint); + } + +## + +#Method SkDrawLooper* getDrawLooper() const + + Returns Draw_Looper if set, or nullptr. + Does not alter Draw_Looper Reference_Count. + + #Return Draw_Looper if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint; + SkDebugf("nullptr %c= draw looper\n", paint.getDrawLooper() ? '!' : '='); + SkLayerDrawLooper::Builder looperBuilder; + paint.setDrawLooper(looperBuilder.detach()); + SkDebugf("nullptr %c= draw looper\n", paint.getDrawLooper() ? '!' : '='); + } + + #StdOut + nullptr == draw looper + nullptr != draw looper + ## + ## + +## + +#Method sk_sp<SkDrawLooper> refDrawLooper() const + + Returns Draw_Looper if set, or nullptr. + Increases Draw_Looper Reference_Count by one. + + #Return Draw_Looper if previously set, nullptr otherwise ## + + #Example + void draw(SkCanvas* canvas) { + SkPaint paint1, paint2; + SkLayerDrawLooper::Builder looperBuilder; + paint1.setDrawLooper(looperBuilder.detach()); + SkDebugf("draw looper unique: %s\n", paint1.getDrawLooper()->unique() ? "true" : "false"); + paint2.setDrawLooper(paint1.refDrawLooper()); + SkDebugf("draw looper unique: %s\n", paint1.getDrawLooper()->unique() ? "true" : "false"); + } + + #StdOut + draw looper unique: true + draw looper unique: false + ## + ## + +## + +#Method SkDrawLooper* getLooper() const + +Deprecated. + +#Deprecated +(see bug.skia.org/6259) +#Deprecated ## + +#Return Draw_Looper if previously set, nullptr otherwise ## +## + +#Method void setDrawLooper(sk_sp<SkDrawLooper> drawLooper) + + Sets Draw_Looper to drawLooper, + decrementing Reference_Count of the previous drawLooper. + Pass nullptr to clear Draw_Looper and leave Draw_Looper effect on drawing unaltered. + setDrawLooper does not alter drawLooper Reference_Count. + + #Param drawLooper Iterates through drawing one or more time, altering Paint ## + + #Example + #Height 128 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setDrawLooper(SkBlurDrawLooper::Make(0x7FFF0000, 4, -5, -10)); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(10); + paint.setAntiAlias(true); + paint.setColor(0x7f0000ff); + canvas->drawCircle(70, 70, 50, paint); + } + ## + +## + +#Method void setLooper(sk_sp<SkDrawLooper> drawLooper) + +Deprecated. + +#Deprecated +(see bug.skia.org/6259) +#Deprecated ## + +#Param drawLooper sets Draw_Looper to drawLooper ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Text_Align + +#Enum Align +#Code + enum Align { + kLeft_Align, + kCenter_Align, + kRight_Align, + }; +## + +Align adjusts the text relative to the text position. +Align affects glyphs drawn with: SkCanvas::drawText, SkCanvas::drawPosText, +SkCanvas::drawPosTextH, SkCanvas::drawTextOnPath, +SkCanvas::drawTextOnPathHV, SkCanvas::drawTextRSXform, SkCanvas::drawTextBlob, +and SkCanvas::drawString; +as well as calls that place text glyphs like getTextWidths and getTextPath. + +The text position is set by the font for both horizontal and vertical text. +Typically, for horizontal text, the position is to the left side of the glyph on the +base line; and for vertical text, the position is the horizontal center of the glyph +at the caps height. + +Align adjusts the glyph position to center it or move it to abut the position +using the metrics returned by the font. + +Align defaults to kLeft_Align. + +#Const kLeft_Align 0 + Leaves the glyph at the position computed by the font offset by the text position. +## + +#Const kCenter_Align 1 + Moves the glyph half its width if Flags has kVerticalText_Flag clear, and + half its height if Flags has kVerticalText_Flag set. +## + +#Const kRight_Align 2 + Moves the glyph by its width if Flags has kVerticalText_Flag clear, + and by its height if Flags has kVerticalText_Flag set. +## + +#Enum ## + +#Enum + +#Code + enum { + kAlignCount = 3 + }; +## + +#Const kAlignCount 3 + The number of different Text_Align values defined. +## + +#Enum ## + +#Example + #Height 160 + #Description + Each position separately moves the glyph in drawPosText. + ## + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(40); + SkPoint position[] = {{100, 50}, {150, 40}}; + for (SkPaint::Align a : { SkPaint::kLeft_Align, + SkPaint::kCenter_Align, + SkPaint::kRight_Align}) { + paint.setTextAlign(a); + canvas->drawPosText("Aa", 2, position, paint); + canvas->translate(0, 50); + } + } +## + +#Example + #Height 160 + #Description + Vertical_Text treats kLeft_Align as top align, and kRight_Align as bottom align. + ## + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(40); + paint.setVerticalText(true); + for (SkPaint::Align a : { SkPaint::kLeft_Align, + SkPaint::kCenter_Align, + SkPaint::kRight_Align }) { + paint.setTextAlign(a); + canvas->drawString("Aa", 50, 80, paint); + canvas->translate(50, 0); + } + } +## + +#Method Align getTextAlign() const + + Returns Text_Align. + Returns kLeft_Align if Text_Align has not been set. + + #Return text placement relative to position ## + + #Example + SkPaint paint; + SkDebugf("kLeft_Align %c= default\n", SkPaint::kLeft_Align == paint.getTextAlign() ? '=' : '!'); + + #StdOut + kLeft_Align == default + ## + ## +## + +#Method void setTextAlign(Align align) + + Sets Text_Align to align. + Has no effect if align is an invalid value. + + #Param align text placement relative to position ## + + #Example + #Height 160 + #Description + Text is left-aligned by default, and then set to center. Setting the + alignment out of range has no effect. + ## + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(40); + canvas->drawString("Aa", 100, 50, paint); + paint.setTextAlign(SkPaint::kCenter_Align); + canvas->drawString("Aa", 100, 100, paint); + paint.setTextAlign((SkPaint::Align) SkPaint::kAlignCount); + canvas->drawString("Aa", 100, 150, paint); + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Text_Size + +Text_Size adjusts the overall text size in points. +Text_Size can be set to any positive value or zero. +Text_Size defaults to 12. +Set SkPaintDefaults_TextSize at compile time to change the default setting. + +#Example +#Height 135 + void draw(SkCanvas* canvas) { + SkPaint paint; + canvas->drawString("12 point", 10, 20, paint); + paint.setTextSize(24); + canvas->drawString("24 point", 10, 60, paint); + paint.setTextSize(48); + canvas->drawString("48 point", 10, 120, paint); + } +## + +#Method SkScalar getTextSize() const + + Returns Text_Size in points. + + #Return typographic height of text ## + + #Example + SkPaint paint; + SkDebugf("12 %c= default text size\n", 12 == paint.getTextSize() ? '=' : '!'); + ## + +## + +#Method void setTextSize(SkScalar textSize) + + Sets Text_Size in points. + Has no effect if textSize is not greater than or equal to zero. + + #Param textSize typographic height of text ## + + #Example + SkPaint paint; + SkDebugf("12 %c= text size\n", 12 == paint.getTextSize() ? '=' : '!'); + paint.setTextSize(-20); + SkDebugf("12 %c= text size\n", 12 == paint.getTextSize() ? '=' : '!'); + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Text_Scale_X + +Text_Scale_X adjusts the text horizontal scale. +Text scaling approximates condensed and expanded type faces when the actual face +is not available. +Text_Scale_X can be set to any value. +Text_Scale_X defaults to 1. + +#Example +#Height 128 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(24); + paint.setTextScaleX(.8f); + canvas->drawString("narrow", 10, 20, paint); + paint.setTextScaleX(1); + canvas->drawString("normal", 10, 60, paint); + paint.setTextScaleX(1.2f); + canvas->drawString("wide", 10, 100, paint); + } +## + +#Method SkScalar getTextScaleX() const + + Returns Text_Scale_X. + Default value is 1. + + #Return text horizontal scale ## + + #Example + SkPaint paint; + SkDebugf("1 %c= default text scale x\n", 1 == paint.getTextScaleX() ? '=' : '!'); + ## + +## + + +#Method void setTextScaleX(SkScalar scaleX) + + Sets Text_Scale_X. + Default value is 1. + + #Param scaleX text horizontal scale ## + + #Example + SkPaint paint; + paint.setTextScaleX(0.f / 0.f); + SkDebugf("text scale %s-a-number\n", SkScalarIsNaN(paint.getTextScaleX()) ? "not" : "is"); + ## + +## + +#Topic ## + +#Topic Text_Skew_X + + +Text_Skew_X adjusts the text horizontal slant. +Text skewing approximates italic and oblique type faces when the actual face +is not available. +Text_Skew_X can be set to any value. +Text_Skew_X defaults to 0. + +#Example +#Height 128 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(24); + paint.setTextSkewX(-.25f); + canvas->drawString("right-leaning", 10, 100, paint); + paint.setTextSkewX(0); + canvas->drawString("normal", 10, 60, paint); + paint.setTextSkewX(.25f); + canvas->drawString("left-leaning", 10, 20, paint); + } +## + +#Method SkScalar getTextSkewX() const + + Returns Text_Skew_X. + Default value is zero. + + #Return additional shear in x-axis relative to y-axis ## + + #Example + SkPaint paint; + SkDebugf("0 %c= default text skew x\n", 0 == paint.getTextSkewX() ? '=' : '!'); + ## + +## + +#Method void setTextSkewX(SkScalar skewX) + + Sets Text_Skew_X. + Default value is zero. + + #Param skewX additional shear in x-axis relative to y-axis ## + + #Example + SkPaint paint; + paint.setTextScaleX(1.f / 0.f); + SkDebugf("text scale %s-finite\n", SkScalarIsFinite(paint.getTextScaleX()) ? "is" : "not"); + ## + +## + +#Topic ## + +# ------------------------------------------------------------------------------ +#Topic Text_Encoding + +#Enum TextEncoding + +#Code + enum TextEncoding { + kUTF8_TextEncoding, + kUTF16_TextEncoding, + kUTF32_TextEncoding, + kGlyphID_TextEncoding + }; +## + +TextEncoding determines whether text specifies character codes and their encoded size, +or glyph indices. Character codes use the encoding specified by the +#A Unicode standard # http://unicode.org/standard/standard.html ##. +Character codes encoded size are specified by UTF-8, UTF-16, or UTF-32. +All character encoding are able to represent all of Unicode, differing only +in the total storage required. + +#A UTF-8 (RFC 3629) # https://tools.ietf.org/html/rfc3629 ## is made up of 8-bit bytes, +and is a superset of ASCII. +#A UTF-16 (RFC 2781) # https://tools.ietf.org/html/rfc2781 ## is made up of 16-bit words, +and is a superset of Unicode ranges 0x0000 to 0xD7FF and 0xE000 to 0xFFFF. +#A UTF-32 # http://www.unicode.org/versions/Unicode5.0.0/ch03.pdf ## is +made up of 32-bit words, and is a superset of Unicode. + +Font_Manager uses font data to convert character code points into glyph indices. +A glyph index is a 16-bit word. + +TextEncoding is set to kUTF8_TextEncoding by default. + +#Const kUTF8_TextEncoding 0 +Uses bytes to represent UTF-8 or ASCII. +## +#Const kUTF16_TextEncoding 1 +Uses two byte words to represent most of Unicode. +## +#Const kUTF32_TextEncoding 2 +Uses four byte words to represent all of Unicode. +## +#Const kGlyphID_TextEncoding 3 +Uses two byte words to represent glyph indices. +## + +#Enum ## + +#Example +#Height 128 +#Description +First line has UTF-8 encoding. +Second line has UTF-16 encoding. +Third line has UTF-32 encoding. +Fourth line has 16 bit glyph indices. +## +void draw(SkCanvas* canvas) { + SkPaint paint; + const char hello8[] = "Hello" "\xE2" "\x98" "\xBA"; + const uint16_t hello16[] = { 'H', 'e', 'l', 'l', 'o', 0x263A }; + const uint32_t hello32[] = { 'H', 'e', 'l', 'l', 'o', 0x263A }; + paint.setTextSize(24); + canvas->drawText(hello8, sizeof(hello8) - 1, 10, 30, paint); + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + canvas->drawText(hello16, sizeof(hello16), 10, 60, paint); + paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); + canvas->drawText(hello32, sizeof(hello32), 10, 90, paint); + uint16_t glyphs[SK_ARRAY_COUNT(hello32)]; + paint.textToGlyphs(hello32, sizeof(hello32), glyphs); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + canvas->drawText(glyphs, sizeof(glyphs), 10, 120, paint); +} +## + +#Method TextEncoding getTextEncoding() const + + Returns Text_Encoding. + Text_Encoding determines how character code points are mapped to font glyph indices. + + #Return one of: kUTF8_TextEncoding, kUTF16_TextEncoding, kUTF32_TextEncoding, or + kGlyphID_TextEncoding + ## + + #Example + SkPaint paint; + SkDebugf("kUTF8_TextEncoding %c= text encoding\n", + SkPaint::kUTF8_TextEncoding == paint.getTextEncoding() ? '=' : '!'); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + SkDebugf("kGlyphID_TextEncoding %c= text encoding\n", + SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding() ? '=' : '!'); + + #StdOut + kUTF8_TextEncoding == text encoding + kGlyphID_TextEncoding == text encoding + ## + ## + +## + + +#Method void setTextEncoding(TextEncoding encoding) + + Sets Text_Encoding to encoding. + Text_Encoding determines how character code points are mapped to font glyph indices. + Invalid values for encoding are ignored. + + #Param encoding one of: kUTF8_TextEncoding, kUTF16_TextEncoding, kUTF32_TextEncoding, or + kGlyphID_TextEncoding ## + + #Example + SkPaint paint; + paint.setTextEncoding((SkPaint::TextEncoding) 4); + SkDebugf("4 %c= text encoding\n", 4 == paint.getTextEncoding() ? '=' : '!'); + + #StdOut + 4 != text encoding + ## + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Font_Metrics + +Font_Metrics describe dimensions common to the glyphs in Typeface. +The dimensions are computed by Font_Manager from font data and do not take +Paint settings other than Text_Size into account. + +Font dimensions specify the anchor to the left of the glyph at baseline as the origin. +X-axis values to the left of the glyph are negative, and to the right of the left glyph edge +are positive. +Y-axis values above the baseline are negative, and below the baseline are positive. + +#Example +#Width 512 +void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(120); + SkPaint::FontMetrics fm; + SkScalar lineHeight = paint.getFontMetrics(&fm); + SkPoint pt = { 70, 180 }; + canvas->drawString("M", pt.fX, pt.fY, paint); + canvas->drawLine(pt.fX, pt.fY, pt.fX, pt.fY + fm.fTop, paint); + SkScalar ascent = pt.fY + fm.fAscent; + canvas->drawLine(pt.fX - 25, ascent, pt.fX - 25, ascent + lineHeight, paint); + canvas->drawLine(pt.fX - 50, pt.fY, pt.fX - 50, pt.fY + fm.fDescent, paint); + canvas->drawLine(pt.fX + 100, pt.fY, pt.fX + 100, pt.fY + fm.fAscent, paint); + canvas->drawLine(pt.fX + 125, pt.fY, pt.fX + 125, pt.fY - fm.fXHeight, paint); + canvas->drawLine(pt.fX + 150, pt.fY, pt.fX + 150, pt.fY - fm.fCapHeight, paint); + canvas->drawLine(pt.fX + 5, pt.fY, pt.fX + 5, pt.fY + fm.fBottom, paint); + SkScalar xmin = pt.fX + fm.fXMin; + canvas->drawLine(xmin, pt.fY + 60, xmin + fm.fMaxCharWidth, pt.fY + 60, paint); + canvas->drawLine(xmin, pt.fY - 145, pt.fX, pt.fY - 145, paint); + canvas->drawLine(pt.fX + fm.fXMax, pt.fY - 160, pt.fX, pt.fY - 160, paint); + SkScalar upos = pt.fY + fm.fUnderlinePosition; + canvas->drawLine(pt.fX + 25, upos, pt.fX + 130, upos, paint); + SkScalar urad = fm.fUnderlineThickness / 2; + canvas->drawLine(pt.fX + 130, upos - urad, pt.fX + 160, upos - urad, paint); + canvas->drawLine(pt.fX + 130, upos + urad, pt.fX + 160, upos + urad, paint); + paint.setTextSize(12); + canvas->drawString("x-min", pt.fX - 50, pt.fY - 148, paint); + canvas->drawString("x-max", pt.fX + 140, pt.fY - 150, paint); + canvas->drawString("max char width", pt.fX + 120, pt.fY + 57, paint); + canvas->drawString("underline position", pt.fX + 30, pt.fY + 22, paint); + canvas->drawString("underline thickness", pt.fX + 162, pt.fY + 13, paint); + canvas->rotate(-90); + canvas->drawString("descent", -pt.fY - 30, pt.fX - 54, paint); + canvas->drawString("line height", -pt.fY, pt.fX - 29, paint); + canvas->drawString("top", -pt.fY + 30, pt.fX - 4, paint); + canvas->drawString("ascent", -pt.fY, pt.fX + 110, paint); + canvas->drawString("x-height", -pt.fY, pt.fX + 135, paint); + canvas->drawString("cap-height", -pt.fY, pt.fX + 160, paint); + canvas->drawString("bottom", -pt.fY - 50, pt.fX + 15, paint); +} +## + +#Struct FontMetrics + +#Code + struct FontMetrics { + enum FontMetricsFlags { + kUnderlineThicknessIsValid_Flag = 1 << 0, + kUnderlinePositionIsValid_Flag = 1 << 1, + kStrikeoutThicknessIsValid_Flag = 1 << 2, + kStrikeoutPositionIsValid_Flag = 1 << 3, + }; + + uint32_t fFlags; + SkScalar fTop; + SkScalar fAscent; + SkScalar fDescent; + SkScalar fBottom; + SkScalar fLeading; + SkScalar fAvgCharWidth; + SkScalar fMaxCharWidth; + SkScalar fXMin; + SkScalar fXMax; + SkScalar fXHeight; + SkScalar fCapHeight; + SkScalar fUnderlineThickness; + SkScalar fUnderlinePosition; + SkScalar fStrikeoutThickness; + SkScalar fStrikeoutPosition; + + bool hasUnderlineThickness(SkScalar* thickness) const; + bool hasUnderlinePosition(SkScalar* position) const; + bool hasStrikeoutThickness(SkScalar* thickness) const; + bool hasStrikeoutPosition(SkScalar* position) const; + }; +## + + FontMetrics is filled out by getFontMetrics. FontMetrics contents reflect the values + computed by Font_Manager using Typeface. Values are set to zero if they are + not availble. + + fUnderlineThickness and fUnderlinePosition have a bit set in fFlags if their values + are valid, since their value may be zero. + + fStrikeoutThickness and fStrikeoutPosition have a bit set in fFlags if their values + are valid, since their value may be zero. + + #Enum FontMetricsFlags + #Code + enum FontMetricsFlags { + kUnderlineThicknessIsValid_Flag = 1 << 0, + kUnderlinePositionIsValid_Flag = 1 << 1, + kStrikeoutThicknessIsValid_Flag = 1 << 2, + kStrikeoutPositionIsValid_Flag = 1 << 3, + }; + ## + + FontMetricsFlags are set in fFlags when underline and strikeout metrics are valid; + the underline or strikeout metric may be valid and zero. + Fonts with embedded bitmaps may not have valid underline or strikeout metrics. + + #Const kUnderlineThicknessIsValid_Flag 0x0001 + Set if fUnderlineThickness is valid. + ## + #Const kUnderlinePositionIsValid_Flag 0x0002 + Set if fUnderlinePosition is valid. + ## + #Const kStrikeoutThicknessIsValid_Flag 0x0004 + Set if fStrikeoutThickness is valid. + ## + #Const kStrikeoutPositionIsValid_Flag 0x0008 + Set if fStrikeoutPosition is valid. + ## + + #Enum ## + + #Member uint32_t fFlags + fFlags is set when underline metrics are valid. + ## + + #Member SkScalar fTop + Largest height for any glyph. + A measure from the baseline, and is less than or equal to zero. + ## + + #Member SkScalar fAscent + Recommended distance above the baseline to reserve for a line of text. + A measure from the baseline, and is less than or equal to zero. + ## + + #Member SkScalar fDescent + Recommended distance below the baseline to reserve for a line of text. + A measure from the baseline, and is greater than or equal to zero. + ## + + #Member SkScalar fBottom + Greatest extent below the baseline for any glyph. + A measure from the baseline, and is greater than or equal to zero. + ## + + #Member SkScalar fLeading + Recommended distance to add between lines of text. + Greater than or equal to zero. + ## + + #Member SkScalar fAvgCharWidth + Average character width, if it is available. + Zero if no average width is stored in the font. + ## + + #Member SkScalar fMaxCharWidth + Maximum character width. + ## + + #Member SkScalar fXMin + Minimum bounding box x value for all glyphs. + Typically less than zero. + ## + + #Member SkScalar fXMax + Maximum bounding box x value for all glyphs. + Typically greater than zero. + ## + + #Member SkScalar fXHeight + Height of a lower-case 'x'. + May be zero if no lower-case height is stored in the font. + ## + + #Member SkScalar fCapHeight + Height of an upper-case letter. + May be zero if no upper-case height is stored in the font. + ## + + #Member SkScalar fUnderlineThickness + Underline thickness. If the metric + is valid, the kUnderlineThicknessIsValid_Flag is set in fFlags. + If kUnderlineThicknessIsValid_Flag is clear, fUnderlineThickness is zero. + ## + + #Member SkScalar fUnderlinePosition + Underline position relative to the baseline. + It may be negative, to draw the underline above the baseline, zero + to draw the underline on the baseline, or positive to draw the underline + below the baseline. + + If the metric is valid, the kUnderlinePositionIsValid_Flag is set in fFlags. + If kUnderlinePositionIsValid_Flag is clear, fUnderlinePosition is zero. + ## + + #Member SkScalar fStrikeoutThickness + Strikeout thickness. If the metric + is valid, the kStrikeoutThicknessIsValid_Flag is set in fFlags. + If kStrikeoutThicknessIsValid_Flag is clear, fStrikeoutThickness is zero. + ## + + #Member SkScalar fStrikeoutPosition + Strikeout position relative to the baseline. + It may be negative, to draw the strikeout above the baseline, zero + to draw the strikeout on the baseline, or positive to draw the strikeout + below the baseline. + + If the metric is valid, the kStrikeoutPositionIsValid_Flag is set in fFlags. + If kStrikeoutPositionIsValid_Flag is clear, fStrikeoutPosition is zero. + ## + + #Method bool hasUnderlineThickness(SkScalar* thickness) const + + If Font_Metrics has a valid underline thickness, return true, and set + thickness to that value. If it doesn't, return false, and ignore + thickness. + + #Param thickness storage for underline width ## + + #Return true if font specifies underline width ## + + #NoExample + ## + ## + + #Method bool hasUnderlinePosition(SkScalar* position) const + + If Font_Metrics has a valid underline position, return true, and set + position to that value. If it doesn't, return false, and ignore + position. + + #Param position storage for underline position ## + + #Return true if font specifies underline position ## + + #NoExample + ## + ## + + #Method bool hasStrikeoutThickness(SkScalar* thickness) const + + If Font_Metrics has a valid strikeout thickness, return true, and set + thickness to that value. If it doesn't, return false, and ignore + thickness. + + #Param thickness storage for strikeout width ## + + #Return true if font specifies strikeout width ## + + #NoExample + ## + ## + + #Method bool hasStrikeoutPosition(SkScalar* position) const + + If Font_Metrics has a valid strikeout position, return true, and set + position to that value. If it doesn't, return false, and ignore + position. + + #Param position storage for strikeout position ## + + #Return true if font specifies strikeout position ## + + #NoExample + ## + ## + +#Struct ## + +#Method SkScalar getFontMetrics(FontMetrics* metrics, SkScalar scale = 0) const + + Returns Font_Metrics associated with Typeface. + The return value is the recommended spacing between lines: the sum of metrics + descent, ascent, and leading. + If metrics is not nullptr, Font_Metrics is copied to metrics. + Results are scaled by Text_Size but does not take into account + dimensions required by Text_Scale_X, Text_Skew_X, Fake_Bold, + Style_Stroke, and Path_Effect. + Results can be additionally scaled by scale; a scale of zero + is ignored. + + #Param metrics storage for Font_Metrics from Typeface; may be nullptr ## + #Param scale additional multiplier for returned values ## + + #Return recommended spacing between lines ## + + #Example + #Height 128 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(32); + SkScalar lineHeight = paint.getFontMetrics(nullptr); + canvas->drawString("line 1", 10, 40, paint); + canvas->drawString("line 2", 10, 40 + lineHeight, paint); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(10); + lineHeight = paint.getFontMetrics(nullptr, 1.10f); // account for stroke height + canvas->drawString("line 3", 120, 40, paint); + canvas->drawString("line 4", 120, 40 + lineHeight, paint); + } + ## + + #SeeAlso Text_Size Typeface Typeface_Methods + +## + + +#Method SkScalar getFontSpacing() const + + Returns the recommended spacing between lines: the sum of metrics + descent, ascent, and leading. + Result is scaled by Text_Size but does not take into account + dimensions required by stroking and Path_Effect. + getFontSpacing returns the same result as getFontMetrics. + + #Return recommended spacing between lines ## + + #Example + SkPaint paint; + for (SkScalar textSize : { 12, 18, 24, 32 } ) { + paint.setTextSize(textSize); + SkDebugf("textSize: %g fontSpacing: %g\n", textSize, paint.getFontSpacing()); + } + + #StdOut + textSize: 12 fontSpacing: 13.9688 + textSize: 18 fontSpacing: 20.9531 + textSize: 24 fontSpacing: 27.9375 + textSize: 32 fontSpacing: 37.25 + ## + ## + +## + + +#Method SkRect getFontBounds() const + +Returns the union of bounds of all glyphs. +Returned dimensions are computed by Font_Manager from font data, +ignoring Hinting. getFontBounds includes Text_Size, Text_Scale_X, +and Text_Skew_X, but not Fake_Bold or Path_Effect. + +If Text_Size is large, Text_Scale_X is one, and Text_Skew_X is zero, +getFontBounds returns the same bounds as Font_Metrics { FontMetrics::fXMin, +FontMetrics::fTop, FontMetrics::fXMax, FontMetrics::fBottom }. + +#Return union of bounds of all glyphs ## + +#Example + SkPaint paint; + SkPaint::FontMetrics fm; + paint.getFontMetrics(&fm); + SkRect fb = paint.getFontBounds(); + SkDebugf("metrics bounds = { %g, %g, %g, %g }\n", fm.fXMin, fm.fTop, fm.fXMax, fm.fBottom ); + SkDebugf("font bounds = { %g, %g, %g, %g }\n", fb.fLeft, fb.fTop, fb.fRight, fm.fBottom ); + + #StdOut + metrics bounds = { -12.2461, -14.7891, 21.5215, 5.55469 } + font bounds = { -12.2461, -14.7891, 21.5215, 5.55469 } + ## +## + +## + +#Topic ## +# ------------------------------------------------------------------------------ + +#Method int textToGlyphs(const void* text, size_t byteLength, + SkGlyphID glyphs[]) const + +Converts text into glyph indices. +Returns the number of glyph indices represented by text. +Text_Encoding specifies how text represents characters or glyphs. +glyphs may be nullptr, to compute the glyph count. + +Does not check text for valid character encoding or valid +glyph indices. + +If byteLength equals zero, textToGlyphs returns zero. +If byteLength includes a partial character, the partial character is ignored. + +If Text_Encoding is kUTF8_TextEncoding and +text contains an invalid UTF-8 sequence, zero is returned. + +#Param text character stroage encoded with Text_Encoding ## +#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 ## + + #Example + #Height 64 + void draw(SkCanvas* canvas) { + SkPaint paint; + const uint8_t utf8[] = { 0x24, 0xC2, 0xA2, 0xE2, 0x82, 0xAC, 0xC2, 0xA5, 0xC2, 0xA3 }; + std::vector<SkGlyphID> glyphs; + int count = paint.textToGlyphs(utf8, sizeof(utf8), nullptr); + glyphs.resize(count); + (void) paint.textToGlyphs(utf8, sizeof(utf8), &glyphs.front()); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + paint.setTextSize(32); + canvas->drawText(&glyphs.front(), glyphs.size() * sizeof(SkGlyphID), 10, 40, paint); + } + ## + +## + +#Method int countText(const void* text, size_t byteLength) const + + Returns the number of glyphs in text. + Uses Text_Encoding to count the glyphs. + Returns the same result as textToGlyphs. + +#Param text character stroage encoded with Text_Encoding ## +#Param byteLength length of character storage in bytes ## + +#Return number of glyphs represented by text of length byteLength ## + + #Example + SkPaint paint; + const uint8_t utf8[] = { 0x24, 0xC2, 0xA2, 0xE2, 0x82, 0xAC, 0xC2, 0xA5, 0xC2, 0xA3 }; + SkDebugf("count = %d\n", paint.countText(utf8, sizeof(utf8))); + + #StdOut + count = 5 + ## + ## +## + +# ------------------------------------------------------------------------------ + +#Method bool containsText(const void* text, size_t byteLength) const + + Returns true if all text corresponds to a non-zero glyph index. + Returns false if any characters in text are not supported in + Typeface. + + If Text_Encoding is kGlyphID_TextEncoding, containsText + returns true if all glyph indices in text are non-zero; containsText + does not check to see if text contains valid glyph indices for Typeface. + + Returns true if bytelength is zero. + + #Param text array of characters or glyphs ## + #Param byteLength number of bytes in text array ## + + #Return true if all text corresponds to a non-zero glyph index ## + + #Example + #Description + containsText succeeds for degree symbol, but cannot find a glyph index + corresponding to the Unicode surrogate code point. + ## + SkPaint paint; + const uint16_t goodChar = 0x00B0; // degree symbol + const uint16_t badChar = 0xD800; // Unicode surrogate + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + SkDebugf("0x%04x %c= has char\n", goodChar, + paint.containsText(&goodChar, 2) ? '=' : '!'); + SkDebugf("0x%04x %c= has char\n", badChar, + paint.containsText(&badChar, 2) ? '=' : '!'); + + #StdOut + 0x00b0 == has char + 0xd800 != has char + ## + ## + + #Example + #Description + containsText returns true that glyph index is greater than zero, not + that it corresponds to an entry in Typeface. + ## + SkPaint paint; + const uint16_t goodGlyph = 511; + const uint16_t zeroGlyph = 0; + const uint16_t badGlyph = 65535; // larger than glyph count in font + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + SkDebugf("0x%04x %c= has glyph\n", goodGlyph, + paint.containsText(&goodGlyph, 2) ? '=' : '!'); + SkDebugf("0x%04x %c= has glyph\n", zeroGlyph, + paint.containsText(&zeroGlyph, 2) ? '=' : '!'); + SkDebugf("0x%04x %c= has glyph\n", badGlyph, + paint.containsText(&badGlyph, 2) ? '=' : '!'); + + #StdOut + 0x01ff == has glyph + 0x0000 != has glyph + 0xffff == has glyph + ## + ## + +#SeeAlso setTextEncoding Typeface + +## + +# ------------------------------------------------------------------------------ + +#Method void glyphsToUnichars(const SkGlyphID glyphs[], + int count, SkUnichar text[]) const + + Converts glyphs into text if possible. + Glyph values without direct Unicode equivalents are mapped to zero. + Uses the Typeface, but is unaffected + by Text_Encoding; the text values returned are equivalent to kUTF32_TextEncoding. + + Only supported on platforms that use FreeType as the Font_Engine. + + #Param glyphs array of indices into font ## + #Param count length of glyph array ## + #Param text storage for character codes, one per glyph ## + + #Example + #Height 64 + #Description + Convert UTF-8 text to glyphs; then convert glyphs to Unichar code points. + ## + void draw(SkCanvas* canvas) { + SkPaint paint; + const char hello[] = "Hello!"; + const int count = sizeof(hello) - 1; + SkGlyphID glyphs[count]; + if (count != paint.textToGlyphs(hello, count, glyphs)) { + return; + } + SkUnichar unichars[count]; + paint.glyphsToUnichars(glyphs, count, unichars); + paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); + canvas->drawText(unichars, sizeof(unichars), 10, 30, paint); + } + ## + +## + +# ------------------------------------------------------------------------------ +#Topic Measure_Text + +#Method SkScalar measureText(const void* text, size_t length, SkRect* bounds) const + + Returns the advance width of text if kVerticalText_Flag is clear, + and the height of text if kVerticalText_Flag is set. + The advance is the normal distance to move before drawing additional text. + Uses Text_Encoding to decode text, Typeface to get the font metrics, + and Text_Size, Text_Scale_X, Text_Skew_X, Stroke_Width, and + Path_Effect to scale the metrics and bounds. + Returns the bounding box of text if bounds is not nullptr. + The bounding box is computed as if the text was drawn at the origin. + + #Param text character codes or glyph indices to be measured ## + #Param length number of bytes of text to measure ## + #Param bounds returns bounding box relative to (0, 0) if not nullptr ## + + #Return advance width or height ## + + #Example + #Height 64 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(50); + const char str[] = "ay^jZ"; + const int count = sizeof(str) - 1; + canvas->drawText(str, count, 25, 50, paint); + SkRect bounds; + paint.measureText(str, count, &bounds); + canvas->translate(25, 50); + paint.setStyle(SkPaint::kStroke_Style); + canvas->drawRect(bounds, paint); + } + ## + +## + +#Method SkScalar measureText(const void* text, size_t length) const + + Returns the advance width of text if kVerticalText_Flag is clear, + and the height of text if kVerticalText_Flag is set. + The advance is the normal distance to move before drawing additional text. + Uses Text_Encoding to decode text, Typeface to get the font metrics, + and Text_Size to scale the metrics. + Does not scale the advance or bounds by Fake_Bold or Path_Effect. + + #Param text character codes or glyph indices to be measured ## + #Param length number of bytes of text to measure ## + + #Return advance width or height ## + + #Example + SkPaint paint; + SkDebugf("default width = %g\n", paint.measureText("!", 1)); + paint.setTextSize(paint.getTextSize() * 2); + SkDebugf("double width = %g\n", paint.measureText("!", 1)); + + #StdOut + default width = 5 + double width = 10 + ## + ## + +## + +#Method size_t breakText(const void* text, size_t length, SkScalar maxWidth, + SkScalar* measuredWidth = NULL) const + + Returns the bytes of text that fit within maxWidth. + If kVerticalText_Flag is clear, the text fragment fits if its advance width is less than or + equal to maxWidth. + If kVerticalText_Flag is set, the text fragment fits if its advance height is less than or + equal to maxWidth. + Measures only while the advance is less than or equal to maxWidth. + Returns the advance or the text fragment in measuredWidth if it not nullptr. + Uses Text_Encoding to decode text, Typeface to get the font metrics, + and Text_Size to scale the metrics. + Does not scale the advance or bounds by Fake_Bold or Path_Effect. + + #Param text character codes or glyph indices to be measured ## + #Param length number of bytes of text to measure ## + #Param maxWidth advance limit; text is measured while advance is less than maxWidth ## + #Param measuredWidth returns the width of the text less than or equal to maxWidth ## + #Return bytes of text that fit, always less than or equal to length ## + + #Example + #Description + Line under "Breakfast" shows desired width, shorter than available characters. + Line under "Bre" shows measured width after breaking text. + ## + #Height 128 + #Width 280 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(50); + const char str[] = "Breakfast"; + const int count = sizeof(str) - 1; + canvas->drawText(str, count, 25, 50, paint); + SkScalar measuredWidth; + int partialBytes = paint.breakText(str, count, 100, &measuredWidth); + canvas->drawText(str, partialBytes, 25, 100, paint); + canvas->drawLine(25, 60, 25 + 100, 60, paint); + canvas->drawLine(25, 110, 25 + measuredWidth, 110, paint); + } + ## + +## + +#Method int getTextWidths(const void* text, size_t byteLength, SkScalar widths[], + SkRect bounds[] = NULL) const + + Retrieves the advance and bounds for each glyph in text, and returns + the glyph count in text. + Both widths and bounds may be nullptr. + If widths is not nullptr, widths must be an array of glyph count entries. + if bounds is not nullptr, bounds must be an array of glyph count entries. + If kVerticalText_Flag is clear, widths returns the horizontal advance. + If kVerticalText_Flag is set, widths returns the vertical advance. + Uses Text_Encoding to decode text, Typeface to get the font metrics, + and Text_Size to scale the widths and bounds. + Does not scale the advance by Fake_Bold or Path_Effect. + Does include Fake_Bold and Path_Effect in the bounds. + + #Param text character codes or glyph indices to be measured ## + #Param byteLength number of bytes of text to measure ## + #Param widths returns text advances for each glyph; may be nullptr ## + #Param bounds returns bounds for each glyph relative to (0, 0); may be nullptr ## + + #Return glyph count in text ## + + #Example + #Height 160 + #Description + Bounds of glyphs increase for stroked text, but text advance remains the same. + The underlines show the text advance, spaced to keep them distinct. + ## + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(50); + const char str[] = "abc"; + const int bytes = sizeof(str) - 1; + int count = paint.getTextWidths(str, bytes, nullptr); + std::vector<SkScalar> widths; + std::vector<SkRect> bounds; + widths.resize(count); + bounds.resize(count); + for (int loop = 0; loop < 2; ++loop) { + (void) paint.getTextWidths(str, count, &widths.front(), &bounds.front()); + SkPoint loc = { 25, 50 }; + canvas->drawText(str, bytes, loc.fX, loc.fY, paint); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(0); + SkScalar advanceY = loc.fY + 10; + for (int index = 0; index < count; ++index) { + bounds[index].offset(loc.fX, loc.fY); + canvas->drawRect(bounds[index], paint); + canvas->drawLine(loc.fX, advanceY, loc.fX + widths[index], advanceY, paint); + loc.fX += widths[index]; + advanceY += 5; + } + canvas->translate(0, 80); + paint.setStrokeWidth(3); + } + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Text_Path + +Text_Path describes the geometry of glyphs used to draw text. + +#Method void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y, + SkPath* path) const + +Returns the geometry as Path equivalent to the drawn text. +Uses Text_Encoding to decode text, Typeface to get the glyph paths, +and Text_Size, Fake_Bold, and Path_Effect to scale and modify the glyph paths. +All of the glyph paths are stored in path. +getTextPath uses x, y, and Text_Align to position path. + + #Param text character codes or glyph indices ## + #Param length number of bytes of text ## + #Param x x-coordinate of the origin of the text ## + #Param y y-coordinate of the origin of the text ## + #Param path geometry of the glyphs ## + + #Example + #Description + Text is added to Path, offset, and subtracted from Path, then added at + the offset location. The result is rendered with one draw call. + ## + #Height 128 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(80); + SkPath path, path2; + paint.getTextPath("ABC", 3, 20, 80, &path); + path.offset(20, 20, &path2); + Op(path, path2, SkPathOp::kDifference_SkPathOp, &path); + path.addPath(path2); + paint.setStyle(SkPaint::kStroke_Style); + canvas->drawPath(path, paint); + } + ## + +## + +#Method void getPosTextPath(const void* text, size_t length, + const SkPoint pos[], SkPath* path) const + +Returns the geometry as Path equivalent to the drawn text. +Uses Text_Encoding to decode text, Typeface to get the glyph paths, +and Text_Size, Fake_Bold, and Path_Effect to scale and modify the glyph paths. +All of the glyph paths are stored in path. +Uses pos array and Text_Align to position path. +pos contains a position for each glyph. + + #Param text character codes or glyph indices ## + #Param length number of bytes of text ## + #Param pos positions of each glyph ## + #Param path geometry of the glyphs ## + + #Example + #Height 85 + #Description + Simplifies three glyphs to eliminate overlaps, and strokes the result. + ## + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(80); + SkPath path, path2; + SkPoint pos[] = {{20, 60}, {30, 70}, {40, 80}}; + paint.getPosTextPath("ABC", 3, pos, &path); + Simplify(path, &path); + paint.setStyle(SkPaint::kStroke_Style); + canvas->drawPath(path, paint); + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ +#Topic Text_Intercepts + +Text_Intercepts describe the intersection of drawn text glyphs with a pair +of lines parallel to the text advance. Text_Intercepts permits creating a +underline that skips descenders. + +#Method int getTextIntercepts(const void* text, size_t length, SkScalar x, SkScalar y, + const SkScalar bounds[2], SkScalar* intervals) const + + Returns the number of intervals that intersect bounds. + bounds describes a pair of lines parallel to the text advance. + The return count is zero or a multiple of two, and is at most twice the number of glyphs in + the string. + Uses Text_Encoding to decode text, Typeface to get the glyph paths, + and Text_Size, Fake_Bold, and Path_Effect to scale and modify the glyph paths. + Uses x, y, and Text_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 text character codes or glyph indices ## + #Param length number of bytes of text ## + #Param x x-coordinate of the origin of the text ## + #Param y y-coordinate of the origin of the text ## + #Param bounds lower and upper line parallel to the advance ## + #Param intervals returned intersections; may be nullptr ## + + #Return number of intersections; may be zero ## + +#Example +#Height 128 +#Description +Underline uses intercepts to draw on either side of the glyph descender. +## +void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(120); + SkPoint textOrigin = { 20, 100 }; + SkScalar bounds[] = { 100, 108 }; + int count = paint.getTextIntercepts("y", 1, textOrigin.fX, textOrigin.fY, bounds, nullptr); + std::vector<SkScalar> intervals; + intervals.resize(count); + (void) paint.getTextIntercepts("y", 1, textOrigin.fX, textOrigin.fY, bounds, + &intervals.front()); + canvas->drawString("y", textOrigin.fX, textOrigin.fY, paint); + paint.setColor(SK_ColorRED); + SkScalar x = textOrigin.fX; + for (int i = 0; i < count; i += 2) { + canvas->drawRect({x, bounds[0], intervals[i], bounds[1]}, paint); + x = intervals[i + 1]; + } + canvas->drawRect({intervals[count - 1], bounds[0], + textOrigin.fX + paint.measureText("y", 1), bounds[1]}, paint); +} +## + +## + +#Method int getPosTextIntercepts(const void* text, size_t length, const SkPoint pos[], + const SkScalar bounds[2], SkScalar* intervals) const + + Returns the number of intervals that intersect bounds. + bounds describes a pair of lines parallel to the text advance. + The return count is zero or a multiple of two, and is at most twice the number of glyphs in + the string. + Uses Text_Encoding to decode text, Typeface to get the glyph paths, + and Text_Size, Fake_Bold, and Path_Effect to scale and modify the glyph paths. + Uses pos array and Text_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 text character codes or glyph indices ## + #Param length number of bytes of text ## + #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 ## + + #Example + #Description + Text intercepts draw on either side of, but not inside, glyphs in a run. + ## + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(120); + paint.setVerticalText(true); + SkPoint textPos[] = {{ 60, 40 }, { 60, 140 }}; + SkScalar bounds[] = { 56, 64 }; + const char str[] = "A-"; + int len = sizeof(str) - 1; + int count = paint.getPosTextIntercepts(str, len, textPos, bounds, nullptr); + std::vector<SkScalar> intervals; + intervals.resize(count); + (void) paint.getPosTextIntercepts(str, len, textPos, bounds, &intervals.front()); + canvas->drawPosText(str, len, textPos, paint); + paint.setColor(SK_ColorRED); + SkScalar y = textPos[0].fY; + for (int i = 0; i < count; i+= 2) { + canvas->drawRect({bounds[0], y, bounds[1], intervals[i]}, paint); + y = intervals[i + 1]; + } + canvas->drawRect({bounds[0], intervals[count - 1], bounds[1], 240}, paint); + } + ## + +## + +#Method int getPosTextHIntercepts(const void* text, size_t length, const SkScalar xpos[], + SkScalar constY, const SkScalar bounds[2], + SkScalar* intervals) const + + Returns the number of intervals that intersect bounds. + bounds describes a pair of lines parallel to the text advance. + The return count is zero or a multiple of two, and is at most twice the number of glyphs in + the string. + Uses Text_Encoding to decode text, Typeface to get the glyph paths, + and Text_Size, Fake_Bold, and Path_Effect to scale and modify the glyph paths. + Uses xpos array, constY, and Text_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 text character codes or glyph indices ## + #Param length number of bytes of text ## + #Param xpos positions of each glyph in x ## + #Param constY position of each glyph in y ## + #Param bounds lower and upper line parallel to the advance ## + #Param intervals returned intersections; may be nullptr ## + + #Return number of intersections; may be zero ## + + #Example + #Height 128 + #Description + Text intercepts do not take stroke thickness into consideration. + ## + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(120); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(4); + SkScalar textPosH[] = { 20, 80, 140 }; + SkScalar y = 100; + SkScalar bounds[] = { 56, 78 }; + const char str[] = "\\-/"; + int len = sizeof(str) - 1; + int count = paint.getPosTextHIntercepts(str, len, textPosH, y, bounds, nullptr); + std::vector<SkScalar> intervals; + intervals.resize(count); + (void) paint.getPosTextHIntercepts(str, len, textPosH, y, bounds, &intervals.front()); + canvas->drawPosTextH(str, len, textPosH, y, paint); + paint.setColor(0xFFFF7777); + paint.setStyle(SkPaint::kFill_Style); + SkScalar x = textPosH[0]; + for (int i = 0; i < count; i+= 2) { + canvas->drawRect({x, bounds[0], intervals[i], bounds[1]}, paint); + x = intervals[i + 1]; + } + canvas->drawRect({intervals[count - 1], bounds[0], 180, bounds[1]}, paint); + } + ## + +## + + +#Method int getTextBlobIntercepts(const SkTextBlob* blob, const SkScalar bounds[2], + SkScalar* intervals) const + + Returns the number of intervals that intersect bounds. + bounds describes a pair of lines parallel to the text advance. + The return count is zero or a multiple of two, and is at most twice the number of glyphs in + the string. + Uses Text_Encoding to decode text, Typeface to get the glyph paths, + and Text_Size, Fake_Bold, and Path_Effect to scale and modify the glyph paths. + Uses pos array and Text_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 bounds lower and upper line parallel to the advance ## + #Param intervals returned intersections; may be nullptr ## + + #Return number of intersections; may be zero ## + + #Example + #Height 143 + void draw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(120); + SkPoint textPos = { 20, 110 }; + int len = 3; + SkTextBlobBuilder textBlobBuilder; + const SkTextBlobBuilder::RunBuffer& run = + textBlobBuilder.allocRun(paint, len, textPos.fX, textPos.fY); + run.glyphs[0] = 10; + run.glyphs[1] = 20; + run.glyphs[2] = 30; + sk_sp<const SkTextBlob> blob = textBlobBuilder.make(); + canvas->drawTextBlob(blob.get(), textPos.fX, textPos.fY, paint); + SkScalar bounds[] = { 116, 134 }; + int count = paint.getTextBlobIntercepts(blob.get(), bounds, nullptr); + std::vector<SkScalar> intervals; + intervals.resize(count); + (void) paint.getTextBlobIntercepts(blob.get(), bounds, &intervals.front()); + canvas->drawTextBlob(blob.get(), 0, 0, paint); + paint.setColor(0xFFFF7777); + SkScalar x = textPos.fX; + for (int i = 0; i < count; i+= 2) { + canvas->drawRect({x, bounds[0], intervals[i], bounds[1]}, paint); + x = intervals[i + 1]; + } + canvas->drawRect({intervals[count - 1], bounds[0], 180, bounds[1]}, paint); + } + ## + +## + +#Topic ## +# ------------------------------------------------------------------------------ + +#Method bool nothingToDraw() const + + Returns true if Paint prevents all drawing. + If nothingToDraw returns false, the Paint may or may not allow drawing. + + Returns true if Blend_Mode and Color_Alpha are enabled, + and computed Color_Alpha is zero. + + #Return true if Paint prevents all drawing ## + + #Example + void draw(SkCanvas* canvas) { + auto debugster = [](const char* prefix, const SkPaint& p) -> void { + SkDebugf("%s nothing to draw: %s\n", prefix, + p.nothingToDraw() ? "true" : "false"); + }; + SkPaint paint; + debugster("initial", paint); + paint.setBlendMode(SkBlendMode::kDst); + debugster("blend dst", paint); + paint.setBlendMode(SkBlendMode::kSrcOver); + debugster("blend src over", paint); + paint.setAlpha(0); + debugster("alpha 0", paint); + } + + #StdOut + initial nothing to draw: false + blend dst nothing to draw: true + blend src over nothing to draw: false + alpha 0 nothing to draw: true + #StdOut ## + ## + +## + +# ------------------------------------------------------------------------------ +#Topic Fast_Bounds + #Private + To be made private. + ## + +Fast_Bounds methods conservatively outset a drawing bounds by additional area +Paint may draw to. + +#Method bool canComputeFastBounds() const + #Private + (to be made private) + ## + + Returns true if Paint does not include elements requiring extensive computation + to compute Device bounds of drawn geometry. For instance, Paint with Path_Effect + always returns false. + + #Return true if Paint allows for fast computation of bounds ## +## + +#Method const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const + #Private + (to be made private) + ## + + 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 + for SkCanvas::quickReject tests. + + The returned rect 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. + + #Private + e.g. + if (paint.canComputeFastBounds()) { + SkRect r, storage; + path.computeBounds(&r, SkPath::kFast_BoundsType); + const SkRect& fastR = paint.computeFastBounds(r, &storage); + if (canvas->quickReject(fastR, ...)) { + // don't draw the path + } + } + ## + + #Param orig geometry modified by Paint when drawn ## + #Param storage computed bounds of geometry; may not be nullptr ## + + #Return fast computed bounds ## +## + +#Method const SkRect& computeFastStrokeBounds(const SkRect& orig, + SkRect* storage) const + #Private + (to be made private) + ## + + #Param orig geometry modified by Paint when drawn ## + #Param storage computed bounds of geometry ## + + #Return fast computed bounds ## +## + +#Method const SkRect& doComputeFastBounds(const SkRect& orig, SkRect* storage, + Style style) const + #Private + (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. + + #Param orig geometry modified by Paint when drawn ## + #Param storage computed bounds of geometry ## + #Param style overrides Style ## + + #Return fast computed bounds ## +## + +#Topic Fast_Bounds ## + +# ------------------------------------------------------------------------------ +#Method void toString(SkString* str) const; + +#DefinedBy SK_TO_STRING_NONVIRT() ## + +#Private +macro expands to: void toString(SkString* str) const; +## + +Converts Paint to machine parsable form in developer mode. + +#Param str storage for string containing parsable Paint ## + +#Example + SkPaint paint; + SkString str; + paint.toString(&str); + const char textSize[] = "TextSize:"; + const int trailerSize = strlen("</dd><dt>"); + int textSizeLoc = str.find(textSize) + strlen(textSize) + trailerSize; + const char* sizeStart = &str.c_str()[textSizeLoc]; + int textSizeEnd = SkStrFind(sizeStart, "</dd>"); + SkDebugf("text size = %.*s\n", textSizeEnd, sizeStart); + + #StdOut + text size = 12 + ## + +## + +#ToDo incomplete ## + +## + +# ------------------------------------------------------------------------------ + +#Class SkPaint ## + +#Topic Paint ## diff --git a/docs/SkPath.bmh b/docs/SkPath.bmh new file mode 100644 index 0000000000..8c414518e9 --- /dev/null +++ b/docs/SkPath.bmh @@ -0,0 +1,5801 @@ +#Topic Path
+#Alias Paths
+
+Path contains Lines and Curves which can be stroked or filled. Contour is
+composed of a series of connected Lines and Curves. Path may contain zero,
+one, or more Contours.
+Each Line and Curve are described by Verb, Points, and optional Weight.
+
+Each pair of connected Lines and Curves share common Point; for instance, Path
+containing two connected Lines are described the Verb sequence:
+SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb; and a Point sequence
+with three entries, sharing
+the middle entry as the end of the first Line and the start of the second Line.
+
+Path components Arc, Rect, Round_Rect, Circle, and Oval are composed of
+Lines and Curves with as many Verbs and Points required
+for an exact description. Once added to Path, these components may lose their
+identity; although Path can be inspected to determine if it decribes a single
+Rect, Oval, Round_Rect, and so on.
+
+#Example
+#Height 192
+#Description
+Path contains three Contours: Line, Circle, and Quad. Line is stroked but
+not filled. Circle is stroked and filled; Circle stroke forms a loop. Quad
+is stroked and filled, but since it is not closed, Quad does not stroke a loop.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPath path;
+ path.moveTo(124, 108);
+ path.lineTo(172, 24);
+ path.addCircle(50, 50, 30);
+ path.moveTo(36, 148);
+ path.quadTo(66, 188, 120, 136);
+ canvas->drawPath(path, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(SK_ColorBLUE);
+ paint.setStrokeWidth(3);
+ canvas->drawPath(path, paint);
+}
+##
+
+Path contains a Fill_Type which determines whether overlapping Contours
+form fills or holes. Fill_Type also determines whether area inside or outside
+Lines and Curves is filled.
+
+#Example
+#Height 192
+#Description
+Path is drawn filled, then stroked, then stroked and filled.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPath path;
+ path.moveTo(36, 48);
+ path.quadTo(66, 88, 120, 36);
+ canvas->drawPath(path, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(SK_ColorBLUE);
+ paint.setStrokeWidth(8);
+ canvas->translate(0, 50);
+ canvas->drawPath(path, paint);
+ paint.setStyle(SkPaint::kStrokeAndFill_Style);
+ paint.setColor(SK_ColorRED);
+ canvas->translate(0, 50);
+ canvas->drawPath(path, paint);
+}
+##
+
+Path contents are never shared. Copying Path by value effectively creates
+a new Path independent of the original. Internally, the copy does not duplicate
+its contents until it is edited, to reduce memory use and improve performance.
+
+#Subtopic Subtopics +#ToDo not all methods are in topics ## +#ToDo subtopics are not in topics ## +#Table +#Legend +# topics # description ## +#Legend ## +#Table ## +# Contour # A loop of lines and curves. ## +# Convexity # Whether Path contains simple loop. ## +# Last_Point # Final Point in Contour. ## +# Point_Array # All Points in Path. ## +# Verb # How Points and Contours are defined. ## +# Verb_Array # All Verbs in Path. ## +# Verb # How Points and Contours are defined. ## +# Weight # Strength of control Point in Conic. ## +#Subtopic ## +
+
+#Subtopic Contour +#Alias Contours +Contour contains one or more Verbs, and as many Points as +are required to satisfy Verb_Array. First Verb in Path is always +SkPath::kMove_Verb; each SkPath::kMove_Verb that follows starts a new Contour. + +#Example +#Description
+Each SkPath::moveTo starts a new Contour, and content after SkPath::close()
+also starts a new Contour. Since SkPath::conicTo wasn't preceded by
+SkPath::moveTo, the first Point of the third Contour starts at the last Point
+of the second Contour.
+##
+#Height 192
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas->drawString("1st contour", 150, 100, paint);
+ canvas->drawString("2nd contour", 130, 160, paint);
+ canvas->drawString("3rd contour", 40, 30, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPath path;
+ path.moveTo(124, 108);
+ path.lineTo(172, 24);
+ path.moveTo(36, 148);
+ path.quadTo(66, 188, 120, 136);
+ path.close();
+ path.conicTo(70, 20, 110, 40, 0.6f);
+ canvas->drawPath(path, paint);
+## + +If final Verb in Contour is SkPath::kClose_Verb, Line connects Last_Point in +Contour with first Point. A closed Contour, stroked, draws +Paint_Stroke_Join at Last_Point and first Point. Without SkPath::kClose_Verb +as final Verb, Last_Point and first Point are not connected; Contour +remains open. An open Contour, stroked, draws Paint_Stroke_Cap at +Last_Point and first Point. + +#Example +#Height 160
+#Description
+Path is drawn stroked, with an open Contour and a closed Contour.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(8);
+ SkPath path;
+ path.moveTo(36, 48);
+ path.quadTo(66, 88, 120, 36);
+ canvas->drawPath(path, paint);
+ path.close();
+ canvas->translate(0, 50);
+ canvas->drawPath(path, paint);
+}
+## + +#Subtopic Zero_Length +#Alias Zero_Length_Contour +Contour length is distance traveled from first Point to Last_Point, +plus, if Contour is closed, distance from Last_Point to first Point. +Even if Contour length is zero, stroked Lines are drawn if Paint_Stroke_Cap +makes them visible. + +#Example +#Height 64
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(8);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+ SkPath path;
+ path.moveTo(36, 48);
+ path.lineTo(36, 48);
+ canvas->drawPath(path, paint);
+ path.reset();
+ paint.setStrokeCap(SkPaint::kSquare_Cap);
+ path.moveTo(56, 48);
+ path.close();
+ canvas->drawPath(path, paint); +## + +#Subtopic Zero_Length ## + +#Subtopic Contour ## +
+# ------------------------------------------------------------------------------
+ +#Class SkPath
+
+#Topic Overview
+
+#Subtopic Constants +#ToDo incomplete ## +#Table +#Legend +# constants # description ## +#Legend ## +# AddPathMode # Sets addPath options. ## +# ArcSize # Sets arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep, SkScalar x, SkScalar y) options. ## +# Convexity # Returns if Path is convex or concave. ## +# Direction # Sets Contour clockwise or counterclockwise. ## +# FillType # Sets winding rule and inverse fill. ## +# SegmentMask +# Verb # Controls how Path Points are interpreted. ## +#Table ## +#Subtopic ## +
+#Subtopic Classes_and_Structs +#Table +#Legend +# class or struct # description ## +#Legend ## +# Iter # Iterates through lines and curves, skipping degenerates. ## +# RawIter # Iterates through lines and curves, including degenerates. ## +#Table ## +#Subtopic ## +
+#Subtopic Constructors +#Table +#Legend +# # description ## +#Legend ## +# SkPath() # Constructs with default values. ## +# SkPath(const SkPath& path) # Makes a shallow copy. ## +# ~SkPath() # Decreases Reference_Count of owned objects. ## +#Table ## +#Subtopic ## + +#Subtopic Operators +#Table +#Legend +# operator # description ## +#Legend ## +# operator=(const SkPath& path) # Makes a shallow copy. ## +# operator==(const SkPath& a, const SkPath& b) # Compares paths for equality. ## +# operator!=(const SkPath& a, const SkPath& b) # Compares paths for inequality. ## +#Table ## +#Subtopic ## +
+#Subtopic Member_Functions
+#Table
+#Legend
+# function # description ##
+#Legend ##
+# ConvertConicToQuads # Approximates Conic with Quad array. ##
+# ConvertToNonInverseFillType # Returns Fill_Type representing inside geometry. ##
+# IsCubicDegenerate # Returns if Cubic is very small. ##
+# IsInverseFillType # Returns if Fill_Type represents outside geometry. ##
+# IsLineDegenerate # Returns if Line is very small. ##
+# IsQuadDegenerate # Returns if Quad is very small. ##
+# addArc # Adds one Contour containing Arc. ##
+# addCircle # Adds one Contour containing Circle. ##
+# addOval # Adds one Contour containing Oval. ##
+# addPath # Adds contents of Path. ##
+# addPoly # Adds one Contour containing connected lines. ##
+# addRRect # Adds one Contour containing Round_Rect. ##
+# addRect # Adds one Contour containing Rect. ##
+# addRoundRect # Adds one Contour containing Round_Rect with common corner radii. ##
+# arcTo # Appends Arc. ##
+# close() # Makes last Contour a loop. ##
+# computeTightBounds # Returns extent of geometry. ##
+# conicTo # Appends Conic. ##
+# conservativelyContainsRect # Returns true if Rect may be inside. ##
+# contains() # Returns if Point is in fill area. ##
+# countPoints # Returns Point_Array length. ##
+# countVerbs # Returns Verb_Array length. ##
+# cubicTo # Appends Cubic. ##
+# dump() # Sends text representation using floats to stdout. ##
+# dumpHex # Sends text representation using hexadecimal to stdout. ##
+# experimentalValidateRef # Experimental; debugging only. ##
+# getBounds # Returns maximum and minimum of Point_Array. ##
+# getConvexity # Returns geometry convexity, computing if necessary. ##
+# getConvexityOrUnknown # Returns geometry convexity if known. ##
+# getFillType # Returns Fill_Type: winding, even-odd, inverse. ##
+# getGenerationID # Returns unique ID. ##
+# getLastPt # Returns Last_Point. ##
+# getPoint # Returns entry from Point_Array. ##
+# getPoints # Returns Point_Array. ##
+# getSegmentMasks # Returns types in Verb_Array. ##
+# getVerbs # Returns Verb_Array. ##
+# incReserve # Hint to reserve space for additional data. ##
+# interpolate() # Interpolates between Path pair. ##
+# isConvex # Returns if geometry is convex. ##
+# isEmpty # Returns if verb count is zero. ##
+# isFinite # Returns if all Point values are finite. ##
+# isInterpolatable # Returns if pair contains equal counts of Verb_Array and Weights. ##
+# isInverseFillType # Returns if Fill_Type fills outside geometry. ##
+# isLastContourClosed # Returns if final Contour forms a loop. ##
+# isLine # Returns if describes Line. ##
+# isNestedFillRects # Returns if describes Rect pair, one inside the other. ##
+# isOval # Returns if describes Oval. ##
+# isRRect # Returns if describes Round_Rect. ##
+# isRect # Returns if describes Rect. ##
+# isVolatile # Returns if Device should not cache. ##
+# lineTo # Appends Line. ##
+# moveTo # Starts Contour. ##
+# offset() # Translates Point_Array. ##
+# quadTo # Appends Quad. ##
+# rArcTo # Appends Arc relative to Last_Point. ##
+# rConicTo # Appends Conic relative to Last_Point. ##
+# rCubicTo # Appends Cubic relative to Last_Point. ##
+# rLineTo # Appends Line relative to Last_Point. ##
+# rMoveTo # Starts Contour relative to Last_Point. ##
+# rQuadTo # Appends Quad relative to Last_Point. ##
+# readFromMemory # Initialize from buffer. ##
+# reset() # Removes Verb_Array, Point_Array, and Weights; frees memory. ##
+# reverseAddPath # Adds contents of Path back to front. ##
+# rewind() # Removes Verb_Array, Point_Array, and Weights; leaves memory allocated. ##
+# setConvexity # Sets if geometry is convex to avoid future computation. ##
+# setFillType # Sets Fill_Type: winding, even-odd, inverse. ##
+# setIsConvex # Deprecated. ##
+# setIsVolatile # Sets if Device should not cache. ##
+# setLastPt # Replaces Last_Point. ##
+# swap() # Exchanges Path pair. ##
+# toggleInverseFillType # Toggles Fill_Type between inside and outside geometry. ##
+# transform() # Applies Matrix to Point_Array and Weights. ##
+# unique() # Returns if data has single owner. ##
+# updateBoundsCache # Refresh result of getBounds. ##
+# writeToMemory # Copy data to buffer. ##
+#Table ##
+#Subtopic Path_Member_Functions ##
+#Topic Overview ##
+
+#Subtopic Verb +#Alias Verbs + +#Enum Verb
+
+#Code
+ enum Verb {
+ kMove_Verb
+ kLine_Verb
+ kQuad_Verb
+ kConic_Verb
+ kCubic_Verb
+ kClose_Verb
+ kDone_Verb
+ };
+##
+
+Verb instructs Path how to interpret one or more Point and optional Weight; +manage Contour, and terminate Path. + +#Const kMove_Verb 0
+ Starts new Contour at next Point.
+##
+#Const kLine_Verb 1
+ Adds Line from Last_Point to next Point.
+ Line is a straight segment from Point to Point.
+##
+#Const kQuad_Verb 2
+ Adds Quad from Last_Point, using control Point, and end Point.
+ Quad is a parabolic section within tangents from Last_Point to control Point,
+ and control Point to end Point.
+##
+#Const kConic_Verb 3
+ Adds Conic from Last_Point, using control Point, end Point, and Weight.
+ Conic is a elliptical, parabolic, or hyperbolic section within tangents
+ from Last_Point to control Point, and control Point to end Point, constrained
+ by Weight. Weight less than one is elliptical; equal to one is parabolic
+ (and identical to Quad); greater than one hyperbolic.
+##
+#Const kCubic_Verb 4
+ Adds Cubic from Last_Point, using two control Points, and end Point.
+ Cubic is a third-order Bezier section within tangents from Last_Point to
+ first control Point, and from second control Point to end Point.
+##
+#Const kClose_Verb 5
+ Closes Contour, connecting Last_Point to kMove_Verb Point.
+##
+#Const kDone_Verb 6
+ Terminates Path. Not in Verb_Array, but returned by Path iterator.
+## + +Each Verb has zero or more Points stored in Path. +Path iterator returns complete curve descriptions, duplicating shared Points +for consecutive entries. + +#Table +#Legend +# Verb # Allocated Points # Iterated Points # Weights ## +## +# kMove_Verb # 1 # 1 # 0 ## +# kLine_Verb # 1 # 2 # 0 ## +# kQuad_Verb # 2 # 3 # 0 ## +# kConic_Verb # 2 # 3 # 1 ## +# kCubic_Verb # 3 # 4 # 0 ## +# kClose_Verb # 0 # 1 # 0 ## +# kDone_Verb # -- # 0 # 0 ## +## +
+#Example
+void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.lineTo(20, 20);
+ path.quadTo(-10, -10, 30, 30);
+ path.close();
+ path.cubicTo(1, 2, 3, 4, 5, 6);
+ path.conicTo(0, 0, 0, 0, 2);
+ uint8_t verbs[7];
+ int count = path.getVerbs(verbs, (int) SK_ARRAY_COUNT(verbs));
+ const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close" };
+ SkDebugf("verb count: %d\nverbs: ", count);
+ for (int i = 0; i < count; ++i) {
+ SkDebugf("k%s_Verb ", verbStr[verbs[i]]);
+ }
+ SkDebugf("\n");
+}
+#StdOut
+verb count: 7
+verbs: kMove_Verb kLine_Verb kQuad_Verb kClose_Verb kMove_Verb kCubic_Verb kConic_Verb
+##
+##
+
+#Enum Verb ##
+#Subtopic Verb ##
+
+# ------------------------------------------------------------------------------
+#Subtopic Direction
+#Alias Directions
+
+#Enum Direction
+
+#Code
+ enum Direction {
+ kCW_Direction
+ kCCW_Direction
+ };
+##
+
+Direction describes whether Contour is clockwise or counterclockwise.
+When Path contains multiple overlapping Contours, Direction together with
+Fill_Type determines whether overlaps are filled or form holes.
+
+Direction also determines how Contour is measured. For instance, dashing
+measures along Path to determine where to start and stop stroke; Direction
+will change dashed results as it steps clockwise or counterclockwise.
+
+Closed Contours like Rect, Round_Rect, Circle, and Oval added with
+kCW_Direction travel clockwise; the same added with kCCW_Direction
+travel counterclockwise.
+
+#Const kCW_Direction
+ Contour travels in a clockwise direction.
+##
+#Const kCCW_Direction
+ Contour travels in a counterclockwise direction.
+##
+
+
+#Example
+#Height 100
+void draw(SkCanvas* canvas) {
+ const SkPoint arrow[] = { {40, -5}, {45, 0}, {40, 5} };
+ const SkRect rect = {10, 10, 90, 90};
+ SkPaint rectPaint;
+ rectPaint.setAntiAlias(true);
+ SkPaint textPaint(rectPaint);
+ textPaint.setTextAlign(SkPaint::kCenter_Align);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ SkPaint arrowPaint(rectPaint);
+ SkPath arrowPath;
+ arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
+ arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 320, 0,
+ SkPath1DPathEffect::kRotate_Style));
+ for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
+ canvas->drawRect(rect, rectPaint);
+ for (unsigned start : { 0, 1, 2, 3 } ) {
+ SkPath path;
+ path.addRect(rect, direction, start);
+ canvas->drawPath(path, arrowPaint);
+ }
+ canvas->drawString(SkPath::kCW_Direction == direction ? "CW" : "CCW", rect.centerX(),
+ rect.centerY(), textPaint);
+ canvas->translate(120, 0);
+ }
+}
+##
+
+#SeeAlso arcTo rArcTo isRect isNestedFillRects addRect addOval
+
+#Enum Direction ##
+#Subtopic Direction ##
+
+# ------------------------------------------------------------------------------
+
+#Method SkPath()
+
+By default, Path has no Verbs, no Points, and no Weights.
+Fill_Type is set to kWinding_FillType.
+
+#Return empty Path. ##
+
+#Example
+ SkPath path;
+ SkDebugf("path is " "%s" "empty", path.isEmpty() ? "" : "not ");
+#StdOut
+path is empty
+##
+##
+
+#SeeAlso reset rewind
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method SkPath(const SkPath& path)
+
+Copy constructor makes two paths identical by value. Internally, path and
+the returned result share pointer values. The underlying Verb_Array, Point_Array
+and Weights are copied when modified.
+
+Creating a Path copy is very efficient and never allocates memory.
+Paths are always copied by value from the interface; the underlying shared
+pointers are not exposed.
+
+#Param path Path to copy by value. ##
+
+#Return Copy of Path. ##
+
+#Example
+#Description
+ Modifying one path does not effect another, even if they started as copies
+ of each other.
+##
+ SkPath path;
+ path.lineTo(20, 20);
+ SkPath path2(path);
+ path2.close();
+ SkDebugf("path verbs: %d\n", path.countVerbs());
+ SkDebugf("path2 verbs: %d\n", path2.countVerbs());
+ path.reset();
+ SkDebugf("after reset\n" "path verbs: %d\n", path.countVerbs());
+ SkDebugf("path2 verbs: %d\n", path2.countVerbs());
+#StdOut
+path verbs: 2
+path2 verbs: 3
+after reset
+path verbs: 0
+path2 verbs: 3
+##
+##
+
+#SeeAlso operator=(const SkPath& path)
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method ~SkPath()
+
+Releases ownership of any shared data and deletes data if Path is sole owner.
+
+#Example
+#Description
+delete calls Path destructor, but copy of original in path2 is unaffected.
+##
+void draw(SkCanvas* canvas) {
+ SkPath* path = new SkPath();
+ path->lineTo(20, 20);
+ SkPath path2(*path);
+ delete path;
+ SkDebugf("path2 is " "%s" "empty", path2.isEmpty() ? "" : "not ");
+}
+##
+
+#SeeAlso SkPath() SkPath(const SkPath& path) operator=(const SkPath& path)
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method SkPath& operator=(const SkPath& path)
+
+Path assignment makes two paths identical by value. Internally, assignment
+shares pointer values. The underlying Verb_Array, Point_Array and Weights
+are copied when modified.
+
+Copying Paths by assignment is very efficient and never allocates memory.
+Paths are always copied by value from the interface; the underlying shared
+pointers are not exposed.
+
+#Param path Verb_Array, Point_Array, Weights, amd Fill_Type to copy. ##
+
+#Return Path copied by value. ##
+
+#Example
+SkPath path1;
+path1.addRect({10, 20, 30, 40});
+SkPath path2 = path1;
+const SkRect& b1 = path1.getBounds();
+SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
+const SkRect& b2 = path2.getBounds();
+SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
+#StdOut
+path1 bounds = 10, 20, 30, 40
+path2 bounds = 10, 20, 30, 40
+#StdOut ##
+##
+
+#SeeAlso swap() SkPath(const SkPath& path)
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method friend SK_API bool operator==(const SkPath& a, const SkPath& b)
+
+Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
+are equivalent.
+
+#Param a Path to compare. ##
+#Param b Path to compare. ##
+
+#Return true if Path pair are equivalent. ##
+
+#Example
+#Description
+Rewind removes Verb_Array but leaves storage; since storage is not compared,
+Path pair are equivalent.
+##
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
+ SkDebugf("%s one %c= two\n", prefix, a == b ? '=' : '!');
+ };
+ SkPath one;
+ SkPath two;
+ debugster("empty", one, two);
+ one.moveTo(0, 0);
+ debugster("moveTo", one, two);
+ one.rewind();
+ debugster("rewind", one, two);
+ one.moveTo(0, 0);
+ one.reset();
+ debugster("reset", one, two);
+}
+#StdOut
+empty one == two
+moveTo one != two
+rewind one == two
+reset one == two
+##
+##
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method friend bool operator!=(const SkPath& a, const SkPath& b)
+
+Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
+are not equivalent.
+
+#Param a Path to compare. ##
+#Param b Path to compare. ##
+
+#Return true if Path pair are not equivalent. ##
+
+#Example
+#Description
+Path pair are equal though their convexity is not equal.
+##
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
+ SkDebugf("%s one %c= two\n", prefix, a != b ? '!' : '=');
+ };
+ SkPath one;
+ SkPath two;
+ debugster("empty", one, two);
+ one.addRect({10, 20, 30, 40});
+ two.addRect({10, 20, 30, 40});
+ debugster("addRect", one, two);
+ one.setConvexity(SkPath::kConcave_Convexity);
+ debugster("setConvexity", one, two);
+ SkDebugf("convexity %c=\n", one.getConvexity() == two.getConvexity() ? '=' : '!');
+}
+#StdOut
+empty one == two
+addRect one == two
+setConvexity one == two
+convexity !=
+##
+##
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isInterpolatable(const SkPath& compare) const
+
+Return true if Paths contain equal Verbs and equal Weights.
+If Paths contain one or more Conics, the Weights must match.
+
+conicTo may add different Verbs depending on Conic_Weight, so it is not
+trival to interpolate a pair of Paths containing Conics with different
+Conic_Weight values.
+
+#Param compare Path to compare. ##
+
+#Return true if Paths Verb_Array and Weights are equivalent. ##
+
+#Example
+ SkPath path, path2;
+ path.moveTo(20, 20);
+ path.lineTo(40, 40);
+ path.lineTo(20, 20);
+ path.lineTo(40, 40);
+ path.close();
+ path2.addRect({20, 20, 40, 40});
+ SkDebugf("paths are " "%s" "interpolatable", path.isInterpolatable(path2) ? "" : "not ");
+#StdOut
+paths are interpolatable
+##
+##
+
+#SeeAlso isInterpolatable
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const
+
+Interpolate between Paths with equal sized Point_Arrays.
+Copy Verb_Array and Weights to out,
+and set out Point_Array to a weighted average of this Point_Array and ending
+Point_Array, using the formula:
+#Formula
+(this->points * weight) + ending->points * (1 - weight)
+##
+
+interpolate() returns false and leaves out unchanged if Point_Array is not
+the same size as ending Point_Array. Call isInterpolatable to check Path
+compatibility prior to calling interpolate().
+
+#Param ending Point_Array averaged with this Point_Array. ##
+#Param weight Most useful when between zero (ending Point_Array) and
+ one (this Point_Array); will work with values outside of this
+ range.
+##
+#Param out ##
+
+#Return true if Paths contain same number of Points. ##
+
+#Example
+#Height 60
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPath path, path2;
+ path.moveTo(20, 20);
+ path.lineTo(40, 40);
+ path.lineTo(20, 40);
+ path.lineTo(40, 20);
+ path.close();
+ path2.addRect({20, 20, 40, 40});
+ for (SkScalar i = 0; i <= 1; i += 1.f / 6) {
+ SkPath interp;
+ path.interpolate(path2, i, &interp);
+ canvas->drawPath(interp, paint);
+ canvas->translate(30, 0);
+ }
+}
+##
+
+#SeeAlso isInterpolatable
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool unique() const
+
+#Private
+To be deprecated; only valid for Android framework.
+##
+
+#Return true if Path has one owner. ##
+
+##
+
+# ------------------------------------------------------------------------------
+#Subtopic Fill_Type + +#Enum FillType
+
+#Code
+ enum FillType {
+ kWinding_FillType
+ kEvenOdd_FillType
+ kInverseWinding_FillType
+ kInverseEvenOdd_FillType
+ };
+##
+ +Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType +fills if the sum of Contour edges is not zero, where clockwise edges add one, and +counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the +number of Contour edges is odd. Each Fill_Type 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. + +#Example +#Height 100 +#Description +The top row has two clockwise rectangles. The second row has one clockwise and +one counterclockwise rectangle. The even-odd variants draw the same. The +winding variants draw the top rectangle overlap, which has a winding of 2, the +same as the outer parts of the top rectangles, which have a winding of 1. +## +void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
+ path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
+ path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
+ path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
+ SkPaint strokePaint;
+ strokePaint.setStyle(SkPaint::kStroke_Style);
+ SkRect clipRect = {0, 0, 51, 100};
+ canvas->drawPath(path, strokePaint);
+ SkPaint fillPaint;
+ for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
+ SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
+ canvas->translate(51, 0);
+ canvas->save();
+ canvas->clipRect(clipRect);
+ path.setFillType(fillType);
+ canvas->drawPath(path, fillPaint);
+ canvas->restore();
+ }
+} +## +
+#Const kWinding_FillType
+Specifies fill as area is enclosed by a non-zero sum of Contour Directions.
+##
+#Const kEvenOdd_FillType
+Specifies fill as area enclosed by an odd number of Contours.
+##
+#Const kInverseWinding_FillType
+Specifies fill as area is enclosed by a zero sum of Contour Directions.
+##
+#Const kInverseEvenOdd_FillType
+Specifies fill as area enclosed by an even number of Contours.
+##
+
+#Example
+#Height 230
+void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
+ path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
+ SkPaint strokePaint;
+ strokePaint.setStyle(SkPaint::kStroke_Style);
+ SkRect clipRect = {0, 0, 128, 128};
+ canvas->drawPath(path, strokePaint);
+ canvas->drawLine({0, 50}, {120, 50}, strokePaint);
+ SkPaint textPaint;
+ textPaint.setAntiAlias(true);
+ textPaint.setTextAlign(SkPaint::kCenter_Align);
+ SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
+ canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
+ textPaint.setTextSize(18);
+ canvas->translate(0, 128);
+ canvas->scale(.5f, .5f);
+ canvas->drawString("inverse", 384, 150, textPaint);
+ SkPaint fillPaint;
+ for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
+ SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
+ canvas->save();
+ canvas->clipRect(clipRect);
+ path.setFillType(fillType);
+ canvas->drawPath(path, fillPaint);
+ canvas->restore();
+ canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
+ canvas->translate(128, 0);
+ }
+}
+##
+
+#SeeAlso SkPaint::Style Direction getFillType setFillType
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method FillType getFillType() const
+
+Returns FillType, the rule used to fill Path. FillType of a new Path is
+kWinding_FillType.
+
+#Return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
+kInverseEvenOdd_FillType.
+##
+
+#Example
+ SkPath path;
+ SkDebugf("default path fill type is %s\n",
+ path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
+ path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
+ path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
+ "kInverseEvenOdd_FillType");
+#StdOut
+default path fill type is kWinding_FillType
+##
+##
+
+#SeeAlso FillType setFillType isInverseFillType
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void setFillType(FillType ft)
+
+Sets FillType, the rule used to fill Path. While setFillType does not check
+that ft is legal, values outside of FillType are not supported.
+
+#Param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
+kInverseEvenOdd_FillType.
+##
+
+#Example
+#Description
+If empty Path is set to inverse FillType, it fills all pixels.
+##
+#Height 64
+ SkPath path;
+ path.setFillType(SkPath::kInverseWinding_FillType);
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawPath(path, paint);
+##
+
+#SeeAlso FillType getFillType toggleInverseFillType
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isInverseFillType() const
+
+Returns if FillType describes area outside Path geometry. The inverse fill area
+extends indefinitely.
+
+#Return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType. ##
+
+#Example
+ SkPath path;
+ SkDebugf("default path fill type is inverse: %s\n",
+ path.isInverseFillType() ? "true" : "false");
+#StdOut
+default path fill type is inverse: false
+##
+##
+
+#SeeAlso FillType getFillType setFillType toggleInverseFillType
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void toggleInverseFillType()
+
+Replace FillType with its inverse. The inverse of FillType describes the area
+unmodified by the original FillType.
+
+#Table
+#Legend
+# FillType # toggled FillType ##
+##
+# kWinding_FillType # kInverseWinding_FillType ##
+# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
+# kInverseWinding_FillType # kWinding_FillType ##
+# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
+##
+
+#Example
+#Description
+Path drawn normally and through its inverse touches every pixel once.
+##
+#Height 100
+SkPath path;
+SkPaint paint;
+paint.setColor(SK_ColorRED);
+paint.setTextSize(80); +paint.getTextPath("ABC", 3, 20, 80, &path); +canvas->drawPath(path, paint);
+path.toggleInverseFillType();
+paint.setColor(SK_ColorGREEN);
+canvas->drawPath(path, paint);
+##
+
+#SeeAlso FillType getFillType setFillType isInverseFillType
+
+##
+
+#Subtopic Fill_Type ## +
+# ------------------------------------------------------------------------------
+ +#Subtopic Convexity +
+#Enum Convexity
+
+#Code
+ enum Convexity {
+ kUnknown_Convexity,
+ kConvex_Convexity,
+ kConcave_Convexity
+ };
+##
+
+Path is convex if it contains one Contour and Contour loops no more than +360 degrees, and Contour angles all have same Direction. Convex Path +may have better performance and require fewer resources on GPU_Surface. + +Path 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 Path Convexity is kUnknown_Convexity. Path Convexity is computed
+if needed by destination Surface.
+
+#Const kUnknown_Convexity
+ Indicates Convexity has not been determined.
+##
+#Const kConvex_Convexity
+ Path has one Contour made of a simple geometry without indentations.
+##
+#Const kConcave_Convexity
+ Path has more than one Contour, or a geometry with indentations.
+##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
+ const char* labels[] = { "unknown", "convex", "concave" };
+ for (SkScalar x : { 40, 100 } ) {
+ SkPath path;
+ quad[0].fX = x;
+ path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
+ canvas->drawPath(path, paint);
+ canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
+ canvas->translate(100, 100);
+ }
+}
+##
+
+#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
+
+#Enum Convexity ##
+
+#Method Convexity getConvexity() const
+
+Computes Convexity if required, and returns stored value.
+Convexity is computed if stored value is kUnknown_Convexity,
+or if Path has been altered since Convexity was computed or set.
+
+#Return Computed or stored Convexity. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkDebugf("%s path convexity is %s\n", prefix,
+ SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
+ SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
+ SkPath path;
+ debugster("initial", path);
+ path.lineTo(50, 0);
+ debugster("first line", path);
+ path.lineTo(50, 50);
+ debugster("second line", path);
+ path.lineTo(100, 50);
+ debugster("third line", path);
+}
+##
+
+#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method Convexity getConvexityOrUnknown() const
+
+Returns last computed Convexity, or kUnknown_Convexity if
+Path has been altered since Convexity was computed or set.
+
+#Return Stored Convexity. ##
+
+#Example
+#Description
+Convexity is unknown unless getConvexity is called without a subsequent call
+that alters the path.
+##
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkDebugf("%s path convexity is %s\n", prefix,
+ SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
+ SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
+ SkPath path;
+ debugster("initial", path);
+ path.lineTo(50, 0);
+ debugster("first line", path);
+ path.getConvexity();
+ path.lineTo(50, 50);
+ debugster("second line", path);
+ path.lineTo(100, 50);
+ path.getConvexity();
+ debugster("third line", path);
+}
+##
+
+#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void setConvexity(Convexity 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 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. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkDebugf("%s path convexity is %s\n", prefix,
+ SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
+ SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
+ SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
+ SkPath path;
+ path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
+ debugster("initial", path);
+ path.setConvexity(SkPath::kConcave_Convexity);
+ debugster("after forcing concave", path);
+ path.setConvexity(SkPath::kUnknown_Convexity);
+ debugster("after forcing unknown", path);
+}
+##
+
+#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isConvex() const
+
+Computes 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, Convexity is not recomputed.
+
+#Return true if Convexity stored or computed is kConvex_Convexity. ##
+
+#Example
+#Description
+Concave shape is erroneously considered convex after a forced call to
+setConvexity.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
+ for (SkScalar x : { 40, 100 } ) {
+ SkPath path;
+ quad[0].fX = x;
+ path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
+ path.setConvexity(SkPath::kConvex_Convexity);
+ canvas->drawPath(path, paint);
+ canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
+ canvas->translate(100, 100);
+ }
+}
+##
+
+#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void setIsConvex(bool isConvex)
+
+#Deprecated
+Use setConvexity.
+##
+
+##
+
+#Subtopic Convexity ##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isOval(SkRect* rect, Direction* dir = nullptr,
+ unsigned* start = nullptr) const
+
+Path is Oval if constructed by addCircle, addOval; and in some cases,
+addRoundRect, addRRect. Path constructed with conicTo or rConicTo will not
+return true though Path draws Oval.
+
+isOval triggers performance optimizations on some GPU_Surface implementations.
+
+#Param rect storage for bounding Rect of Oval. Oval is Circle if rect width
+equals rect height. Unwritten if Path is not Oval. May be nullptr.
+##
+#Param dir storage for Direction; kCW_Direction if clockwise, kCCW_Direction if
+counterclockwise. Unwritten if Path is not Oval. May be nullptr.
+##
+#Param start storage for start of Oval: 0 for top,
+1 for right, 2 for bottom, 3 for left. Unwritten if Path is not Oval. May be nullptr.
+##
+
+#Return true if Path was constructed by method that reduces to Oval. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPath path;
+ path.addOval({20, 20, 220, 220}, SkPath::kCW_Direction, 1);
+ SkRect bounds;
+ SkPath::Direction direction;
+ unsigned start;
+ path.isOval(&bounds, &direction, &start);
+ paint.setColor(0xFF9FBFFF);
+ canvas->drawRect(bounds, paint);
+ paint.setColor(0x3f000000);
+ canvas->drawPath(path, paint);
+ paint.setColor(SK_ColorBLACK);
+ canvas->rotate(start * 90, bounds.centerX(), bounds.centerY());
+ char startText = '0' + start;
+ paint.setTextSize(20);
+ canvas->drawText(&startText, 1, bounds.centerX(), bounds.fTop + 20, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(4);
+ path.reset();
+ path.addArc(bounds, -90, SkPath::kCW_Direction == direction ? 90 : -90);
+ path.rLineTo(20, -20);
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso Oval addCircle addOval
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isRRect(SkRRect* rrect, Direction* dir = nullptr,
+ unsigned* start = nullptr) const
+
+Path is Round_Rect if constructed by addRoundRect, addRRect; and if construction
+is not empty, not Rect, and not Oval. Path constructed with other other calls
+will not return true though Path draws Round_Rect.
+
+isRRect triggers performance optimizations on some GPU_Surface implementations.
+
+#Param rrect storage for bounding Rect of Round_Rect.
+Unwritten if Path is not Round_Rect. May be nullptr.
+##
+#Param dir storage for Direction; kCW_Direction if clockwise, kCCW_Direction if
+counterclockwise. Unwritten if Path is not Round_Rect. May be nullptr.
+##
+#Param start storage for start of Round_Rect: 0 for top,
+1 for right, 2 for bottom, 3 for left. Unwritten if Path is not Round_Rect. May be nullptr.
+##
+
+#Return true for Round_Rect Path constructed by addRoundRect or addRRect. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPath path;
+ path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50), SkPath::kCCW_Direction, 3);
+ SkRRect rrect;
+ SkPath::Direction direction;
+ unsigned start;
+ path.isRRect(&rrect, &direction, &start);
+ const SkRect& bounds = rrect.rect();
+ paint.setColor(0xFF9FBFFF);
+ canvas->drawRect(bounds, paint);
+ paint.setColor(0x3f000000);
+ canvas->drawPath(path, paint);
+ paint.setColor(SK_ColorBLACK);
+ canvas->rotate(start * 90, bounds.centerX(), bounds.centerY());
+ char startText = '0' + start;
+ paint.setTextSize(20);
+ canvas->drawText(&startText, 1, bounds.centerX(), bounds.fTop + 20, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(4);
+ path.reset();
+ path.addArc(bounds, -90, SkPath::kCW_Direction == direction ? 90 : -90);
+ path.rLineTo(20, -20);
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso Round_Rect addRoundRect addRRect
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void reset()
+
+Sets Path to its intial state.
+Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
+Internal storage associated with Path is released.
+
+#Example
+ SkPath path1, path2;
+ path1.setFillType(SkPath::kInverseWinding_FillType);
+ path1.addRect({10, 20, 30, 40});
+ SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
+ path1.reset();
+ SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
+##
+
+#SeeAlso rewind()
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void rewind()
+
+Sets Path to its intial state, preserving internal storage.
+Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
+Internal storage associated with Path is retained.
+
+Use rewind() instead of reset() if Path storage will be reused and performance
+is critical.
+
+#Example
+#Description
+Although path1 retains its internal storage, it is indistinguishable from
+a newly initialized path.
+##
+ SkPath path1, path2;
+ path1.setFillType(SkPath::kInverseWinding_FillType);
+ path1.addRect({10, 20, 30, 40});
+ SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
+ path1.rewind();
+ SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
+##
+
+#SeeAlso reset()
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isEmpty() const
+
+Empty Path may have FillType but has no SkPoint, Verb, or Conic_Weight.
+SkPath() constructs empty Path; reset() and (rewind) make Path empty.
+
+#Return true if the path contains no Verb array. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
+ };
+ SkPath path;
+ debugster("initial", path);
+ path.moveTo(0, 0);
+ debugster("after moveTo", path);
+ path.rewind();
+ debugster("after rewind", path);
+ path.lineTo(0, 0);
+ debugster("after lineTo", path);
+ path.reset();
+ debugster("after reset", path);
+}
+#StdOut
+initial path is empty
+after moveTo path is not empty
+after rewind path is empty
+after lineTo path is not empty
+after reset path is empty
+##
+##
+
+#SeeAlso SkPath() reset() rewind()
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isLastContourClosed() const
+
+Contour is closed if Path Verb array was last modified by close(). When stroked,
+closed Contour draws Paint_Stroke_Join instead of Paint_Stroke_Cap at first and last Point.
+
+#Return true if the last Contour ends with a kClose_Verb. ##
+
+#Example
+#Description
+close() has no effect if Path is empty; isLastContourClosed() returns
+false until Path has geometry followed by close().
+##
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkDebugf("%s last contour is %s" "closed\n", prefix,
+ path.isLastContourClosed() ? "" : "not ");
+ };
+ SkPath path;
+ debugster("initial", path);
+ path.close();
+ debugster("after close", path);
+ path.lineTo(0, 0);
+ debugster("after lineTo", path);
+ path.close();
+ debugster("after close", path);
+}
+#StdOut
+initial last contour is not closed
+after close last contour is not closed
+after lineTo last contour is not closed
+after close last contour is closed
+##
+##
+
+#SeeAlso close()
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isFinite() const
+
+Finite Point array values are between negative SK_ScalarMax and
+positive SK_ScalarMax. Any Point array value of
+SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN
+cause isFinite to return false.
+
+#Return true if all Point values are finite. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
+ };
+ SkPath path;
+ debugster("initial", path);
+ path.lineTo(SK_ScalarMax, SK_ScalarMax);
+ debugster("after line", path);
+ SkMatrix matrix;
+ matrix.setScale(2, 2);
+ path.transform(matrix);
+ debugster("after scale", path);
+}
+#StdOut
+initial path is finite
+after line path is finite
+after scale path is not finite
+##
+##
+
+#SeeAlso SkScalar
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isVolatile() const
+
+Returns true if the path is volatile; it will not be altered or discarded
+by the caller after it is drawn. Paths by default have volatile set false, allowing
+Surface to attach a cache of data which speeds repeated drawing. If true, Surface
+may not speed repeated drawing.
+
+#Return true if caller will alter Path after drawing. ##
+
+#Example
+ SkPath path;
+ SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
+#StdOut
+volatile by default is false
+##
+##
+
+#SeeAlso setIsVolatile
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void setIsVolatile(bool isVolatile)
+
+Specify whether Path is volatile; whether it will be altered or discarded
+by the caller after it is drawn. Paths by default have volatile set false, allowing
+Device to attach a cache of data which speeds repeated drawing.
+
+Mark temporary paths, discarded or modified after use, as volatile
+to inform Device that the path need not be cached.
+
+Mark animating Path volatile to improve performance.
+Mark unchanging Path non-volative to improve repeated rendering.
+
+Raster_Surface Path draws are affected by volatile for some shadows.
+GPU_Surface Path draws are affected by volatile for some shadows and concave geometries.
+
+#Param isVolatile true if caller will alter Path after drawing. ##
+
+#Example
+#Height 50
+#Width 50
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPath path;
+ path.setIsVolatile(true);
+ path.lineTo(40, 40);
+ canvas->drawPath(path, paint);
+ path.rewind();
+ path.moveTo(0, 40);
+ path.lineTo(40, 0);
+ canvas->drawPath(path, paint);
+##
+
+#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
+
+#SeeAlso isVolatile
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
+
+Test if Line between Point pair is degenerate.
+Line with no length or that moves a very short distance is degenerate; it is
+treated as a point.
+
+#Param p1 Line start point. ##
+#Param p2 Line end point. ##
+#Param exact If true, returns true only if p1 equals p2. If false, returns true
+ if p1 equals or nearly equals p2.
+##
+
+#Return true if Line is degenerate; its length is effectively zero. ##
+
+#Example
+#Description
+As single precision floats, 100 and 100.000001f have the same bit representation,
+and are exactly equal. 100 and 100.0001f have different bit representations, and
+are not exactly equal, but are nearly equal.
+##
+void draw(SkCanvas* canvas) {
+ SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
+ for (bool exact : { false, true } ) {
+ SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
+ points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
+ SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
+ ? "" : "not ", exact ? "exactly" : "nearly");
+ }
+ }
+}
+#StdOut
+line from (100,100) to (100,100) is degenerate, nearly
+line from (100,100) to (100,100) is degenerate, exactly
+line from (100,100) to (100.0001,100.0001) is degenerate, nearly
+line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
+#StdOut ##
+##
+
+#SeeAlso IsQuadDegenerate IsCubicDegenerate SkPoint::equalsWithinTolerance
+##
+
+# ------------------------------------------------------------------------------
+
+#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
+ const SkPoint& p3, bool exact)
+
+Test if Quad is degenerate.
+Quad with no length or that moves a very short distance is degenerate; it is
+treated as a point.
+
+#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. ##
+
+#Example
+#Description
+As single precision floats: 100, 100.00001f, and 100.00002f have different bit representations
+but nearly the same value. Translating all three by 1000 gives them the same bit representation;
+the fractional portion of the number can't be represented by the float and is lost.
+##
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const SkPath& path, bool exact) -> void {
+ SkDebugf("quad (%1.8g,%1.8g), (%1.8g,%1.8g), (%1.8g,%1.8g) is %s" "degenerate, %s\n",
+ path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
+ path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
+ SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
+ "" : "not ", exact ? "exactly" : "nearly");
+ };
+ SkPath path, offset;
+ path.moveTo({100, 100});
+ path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
+ offset.addPath(path, 1000, 1000);
+ for (bool exact : { false, true } ) {
+ debugster(path, exact);
+ debugster(offset, exact);
+ }
+}
+#StdOut
+quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
+quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
+quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
+quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
+#StdOut ##
+##
+
+#SeeAlso IsLineDegenerate IsCubicDegenerate SkPoint::equalsWithinTolerance
+##
+
+# ------------------------------------------------------------------------------
+
+#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
+ const SkPoint& p3, const SkPoint& p4, bool exact)
+
+Test if Cubic is degenerate.
+Cubic with no length or that moves a very short distance is degenerate; it is
+treated as a point.
+
+#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. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
+ SkScalar step = 1;
+ SkScalar prior, length, degenerate;
+ do {
+ prior = points[0].fX;
+ step /= 2;
+ if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
+ degenerate = prior;
+ points[0].fX += step;
+ } else {
+ length = prior;
+ points[0].fX -= step;
+ }
+ } while (prior != points[0].fX);
+ SkDebugf("%1.8g is degenerate\n", degenerate);
+ SkDebugf("%1.8g is length\n", length);
+}
+#StdOut
+0.00024414062 is degenerate
+0.00024414065 is length
+#StdOut ##
+##
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isLine(SkPoint line[2]) const
+
+Returns true if Path contains only one Line;
+Path_Verb array has two entries: kMove_Verb, kLine_Verb.
+If Path contains one Line and line is not nullptr, line is set to
+Line start point and Line end point.
+Returns false if Path is not one Line; line is unaltered.
+
+#Param line storage for Line. May be nullptr. ##
+
+#Return true if Path contains exactly one Line. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkPoint line[2];
+ if (path.isLine(line)) {
+ SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
+ line[0].fX, line[0].fY, line[1].fX, line[1].fY);
+ } else {
+ SkDebugf("%s is not line\n", prefix);
+ }
+ };
+ SkPath path;
+ debugster("empty", path);
+ path.lineTo(0, 0);
+ debugster("zero line", path);
+ path.rewind();
+ path.moveTo(10, 10);
+ path.lineTo(20, 20);
+ debugster("line", path);
+ path.moveTo(20, 20);
+ debugster("second move", path);
+}
+#StdOut
+empty is not line
+zero line is line (0,0) (0,0)
+line is line (10,10) (20,20)
+second move is not line
+##
+##
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Subtopic Point_Array +#Alias Point_Arrays + +Point_Array contains Points satisfying the allocated Points for +each Verb in Verb_Array. For instance, Path containing one Contour with Line +and Quad is described by Verb_Array: move to, line to, quad to; and +one Point for move, one Point for Line, two Points for Quad; totaling four Points. + +Point_Array may be read directly from Path with getPoints, or inspected with +getPoint, with Iter, or with RawIter. +
+#Method int getPoints(SkPoint points[], int max) const
+
+Returns number of points in Path. 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 storage for Path Point array. May be nullptr. ##
+#Param max Number of points alloted in points storage; must be greater than or equal to zero. ##
+
+#Return Path Point array length. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
+ int count = path.getPoints(points, max);
+ SkDebugf("%s point count: %d ", prefix, count);
+ for (int i = 0; i < SkTMin(count, max) && points; ++i) {
+ SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
+ }
+ SkDebugf("\n");
+ };
+ SkPath path;
+ path.lineTo(20, 20);
+ path.lineTo(-10, -10);
+ SkPoint points[3];
+ debugster("no points", path, nullptr, 0);
+ debugster("zero max", path, points, 0);
+ debugster("too small", path, points, 2);
+ debugster("just right", path, points, path.countPoints());
+}
+#StdOut
+no points point count: 3
+zero max point count: 3
+too small point count: 3 (0,0) (20,20)
+just right point count: 3 (0,0) (20,20) (-10,-10)
+##
+##
+
+#SeeAlso countPoints getPoint
+##
+
+#Method int countPoints() const
+
+Returns the number of points in Path.
+Point count is initially zero.
+
+#Return Path Point array length. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkDebugf("%s point count: %d\n", prefix, path.countPoints());
+ };
+ SkPath path;
+ debugster("empty", path);
+ path.lineTo(0, 0);
+ debugster("zero line", path);
+ path.rewind();
+ path.moveTo(10, 10);
+ path.lineTo(20, 20);
+ debugster("line", path);
+ path.moveTo(20, 20);
+ debugster("second move", path);
+}
+#StdOut
+empty point count: 0
+zero line point count: 2
+line point count: 2
+second move point count: 3
+##
+##
+
+#SeeAlso getPoints
+##
+
+#Method SkPoint getPoint(int index) const
+
+Returns Point at index in Point_Array. Valid range for index is
+0 to countPoints - 1.
+If the index is out of range, getPoint returns (0, 0).
+
+#Param index Point_Array element selector. ##
+
+#Return Point_Array value or (0, 0). ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkDebugf("%s point count: %d\n", prefix, path.countPoints());
+ };
+ SkPath path;
+ path.lineTo(20, 20);
+ path.offset(-10, -10);
+ for (int i= 0; i < path.countPoints(); ++i) {
+ SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
+ }
+}
+#StdOut
+point 0: (-10,-10)
+point 1: (10,10)
+##
+##
+
+#SeeAlso countPoints getPoints
+##
+
+
+#Subtopic Point_Array ##
+
+# ------------------------------------------------------------------------------
+#Subtopic Verb_Array + +Verb_Array always starts with kMove_Verb. +If kClose_Verb is not the last entry, it is always followed by kMove_Verb; +the quantity of kMove_Verb equals the Contour count. +Verb_Array does not include or count kDone_Verb; it is a convenience +returned when iterating through Verb_Array. + +Verb_Array may be read directly from Path with getVerbs, or inspected with Iter, +or with RawIter. +
+#Method int countVerbs() const
+
+Returns the number of Verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
+kCubic_Verb, and kClose_Verb; added to Path.
+
+#Return Length of Verb_Array. ##
+
+#Example
+SkPath path;
+SkDebugf("empty verb count: %d\n", path.countVerbs());
+path.addRoundRect({10, 20, 30, 40}, 5, 5);
+SkDebugf("round rect verb count: %d\n", path.countVerbs());
+#StdOut
+empty verb count: 0
+round rect verb count: 10
+##
+##
+
+#SeeAlso getVerbs Iter RawIter
+
+##
+
+#Method int getVerbs(uint8_t verbs[], int max) 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 ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
+ int count = path.getVerbs(verbs, max);
+ SkDebugf("%s verb count: %d ", prefix, count);
+ const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
+ for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
+ SkDebugf("%s ", verbStr[verbs[i]]);
+ }
+ SkDebugf("\n");
+ };
+ SkPath path;
+ path.lineTo(20, 20);
+ path.lineTo(-10, -10);
+ uint8_t verbs[3];
+ debugster("no verbs", path, nullptr, 0);
+ debugster("zero max", path, verbs, 0);
+ debugster("too small", path, verbs, 2);
+ debugster("just right", path, verbs, path.countVerbs());
+}
+#StdOut
+no verbs verb count: 3
+zero max verb count: 3
+too small verb count: 3 move line
+just right verb count: 3 move line line
+##
+##
+
+#SeeAlso countVerbs getPoints Iter RawIter
+##
+ +#Subtopic Verb_Array ## +
+# ------------------------------------------------------------------------------
+
+#Method void swap(SkPath& other)
+
+Exchanges the Verb_Array, Point_Array, Weights, and Fill_Type 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).
+Paths do not copy their content on assignment util they are written to,
+making assignment as efficient as swap().
+
+#Param other Path exchanged by value. ##
+
+#Example
+SkPath path1, path2;
+path1.addRect({10, 20, 30, 40});
+path1.swap(path2);
+const SkRect& b1 = path1.getBounds();
+SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
+const SkRect& b2 = path2.getBounds();
+SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
+#StdOut
+path1 bounds = 0, 0, 0, 0
+path2 bounds = 10, 20, 30, 40
+#StdOut ##
+##
+
+#SeeAlso operator=(const SkPath& path)
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method const SkRect& getBounds() const
+
+Returns minimum and maximum x and y values of Point_Array. If Path contains
+no points, getBounds returns (0, 0, 0, 0). Returned bounds width and height may
+be larger or smaller than area affected when Path is drawn.
+
+getBounds includes all Points added to Path, including Points associated with
+kMove_Verb that define empty Contours.
+
+#Return bounds of all Points in Point_Array. ##
+
+#Example
+#Description
+Bounds of upright Circle can be predicted from center and radius.
+Bounds of rotated Circle includes control Points outside of filled area.
+##
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ const SkRect& bounds = path.getBounds();
+ SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
+ bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+ };
+ SkPath path;
+ debugster("empty", path);
+ path.addCircle(50, 45, 25);
+ debugster("circle", path);
+ SkMatrix matrix;
+ matrix.setRotate(45, 50, 45);
+ path.transform(matrix);
+ debugster("rotated circle", path);
+#StdOut
+empty bounds = 0, 0, 0, 0
+circle bounds = 25, 20, 75, 70
+rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
+##
+##
+
+#SeeAlso computeTightBounds updateBoundsCache
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void updateBoundsCache() const
+
+Update internal bounds so that subsequent calls to getBounds are instantaneous.
+Unaltered copies of Path may also access cached bounds through getBounds.
+
+For now, updateBoundsCache is identical to getBounds, where the
+returned value is ignored.
+
+updateBoundsCache prepares a Path subsequently drawn from multiple threads,
+to avoid a race condition where each draw separately computes the bounds.
+
+#Example
+ double times[2] = { 0, 0 };
+ for (int i = 0; i < 10000; ++i) {
+ SkPath path;
+ for (int j = 1; j < 100; ++ j) {
+ path.addCircle(50 + j, 45 + j, 25 + j);
+ }
+ if (1 & i) {
+ path.updateBoundsCache();
+ }
+ double start = SkTime::GetNSecs();
+ (void) path.getBounds();
+ times[1 & i] += SkTime::GetNSecs() - start;
+ }
+ SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
+ SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
+#StdOut
+#Volatile
+uncached avg: 0.18048 ms
+cached avg: 0.182784 ms
+##
+##
+
+#SeeAlso getBounds
+#ToDo the results don't make sense, need to profile to figure this out ##
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method SkRect computeTightBounds() const
+
+Returns minimum and maximum x and y values of the lines and curves in Path.
+If Path contains no points, computeTightBounds returns (0, 0, 0, 0).
+Returned bounds width and height may be larger or smaller than area affected
+when Path is drawn.
+
+computeTightBounds behaves identically to getBounds when Path contains
+only lines. If Path contains curves, compute computeTightBounds includes
+the maximum extent of the Quad, Conic, or Cubic; is slower,
+and does not cache the result.
+
+Like getBounds, computeTightBounds includes Points associated with
+kMove_Verb that define empty Contours.
+
+#Return ##
+
+#Example
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ const SkRect& bounds = path.computeTightBounds();
+ SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
+ bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+ };
+ SkPath path;
+ debugster("empty", path);
+ path.addCircle(50, 45, 25);
+ debugster("circle", path);
+ SkMatrix matrix;
+ matrix.setRotate(45, 50, 45);
+ path.transform(matrix);
+ debugster("rotated circle", path);
+#StdOut
+empty bounds = 0, 0, 0, 0
+circle bounds = 25, 20, 75, 70
+rotated circle bounds = 25, 20, 75, 70
+##
+##
+
+#SeeAlso getBounds
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool conservativelyContainsRect(const SkRect& rect) const
+
+Returns true if rect is contained by Path.
+May return false when rect is contained by Path.
+
+For now, only returns true if Path has one Contour and is convex.
+rect may share points and edges with Path and be contained.
+If rect is empty, that is, it has zero width or height; conservativelyContainsRect
+returns true if the Point or Line described by rect is contained by Path.
+
+#Param rect Rect, Line, or Point checked for containment. ##
+
+#Return true if rect is contained. ##
+
+#Example
+#Height 140
+#Description
+Rect is drawn in blue if it is contained by red Path.
+##
+void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.addRoundRect({10, 20, 54, 120}, 10, 20);
+ SkRect tests[] = {
+ { 10, 40, 54, 80 },
+ { 25, 20, 39, 120 },
+ { 15, 25, 49, 115 },
+ { 13, 27, 51, 113 },
+ };
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
+ SkPaint paint;
+ paint.setColor(SK_ColorRED);
+ canvas->drawPath(path, paint);
+ bool rectInPath = path.conservativelyContainsRect(tests[i]);
+ paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
+ canvas->drawRect(tests[i], paint);
+ canvas->translate(64, 0);
+ }
+}
+##
+
+#SeeAlso contains Op Rect Convexity
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void incReserve(unsigned extraPtCount)
+
+grows Path Verb_Array and Point_Array to contain extraPtCount additional Points.
+incReserve may improve performance and use less memory by
+reducing the number and size of allocations when creating Path.
+
+#Param extraPtCount number of additional Points to preallocate. ##
+
+#Example
+#Height 192
+void draw(SkCanvas* canvas) {
+ auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
+ path->moveTo(size, 0);
+ for (int i = 1; i < sides; i++) {
+ SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
+ path->lineTo(c * size, s * size);
+ }
+ path->close();
+ };
+ SkPath path;
+ path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
+ for (int sides = 3; sides < 10; ++sides) {
+ addPoly(sides, sides, &path);
+ }
+ SkMatrix matrix;
+ matrix.setScale(10, 10, -10, -10);
+ path.transform(matrix);
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso Point_Array
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void moveTo(SkScalar x, SkScalar y)
+
+Adds beginning of Contour at Point (x, y).
+
+#Param x x-coordinate of Contour start. ##
+#Param y y-coordinate of Contour start. ##
+
+#Example
+ #Width 140
+ #Height 100
+ void draw(SkCanvas* canvas) {
+ SkRect rect = { 20, 20, 120, 80 };
+ SkPath path;
+ path.addRect(rect);
+ path.moveTo(rect.fLeft, rect.fTop);
+ path.lineTo(rect.fRight, rect.fBottom);
+ path.moveTo(rect.fLeft, rect.fBottom);
+ path.lineTo(rect.fRight, rect.fTop);
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawPath(path, paint);
+ }
+##
+
+#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
+
+##
+
+#Method void moveTo(const SkPoint& p)
+
+Adds beginning of Contour at Point p.
+
+#Param p Contour start. ##
+
+#Example
+ #Width 128
+ #Height 128
+void draw(SkCanvas* canvas) {
+ SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
+ {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
+ SkPath path;
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
+ path.moveTo(data[i][0]);
+ path.lineTo(data[i][1]);
+ path.lineTo(data[i][2]);
+ }
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
+
+##
+
+#Method void rMoveTo(SkScalar dx, SkScalar dy)
+
+Adds beginning of Contour relative to Last_Point.
+If Path is empty, starts Contour at (dx, dy).
+Otherwise, start Contour at Last_Point offset by (dx, dy).
+rMoveTo stands for relative move to.
+
+#Param dx offset from Last_Point x to Contour start x. ##
+#Param dy offset from Last_Point y to Contour start y. ##
+
+#Example
+ #Height 100
+ SkPath path;
+ path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
+ path.rMoveTo(25, 2);
+ SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
+ path.rLineTo(arrow[i].fX, arrow[i].fY);
+ }
+ SkPaint paint;
+ canvas->drawPath(path, paint);
+ SkPoint lastPt;
+ path.getLastPt(&lastPt);
+ canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
+##
+
+#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void lineTo(SkScalar x, SkScalar y)
+
+Adds Line from Last_Point to (x, y). If Path is empty, or last Verb is
+kClose_Verb, Last_Point is set to (0, 0) before adding Line.
+
+lineTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
+lineTo then appends kLine_Verb to Verb_Array and (x, y) to Point_Array.
+
+#Param x end of added Line in x. ##
+#Param y end of added Line in y. ##
+
+#Example
+#Height 100
+###$
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextSize(72);
+ canvas->drawString("#", 120, 80, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(5);
+ SkPath path;
+ SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
+ SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
+ unsigned o = 0;
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
+ for (unsigned j = 0; j < 2; o++, j++) {
+ path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
+ path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
+ }
+ }
+ canvas->drawPath(path, paint);
+}
+$$$#
+##
+
+#SeeAlso Contour moveTo rLineTo addRect
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void lineTo(const SkPoint& p)
+
+Adds Line from Last_Point to Point p. If Path is empty, or last Verb is
+kClose_Verb, Last_Point is set to (0, 0) before adding Line.
+
+lineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
+lineTo then appends kLine_Verb to Verb_Array and Point p to Point_Array.
+
+#Param p end Point of added Line. ##
+
+#Example
+#Height 100
+ SkPath path;
+ SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
+ {40, 20}, {40, 80}, {60, 20}, {60, 80},
+ {20, 40}, {80, 40}, {20, 60}, {80, 60}};
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
+ path.moveTo(oxo[i]);
+ path.lineTo(oxo[i + 1]);
+ }
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawPath(path, paint);
+##
+
+#SeeAlso Contour moveTo rLineTo addRect
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void rLineTo(SkScalar dx, SkScalar dy)
+
+Adds Line from Last_Point to Vector (dx, dy). If Path is empty, or last Verb is
+kClose_Verb, Last_Point is set to (0, 0) before adding Line.
+
+rLineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
+rLineTo then appends kLine_Verb to Verb_Array and Line end to Point_Array.
+Line end is Last_Point plus Vector (dx, dy).
+rLineTo 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. ##
+
+#Example
+#Height 128
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPath path;
+ path.moveTo(10, 98);
+ SkScalar x = 0, y = 0;
+ for (int i = 10; i < 100; i += 5) {
+ x += i * ((i & 2) - 1);
+ y += i * (((i + 1) & 2) - 1);
+ path.rLineTo(x, y);
+
+ }
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso Contour moveTo lineTo addRect
+
+##
+
+# ------------------------------------------------------------------------------
+#Topic Quad + +Quad describes a quadratic Bezier, a second-order curve identical to a section +of a parabola. Quad begins at a start Point, curves towards a control Point, +and then curves to an end Point. + +#Example +#Height 110 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
+ canvas->drawLine(quadPts[0], quadPts[1], paint);
+ canvas->drawLine(quadPts[1], quadPts[2], paint);
+ SkPath path;
+ path.moveTo(quadPts[0]);
+ path.quadTo(quadPts[1], quadPts[2]);
+ paint.setStrokeWidth(3);
+ canvas->drawPath(path, paint);
+}
+## + +Quad is a special case of Conic where Conic_Weight is set to one. + +Quad is always contained by the triangle connecting its three Points. Quad +begins tangent to the line between start Point and control Point, and ends +tangent to the line between control Point and end Point. + +#Example +#Height 160 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
+ SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
+ paint.setColor(0x7fffffff & colors[i]);
+ paint.setStrokeWidth(1);
+ canvas->drawLine(quadPts[0], quadPts[1], paint);
+ canvas->drawLine(quadPts[1], quadPts[2], paint);
+ SkPath path;
+ path.moveTo(quadPts[0]);
+ path.quadTo(quadPts[1], quadPts[2]);
+ paint.setStrokeWidth(3);
+ paint.setColor(colors[i]);
+ canvas->drawPath(path, paint);
+ quadPts[1].fY += 30;
+ }
+} +## +
+#Method void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
+
+ Adds Quad from Last_Point towards (x1, y1), to (x2, y2).
+ If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
+ before adding Quad.
+
+ quadTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
+ quadTo then appends kQuad_Verb to Verb_Array; and (x1, y1), (x2, y2)
+ to Point_Array.
+
+ #Param x1 control Point of Quad in x. ##
+ #Param y1 control Point of Quad in y. ##
+ #Param x2 end Point of Quad in x. ##
+ #Param y2 end Point of Quad in y. ##
+
+ #Example
+ void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPath path;
+ path.moveTo(0, -10);
+ for (int i = 0; i < 128; i += 16) {
+ path.quadTo( 10 + i, -10 - i, 10 + i, 0);
+ path.quadTo( 14 + i, 14 + i, 0, 14 + i);
+ path.quadTo(-18 - i, 18 + i, -18 - i, 0);
+ path.quadTo(-22 - i, -22 - i, 0, -22 - i);
+ }
+ path.offset(128, 128);
+ canvas->drawPath(path, paint); + }
+ ##
+
+ #SeeAlso Contour moveTo conicTo rQuadTo
+
+##
+
+#Method void quadTo(const SkPoint& p1, const SkPoint& p2)
+
+ Adds Quad from Last_Point towards Point p1, to Point p2.
+ If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
+ before adding Quad.
+
+ quadTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
+ quadTo then appends kQuad_Verb to Verb_Array; and Points p1, p2
+ to Point_Array.
+
+ #Param p1 control Point of added Quad. ##
+ #Param p2 end Point of added Quad. ##
+
+ #Example
+ void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setAntiAlias(true);
+ SkPath path;
+ SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
+ path.moveTo(pts[1]);
+ for (int i = 0; i < 3; ++i) {
+ path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
+ }
+ canvas->drawPath(path, paint);
+ }
+ ##
+
+ #SeeAlso Contour moveTo conicTo rQuadTo
+
+##
+
+#Method void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
+
+ Adds Quad from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2).
+ If Path is empty, or last Verb
+ is kClose_Verb, Last_Point is set to (0, 0) before adding Quad.
+
+ rQuadTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
+ if needed. rQuadTo then appends kQuad_Verb to Verb_Array; and appends Quad
+ control and Quad end to Point_Array.
+ Quad control is Last_Point plus Vector (dx1, dy1).
+ Quad end is Last_Point plus Vector (dx2, dy2).
+ rQuadTo 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. ##
+
+ #Example
+ void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPath path;
+ path.moveTo(128, 20);
+ path.rQuadTo(-6, 10, -7, 10);
+ for (int i = 1; i < 32; i += 4) {
+ path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
+ path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
+ }
+ path.quadTo(92, 220, 128, 215);
+ canvas->drawPath(path, paint);
+ }
+ ##
+
+ #SeeAlso Contour moveTo conicTo quadTo
+
+##
+
+#Topic Quad ## +
+# ------------------------------------------------------------------------------
+
+#Topic Conic +#Alias Conics + +Conic describes a conical section: a piece of an ellipse, or a piece of a +parabola, or a piece of a hyperbola. Conic begins at a start Point, +curves towards a control Point, and then curves to an end Point. The influence +of the control Point is determined by Conic_Weight. + +Each Conic in Path adds two Points and one Weight. Weights in Path may be +inspected with Iter, or with RawIter. + +#Subtopic Weight +#Alias Weights + +Weight determines both the strength of the control Point and the type of Conic. +If Weight is exactly one, then Conic is identical to Quad; it is always a +parabolic segment. + + + +#Example +#Description +When Conic weight is one, Quad is added to path; the two are identical. +## +void draw(SkCanvas* canvas) {
+ const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
+ const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
+ SkPath path;
+ path.conicTo(20, 30, 50, 60, 1);
+ SkPath::Iter iter(path, false);
+ SkPath::Verb verb;
+ do {
+ SkPoint points[4];
+ verb = iter.next(points);
+ SkDebugf("%s ", verbNames[(int) verb]);
+ for (int i = 0; i < pointCount[(int) verb]; ++i) {
+ SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
+ }
+ if (SkPath::kConic_Verb == verb) {
+ SkDebugf("weight = %g", iter.conicWeight());
+ }
+ SkDebugf("\n");
+ } while (SkPath::kDone_Verb != verb);
+} +#StdOut +move {0, 0},
+quad {0, 0}, {20, 30}, {50, 60},
+done +## +## + +If weight is less than one, Conic is an elliptical segment. + +#Example +#Description +A 90 degree circular arc has the weight +#Formula +1 / sqrt(2) +## + . +## +void draw(SkCanvas* canvas) {
+ const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
+ const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
+ SkPath path;
+ path.arcTo(20, 0, 20, 20, 20);
+ SkPath::Iter iter(path, false);
+ SkPath::Verb verb;
+ do {
+ SkPoint points[4];
+ verb = iter.next(points);
+ SkDebugf("%s ", verbNames[(int) verb]);
+ for (int i = 0; i < pointCount[(int) verb]; ++i) {
+ SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
+ }
+ if (SkPath::kConic_Verb == verb) {
+ SkDebugf("weight = %g", iter.conicWeight());
+ }
+ SkDebugf("\n");
+ } while (SkPath::kDone_Verb != verb);
+} +#StdOut +move {0, 0},
+conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
+done +## +## + +If weight is greater than one, Conic is a hyperbolic segment. As w gets large, +a hyperbolic segment can be approximated by straight lines connecting the +control Point with the end Points. + +#Example +void draw(SkCanvas* canvas) {
+ const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
+ const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
+ SkPath path;
+ path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
+ SkPath::Iter iter(path, false);
+ SkPath::Verb verb;
+ do {
+ SkPoint points[4];
+ verb = iter.next(points);
+ SkDebugf("%s ", verbNames[(int) verb]);
+ for (int i = 0; i < pointCount[(int) verb]; ++i) {
+ SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
+ }
+ if (SkPath::kConic_Verb == verb) {
+ SkDebugf("weight = %g", iter.conicWeight());
+ }
+ SkDebugf("\n");
+ } while (SkPath::kDone_Verb != verb);
+} +#StdOut +move {0, 0},
+line {0, 0}, {20, 0},
+line {20, 0}, {20, 20},
+done +## +## + +#Subtopic Weight ## +
+#Method void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
+ SkScalar w)
+
+ Adds Conic from Last_Point towards (x1, y1), to (x2, y2), weighted by w.
+ If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
+ before adding Conic.
+
+ conicTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
+
+ If w is finite and not one, conicTo then appends kConic_Verb to Verb_Array;
+ and (x1, y1), (x2, y2) to Point_Array; and w to Weights.
+
+ If w is one, conicTo appends kQuad_Verb to Verb_Array, and
+ (x1, y1), (x2, y2) to Point_Array.
+
+ If w is not finite, conicTo appends kLine_Verb twice to Verb_Array, and
+ (x1, y1), (x2, y2) to Point_Array.
+
+ #Param x1 control Point of Conic in x. ##
+ #Param y1 control Point of Conic in y. ##
+ #Param x2 end Point of Conic in x. ##
+ #Param y2 end Point of Conic in y. ##
+ #Param w weight of added Conic. ##
+
+ #Example
+ #Height 160 + #Description
+ As weight increases, curve is pulled towards control point.
+ The bottom two curves are elliptical; the next is parabolic; the
+ top curve is hyperbolic.
+ ##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
+ canvas->drawLine(conicPts[0], conicPts[1], paint);
+ canvas->drawLine(conicPts[1], conicPts[2], paint);
+ SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
+ paint.setStrokeWidth(3);
+ SkScalar weight = 0.5f;
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
+ SkPath path;
+ path.moveTo(conicPts[0]);
+ path.conicTo(conicPts[1], conicPts[2], weight);
+ paint.setColor(colors[i]);
+ canvas->drawPath(path, paint);
+ weight += 0.25f;
+ }
+}
+ ##
+
+ #SeeAlso rConicTo arcTo addArc quadTo
+
+##
+
+#Method void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
+
+ Adds Conic from Last_Point towards Point p1, to Point p2, weighted by w.
+ If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
+ before adding Conic.
+
+ conicTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
+
+ If w is finite and not one, conicTo then appends kConic_Verb to Verb_Array;
+ and Points p1, p2 to Point_Array; and w to Weights.
+
+ If w is one, conicTo appends kQuad_Verb to Verb_Array, and Points p1, p2
+ to Point_Array.
+
+ If w is not finite, conicTo appends kLine_Verb twice to Verb_Array, and
+ Points p1, p2 to Point_Array.
+
+ #Param p1 control Point of added Conic. ##
+ #Param p2 end Point of added Conic. ##
+ #Param w weight of added Conic. ##
+
+ #Example
+ #Height 128 + #Description
+ Conics and arcs use identical representations. As the arc sweep increases
+ the conic weight also increases, but remains smaller than one.
+ ##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkRect oval = {0, 20, 120, 140};
+ SkPath path;
+ for (int i = 0; i < 4; ++i) {
+ path.moveTo(oval.centerX(), oval.fTop);
+ path.arcTo(oval, -90, 90 - 20 * i, false);
+ oval.inset(15, 15);
+ }
+ path.offset(100, 0);
+ SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
+ SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
+ { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
+ { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
+ { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
+ for (int i = 0; i < 4; ++i) {
+ path.moveTo(conicPts[i][0]);
+ path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
+ }
+ canvas->drawPath(path, paint);
+}
+ ##
+
+ #SeeAlso rConicTo arcTo addArc quadTo
+
+##
+
+#Method void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
+ SkScalar w)
+
+ Adds Conic from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2),
+ weighted by w. If Path is empty, or last Verb
+ is kClose_Verb, Last_Point is set to (0, 0) before adding Conic.
+
+ rConicTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
+ if needed.
+
+ If w is finite and not one, rConicTo then appends kConic_Verb to Verb_Array,
+ and w is recorded as Conic_Weight; otherwise, if w is one, rConicTo appends
+ kQuad_Verb to Verb_Array; or if w is not finite, rConicTo appends kLine_Verb
+ twice to Verb_Array.
+
+ In all cases rConicTo then appends Points control and end to Point_Array.
+ control is Last_Point plus Vector (dx1, dy1).
+ end is Last_Point plus Vector (dx2, dy2).
+
+ rConicTo 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. ##
+
+ #Example
+ #Height 140
+ void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPath path;
+ path.moveTo(20, 80);
+ path.rConicTo( 60, 0, 60, 60, 0.707107f);
+ path.rConicTo( 0, -60, 60, -60, 0.707107f);
+ path.rConicTo(-60, 0, -60, -60, 0.707107f);
+ path.rConicTo( 0, 60, -60, 60, 0.707107f);
+ canvas->drawPath(path, paint);
+ }
+ ##
+
+ #SeeAlso conicTo arcTo addArc quadTo
+
+##
+
+#Topic Conic ##
+
+# ------------------------------------------------------------------------------
+#Topic Cubic +#Alias Cubics + +Cubic describes a cubic Bezier, a third-order curve. +Cubic begins at a start Point, curving towards the first control Point; +and curves from the end Point towards the second control Point. + +#Example +#Height 160 +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
+ SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
+ paint.setColor(0x7fffffff & colors[i]);
+ paint.setStrokeWidth(1);
+ for (unsigned j = 0; j < 3; ++j) {
+ canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
+ }
+ SkPath path;
+ path.moveTo(cubicPts[0]);
+ path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
+ paint.setStrokeWidth(3);
+ paint.setColor(colors[i]);
+ canvas->drawPath(path, paint);
+ cubicPts[1].fY += 30;
+ cubicPts[2].fX += 30;
+ }
+} +## +
+#Method void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
+ SkScalar x3, SkScalar y3)
+
+Adds Cubic from Last_Point towards (x1, y1), then towards (x2, y2), ending at
+(x3, y3). If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
+(0, 0) before adding Cubic.
+
+cubicTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
+cubicTo then appends kCubic_Verb to Verb_Array; and (x1, y1), (x2, y2), (x3, y3)
+to Point_Array.
+
+#Param x1 first control Point of Cubic in x. ##
+#Param y1 first control Point of Cubic in y. ##
+#Param x2 second control Point of Cubic in x. ##
+#Param y2 second control Point of Cubic in y. ##
+#Param x3 end Point of Cubic in x. ##
+#Param y3 end Point of Cubic in y. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPath path;
+ path.moveTo(0, -10);
+ for (int i = 0; i < 128; i += 16) {
+ SkScalar c = i * 0.5f;
+ path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
+ path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
+ path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
+ path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
+ }
+ path.offset(128, 128);
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso Contour moveTo rCubicTo quadTo
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
+
+Adds Cubic from Last_Point towards Point p1, then towards Point p2, ending at
+Point p3. If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
+(0, 0) before adding Cubic.
+
+cubicTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
+cubicTo then appends kCubic_Verb to Verb_Array; and Points p1, p2, p3
+to Point_Array.
+
+#Param p1 first control Point of Cubic. ##
+#Param p2 second control Point of Cubic. ##
+#Param p3 end Point of Cubic. ##
+
+#Example
+#Height 84
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+ canvas->drawPath(path, paint);
+##
+
+#SeeAlso Contour moveTo rCubicTo quadTo
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
+ SkScalar x3, SkScalar y3)
+
+ Adds Cubic from Last_Point towards Vector (dx1, dy1), then towards
+ Vector (dx2, dy2), to Vector (dx3, dy3).
+ If Path is empty, or last Verb
+ is kClose_Verb, Last_Point is set to (0, 0) before adding Cubic.
+
+ rCubicTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
+ if needed. rCubicTo then appends kCubic_Verb to Verb_Array; and appends Cubic
+ control and Cubic end to Point_Array.
+ Cubic control is Last_Point plus Vector (dx1, dy1).
+ Cubic end is Last_Point plus Vector (dx2, dy2).
+ rCubicTo 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. ##
+
+#Example
+ void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ SkPath path;
+ path.moveTo(24, 108);
+ for (int i = 0; i < 16; i++) {
+ SkScalar sx, sy;
+ sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
+ path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
+ }
+ canvas->drawPath(path, paint);
+ }
+##
+
+#SeeAlso Contour moveTo cubicTo quadTo
+
+##
+
+#Topic Cubic ##
+
+# ------------------------------------------------------------------------------
+
+#Topic Arc
+
+Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
+by start point and end point, and by radius and tangent lines. Each construction has advantages,
+and some constructions correspond to Arc drawing in graphics standards.
+
+All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
+Conic describes an Arc of some Oval or Circle.
+
+arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
+describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
+which may continue Contour or start a new one. This construction is similar to PostScript and
+HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
+requiring Path.
+
+arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
+describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
+where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
+HTML_Canvas arcs.
+
+arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
+ SkScalar x, SkScalar y)
+describes Arc as part of Oval with radii (rx, ry), beginning at
+last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
+so additional values choose a single solution. This construction is similar to SVG arcs.
+
+conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
+conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
+constructions are converted to Conic data when added to Path.
+
+#ToDo allow example to hide source and not be exposed as fiddle since markdown / html can't
+ do the kind of table shown in the illustration.
+ example is spaced correctly on fiddle but spacing is too wide on pc
+##
+
+#Example
+#Height 300
+#Width 600
+#Description
+#List
+# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
+# <sup>2</sup> parameter sets force MoveTo ##
+# <sup>3</sup> start angle must be multiple of 90 degrees. ##
+# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
+# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
+ Direction sweep, SkScalar x, SkScalar y) ##
+#List ##
+#Description ##
+#Function
+struct data {
+ const char* name;
+ char super;
+ int yn[10];
+};
+
+const data dataSet[] = {
+{ "arcTo sweep", '1', {1, 3, 1, 0, 0, 0, 0, 1, 0, 0 }},
+{ "drawArc", 0, {1, -1, 1, 1, 1, 1, 1, 0, 0, 0 }},
+{ "addArc", 0, {1, 1, 1, 4, 0, 1, 1, 1, 0, 0 }},
+{ "arcTo tangents", '4', {0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }},
+{ "arcTo radii", '5', {1, 0, 1, 0, 0, 0, 0, 1, 1, 0 }},
+{ "conicTo", 0, {1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }}
+};
+
+#define __degree_symbol__ "\xC2" "\xB0"
+
+const char* headers[] = {
+ "Oval part",
+ "force moveTo",
+ "can draw 180" __degree_symbol__,
+ "can draw 360" __degree_symbol__,
+ "can draw greater than 360" __degree_symbol__,
+ "ignored if radius is zero",
+ "ignored if sweep is zero",
+ "requires Path",
+ "describes rotation",
+ "describes perspective",
+};
+
+const char* yna[] = {
+ "n/a",
+ "no",
+ "yes"
+};
+
+##
+void draw(SkCanvas* canvas) {
+ SkPaint lp;
+ lp.setAntiAlias(true);
+ SkPaint tp(lp);
+ SkPaint sp(tp);
+ SkPaint bp(tp);
+ bp.setFakeBoldText(true);
+ sp.setTextSize(10);
+ lp.setColor(SK_ColorGRAY);
+ canvas->translate(0, 32);
+ const int tl = 115;
+ for (unsigned col = 0; col <= SK_ARRAY_COUNT(headers); ++col) {
+ canvas->drawLine(tl + col * 35, 100, tl + col * 35, 250, lp);
+ if (0 == col) {
+ continue;
+ }
+ canvas->drawLine(tl + col * 35, 100, tl + 100 + col * 35, 0, lp);
+ SkPath path;
+ path.moveTo(tl - 3 + col * 35, 103);
+ path.lineTo(tl + 124 + col * 35, -24);
+ canvas->drawTextOnPathHV(headers[col -1], strlen(headers[col -1]), path, 0, -9, bp);
+ }
+ for (unsigned row = 0; row <= SK_ARRAY_COUNT(dataSet); ++row) {
+ if (0 == row) {
+ canvas->drawLine(tl, 100, tl + 350, 100, lp);
+ } else {
+ canvas->drawLine(5, 100 + row * 25, tl + 350, 100 + row * 25, lp);
+ }
+ if (row == SK_ARRAY_COUNT(dataSet)) {
+ break;
+ }
+ canvas->drawString(dataSet[row].name, 5, 117 + row * 25, bp);
+ if (dataSet[row].super) {
+ SkScalar width = bp.measureText(dataSet[row].name, strlen(dataSet[row].name));
+ canvas->drawText(&dataSet[row].super, 1, 8 + width, 112 + row * 25, sp);
+ }
+ for (unsigned col = 0; col < SK_ARRAY_COUNT(headers); ++col) {
+ int val = dataSet[row].yn[col];
+ canvas->drawString(yna[SkTMin(2, val + 1)], tl + 5 + col * 35, 117 + row * 25, tp);
+ if (val > 1) {
+ char supe = '0' + val - 1;
+ canvas->drawText(&supe, 1, tl + 25 + col * 35, 112 + row * 25, sp);
+ }
+ }
+ }
+}
+#Example ##
+
+#Example
+#Height 128
+#Description
+#ToDo make this a list or table ##
+1 describes an arc from an oval, a starting angle, and a sweep angle.
+2 is similar to 1, but does not require building a path to draw.
+3 is similar to 1, but always begins new Contour.
+4 describes an arc from a pair of tangent lines and a radius.
+5 describes an arc from Oval center, arc start Point and arc end Point.
+6 describes an arc from a pair of tangent lines and a Conic_Weight.
+##
+void draw(SkCanvas* canvas) {
+ SkRect oval = {8, 8, 56, 56};
+ SkPaint ovalPaint;
+ ovalPaint.setAntiAlias(true);
+ SkPaint textPaint(ovalPaint);
+ ovalPaint.setStyle(SkPaint::kStroke_Style);
+ SkPaint arcPaint(ovalPaint);
+ arcPaint.setStrokeWidth(5);
+ arcPaint.setColor(SK_ColorBLUE);
+ canvas->translate(-64, 0);
+ for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
+ '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
+ canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
+ canvas->drawOval(oval, ovalPaint);
+ SkPath path;
+ path.moveTo({56, 32});
+ switch (arcStyle) {
+ case '1':
+ path.arcTo(oval, 0, 90, false);
+ break;
+ case '2':
+ canvas->drawArc(oval, 0, 90, false, arcPaint);
+ continue;
+ case '3':
+ path.addArc(oval, 0, 90);
+ break;
+ case '4':
+ path.arcTo({56, 56}, {32, 56}, 24);
+ break;
+ case '5':
+ path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
+ break;
+ case '6':
+ path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
+ break;
+ }
+ canvas->drawPath(path, arcPaint);
+ }
+}
+#Example ##
+
+
+#Method void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
+
+Append Arc to Path. 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 Path last Point to initial Arc Point if forceMoveTo
+is false and Path 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. ##
+
+#Example
+#Height 200
+#Description
+arcTo continues a previous contour when forceMoveTo is false and when Path
+is not empty.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPath path;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(4);
+ path.moveTo(0, 0);
+ path.arcTo({20, 20, 120, 120}, -90, 90, false);
+ canvas->drawPath(path, paint);
+ path.rewind();
+ path.arcTo({120, 20, 220, 120}, -90, 90, false);
+ canvas->drawPath(path, paint);
+ path.rewind();
+ path.moveTo(0, 0);
+ path.arcTo({20, 120, 120, 220}, -90, 90, true);
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso addArc SkCanvas::drawArc conicTo
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
+
+Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
+weighted to describe part of Circle. Arc is contained by tangent from
+last Path 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.
+
+#ToDo allow example to hide source and not be exposed as fiddle ##
+
+#Example
+#Height 226
+void draw(SkCanvas* canvas) {
+ SkPaint tangentPaint;
+ tangentPaint.setAntiAlias(true);
+ SkPaint textPaint(tangentPaint);
+ tangentPaint.setStyle(SkPaint::kStroke_Style);
+ tangentPaint.setColor(SK_ColorGRAY);
+ SkPaint arcPaint(tangentPaint);
+ arcPaint.setStrokeWidth(5);
+ arcPaint.setColor(SK_ColorBLUE);
+ SkPath path;
+ SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
+ SkScalar radius = 50;
+ path.moveTo(pts[0]);
+ path.arcTo(pts[1], pts[2], radius);
+ canvas->drawLine(pts[0], pts[1], tangentPaint);
+ canvas->drawLine(pts[1], pts[2], tangentPaint);
+ SkPoint lastPt;
+ (void) path.getLastPt(&lastPt);
+ SkVector radial = pts[2] - pts[1];
+ radial.setLength(radius);
+ SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
+ canvas->drawCircle(center, radius, tangentPaint);
+ canvas->drawLine(lastPt, center, tangentPaint);
+ radial = pts[1] - pts[0];
+ radial.setLength(radius);
+ SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
+ canvas->drawLine(center, arcStart, tangentPaint);
+ canvas->drawPath(path, arcPaint);
+ textPaint.setTextAlign(SkPaint::kRight_Align);
+ canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
+ textPaint.setTextAlign(SkPaint::kLeft_Align);
+ canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
+ textPaint.setTextAlign(SkPaint::kCenter_Align);
+ canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
+ textPaint.setTextAlign(SkPaint::kRight_Align);
+ canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
+ canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
+}
+##
+
+If last Path Point does not start Arc, arcTo appends connecting Line to Path.
+The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
+
+#Example
+#Height 128
+void draw(SkCanvas* canvas) {
+ SkPaint tangentPaint;
+ tangentPaint.setAntiAlias(true);
+ SkPaint textPaint(tangentPaint);
+ tangentPaint.setStyle(SkPaint::kStroke_Style);
+ tangentPaint.setColor(SK_ColorGRAY);
+ SkPaint arcPaint(tangentPaint);
+ arcPaint.setStrokeWidth(5);
+ arcPaint.setColor(SK_ColorBLUE);
+ SkPath path;
+ SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
+ SkScalar radius = 50;
+ path.moveTo(pts[0]);
+ path.arcTo(pts[1], pts[2], radius);
+ canvas->drawLine(pts[0], pts[1], tangentPaint);
+ canvas->drawLine(pts[1], pts[2], tangentPaint);
+ SkPoint lastPt;
+ (void) path.getLastPt(&lastPt);
+ SkVector radial = pts[2] - pts[1];
+ radial.setLength(radius);
+ SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
+ canvas->drawLine(lastPt, center, tangentPaint);
+ radial = pts[1] - pts[0];
+ radial.setLength(radius);
+ SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
+ canvas->drawLine(center, arcStart, tangentPaint);
+ canvas->drawPath(path, arcPaint);
+ textPaint.setTextAlign(SkPaint::kCenter_Align);
+ canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
+ textPaint.setTextAlign(SkPaint::kLeft_Align);
+ canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
+ textPaint.setTextAlign(SkPaint::kCenter_Align);
+ canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
+ textPaint.setTextAlign(SkPaint::kRight_Align);
+ canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
+ canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
+}
+##
+
+Arc sweep is always less than 180 degrees. If radius is zero, or if
+tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
+
+arcTo appends at most one Line and one Conic.
+arcTo implements the functionality of PostScript_arct and HTML_Canvas_arcTo.
+
+#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. ##
+
+#Example
+#Description
+arcTo is represented by Line and circular Conic in Path.
+##
+void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.moveTo({156, 20});
+ path.arcTo(200, 20, 170, 50, 50);
+ SkPath::Iter iter(path, false);
+ SkPoint p[4];
+ SkPath::Verb verb;
+ while (SkPath::kDone_Verb != (verb = iter.next(p))) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
+ break;
+ case SkPath::kLine_Verb:
+ SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
+ break;
+ case SkPath::kConic_Verb:
+ SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
+ p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
+ break;
+ default:
+ SkDebugf("unexpected verb\n");
+ }
+ }
+}
+#StdOut
+move to (156,20)
+line (156,20),(79.2893,20)
+conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
+##
+##
+
+#SeeAlso conicTo
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
+
+Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
+weighted to describe part of Circle. Arc is contained by tangent from
+last Path 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 Path Point does not start Arc, arcTo appends connecting Line to Path.
+The length of Vector 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 Path Point to p1.
+
+arcTo appends at most one Line and one Conic.
+arcTo implements the functionality of PostScript_arct and HTML_Canvas_arcTo.
+
+#Param p1 Point common to pair of tangents. ##
+#Param p2 end of second tangent. ##
+#Param radius distance from Arc to Circle center. ##
+
+#Example
+#Description
+Because tangent lines are parallel, arcTo appends line from last Path Point to
+p1, but does not append a circular Conic.
+##
+void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.moveTo({156, 20});
+ path.arcTo({200, 20}, {170, 20}, 50);
+ SkPath::Iter iter(path, false);
+ SkPoint p[4];
+ SkPath::Verb verb;
+ while (SkPath::kDone_Verb != (verb = iter.next(p))) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
+ break;
+ case SkPath::kLine_Verb:
+ SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
+ break;
+ case SkPath::kConic_Verb:
+ SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
+ p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
+ break;
+ default:
+ SkDebugf("unexpected verb\n");
+ }
+ }
+}
+#StdOut
+move to (156,20)
+line (156,20),(200,20)
+##
+##
+
+#SeeAlso conicTo
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Enum ArcSize
+
+#Code
+ enum ArcSize {
+ kSmall_ArcSize
+ kLarge_ArcSize
+ };
+##
+
+Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
+ArcSize and Direction select one of the four Oval parts.
+
+#Const kSmall_ArcSize 0
+Smaller of Arc pair.
+##
+#Const kLarge_ArcSize 1
+Larger of Arc pair.
+##
+
+#Example
+#Height 160
+#Description
+Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
+Two routes are large, and two routes are counterclockwise. The one route both large
+and counterclockwise is blue.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
+ for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
+ SkPath path;
+ path.moveTo({120, 50});
+ path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
+ if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
+ paint.setColor(SK_ColorBLUE);
+ paint.setStrokeWidth(3);
+ }
+ canvas->drawPath(path, paint);
+ }
+ }
+}
+##
+
+#SeeAlso arcTo Direction
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
+ Direction sweep, SkScalar x, SkScalar y)
+
+Append Arc to Path. 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 Path Point 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 Path Point equals (x, y). arcTo scales radii (rx, ry) to fit last Path Point and
+(x, y) if both are greater than zero but too small.
+
+arcTo appends up to four Conic curves.
+arcTo implements the functionatlity 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; positve 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. ##
+
+#Example
+#Height 160
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
+ for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
+ SkPath path;
+ path.moveTo({120, 50});
+ path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
+ if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
+ paint.setColor(SK_ColorBLUE);
+ paint.setStrokeWidth(3);
+ }
+ canvas->drawPath(path, paint);
+ }
+ }
+}
+##
+
+#SeeAlso rArcTo ArcSize Direction
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
+ const SkPoint xy)
+
+Append Arc to Path. 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 Path Point 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 Path Point equals (x, y). arcTo scales radii r to fit last Path Point and
+xy if both are greater than zero but too small.
+
+arcTo appends up to four Conic curves.
+arcTo implements the functionatlity 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; positve values are clockwise. ##
+#Param largeArc chooses smaller or larger Arc. ##
+#Param sweep chooses clockwise or counterclockwise Arc. ##
+#Param xy end of Arc. ##
+
+#Example
+#Height 108
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPath path;
+ const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
+ for (auto start : starts) {
+ path.moveTo(start.fX, start.fY);
+ path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
+ }
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso rArcTo ArcSize Direction
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
+ Direction sweep, SkScalar dx, SkScalar dy)
+
+Append Arc to Path, relative to last Path Point. 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 Path Point (x0, y0) to
+(x0 + dx, y0 + dy), choosing one of four possible routes: clockwise or
+counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
+is (0, 0).
+
+Arc sweep is always less than 360 degrees. arcTo appends Line to xy if either
+radii are zero, or if last Path Point equals (x, y). arcTo scales radii r to fit
+last Path Point and xy if both are greater than zero but too small.
+
+arcTo appends up to four Conic curves.
+arcTo implements the functionatlity 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; positve 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 Path Point. ##
+#Param dy y offset end of Arc from last Path Point. ##
+
+#Example
+#Height 108
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPath path;
+ const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
+ for (auto start : starts) {
+ path.moveTo(start.fX, start.fY);
+ path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
+ }
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso arcTo ArcSize Direction
+
+##
+
+#Topic Arc ##
+
+# ------------------------------------------------------------------------------
+
+#Method void close()
+
+Append kClose_Verb to Path. A closed Contour connects the first and last Point
+with Line, forming a continous loop. Open and closed Contour draw the same
+with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open Contour draws
+Paint_Stroke_Cap at Contour start and end; closed Contour draws
+Paint_Stroke_Join at Contour start and end.
+
+close() has no effect if Path is empty or last Path Verb is kClose_Verb.
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setStrokeWidth(15);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+ SkPath path;
+ const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
+ path.addPoly(points, SK_ARRAY_COUNT(points), false);
+ for (int loop = 0; loop < 2; ++loop) {
+ for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
+ SkPaint::kStrokeAndFill_Style} ) {
+ paint.setStyle(style);
+ canvas->drawPath(path, paint);
+ canvas->translate(85, 0);
+ }
+ path.close();
+ canvas->translate(-255, 128);
+ }
+}
+##
+
+#SeeAlso
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method static bool IsInverseFillType(FillType fill)
+
+Returns true if fill is inverted and Path with fill represents area outside
+of its geometric bounds.
+
+#Table
+#Legend
+# FillType # is inverse ##
+##
+# kWinding_FillType # false ##
+# kEvenOdd_FillType # false ##
+# kInverseWinding_FillType # true ##
+# kInverseEvenOdd_FillType # true ##
+##
+
+#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
+ kInverseWinding_FillType, kInverseEvenOdd_FillType.
+##
+
+#Return true if Path fills outside its bounds. ##
+
+#Example
+#Function
+#define nameValue(fill) { SkPath::fill, #fill }
+
+##
+void draw(SkCanvas* canvas) {
+ struct {
+ SkPath::FillType fill;
+ const char* name;
+ } fills[] = {
+ nameValue(kWinding_FillType),
+ nameValue(kEvenOdd_FillType),
+ nameValue(kInverseWinding_FillType),
+ nameValue(kInverseEvenOdd_FillType),
+ };
+ for (auto fill: fills ) {
+ SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
+ "true" : "false");
+ }
+}
+#StdOut
+IsInverseFillType(kWinding_FillType) == false
+IsInverseFillType(kEvenOdd_FillType) == false
+IsInverseFillType(kInverseWinding_FillType) == true
+IsInverseFillType(kInverseEvenOdd_FillType) == true
+##
+##
+
+#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method static FillType ConvertToNonInverseFillType(FillType fill)
+
+Returns equivalent Fill_Type representing Path fill inside its bounds.
+.
+
+#Table
+#Legend
+# FillType # inside FillType ##
+##
+# kWinding_FillType # kWinding_FillType ##
+# kEvenOdd_FillType # kEvenOdd_FillType ##
+# kInverseWinding_FillType # kWinding_FillType ##
+# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
+##
+
+#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
+ kInverseWinding_FillType, kInverseEvenOdd_FillType.
+##
+
+#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted. ##
+
+#Example
+#Function
+#define nameValue(fill) { SkPath::fill, #fill }
+
+##
+void draw(SkCanvas* canvas) {
+ struct {
+ SkPath::FillType fill;
+ const char* name;
+ } fills[] = {
+ nameValue(kWinding_FillType),
+ nameValue(kEvenOdd_FillType),
+ nameValue(kInverseWinding_FillType),
+ nameValue(kInverseEvenOdd_FillType),
+ };
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
+ if (fills[i].fill != (SkPath::FillType) i) {
+ SkDebugf("fills array order does not match FillType enum order");
+ break;
+ }
+ SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
+ fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
+ }
+}
+#StdOut
+ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
+ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
+ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
+ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
+##
+##
+
+#SeeAlso FillType getFillType setFillType IsInverseFillType
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
+ SkScalar w, SkPoint pts[], int pow2)
+
+Approximates Conic with Quad array. Conic is constructed from start Point p0,
+control Point p1, end Point 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 Point of previous Quad and first Point of
+next Quad. Maximum pts storage size is given by:
+#Formula
+(1 + 2 * (1 << pow2)) * sizeof(SkPoint)
+##
+ConvertConicToQuads returns Quad count used the approximation, which may be smaller
+than the number requested.
+
+Conic_Weight determines the amount of influence Conic control point has on the curve.
+w less than one represents an elliptical section. w greater than one represents
+a hyperbolic section. w equal to one represents a parabolic section.
+
+Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
+of up to 90 degrees; in this case, set pow2 to one.
+
+#Param p0 Conic start Point. ##
+#Param p1 Conic control Point. ##
+#Param p2 Conic end Point. ##
+#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. ##
+
+#Example
+#Description
+A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
+The middle curve is nearly circular. The top-right curve is parabolic, which can
+be drawn exactly with a single Quad.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint conicPaint;
+ conicPaint.setAntiAlias(true);
+ conicPaint.setStyle(SkPaint::kStroke_Style);
+ SkPaint quadPaint(conicPaint);
+ quadPaint.setColor(SK_ColorRED);
+ SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
+ for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
+ SkPoint quads[5];
+ SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
+ SkPath path;
+ path.moveTo(conic[0]);
+ path.conicTo(conic[1], conic[2], weight);
+ canvas->drawPath(path, conicPaint);
+ path.rewind();
+ path.moveTo(quads[0]);
+ path.quadTo(quads[1], quads[2]);
+ path.quadTo(quads[3], quads[4]);
+ canvas->drawPath(path, quadPaint);
+ canvas->translate(50, -50);
+ }
+}
+##
+
+#SeeAlso Conic Quad
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isRect(SkRect* rect, bool* isClosed = NULL, Direction* direction = NULL) const
+
+Returns true if Path is eqivalent to Rect when filled.
+If isRect returns false: rect, isClosed, and direction are unchanged.
+If isRect returns true: rect, isClosed, and direction are written to if not nullptr.
+
+rect may be smaller than the Path bounds. Path bounds may include kMove_Verb points
+that do not alter the area drawn by the returned rect.
+
+#Param rect storage for bounds of Rect; may be nullptr. ##
+#Param isClosed storage set to true if Path is closed; may be nullptr ##
+#Param direction storage set to Rect direction; may be nullptr. ##
+
+#Return true if Path contains Rect. ##
+
+#Example
+#Description
+After addRect, isRect returns true. Following moveTo permits isRect to return true, but
+following lineTo does not. addPoly returns true even though rect is not closed, and one
+side of rect is made up of consecutive line segments.
+##
+void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path) -> void {
+ SkRect rect;
+ SkPath::Direction direction;
+ bool isClosed;
+ path.isRect(&rect, &isClosed, &direction) ?
+ SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
+ rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
+ SkPath::kCW_Direction == direction ? "CW" : "CCW") :
+ SkDebugf("%s is not rect\n", prefix);
+ };
+ SkPath path;
+ debugster("empty", path);
+ path.addRect({10, 20, 30, 40});
+ debugster("addRect", path);
+ path.moveTo(60, 70);
+ debugster("moveTo", path);
+ path.lineTo(60, 70);
+ debugster("lineTo", path);
+ path.reset();
+ const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
+ path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
+ debugster("addPoly", path);
+}
+#StdOut
+empty is not rect
+addRect is rect (10, 20, 30, 40); is closed; direction CW
+moveTo is rect (10, 20, 30, 40); is closed; direction CW
+lineTo is not rect
+addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
+##
+##
+
+#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = NULL) const
+
+Returns true if Path is equivalent to nested Rect pair when filled.
+If isNestedFillRects returns false, rect and dirs are unchanged.
+If isNestedFillRects returns true, rect and dirs are written to if not nullptr:
+setting rect[0] to outer Rect, and rect[1] to inner Rect;
+setting dirs[0] to Direction of outer Rect, and dirs[1] to Direction of inner
+Rect.
+
+#Param rect storage for Rect pair; may be nullptr. ##
+#Param dirs storage for Direction pair; may be nullptr. ##
+
+#Return true if Path contains nested Rect pair. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(5);
+ SkPath path;
+ path.addRect({10, 20, 30, 40});
+ paint.getFillPath(path, &path);
+ SkRect rects[2];
+ SkPath::Direction directions[2];
+ if (path.isNestedFillRects(rects, directions)) {
+ for (int i = 0; i < 2; ++i) {
+ SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
+ rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
+ SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
+ }
+ } else {
+ SkDebugf("is not nested rectangles\n");
+ }
+}
+#StdOut
+outer (7.5, 17.5, 32.5, 42.5); direction CW
+inner (12.5, 22.5, 27.5, 37.5); direction CCW
+##
+##
+
+#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addRect(const SkRect& rect, Direction dir = kCW_Direction)
+
+Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
+starting with top-left corner of Rect; 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 Rect to add as a closed contour. ##
+#Param dir Direction to wind added contour. ##
+
+#Example
+#Description
+The left Rect dashes starting at the top-left corner, to the right.
+The right Rect dashes starting at the top-left corner, towards the bottom.
+##
+#Height 128
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setStrokeWidth(15);
+ paint.setStrokeCap(SkPaint::kSquare_Cap);
+ float intervals[] = { 5, 21.75f };
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
+ SkPath path;
+ path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
+ canvas->drawPath(path, paint);
+ path.rewind();
+ path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso SkCanvas::drawRect Direction
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addRect(const SkRect& rect, Direction dir, unsigned start)
+
+Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
+If dir is kCW_Direction, Rect corners are added clockwise; if dir is
+kCCW_Direction, Rect corners are added counterclockwise.
+start determines the first corner added.
+
+#Table
+#Legend
+# start # first corner ##
+#Legend ##
+# 0 # top-left ##
+# 1 # top-right ##
+# 2 # bottom-right ##
+# 3 # bottom-left ##
+#Table ##
+
+#Param rect Rect to add as a closed contour. ##
+#Param dir Direction to wind added contour. ##
+#Param start Initial corner of Rect to add. ##
+
+#Example
+#Height 128
+#Description
+The arrow is just after the initial corner and points towards the next
+corner appended to Path.
+##
+void draw(SkCanvas* canvas) {
+ const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
+ const SkRect rect = {10, 10, 54, 54};
+ SkPaint rectPaint;
+ rectPaint.setAntiAlias(true);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ SkPaint arrowPaint(rectPaint);
+ SkPath arrowPath;
+ arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
+ arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
+ SkPath1DPathEffect::kRotate_Style));
+ for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
+ for (unsigned start : { 0, 1, 2, 3 } ) {
+ SkPath path;
+ path.addRect(rect, direction, start);
+ canvas->drawPath(path, rectPaint);
+ canvas->drawPath(path, arrowPaint);
+ canvas->translate(64, 0);
+ }
+ canvas->translate(-256, 64);
+ }
+}
+##
+
+#SeeAlso SkCanvas::drawRect Direction
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
+ Direction dir = kCW_Direction)
+
+Add Rect (left, top, right, bottom) to Path,
+appending kMove_Verb, three kLine_Verb, and kClose_Verb,
+starting with top-left corner of Rect; 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 Rect. ##
+#Param top smaller y of Rect. ##
+#Param right larger x of Rect. ##
+#Param bottom larger y of Rect. ##
+#Param dir Direction to wind added contour. ##
+
+#Example
+#Description
+The left Rect dashes start at the top-left corner, and continue to the right.
+The right Rect dashes start at the top-left corner, and continue down.
+##
+#Height 128
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setStrokeWidth(15);
+ paint.setStrokeCap(SkPaint::kSquare_Cap);
+ float intervals[] = { 5, 21.75f };
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
+ for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
+ SkPath path;
+ path.addRect(20, 20, 100, 100, direction);
+ canvas->drawPath(path, paint);
+ canvas->translate(128, 0);
+ }
+}
+##
+
+#SeeAlso SkCanvas::drawRect Direction
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addOval(const SkRect& oval, Direction dir = kCW_Direction)
+
+Add Oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
+Oval is upright ellipse bounded by Rect 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 Direction to wind ellipse. ##
+
+#Example
+#Height 120
+ SkPaint paint;
+ SkPath oval;
+ oval.addOval({20, 20, 160, 80});
+ canvas->drawPath(oval, paint);
+##
+
+#SeeAlso SkCanvas::drawOval Direction Oval
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addOval(const SkRect& oval, Direction dir, unsigned start)
+
+Add Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
+Oval is upright ellipse bounded by Rect 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.
+
+#Table
+#Legend
+# start # Point ##
+#Legend ##
+# 0 # oval.centerX(), oval.fTop ##
+# 1 # oval.fRight, oval.centerY() ##
+# 2 # oval.centerX(), oval.fBottom ##
+# 3 # oval.fLeft, oval.centerY() ##
+#Table ##
+
+#Param oval bounds of ellipse added. ##
+#Param dir Direction to wind ellipse. ##
+#Param start index of initial point of ellipse. ##
+
+#Example
+#Height 160
+void draw(SkCanvas* canvas) {
+ const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
+ const SkRect rect = {10, 10, 54, 54};
+ SkPaint ovalPaint;
+ ovalPaint.setAntiAlias(true);
+ SkPaint textPaint(ovalPaint);
+ textPaint.setTextAlign(SkPaint::kCenter_Align);
+ ovalPaint.setStyle(SkPaint::kStroke_Style);
+ SkPaint arrowPaint(ovalPaint);
+ SkPath arrowPath;
+ arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
+ arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
+ SkPath1DPathEffect::kRotate_Style));
+ for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
+ for (unsigned start : { 0, 1, 2, 3 } ) {
+ SkPath path;
+ path.addOval(rect, direction, start);
+ canvas->drawPath(path, ovalPaint);
+ canvas->drawPath(path, arrowPaint);
+ canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
+ canvas->translate(64, 0);
+ }
+ canvas->translate(-256, 72);
+ canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
+ 128, 0, textPaint);
+ }
+}
+##
+
+#SeeAlso SkCanvas::drawOval Direction Oval
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addCircle(SkScalar x, SkScalar y, SkScalar radius,
+ Direction dir = kCW_Direction)
+
+Add Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
+four kConic_Verb, and kClose_Verb. Circle begins at (x + radius, y) and
+continues clockwise if dir is kCW_Direction, counterclockwise if dir is
+kCCW_Direction.
+
+addCircle has no effect if radius is zero or negative.
+
+#Param x center of Circle. ##
+#Param y center of Circle. ##
+#Param radius distance from center to edge. ##
+#Param dir Direction to wind Circle. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(10);
+ for (int size = 10; size < 300; size += 20) {
+ SkPath path;
+ path.addCircle(128, 128, size, SkPath::kCW_Direction);
+ canvas->drawPath(path, paint);
+ }
+}
+##
+
+#SeeAlso SkCanvas::drawCircle Direction Circle
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
+
+Append Arc to Path, 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.
+
+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. ##
+
+#Example
+#Description
+The middle row of the left and right columns draw differently from the entries
+above and below because sweepAngle is outside of the range of +/-360,
+and startAngle modulo 90 is not zero.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ for (auto start : { 0, 90, 135, 180, 270 } ) {
+ for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
+ SkPath path;
+ path.addArc({10, 10, 35, 45}, start, sweep);
+ canvas->drawPath(path, paint);
+ canvas->translate(252 / 6, 0);
+ }
+ canvas->translate(-252, 255 / 5);
+ }
+}
+##
+
+#SeeAlso Arc arcTo SkCanvas::drawArc
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
+ Direction dir = kCW_Direction)
+
+Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
+equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
+dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner and
+winds clockwise. If dir is kCCW_Direction, Round_Rect 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
+Rect rect to Path.
+
+After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
+
+#Param rect bounds of Round_Rect. ##
+#Param rx x-radius of rounded corners on the Round_Rect ##
+#Param ry y-radius of rounded corners on the Round_Rect ##
+#Param dir Direction to wind Round_Rect. ##
+
+#Example
+#Description
+If either radius is zero, path contains Rect and is drawn red.
+If sides are only radii, path contains Oval and is drawn blue.
+All remaining path draws are convex, and are drawn in gray; no
+paths constructed from addRoundRect are concave, so none are
+drawn in green.
+##
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ for (auto xradius : { 0, 7, 13, 20 } ) {
+ for (auto yradius : { 0, 9, 18, 40 } ) {
+ SkPath path;
+ path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
+ paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
+ SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
+ canvas->drawPath(path, paint);
+ canvas->translate(64, 0);
+ }
+ canvas->translate(-256, 64);
+ }
+}
+##
+
+#SeeAlso addRRect SkCanvas::drawRoundRect
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addRoundRect(const SkRect& rect, const SkScalar radii[],
+ Direction dir = kCW_Direction)
+
+Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
+equal to rect; each corner is 90 degrees of an ellipse with radii from the
+array.
+
+#Table
+#Legend
+# radii index # location ##
+#Legend ##
+# 0 # x-radius of top-left corner ##
+# 1 # y-radius of top-left corner ##
+# 2 # x-radius of top-right corner ##
+# 3 # y-radius of top-right corner ##
+# 4 # x-radius of bottom-right corner ##
+# 5 # y-radius of bottom-right corner ##
+# 6 # x-radius of bottom-left corner ##
+# 7 # y-radius of bottom-left corner ##
+#Table ##
+
+If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
+and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
+bottom-left of the upper-left corner and winds counterclockwise.
+
+If both radii on any side of rect exceed its length, all radii are scaled
+uniformly until the corners fit. If either radius of a corner is less than or
+equal to zero, both are treated as zero.
+
+After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
+
+#Param rect bounds of Round_Rect. ##
+#Param radii array of 8 SkScalar values, a radius pair for each corner. ##
+#Param dir Direction to wind Round_Rect. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
+ SkPath path;
+ SkMatrix rotate90;
+ rotate90.setRotate(90, 128, 128);
+ for (int i = 0; i < 4; ++i) {
+ path.addRoundRect({10, 10, 110, 110}, radii);
+ path.transform(rotate90);
+ }
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso addRRect SkCanvas::drawRoundRect
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
+
+Add rrect to Path, 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, Path may be empty, or may contain: Rect, Oval, or RRect.
+
+#Param rrect bounds and radii of rounded rectangle. ##
+#Param dir Direction to wind Round_Rect. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkRRect rrect;
+ SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
+ rrect.setRectRadii({10, 10, 110, 110}, radii);
+ SkPath path;
+ SkMatrix rotate90;
+ rotate90.setRotate(90, 128, 128);
+ for (int i = 0; i < 4; ++i) {
+ path.addRRect(rrect);
+ path.transform(rotate90);
+ }
+ canvas->drawPath(path, paint);
+}
+##
+
+#SeeAlso addRoundRect SkCanvas::drawRRect
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addRRect(const SkRRect& rrect, Direction dir, unsigned start)
+
+Add rrect to Path, 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.
+
+#Table
+#Legend
+# start # location ##
+#Legend ##
+# 0 # right of top-left corner ##
+# 1 # left of top-right corner ##
+# 2 # bottom of top-right corner ##
+# 3 # top of bottom-right corner ##
+# 4 # left of bottom-right corner ##
+# 5 # right of bottom-left corner ##
+# 6 # top of bottom-left corner ##
+# 7 # bottom of top-left corner ##
+#Table ##
+
+After appending, Path may be empty, or may contain: Rect, Oval, or RRect.
+
+#Param rrect bounds and radii of rounded rectangle. ##
+#Param dir Direction to wind RRect. ##
+#Param start Index of initial point of RRect. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkRRect rrect;
+ rrect.setRectXY({40, 40, 215, 215}, 50, 50);
+ SkPath path;
+ path.addRRect(rrect);
+ canvas->drawPath(path, paint);
+ for (int start = 0; start < 8; ++start) {
+ SkPath textPath;
+ textPath.addRRect(rrect, SkPath::kCW_Direction, start);
+ canvas->drawTextOnPathHV(&"01234567"[start], 1, textPath, 0, -5, paint);
+ }
+}
+##
+
+#SeeAlso addRoundRect SkCanvas::drawRRect
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addPoly(const SkPoint pts[], int count, bool close)
+
+Add Contour created from Line Array. Given count pts, addPoly adds
+count - 1 Line segments. Contour added starts at pt[0], then adds a line
+for every additional Point in pts array. If close is true, addPoly
+appends kClose_Verb to Path, connecting pts[count - 1] and pts[0].
+
+If count is zero, append kMove_Verb to path.
+addPoly has no effect if count is less than one.
+
+#Param pts Array of Line sharing end and start Point. ##
+#Param count Length of Point array. ##
+#Param close true to add Line connecting Contour end and start. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setStrokeWidth(15);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+ const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
+ for (bool close : { false, true } ) {
+ SkPath path;
+ path.addPoly(points, SK_ARRAY_COUNT(points), close);
+ for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
+ SkPaint::kStrokeAndFill_Style} ) {
+ paint.setStyle(style);
+ canvas->drawPath(path, paint);
+ canvas->translate(85, 0);
+ }
+ canvas->translate(-255, 128);
+ }
+}
+##
+
+#SeeAlso SkCanvas::drawPoints
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Enum AddPathMode
+
+#Code
+ enum AddPathMode {
+ kAppend_AddPathMode
+ kExtend_AddPathMode
+ };
+##
+
+AddPathMode chooses how addPath appends. Adding one Path to another can extend
+the last Contour or start a new Contour.
+
+#Const kAppend_AddPathMode
+ Path Verbs, Points, and Weights are appended to destination unaltered.
+ Since Path Verb_Array begins with kMove_Verb if src is not empty, this
+ starts a new Contour.
+##
+#Const kExtend_AddPathMode
+ If destination is closed or empty, start a new Contour. If destination
+ is not empty, add Line from Last_Point to added Path first Point. Skip added
+ Path initial kMove_Verb, then append remining Verbs, Points, and Weights.
+##
+
+#Example
+#Description
+test is built from path, open on the top row, and closed on the bottom row.
+The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
+The top right composition is made up of one contour; the other three have two.
+##
+#Height 180
+ SkPath path, path2; + path.moveTo(20, 20); + path.lineTo(20, 40); + path.lineTo(40, 20); + path2.moveTo(60, 60); + path2.lineTo(80, 60); + path2.lineTo(80, 40); + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + for (int i = 0; i < 2; i++) { + for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) { + SkPath test(path); + test.addPath(path2, addPathMode); + canvas->drawPath(test, paint); + canvas->translate(100, 0); + } + canvas->translate(-200, 100); + path.close(); + } +##
+
+#SeeAlso addPath reverseAddPath
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
+ AddPathMode mode = kAppend_AddPathMode)
+
+Append src to Path, offset by (dx, dy).
+
+If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Weights are
+added unaltered. If mode is kExtend_AddPathMode, add Line before appending
+Verbs, Points, and Weights.
+
+#Param src Path Verbs, Points, and Weights to add. ##
+#Param dx offset added to src Point_Array x coordinates. ##
+#Param dy offset added to src Point_Array y coordinates. ##
+#Param mode kAppend_AddPathMode or kExtend_AddPathMode. ##
+
+#Example
+#Height 180
+ SkPaint paint; + paint.setTextSize(128); + paint.setFakeBoldText(true); + SkPath dest, text; + paint.getTextPath("O", 1, 50, 120, &text); + for (int i = 0; i < 3; i++) { + dest.addPath(text, i * 20, i * 20); + } + Simplify(dest, &dest); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(3); + canvas->drawPath(dest, paint); +##
+
+#SeeAlso AddPathMode offset() reverseAddPath
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
+
+Append src to Path.
+
+If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Weights are
+added unaltered. If mode is kExtend_AddPathMode, add Line before appending
+Verbs, Points, and Weights.
+
+#Param src Path Verbs, Points, and Weights to add. ##
+#Param mode kAppend_AddPathMode or kExtend_AddPathMode. ##
+
+#Example
+#Height 80
+ SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + SkPath dest, path; + path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1); + for (int i = 0; i < 2; i++) { + dest.addPath(path, SkPath::kExtend_AddPathMode); + dest.offset(100, 0); + } + canvas->drawPath(dest, paint);
+##
+
+#SeeAlso AddPathMode reverseAddPath
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
+
+Append src to Path, transformed by matrix. Transformed curves may have different
+Verbs, Points, and Weights.
+
+If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Weights are
+added unaltered. If mode is kExtend_AddPathMode, add Line before appending
+Verbs, Points, and Weights.
+
+#Param src Path Verbs, Points, and Weights to add. ##
+#Param matrix Transform applied to src. ##
+#Param mode kAppend_AddPathMode or kExtend_AddPathMode. ##
+
+#Example
+#Height 160
+ SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + SkPath dest, path; + path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1); + for (int i = 0; i < 6; i++) { + SkMatrix matrix; + matrix.reset(); + matrix.setPerspX(i / 400.f); + dest.addPath(path, matrix); + } + canvas->drawPath(dest, paint); +##
+
+#SeeAlso AddPathMode transform() offset() reverseAddPath
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void reverseAddPath(const SkPath& src)
+
+Append src to Path, from back to front.
+Reversed src always appends a new Contour to Path.
+
+#Param src Path Verbs, Points, and Weights to add. ##
+
+#Example
+#Height 200
+ SkPath path; + path.moveTo(20, 20); + path.lineTo(20, 40); + path.lineTo(40, 20); + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + for (int i = 0; i < 2; i++) { + SkPath path2; + path2.moveTo(60, 60); + path2.lineTo(80, 60); + path2.lineTo(80, 40); + for (int j = 0; j < 2; j++) { + SkPath test(path); + test.reverseAddPath(path2); + canvas->drawPath(test, paint); + canvas->translate(100, 0); + path2.close(); + } + canvas->translate(-200, 100); + path.close(); + } +##
+
+#SeeAlso AddPathMode transform() offset() addPath
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
+
+Offset Point_Array by (dx, dy). Offset Path replaces dst.
+If dst is nullptr, Path is replaced by offset data.
+
+#Param dx offset added to Point_Array x coordinates. ##
+#Param dy offset added to Point_Array y coordinates. ##
+#Param dst overwritten, translated copy of Path; may be nullptr. ##
+
+#Example
+#Height 60
+ SkPath pattern; + pattern.moveTo(20, 20); + pattern.lineTo(20, 40); + pattern.lineTo(40, 20); + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + for (int i = 0; i < 10; i++) { + SkPath path; + pattern.offset(20 * i, 0, &path); + canvas->drawPath(path, paint); + } +##
+
+#SeeAlso addPath transform
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void offset(SkScalar dx, SkScalar dy)
+
+Offset Point_Array by (dx, dy). Path is replaced by offset data.
+
+#Param dx offset added to Point_Array x coordinates. ##
+#Param dy offset added to Point_Array y coordinates. ##
+
+#Example
+#Height 60
+ SkPath path; + path.moveTo(20, 20); + path.lineTo(20, 40); + path.lineTo(40, 20); + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + for (int i = 0; i < 10; i++) { + canvas->drawPath(path, paint); + path.offset(20, 0); + } +##
+
+#SeeAlso addPath transform SkCanvas::translate()
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void transform(const SkMatrix& matrix, SkPath* dst) const
+
+Transform Verb_Array, Point_Array, and weight by matrix.
+transform may change Verbs and increase their number.
+Transformed Path replaces dst; if dst is nullptr, original data
+is replaced.
+
+#Param matrix Matrix to apply to Path. ##
+#Param dst overwritten, transformed copy of Path; may be nullptr. ##
+
+#Example
+#Height 200 + SkPath pattern; + pattern.moveTo(100, 100); + pattern.lineTo(100, 20); + pattern.lineTo(20, 100); + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + for (int i = 0; i < 10; i++) { + SkPath path; + SkMatrix matrix; + matrix.setRotate(36 * i, 100, 100); + pattern.transform(matrix, &path); + canvas->drawPath(path, paint); + }
+##
+
+#SeeAlso addPath offset SkCanvas::concat() SkMatrix
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void transform(const SkMatrix& matrix)
+
+Transform Verb_Array, Point_Array, and weight by matrix.
+transform may change Verbs and increase their number.
+Path is replaced by transformed data.
+
+#Param matrix Matrix to apply to Path. ##
+
+#Example
+#Height 200 + SkPath path; + path.moveTo(100, 100); + path.quadTo(100, 20, 20, 100); + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + for (int i = 0; i < 10; i++) { + SkMatrix matrix; + matrix.setRotate(36, 100, 100); + path.transform(matrix); + canvas->drawPath(path, paint); + }
+##
+
+#SeeAlso addPath offset SkCanvas::concat() SkMatrix
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Subtopic Last_Point + +Path is defined cumulatively, often by adding a segment to the end of last +Contour. Last_Point of Contour is shared as first Point of added Line or Curve. +Last_Point can be read and written directly with getLastPt and setLastPt. + +#Method bool getLastPt(SkPoint* lastPt) const
+
+ Returns Last_Point on Path in lastPt. Returns false if Point_Array is empty,
+ storing (0, 0) if lastPt is not nullptr.
+
+ #Param lastPt storage for final Point in Point_Array; may be nullptr. ##
+
+ #Return true if Point_Array contains one or more Points. ##
+
+ #Example
+ SkPath path; + path.moveTo(100, 100); + path.quadTo(100, 20, 20, 100); + SkMatrix matrix; + matrix.setRotate(36, 100, 100); + path.transform(matrix); + SkPoint last; + path.getLastPt(&last); + SkDebugf("last point: %g, %g\n", last.fX, last.fY);
+ #StdOut
+ last point: 35.2786, 52.9772
+ ##
+ ##
+
+ #SeeAlso setLastPt
+
+##
+
+#Method void setLastPt(SkScalar x, SkScalar y)
+
+ Set Last_Point to (x, y). If Point_Array is empty, append kMove_Verb to
+ Verb_Array and (x, y) to Point_Array.
+
+ #Param x set x-coordinate of Last_Point. ##
+ #Param y set y-coordinate of Last_Point. ##
+
+ #Example
+ #Height 128
+ SkPaint paint; + paint.setTextSize(128); + SkPath path; + paint.getTextPath("@", 1, 60, 100, &path); + path.setLastPt(20, 120); + canvas->drawPath(path, paint);
+ ##
+
+ #SeeAlso getLastPt
+
+##
+
+#Method void setLastPt(const SkPoint& p)
+
+ Set the last point on the path. If no points have been added, moveTo(p)
+ is automatically called.
+
+ #Param p set value of Last_Point. ##
+
+ #Example
+ #Height 128
+ SkPaint paint; + paint.setTextSize(128); + SkPath path, path2; + paint.getTextPath("A", 1, 60, 100, &path); + paint.getTextPath("Z", 1, 60, 100, &path2); + SkPoint pt, pt2; + path.getLastPt(&pt); + path2.getLastPt(&pt2); + path.setLastPt(pt2); + path2.setLastPt(pt); + canvas->drawPath(path, paint); + canvas->drawPath(path2, paint); + ##
+
+ #SeeAlso getLastPt
+
+##
+
+#Subtopic Last_Point ##
+
+# ------------------------------------------------------------------------------
+
+#Enum SegmentMask
+
+#Code
+ enum SegmentMask {
+ kLine_SegmentMask = 1 << 0
+ kQuad_SegmentMask = 1 << 1
+ kConic_SegmentMask = 1 << 2
+ kCubic_SegmentMask = 1 << 3
+ };
+##
+
+SegmentMask constants correspond to each drawing Verb type in Path; for
+instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
+
+#Bug 6785 ##
+#Const kLine_SegmentMask 1
+Set if Verb_Array contains kLine_Verb.
+##
+#Const kQuad_SegmentMask 2
+Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
+##
+#Const kConic_SegmentMask 4
+Set if Verb_Array contains kConic_Verb.
+##
+#Const kCubic_SegmentMask 8
+Set if Verb_Array contains kCubic_Verb.
+##
+
+#Example
+#Description
+When conicTo has a weight of one, Quad is added to Path.
+##
+ SkPath path;
+ path.conicTo(10, 10, 20, 30, 1);
+ SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
+ SkPath::kConic_SegmentMask ? "set" : "clear");
+ SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
+ SkPath::kQuad_SegmentMask ? "set" : "clear");
+#StdOut
+Path kConic_SegmentMask is clear
+Path kQuad_SegmentMask is set
+##
+##
+
+#SeeAlso getSegmentMasks Verb
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method uint32_t getSegmentMasks() const
+
+Returns a mask, where each set bit corresponds to a SegmentMask constant
+if Path contains one or more Verbs of that type.
+Returns zero if Path contains no Lines, Quads, Conics, or Cubics.
+
+getSegmentMasks() returns a cached result; it is very fast.
+
+#Return SegmentMask bits or zero. ##
+
+#Example
+SkPath path;
+path.quadTo(20, 30, 40, 50);
+path.close();
+const char* masks[] = { "line", "quad", "conic", "cubic" };
+int index = 0;
+for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
+ SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
+ if (mask & path.getSegmentMasks()) {
+ SkDebugf("mask %s set\n", masks[index]);
+ }
+ ++index;
+}
+#StdOut
+mask quad set
+##
+##
+
+#SeeAlso getSegmentMasks Verb
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method bool contains(SkScalar x, SkScalar y) const
+
+Returns true if the point (x, y) is contained by Path, taking into
+account FillType.
+
+#Table
+#Legend
+# FillType # contains() returns true if Point is enclosed by ##
+##
+# kWinding_FillType # a non-zero sum of Contour Directions. ##
+# kEvenOdd_FillType # an odd number of Contours. ##
+# kInverseWinding_FillType # a zero sum of Contour Directions. ##
+# kInverseEvenOdd_FillType # and even number of Contours. ##
+##
+
+#Param x x-coordinate of containment test. ##
+#Param y y-coordinate of containment test. ##
+
+#Return true if Point is in Path. ##
+
+#Example
+SkPath path;
+SkPaint paint;
+paint.setTextSize(256);
+paint.getTextPath("&", 1, 30, 220, &path);
+for (int y = 2; y < 256; y += 9) {
+ for (int x = 2; x < 256; x += 9) {
+ int coverage = 0;
+ for (int iy = -4; iy <= 4; iy += 2) {
+ for (int ix = -4; ix <= 4; ix += 2) {
+ coverage += path.contains(x + ix, y + iy);
+ }
+ }
+ paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
+ canvas->drawCircle(x, y, 8, paint);
+ }
+}
+##
+
+#SeeAlso conservativelyContainsRect Fill_Type Op
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
+
+Writes text representation of Path to stream. If stream is nullptr, dump() writes to
+stdout. Set forceClose to true to get
+edges used to fill Path. Set dumpAsHex true to get exact binary representations
+of floating point numbers used in Point_Array and Weights.
+
+#Param stream writable Stream receiving Path text representation; may be nullptr. ##
+#Param forceClose true if missing kClose_Verb is output. ##
+#Param dumpAsHex true if SkScalar values are written as hexidecimal. ##
+
+#Example
+ SkPath path;
+ path.quadTo(20, 30, 40, 50);
+ for (bool forceClose : { false, true } ) {
+ for (bool dumpAsHex : { false, true } ) {
+ path.dump(nullptr, forceClose, dumpAsHex);
+ SkDebugf("\n");
+ }
+ }
+#StdOut
+path.setFillType(SkPath::kWinding_FillType);
+path.moveTo(0, 0);
+path.quadTo(20, 30, 40, 50);
+
+path.setFillType(SkPath::kWinding_FillType);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
+path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
+
+path.setFillType(SkPath::kWinding_FillType);
+path.moveTo(0, 0);
+path.quadTo(20, 30, 40, 50);
+path.lineTo(0, 0);
+path.close();
+
+path.setFillType(SkPath::kWinding_FillType);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
+path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
+path.close();
+##
+##
+
+#SeeAlso SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void dump() const
+
+Writes text representation of Path to stdout. The representation may be
+directly compiled as C++ code. Floating point values are written
+with limited precision; it may not be possible to reconstruct original Path
+from output.
+
+#Example
+SkPath path, copy;
+path.lineTo(6.f / 7, 2.f / 3);
+path.dump();
+copy.setFillType(SkPath::kWinding_FillType);
+copy.moveTo(0, 0);
+copy.lineTo(0.857143f, 0.666667f);
+SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
+#StdOut
+path.setFillType(SkPath::kWinding_FillType);
+path.moveTo(0, 0);
+path.lineTo(0.857143f, 0.666667f);
+path is not equal to copy
+##
+##
+
+#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void dumpHex() const
+
+Writes text representation of Path to stdout. 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 Path.
+
+Use dumpHex when submitting #A bug reports against Skia # http://bug.skia.org ##.
+Slight value changes in Point_Array may cause the bug to disappear.
+
+#Example
+SkPath path, copy;
+path.lineTo(6.f / 7, 2.f / 3);
+path.dumpHex();
+copy.setFillType(SkPath::kWinding_FillType);
+copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
+copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
+SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
+#StdOut
+path.setFillType(SkPath::kWinding_FillType);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
+path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
+path is equal to copy
+##
+##
+
+#SeeAlso dump SkRect::dumpHex() SkRRect::dumpHex() writeToMemory
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method size_t writeToMemory(void* buffer) const
+
+Write Path to buffer, returning the number of bytes written.
+Pass nullptr to obtain the storage size.
+
+writeToMemory writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
+additionally writes computed information like Convexity and bounds.
+
+writeToMemory should only be used in concert with readFromMemory.
+The format used for Path in memory is not guaranteed.
+
+#Param buffer storage for Path; may be nullptr. ##
+
+#Return size of storage required for Path; always a multiple of 4. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPath path, copy;
+ path.lineTo(6.f / 7, 2.f / 3);
+ size_t size = path.writeToMemory(nullptr);
+ SkTDArray<char> storage;
+ storage.setCount(size);
+ path.writeToMemory(storage.begin());
+ copy.readFromMemory(storage.begin(), size);
+ SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
+}
+##
+
+#SeeAlso readFromMemory dump dumpHex
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method size_t readFromMemory(const void* buffer, size_t length)
+
+Initializes Path from buffer of size length. Returns zero if the buffer is
+data is inconsistent, or the length is too small.
+
+readFromMemory reads Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
+additionally reads computed information like Convexity and bounds.
+
+readFromMemory should only be used in concert with writeToMemory.
+The format used for Path in memory is not guaranteed.
+
+#Param buffer storage for Path. ##
+#Param length buffer size in bytes; must be multiple of 4. ##
+
+#Return number of bytes read, or zero on failure. ##
+
+#Example
+void draw(SkCanvas* canvas) {
+ SkPath path, copy;
+ path.lineTo(6.f / 7, 2.f / 3);
+ size_t size = path.writeToMemory(nullptr);
+ SkTDArray<char> storage;
+ storage.setCount(size);
+ path.writeToMemory(storage.begin());
+ size_t wrongSize = size - 4;
+ size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
+ SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
+ size_t largerSize = size + 4;
+ bytesRead = copy.readFromMemory(storage.begin(), largerSize);
+ SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
+}
+#StdOut
+length = 60; returned by readFromMemory = 0
+length = 68; returned by readFromMemory = 64
+##
+##
+
+#SeeAlso writeToMemory
+
+##
+
+# ------------------------------------------------------------------------------
+#Topic Generation_ID
+#Alias Generation_IDs
+
+Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
+Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
+not necessarily have matching Generation_IDs.
+
+Empty Paths have a Generation_ID of one.
+
+#Method uint32_t getGenerationID() const
+
+Returns a non-zero, globally unique value. A different value is returned
+if Verb_Array, Point_Array, or Conic_Weight changes.
+
+Setting Fill_Type does not change Generation_ID.
+
+Each time the path is modified, a different Generation_ID will be returned.
+
+#Bug 1762
+Fill_Type does affect Generation_ID on Android framework.
+##
+
+#Return non-zero, globally unique value. ##
+
+#Example
+SkPath path;
+SkDebugf("empty genID = %u\n", path.getGenerationID());
+path.lineTo(1, 2);
+SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
+path.rewind();
+SkDebugf("empty genID = %u\n", path.getGenerationID());
+path.lineTo(1, 2);
+SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
+#StdOut
+empty genID = 1
+1st lineTo genID = 2
+empty genID = 1
+2nd lineTo genID = 3
+##
+##
+
+#SeeAlso operator==(const SkPath& a, const SkPath& b)
+
+##
+
+#Topic ##
+
+# ------------------------------------------------------------------------------
+
+#Method void validate() const
+
+Debugging check to see if Path data is consistent.
+Not currently maintained.
+
+#NoExample
+##
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Method void experimentalValidateRef() const
+
+#Private
+Debugging check to see if Path data is consistent.
+Not ready for public use.
+##
+
+##
+
+# ------------------------------------------------------------------------------
+
+#Class Iter + +Iterates through Verb_Array, and associated Point_Array and Conic_Weight. +Provides options to treat open Contours as closed, and to ignore +degenerate data. + +#Example +#Height 128 +#Description +Ignoring the actual Verbs and replacing them with quads rounds the +path of the glyph. +## +void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextSize(256);
+ SkPath asterisk, path;
+ paint.getTextPath("*", 1, 50, 192, &asterisk);
+ SkPath::Iter iter(asterisk, true);
+ SkPoint start[4], pts[4];
+ iter.next(start); // skip moveTo
+ iter.next(start); // first quadTo
+ path.moveTo((start[0] + start[1]) * 0.5f);
+ while (SkPath::kClose_Verb != iter.next(pts)) {
+ path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
+ }
+ path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
+ canvas->drawPath(path, paint);
+} +## + +#SeeAlso RawIter + +#Method Iter() + +Initializes Iter with an empty Path. next() on Iter returns kDone_Verb. +Call setPath to initialize Iter at a later time. + +#Return Iter of empty Path. ## + +#Example +void draw(SkCanvas* canvas) {
+ SkPath::Iter iter;
+ SkPoint points[4];
+ SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
+ SkPath path;
+ iter.setPath(path, false);
+ SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
+} +#StdOut
+iter is done
+iter is done
+##
+## + +#SeeAlso setPath + +## + +#Method Iter(const SkPath& path, bool forceClose) + +Sets Iter to return elements of Verb_Array, Point_Array, 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 Path to iterate. ## +#Param forceClose true if open Contours generate kClose_Verb. ## + +#Return Iter of path. ## + +#Example +void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
+ SkDebugf("%s:\n", prefix);
+ const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
+ const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
+ SkPath::Verb verb;
+ do {
+ SkPoint points[4];
+ verb = iter.next(points);
+ SkDebugf("k%s_Verb ", verbStr[(int) verb]);
+ for (int i = 0; i < pointCount[(int) verb]; ++i) {
+ SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
+ }
+ if (SkPath::kConic_Verb == verb) {
+ SkDebugf("weight = %g", iter.conicWeight());
+ }
+ SkDebugf("\n");
+ } while (SkPath::kDone_Verb != verb);
+ SkDebugf("\n");
+ };
+
+ SkPath path;
+ path.quadTo(10, 20, 30, 40);
+ SkPath::Iter openIter(path, false);
+ debugster("open", openIter);
+ SkPath::Iter closedIter(path, true);
+ debugster("closed", closedIter);
+} +#StdOut +open: +kMove_Verb {0, 0},
+kQuad_Verb {0, 0}, {10, 20}, {30, 40},
+kDone_Verb
+
+closed:
+kMove_Verb {0, 0},
+kQuad_Verb {0, 0}, {10, 20}, {30, 40},
+kLine_Verb {30, 40}, {0, 0},
+kClose_Verb {0, 0},
+kDone_Verb +## +## + +#SeeAlso setPath + +## + +#Method void setPath(const SkPath& path, bool forceClose) + +Sets Iter to return elements of Verb_Array, Point_Array, 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 Path to iterate. ## +#Param forceClose true if open Contours generate kClose_Verb. ## + +#Example +void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
+ SkDebugf("%s:\n", prefix);
+ const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
+ const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
+ SkPath::Verb verb;
+ do {
+ SkPoint points[4];
+ verb = iter.next(points);
+ SkDebugf("k%s_Verb ", verbStr[(int) verb]);
+ for (int i = 0; i < pointCount[(int) verb]; ++i) {
+ SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
+ }
+ if (SkPath::kConic_Verb == verb) {
+ SkDebugf("weight = %g", iter.conicWeight());
+ }
+ SkDebugf("\n");
+ } while (SkPath::kDone_Verb != verb);
+ SkDebugf("\n");
+ };
+
+ SkPath path;
+ path.quadTo(10, 20, 30, 40);
+ SkPath::Iter iter(path, false);
+ debugster("quad open", iter);
+ SkPath path2;
+ path2.conicTo(1, 2, 3, 4, .5f);
+ iter.setPath(path2, true);
+ debugster("conic closed", iter);
+} +#StdOut +quad open:
+kMove_Verb {0, 0},
+kQuad_Verb {0, 0}, {10, 20}, {30, 40},
+kDone_Verb
+
+conic closed:
+kMove_Verb {0, 0},
+kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
+kLine_Verb {3, 4}, {0, 0},
+kClose_Verb {0, 0},
+kDone_Verb +## +## + +#SeeAlso Iter(const SkPath& path, bool forceClose) + +## + +#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false) + + Returns next Verb in Verb_Array, and advances Iter. + When Verb_Array is exhausted, returns kDone_Verb. +Zero to four Points are stored in pts, depending on the returned 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 Point data describing returned Verb. ## + #Param doConsumeDegenerates If true, skip degenerate Verbs. ## + #Param exact If true, skip zero length curves. Has no effect if doConsumeDegenerates + is false. + ## + + #Return next Verb from Verb_Array. ## + +#Example +#Description +skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb +followed by the kClose_Verb, the zero length Line and the very small Line. + +skip degenerate if exact skips the same as skip degenerate, but shows +the very small Line. + +skip none shows all of the Verbs and Points in Path. +## +void draw(SkCanvas* canvas) {
+ auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
+ SkPath::Iter iter(path, false);
+ SkDebugf("%s:\n", prefix);
+ const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
+ const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
+ SkPath::Verb verb;
+ do {
+ SkPoint points[4];
+ verb = iter.next(points, degen, exact);
+ SkDebugf("k%s_Verb ", verbStr[(int) verb]);
+ for (int i = 0; i < pointCount[(int) verb]; ++i) {
+ SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
+ }
+ SkDebugf("\n");
+ } while (SkPath::kDone_Verb != verb);
+ SkDebugf("\n");
+ };
+
+ SkPath path;
+ path.moveTo(10, 10);
+ path.moveTo(20, 20);
+ path.quadTo(10, 20, 30, 40);
+ path.moveTo(1, 1);
+ path.close();
+ path.moveTo(30, 30);
+ path.lineTo(30, 30);
+ path.moveTo(30, 30);
+ path.lineTo(30.00001f, 30);
+ debugster("skip degenerate", path, true, false);
+ debugster("skip degenerate if exact", path, true, true);
+ debugster("skip none", path, false, false);
+} +#StdOut +skip degenerate:
+kMove_Verb {20, 20},
+kQuad_Verb {20, 20}, {10, 20}, {30, 40},
+kDone_Verb
+
+skip degenerate if exact:
+kMove_Verb {20, 20},
+kQuad_Verb {20, 20}, {10, 20}, {30, 40},
+kMove_Verb {30, 30},
+kLine_Verb {30, 30}, {30.00001, 30},
+kDone_Verb
+
+skip none:
+kMove_Verb {10, 10},
+kMove_Verb {20, 20},
+kQuad_Verb {20, 20}, {10, 20}, {30, 40},
+kMove_Verb {1, 1},
+kClose_Verb {1, 1},
+kMove_Verb {30, 30},
+kLine_Verb {30, 30}, {30, 30},
+kMove_Verb {30, 30},
+kLine_Verb {30, 30}, {30.00001, 30},
+kDone_Verb
+## +## + +#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate + +## + +#Method SkScalar conicWeight() const + + 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(). ## + + #Example + void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.conicTo(1, 2, 3, 4, .5f);
+ SkPath::Iter iter(path, false);
+ SkPoint p[4];
+ SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
+ SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
+ SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
+ p[2].fX, p[2].fY);
+ SkDebugf("conic weight: %g\n", iter.conicWeight());
+ } + #StdOut +first verb is move
+next verb is conic
+conic points: {0,0}, {1,2}, {3,4}
+conic weight: 0.5 + ## + ## + + #SeeAlso Conic_Weight + +## + +#Method bool isCloseLine() const + + 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. + + 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. ## + + #Example +void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.moveTo(6, 7);
+ path.conicTo(1, 2, 3, 4, .5f);
+ path.close();
+ SkPath::Iter iter(path, false);
+ SkPoint p[4];
+ SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
+ SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
+ SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
+ SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
+ SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
+ SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
+ SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
+} + #StdOut +1st verb is move
+moveTo point: {6,7}
+2nd verb is conic
+3rd verb is line
+line points: {3,4}, {6,7}
+line generated by close
+4th verb is close + ## + ## + + #SeeAlso close() +## + +#Method bool isClosedContour() const + +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. ## + +#Example +void draw(SkCanvas* canvas) {
+ for (bool forceClose : { false, true } ) {
+ SkPath path;
+ path.conicTo(1, 2, 3, 4, .5f);
+ SkPath::Iter iter(path, forceClose);
+ SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
+ forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
+ path.close();
+ iter.setPath(path, forceClose);
+ SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
+ forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
+ }
+} +#StdOut +without close(), forceClose is false: isClosedContour returns false
+with close(), forceClose is false: isClosedContour returns true
+without close(), forceClose is true : isClosedContour returns true
+with close(), forceClose is true : isClosedContour returns true +## +## + +#SeeAlso Iter(const SkPath& path, bool forceClose) + +## +
+#Class Iter ##
+
+#Class RawIter + +Iterates through Verb_Array, and associated Point_Array and Conic_Weight. +Verb_Array, Point_Array, and Conic_Weight are returned unaltered. + + #Method RawIter() + + Initializes RawIter with an empty Path. next() on RawIter returns kDone_Verb. + Call setPath to initialize Iter at a later time. + + #Return RawIter of empty Path. ##
+
+ #NoExample
+ ##
+ ##
+ + #Method RawIter(const SkPath& path) + + + Sets RawIter to return elements of Verb_Array, Point_Array, and Conic_Weight in path. + + #Param path Path to iterate. ## + + #Return RawIter of path. ## +
+ #NoExample
+ ##
+ ##
+ + #Method void setPath(const SkPath& path) + + Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path. + + #Param path Path to iterate. ## +
+ #NoExample
+ ##
+ ##
+ + #Method Verb next(SkPoint pts[4]) + + Returns next 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 Verb. + + #Param pts Storage for Point data describing returned Verb. ## + + #Return next Verb from Verb_Array. ## + + #Example + void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.moveTo(50, 60);
+ path.quadTo(10, 20, 30, 40);
+ path.close();
+ path.lineTo(30, 30);
+ path.conicTo(1, 2, 3, 4, .5f);
+ path.cubicTo(-1, -2, -3, -4, -5, -6);
+ SkPath::RawIter iter(path);
+ const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
+ const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
+ SkPath::Verb verb;
+ do {
+ SkPoint points[4];
+ verb = iter.next(points);
+ SkDebugf("k%s_Verb ", verbStr[(int) verb]);
+ for (int i = 0; i < pointCount[(int) verb]; ++i) {
+ SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
+ }
+ if (SkPath::kConic_Verb == verb) {
+ SkDebugf("weight = %g", iter.conicWeight());
+ }
+ SkDebugf("\n");
+ } while (SkPath::kDone_Verb != verb);
+ } + #StdOut + kMove_Verb {50, 60},
+ kQuad_Verb {50, 60}, {10, 20}, {30, 40},
+ kClose_Verb {50, 60},
+ kMove_Verb {50, 60},
+ kLine_Verb {50, 60}, {30, 30},
+ kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
+ kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
+ kDone_Verb + ## + ## + + #SeeAlso peek() + + ##
+ + #Method Verb peek() const + + Returns next Verb, but does not advance RawIter. + + #Return next Verb from Verb_Array. ## + + #Example + SkPath path;
+ path.quadTo(10, 20, 30, 40);
+ path.conicTo(1, 2, 3, 4, .5f);
+ path.cubicTo(1, 2, 3, 4, .5, 6);
+ SkPath::RawIter iter(path);
+ SkPath::Verb verb, peek = iter.peek();
+ const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
+ do {
+ SkPoint points[4];
+ verb = iter.next(points);
+ SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
+ peek = iter.peek();
+ } while (SkPath::kDone_Verb != verb); + SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
+ #StdOut
+ #Volatile
+ peek Move == verb Move
+ peek Quad == verb Quad
+ peek Conic == verb Conic
+ peek Cubic == verb Cubic
+ peek Done == verb Done
+ peek Done == verb Done
+ ##
+ ## + + #Bug 6832 + StdOut isn't really volatile, it just produces the wrong result. + A simple fix changes the output of hairlines and needs to be + investigated to see if the change is correct or not. + https://skia-review.googlesource.com/c/21340/ + ## + + #SeeAlso next() + + ##
+ + #Method SkScalar conicWeight() const
+
+ 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(). ## + + #Example + void draw(SkCanvas* canvas) {
+ SkPath path;
+ path.conicTo(1, 2, 3, 4, .5f);
+ SkPath::RawIter iter(path);
+ SkPoint p[4];
+ SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
+ SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
+ SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
+ p[2].fX, p[2].fY);
+ SkDebugf("conic weight: %g\n", iter.conicWeight());
+ } + #StdOut + first verb is move
+ next verb is conic
+ conic points: {0,0}, {1,2}, {3,4}
+ conic weight: 0.5 + ## + ## + + #SeeAlso Conic_Weight +
+ ##
+
+#Class RawIter ##
+
+#Class SkPath ##
+
+#Topic Path ##
diff --git a/docs/markup.bmh b/docs/markup.bmh new file mode 100644 index 0000000000..2127fc71f4 --- /dev/null +++ b/docs/markup.bmh @@ -0,0 +1,88 @@ +#Topic Bookmaker_Markup + +# redefine markup character so examples below will not be parsed +###$ + +Text, except for the single markup character, requires no annotation. + +# comments are preceded by a hash symbol and whitespace +# comments may terminated by linefeed or double hash ## <- end of comment + +Keywords are preceded by a single hash symbol without whitespace. +#Keyword + +Keywords are terminated by double hash and may be labeled +## <- end of #keyword + +#Keyword +#Keyword ## <- alternate labeled end of #Keyword + +Tables use single hash symbols to delimit columns, and double to end row. +#Table +#Legend +# first column in table # next column in table ## +## <- end of #Legend +# a row # another row ## +# another row # another row ## +#Table ## <- or, just ## + +$Table +$Legend +$ first column in table $ next column in table $$ +$$ +$ a row $ another row $$ +$ another row $ another row $$ +$Table $$ + +The markup character is initially # at the start of any .bmh file +###x <- redefine the markup character as 'x' +xxx# <- restore the default markup character + + anchor, ala HTML + anchors may start anywhere in the line +#A text #_reference ## + + class description +#Class SkClassName +description +methods +## + + if the example is not named, it inherits the name of its container +#Example + #Description + ## + #Image + #Width + #Height + code... + #StdOut + expected example output + ## +## + +#Enum __required_reference +description +#Code +## +#Example +## +#Enum ## + + method description + the _method_reference must be unique within the class +#Method type name(params..) +description +#Param name description ## +#Return return ## +#Example +## +#SeeAlso ## +## + +#ToDo description ## + +$ restore markup character +$$$# + +## diff --git a/docs/overview.bmh b/docs/overview.bmh new file mode 100644 index 0000000000..c6b0d1fef8 --- /dev/null +++ b/docs/overview.bmh @@ -0,0 +1,8 @@ +overview + +-------------------------------------------------------------------------------- + +Skia draws 2D primitives, paths and bitmaps, using the styles in the SkPaint, to +the device contained by the SkCanvas. + +-------------------------------------------------------------------------------- diff --git a/docs/undocumented.bmh b/docs/undocumented.bmh new file mode 100644 index 0000000000..8aecc3168f --- /dev/null +++ b/docs/undocumented.bmh @@ -0,0 +1,528 @@ +# external references that will be documented eventually ... +#External + DirectWrite TrueType Windows Linux Android + FreeType FreeType-based Harfbuzz + PostScript PostScript_arct + OS_X Core_Graphics Core_Text iOS + LCD RGB + Premultiplied Unpremultiplied + Unicode Unicode5 UTF-8 UTF-16 UTF-32 ASCII Unichar + HTML_Canvas HTML_Canvas_arcTo + API + CPU + GPU GPU-backed GPU_Context OpenGL Vulkan + NULL + RFC + Bezier Coons + SkUserConfig.h # not external, but still thinking about how markup refers to this + Skia # ditto + SK_USE_FREETYPE_EMBOLDEN # ditto + SK_SUPPORT_LEGACY_PAINT_TEXTDECORATION # ditto + SK_BUILD_FOR_ANDROID_FRAMEWORK # ditto + Developer_Mode # ditto + Draw_Layer # ditto + Raster_Engine # ditto + +# FreeType related +FT_LOAD_TARGET_LIGHT +FT_LOAD_TARGET_NORMAL +FT_LOAD_TARGET_LCD +FT_LOAD_TARGET_LCD_V +FT_LOAD_NO_HINTING +FT_Load_Glyph + +#External ## + +#Topic Arc +#Substitute arcs +#Topic ## + +#Topic BBH_Factory +#Class SkBBHFactory +## +## + +#Topic Bitmap +#Class SkBitmap + #Subtopic Row_Bytes + ## +#Class ## +## + +#Topic Blend_Mode +#EnumClass SkBlendMode + #Const kSrc 1 + ## + #Const kSrcOver 3 + ## + #Const kPlus 12 + ## +#EnumClass ## +#Topic ## + +#Topic Circle +#Substitute circles +#Topic ## + +#Topic Clip_Op +#EnumClass SkClipOp + #Const kDifference 0 + ## + #Const kIntersect 1 + ## +## +## + +#Topic Color + #Typedef SkColor + #Typedef ## + + # fixme: defines, not methods, need new markup type + #Method int SkColorGetA(color) + ## + #Method int SkColorGetR(color) + ## + #Method int SkColorGetG(color) + ## + #Method int SkColorGetB(color) + ## + #Method int SkColorSetARGB(a, r, g, b) + ## + + #Const SK_ColorBLACK 0xFF000000 + ## + #Const SK_ColorBLUE 0xFF0000FF + ## + #Const SK_ColorGREEN 0xFF00FF00 + ## + #Const SK_ColorRED 0xFFFF0000 + ## + #Const SK_ColorWHITE 0xFFFFFFFF + ## + #Subtopic Alpha + #Substitute alpha + #Subtopic ## + #Subtopic RGB + #Substitute RGB + #Subtopic Red + #Substitute red + #Subtopic ## + #Subtopic Blue + #Substitute blue + #Subtopic ## + #Subtopic Green + #Substitute green + #Subtopic ## + #Subtopic ## + #Subtopic ARGB + #Substitute ARGB + #Subtopic ## + + #Subtopic RBG + #Substitute RBG + #Subtopic ## + + #Subtopic RGB-565 + #Substitute RGB-565 + #Alias Color_RGB-565 # quit changing - to _ ! + #Subtopic ## +#Topic ## + +#Topic Color_Filter +#Class SkColorFilter +#Class ## +#Topic ## + +#Topic Color_Space +## + +#Topic Curve +#Alias Curves +## + +#Topic Data +## + +#Topic Device +#Class SkBaseDevice +## +#Topic ## + +#Topic Document +#Class SkDocument + #Method SkCanvas* beginPage(SkScalar width, SkScalar height, + const SkRect* content = NULL) + ## +## +#Subtopic PDF +## +## + +#Topic Draw_Filter +#Class SkDrawFilter +## +## + +#Topic Draw_Looper +#Class SkDrawLooper +#Class ## +#Topic ## + +#Topic Drawable +#Class SkDrawable + #Method void draw(SkCanvas*, const SkMatrix* = NULL) + ## +## +## + +#Topic Dump_Canvas +#Class SkDumpCanvas +## +#Topic ## + +#Topic Filter_Quality +#Enum SkFilterQuality + #Const kNone_SkFilterQuality 0 + ## + #Const kLow_SkFilterQuality 1 + ## + #Const kMedium_SkFilterQuality 2 + ## + #Const kHigh_SkFilterQuality 3 + ## +#Enum ## +#Topic ## + +#Topic Font +#Subtopic Advance +#Subtopic ## +#Subtopic Engine +## +#Topic ## + +#Topic Font_Manager +#Topic ## + +#Topic Glyph +## + +#Topic Image + #Subtopic Alpha_Type + #Enum SkAlphaType + #Const kPremul_SkAlphaType 2 + ## + ## + #Subtopic ## + #Subtopic Color_Type + #Enum SkColorType + #Const kUnknown_SkColorType 0 + ## + #Const kAlpha_8_SkColorType 1 + ## + #Const kRGB_565_SkColorType 2 + ## + #Const kARGB_4444_SkColorType 3 + ## + #Const kRGBA_8888_SkColorType 4 + ## + #Const kBGRA_8888_SkColorType 5 + ## + #Const kIndex_8_SkColorType 6 + ## + #Const kGray_8_SkColorType 7 + ## + #Const kRGBA_F16_SkColorType 8 + ## + #ToDo this is a lie; need to not require values for consts ## + #Const kN32_SkColorType 4 + ## + #Enum ## + #Subtopic ## + #Subtopic Info + #Struct SkImageInfo + #Method SkImageInfo() + ## + ## + #Subtopic ## + #Class SkImage + #Method sk_sp<SkShader> makeShader(SkShader::TileMode, SkShader::TileMode, + const SkMatrix* localMatrix = nullptr) const + ## + ## +#Topic ## + +#Topic Image_Filter +#Subtopic Scaling +#Subtopic ## +#Class SkImageFilter +#Class ## +#Topic ## + +#Topic Image_Scaling +## + +#Topic IRect +#Struct SkIRect +## +## + +#Topic Line +#Substitute lines +#Alias Lines +#Topic ## + +#Topic Mask +#Topic ## + +#Topic Mask_Alpha +#Topic ## + +#Topic Mask_Filter +#Class SkMaskFilter +#Class ## +#Topic ## + +#Topic Matrix +#Struct SkMatrix +#Struct ## +#Topic ## + +#Topic Nine_Patch +## + +#Topic Number_Types + #Typedef SkGlyphID + #Typedef ## + #Typedef SkScalar + #Typedef ## + #Const SK_ScalarMax + to be written + ## + #Const SK_ScalarInfinity + to be written + ## + #Const SK_ScalarNegativeInfinity + to be written + ## + #Const SK_ScalarNaN + to be written + ## + #Typedef SkUnichar + #Typedef ## + #Typedef U8CPU + #Typedef ## +#Topic ## + +#Topic Oval +#Substitute ovals +#Topic ## + +#Topic Paint_Defaults +#Const SkPaintDefaults_Flags 0 +## +#Const SkPaintDefaults_Hinting 2 +## +#Const SkPaintDefaults_TextSize 12 +## +#Const SkPaintDefaults_MiterLimit 4 +## +#Topic ## + +#Topic Patch +#Substitute patches +#Topic ## + +#Topic Path_Effect + #Class SkPathEffect + #Class ## +#Topic ## + +#Topic Path_Measure + #Class SkPathMeasure + #Method void dump() const + ## + ## +## + +#Topic PathOps + #Method bool SK_API Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) + ## +#Topic ## + +#Topic Picture +#Subtopic Recorder + #Class SkPictureRecorder + #Method SkCanvas* beginRecording(const SkRect& bounds, + SkBBHFactory* bbhFactory = NULL, + uint32_t recordFlags = 0) + ## + ## +## +## + +#Topic Pixel +#Subtopic Storage +## +## + +#Topic Pixmap +#Class SkPixmap +## +## + +#Topic Point +#Alias Points + #Struct SkPoint + #Method bool equalsWithinTolerance(const SkPoint& p) const + ## + #Struct ## + #Subtopic Array + #Substitute SkPoint arrays + #Subtopic ## +#Topic ## + +#Topic Raster_Handle_Allocator +#Class SkRasterHandleAllocator + #Struct Rec + ## + #Method static std::unique_ptr<SkCanvas> MakeCanvas(std::unique_ptr<SkRasterHandleAllocator>, const SkImageInfo&, const Rec* rec = nullptr) + ## +## +## + +#Topic Rasterizer +#Class SkRasterizer +#Class ## +#Subtopic Layer +#Subtopic ## +#Topic ## + +#Topic Rect +#Alias Rects + #Struct SkRect + #Method static constexpr SkRect SK_WARN_UNUSED_RESULT MakeEmpty() + ## + #Method void dump() const + ## + #Method void dumpHex() const + ## + #Struct ## +#Topic ## + +#Topic Reference_Count +#Substitute SkRefCnt +#Class sk_sp +#Class ## +#Topic ## + +#Topic Region +#Class SkRegion +## +#Topic ## + +#Topic Round_Rect + #Class SkRRect + #Method void dump() const + ## + #Method void dumpHex() const + ## + ## +#Topic ## + +#Topic RSXform +#Struct SkRSXform +## +## + +#Topic Shader +#Class SkShader + #Enum TileMode + #Const kClamp_TileMode 0 + ## + ## + #Method static sk_sp<SkShader> MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, + const SkMatrix* localMatrix = nullptr) + ## +#Class ## +#Subtopic Gradient +#Subtopic ## +#Topic ## + +#Topic Sprite +#Substitute sprites +#Topic ## + +#Topic Stream +#Class SkFlattenable +#Class ## +#Topic ## + +#Topic String +#Class SkString +#Class ## +#Topic ## + +#Topic Surface +#Class SkSurface + #Method static sk_sp<SkSurface> MakeRasterDirect(const SkImageInfo&, void* pixels, size_t rowBytes, + const SkSurfaceProps* = nullptr) + ## +## +#Subtopic Properties + #Class SkSurfaceProps + #Enum InitType + #Const kLegacyFontHost_InitType 0 + ## + ## + ## +## +#Subtopic GPU +#Alias GPU_Surface +## +#Subtopic Raster +#Alias Raster_Surface +## +## + +#Topic SVG +#Subtopic Canvas +## +#Subtopic Arc +## +## + +#Topic Text +#Topic ## + +#Topic Text_Blob +#Class SkTextBlob +#Class ## +#Topic ## + +#Topic Typeface +#Class SkTypeface +#Class ## +#Topic ## + +#Topic Vector +#Struct SkVector +## +## + +#Topic Vertices +#Substitute vertices +#Subtopic Colors +## +#Subtopic Texs +## +#Topic ## + +#Topic Read_Buffer + #Struct SkReadBuffer + #Struct ## +## + +#Topic Write_Buffer + #Struct SkWriteBuffer + #Struct ## +#Topic ## diff --git a/docs/usingBookmaker.bmh b/docs/usingBookmaker.bmh new file mode 100644 index 0000000000..65a8df561f --- /dev/null +++ b/docs/usingBookmaker.bmh @@ -0,0 +1,95 @@ +#External
+SkXXX
+bmh_SkXXX
+CL
+C
+Visual_Studio
+##
+
+#Topic Bookmaker
+
+How to use the Bookmaker utility.
+
+Get the fiddle command line interface tool.
+
+#Code
+$ go get go.skia.org/infra/fiddle/go/fiddlecli
+##
+
+Get the Bookmaker CL and build it.
+
+#Code
+$ git cl patch 9919
+$ ninja -C out/dir bookmaker
+##
+
+Generate an starter Bookmaker file from an existing include.
+This writes SkXXX.bmh in the current directory, which is
+out/dir/obj/ from an IDE.
+
+#Code
+$ ./out/dir/bookmaker -t -i include/core/SkXXX.h
+##
+
+Use your favorite editor to fill out SkXXX.bmh.
+
+Generate fiddle.json from all examples, including the ones you just wrote.
+Error checking is syntatic: starting keywords are closed, keywords have the
+correct parents.
+If you run Bookmaker inside Visual_Studio, you can click on errors and it
+will take you to the source line in question.
+
+#Code
+$ ./out/dir/bookmaker -e fiddle.json -b current_directory
+##
+
+Once complete, run fiddlecli to generate the example hashes.
+Errors are contained by the output but aren't reported yet.
+
+#Code
+$ $GOPATH/bin/fiddlecli --input fiddle.json --output fiddleout.json
+##
+
+Generate bmh_SkXXX.md from SkXXX.bmh and fiddleout.json.
+Error checking includes: undefined references, fiddle compiler errors,
+missing or mismatched printf output.
+Again, you can click on any errors inside Visual_Studio.
+
+#Code
+$ ./out/dir/bookmaker -r site/user/api -b current_directory -f fiddleout.json
+##
+
+The original include may have changed since you started creating the markdown.
+Check to see if it is up to date.
+This reports if a method no longer exists or its parameters have changed.
+
+#Code
+$ ./out/dir/bookmaker -x -b current_directory/SkXXX.bmh -i include/core/SkXXX.h
+##
+
+#Topic Bugs
+#List +overaggressive reference finding in code block
+missing examples
+redundant examples -- got tired so used the same one more than once
+some examples need vertical resizing
+list doesn't work (ironic, huh)
+##
+##
+
+#Topic To_Do
+#List +check that all methods have one line descriptions in overview
+see also -- anything that can be done automatically? maybe any ref shows up everywhere
+index by example png
+generate pdf or pdf-like out
+generate b/w out instead of color -- have b/w versions of examples?
+formalize voice / syntax for parts of topic and method
+write bmh data back into include
+ have a way to write one block that covers multiple nearly indentical methods?
+ may want to do this for pdf view as well
+write a one-method-per-page online view?
+##
+##
+
+#Topic Bookmaker ##
|