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>
diff --git a/docs/SkCanvas.bmh b/docs/SkCanvas.bmh
new file mode 100644
index 0000000..aefbae4
--- /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 ##