| #Topic Canvas | 
 | #Alias Canvas_Reference | 
 |  | 
 | #Class SkCanvas | 
 |  | 
 | 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 use Paint to supply drawing | 
 | state such as Color, Typeface, text size, 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. | 
 |  | 
 | 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. | 
 |  | 
 | Canvas can be constructed to draw to Bitmap without first creating Raster_Surface. | 
 | This approach may be deprecated in the future.   | 
 |  | 
 | #Topic Overview | 
 |  | 
 | #Subtopic Subtopics | 
 | #Table | 
 | #Legend | 
 | # name                  # description                                        ## | 
 | #Legend ## | 
 | # Classes_and_Structs   # embedded struct and class members                  ## | 
 | # Constants             # enum and enum class, const values                  ## | 
 | # Constructors          # functions that construct SkPath                    ## | 
 | # Member_Functions      # static functions and member methods                ## | 
 | # Operators             # operator overloading methods                       ## | 
 | #Table ## | 
 | #Subtopic ## | 
 |  | 
 | #Subtopic Constants | 
 | #Table | 
 | #Legend | 
 | # name                           # description                                 ## | 
 | #Legend ## | 
 | # Lattice::Flags                 # controls Lattice transparency ## | 
 | # PointMode                      # sets drawPoints options ## | 
 | # SaveLayerFlags                 # sets SaveLayerRec options ## | 
 | # SrcRectConstraint              # sets drawImageRect options ## | 
 | #Table ## | 
 | #Subtopic ## | 
 |  | 
 | #Subtopic Classes_and_Structs | 
 | #Table | 
 | #Legend | 
 | # name                           # description                                   ## | 
 | #Legend ## | 
 | # Lattice                        # divides Bitmap, Image into a rectangular grid ## | 
 | # SaveLayerRec                   # contains state to create Layer                ## | 
 | #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 | 
 | # name                                                          # description                                    ## | 
 | #Legend ## | 
 | # MakeRasterDirect                                              # creates from SkImageInfo and Pixel_Storage     ## | 
 | # MakeRasterDirectN32                                           # creates from image data and Pixel_Storage      ## | 
 | # SkCanvas()                                                    # creates with no Surface, no dimensions         ## | 
 | # SkCanvas(SkBaseDevice* device)                                # to be deprecated                               ## | 
 | # SkCanvas(const SkBitmap& bitmap)                              # uses existing Bitmap                           ## | 
 | # SkCanvas(const SkBitmap& bitmap, ColorBehavior behavior)      # Android framework only                         ## | 
 | # SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) # uses existing Bitmap and Surface_Properties    ## | 
 | # SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr) # no Surface, set dimensions, Surface_Properties ## | 
 | # ~SkCanvas()                                                   # draws saved Layers, frees resources            ## | 
 | #Table ## | 
 | #Subtopic ## | 
 |  | 
 | #Subtopic Member_Functions | 
 | #Table | 
 | #Legend | 
 | # name                             # description                                                   ## | 
 | #Legend ## | 
 | # MakeRasterDirect                 # creates Canvas from SkImageInfo and pixel data ## | 
 | # MakeRasterDirectN32              # creates Canvas from image specifications and pixel data ## | 
 | # 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 proportionally 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 proportionally 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 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 ## | 
 | # drawString                       # draws null terminated string at (x, y) using font advance ## | 
 | # 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 ## | 
 | # drawVertices                     # draws Vertices, a triangle mesh ## | 
 | # flush()                          # triggers execution of all pending draw operations ## | 
 | # getBaseLayerSize                 # returns 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 ## | 
 | # 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 Layer ## | 
 | # saveLayerAlpha                   # saves Clip and Matrix on stack; creates Layer; sets opacity ## | 
 | # saveLayerPreserveLCDTextRequests # saves Clip and Matrix on stack; creates Layer 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, | 
 |                                                           const SkSurfaceProps* props = nullptr) | 
 |  | 
 | Allocates raster Canvas that will draw directly into pixels. | 
 |  | 
 | Canvas is returned if all parameters are valid. | 
 | Valid parameters include: | 
 | info dimensions are zero or positive; | 
 | info contains Image_Color_Type and Image_Alpha_Type supported by Raster_Surface; | 
 | pixels is not nullptr; | 
 | rowBytes is zero or large enough to contain info width pixels of Image_Color_Type. | 
 |  | 
 | Pass zero for rowBytes to compute rowBytes from info width and size of pixel.  | 
 | If rowBytes is greater than zero, it must be equal to or greater than | 
 | info width times bytes required for Image_Color_Type. | 
 |  | 
 | Pixel buffer size should be info height times computed rowBytes. | 
 | Pixels are not initialized. | 
 | 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 | 
 | ## | 
 | #Param rowBytes  interval from one Surface row to the next, or zero | 
 | ## | 
 | #Param props  LCD striping orientation and setting for device independent fonts; | 
 |               may be nullptr | 
 | ## | 
 |  | 
 | #Return  Canvas if all parameters are valid; otherwise, nullptr ## | 
 |  | 
 | #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, Premultiplied | 
 |     const size_t minRowBytes = info.minRowBytes();  // bytes used by one bitmap row | 
 |     const size_t size = info.computeMinByteSize();  // 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- | 
 |         --- | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso MakeRasterDirectN32 SkSurface::MakeRasterDirect | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method static std::unique_ptr<SkCanvas> MakeRasterDirectN32(int width, int height, SkPMColor* pixels, | 
 |                                                          size_t rowBytes)  | 
 |  | 
 | Allocates raster Canvas specified by inline image specification. Subsequent Canvas | 
 | calls draw 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. | 
 |  | 
 | Canvas is returned if all parameters are valid. | 
 | Valid parameters include: | 
 | width and height are zero or positive; | 
 | pixels is not nullptr; | 
 | rowBytes is zero or large enough to contain width pixels of kN32_SkColorType. | 
 |  | 
 | Pass zero for rowBytes to compute rowBytes from width and size of pixel.  | 
 | If rowBytes is greater than zero, it must be equal to or greater than | 
 | width times bytes required for Image_Color_Type. | 
 |  | 
 | Pixel buffer size should be height times rowBytes. | 
 |  | 
 | #Param width  pixel column count on Raster_Surface created; must be zero or greater ## | 
 | #Param height  pixel row count on Raster_Surface created; must be zero or greater ## | 
 | #Param pixels  pointer to destination pixels buffer; buffer size should be height | 
 |                times rowBytes | 
 | ## | 
 | #Param rowBytes  interval from one Surface row to the next, or zero | 
 | ## | 
 |  | 
 | #Return  Canvas if all parameters are valid; otherwise, nullptr ## | 
 |  | 
 | #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 premultiplied 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- | 
 |         --- | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso MakeRasterDirect SkSurface::MakeRasterDirect SkImageInfo::MakeN32Premul | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method SkCanvas() | 
 |  | 
 | Creates an empty Canvas with no backing device or pixels, with  | 
 | a width and height of zero. | 
 |  | 
 | #Return  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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr) | 
 |  | 
 | Creates Canvas of the specified dimensions without a Surface. | 
 | Used by Subclasses with custom implementations for draw methods. | 
 |  | 
 | If props equals nullptr, Surface_Properties are created with | 
 | Surface_Properties_Legacy_Font_Host settings, which choose the pixel striping  | 
 | direction and order. Since a platform may dynamically change its direction when | 
 | the device is rotated, and since a platform may have multiple monitors with | 
 | different characteristics, it is best not to rely on this legacy behavior. | 
 |  | 
 | #Param width  zero or greater ## | 
 | #Param height zero or greater ## | 
 | #Param props  LCD striping orientation and setting for device independent fonts; | 
 |               may be nullptr | 
 | ## | 
 |  | 
 | #Return       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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso MakeRasterDirect SkSurfaceProps SkPixelGeometry SkCreateColorSpaceXformCanvas | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 or figure out a way to fiddle it ## | 
 |  | 
 | #SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method explicit SkCanvas(const SkBitmap& bitmap) | 
 |  | 
 | Construct a canvas that draws into bitmap. | 
 | Sets SkSurfaceProps::kLegacyFontHost_InitType in constructed Surface.  | 
 |  | 
 | Bitmap is copied so that subsequently editing bitmap will not affect | 
 | constructed Canvas. | 
 |  | 
 | May be deprecated in the future. | 
 |  | 
 | #ToDo Should be deprecated? ## | 
 |  | 
 | #Param bitmap   width, height, Image_Color_Type, Image_Alpha_Type, and pixel | 
 |                 storage of Raster_Surface | 
 | ## | 
 |  | 
 | #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 ## | 
 | ## | 
 |  | 
 | #SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas | 
 |  | 
 | ## | 
 |  | 
 | #EnumClass ColorBehavior | 
 |  | 
 | #Private | 
 | Android framework only. | 
 | ## | 
 |  | 
 | #Code | 
 |     enum class ColorBehavior { | 
 |         kLegacy, | 
 |     }; | 
 | ## | 
 | #Const kLegacy 0 | 
 |     Is a placeholder to allow specialized constructor; has no meaning. | 
 | ## | 
 | ## | 
 |  | 
 | #Method SkCanvas(const SkBitmap& bitmap, ColorBehavior behavior) | 
 |  | 
 | #Private | 
 | Android framework only. | 
 | ## | 
 |  | 
 | #Param bitmap    specifies a bitmap for the canvas to draw into ## | 
 | #Param behavior  specializes this constructor; value is unused ## | 
 | #Return          Canvas that can be used to draw into bitmap ## | 
 |  | 
 | #NoExample | 
 | ## | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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. | 
 |  | 
 | bitmap is copied so that subsequently editing bitmap will not affect | 
 | constructed Canvas. | 
 |  | 
 | #Param bitmap   width, height, Image_Color_Type, Image_Alpha_Type, | 
 |                 and pixel storage of Raster_Surface  | 
 | ## | 
 | #Param props    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 ## | 
 | ## | 
 |  | 
 | #SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method virtual ~SkCanvas() | 
 |  | 
 | Draws saved Layers, if any. | 
 | Frees up resources used by Canvas. | 
 |  | 
 | #Example | 
 | #Description | 
 | Canvas Layer draws into bitmap. saveLayerAlpha sets up an additional | 
 | drawing surface that blends with the bitmap. When Layer goes out of | 
 | scope, Layer Destructor is called. The saved Layer is restored, drawing | 
 | transparent letters. | 
 | ## | 
 | void draw(SkCanvas* canvas) { | 
 |     SkBitmap bitmap; | 
 |     bitmap.allocPixels(SkImageInfo::MakeN32Premul(200, 200)); | 
 |     { | 
 |         SkCanvas offscreen(bitmap); | 
 |         SkPaint paint; | 
 |         paint.setTextSize(100); | 
 |         offscreen.drawString("ABC", 20, 160, paint); | 
 |         SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192); | 
 |         offscreen.saveLayerAlpha(&layerBounds, 128); | 
 |         offscreen.clear(SK_ColorWHITE); | 
 |         offscreen.drawString("DEF", 20, 160, paint); | 
 |     } | 
 |     canvas->drawBitmap(bitmap, 0, 0, nullptr); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso State_Stack | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method SkMetaData& getMetaData() | 
 |  | 
 | Returns storage to associate 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 ## | 
 | ## | 
 |  | 
 | #SeeAlso SkMetaData | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method SkImageInfo imageInfo() const | 
 |  | 
 | Returns Image_Info for Canvas. If Canvas is not associated with Raster_Surface or | 
 | GPU_Surface, returned Image_Color_Type is set to kUnknown_SkColorType. | 
 |  | 
 | #Return  dimensions and Image_Color_Type of Canvas ## | 
 |  | 
 | #Example | 
 |     SkCanvas emptyCanvas; | 
 |     SkImageInfo canvasInfo = emptyCanvas.imageInfo(); | 
 |     SkImageInfo emptyInfo; | 
 |     SkDebugf("emptyInfo %c= canvasInfo\n", emptyInfo == canvasInfo ? '=' : '!'); | 
 |  | 
 |     #StdOut | 
 |         emptyInfo == canvasInfo | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso SkImageInfo MakeRasterDirect makeSurface | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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  storage for 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 ## | 
 | ## | 
 |  | 
 | #SeeAlso SkSurfaceProps makeSurface | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void flush() | 
 |  | 
 | Triggers the immediate execution of all pending draw operations.  | 
 | If Canvas is associated with GPU_Surface, resolves all pending GPU operations. | 
 | If Canvas is associated with Raster_Surface, has no effect; raster draw | 
 | operations are never deferred. | 
 |  | 
 | #ToDo | 
 | In an overview section on managing the GPU, include: | 
 | - flush should never change what is drawn | 
 | - call to kick off gpu work | 
 | - calling too much impacts performance | 
 | - some calls (peekPixels, prepareForExternalIO) call it internally | 
 | - canvas call is local, GrContext::flush is global | 
 | - diffentiate between flush, flushAndSignalSemaphores | 
 | - normally never needs to be called | 
 | - call it when sharing gpu resources, feeling memory pressure, swapping out app, and before | 
 |   abandoning context | 
 | - also call to say "I'm finished drawing here", e.g., when drawing to a GPU-backed offscreen surface | 
 |   (created with SkSurface::MakeRenderTarget) | 
 |  | 
 | for posterity: this doesn't show a difference: fiddle.skia.org/c/@flushfail | 
 | ## | 
 |  | 
 | #Example | 
 | #Error "haven't thought of a useful example to put here" | 
 | ## | 
 |  | 
 | #SeeAlso peekPixels SkSurface::flush() GrContext::flush() SkSurface::prepareForExternalIO GrContext::abandonContext() | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 area available for drawing 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? ## | 
 |  | 
 | #SeeAlso getDeviceClipBounds | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method sk_sp<SkSurface> makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr) | 
 |  | 
 | Creates Surface matching info and props, and associates it with Canvas. | 
 | Returns nullptr if no match found. | 
 |  | 
 | If props is nullptr, matches Surface_Properties in Canvas. If props is nullptr and Canvas | 
 | does not have Surface_Properties, creates Surface with default Surface_Properties. | 
 |  | 
 | #Param info  width, height, Image_Color_Type, Image_Alpha_Type, and Color_Space ## | 
 | #Param props  Surface_Properties to match; may be nullptr to match Canvas ## | 
 |  | 
 | #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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso SkSurface SkSurface::makeSurface SkImageInfo SkSurfaceProps | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 ## | 
 |  | 
 | #SeeAlso GrContext  | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr) | 
 |  | 
 | 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      storage for writable pixels' Image_Info; may be nullptr ## | 
 | #Param rowBytes  storage for writable pixels' row bytes; may be nullptr ## | 
 | #Param origin    storage for Canvas top Layer origin, its top-left corner; | 
 |                  may be nullptr | 
 | ## | 
 |  | 
 | #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 Layer, and reads | 
 | Layer to add a large dotted "DEF". Finally blends Layer with the | 
 | device.  | 
 |  | 
 | The Layer 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 ## | 
 |  | 
 | #SeeAlso SkImageInfo SkPixmap | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 user interface. The custom context returned is generated by | 
 | SkRasterHandleAllocator::MakeCanvas, which creates a custom canvas with raster storage for | 
 | the drawing destination. | 
 |  | 
 | #Return  context of custom allocation ## | 
 |  | 
 | #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 Canvas | 
 | is returned from GPU_Surface, returned by SkDocument::beginPage, returned by | 
 | SkPictureRecorder::beginRecording, or Canvas is the base of a utility class | 
 | like SkDumpCanvas. | 
 |  | 
 | pixmap is valid only while Canvas is in scope and unchanged. Any | 
 | Canvas or Surface call may invalidate the pixmap values. | 
 |  | 
 | #Param pixmap  storage for pixel state if 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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso readPixels SkBitmap::peekPixels SkImage::peekPixels SkSurface::peekPixels | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, | 
 |                     int srcX, int srcY) | 
 |  | 
 | Copies Rect of pixels from Canvas into dstPixels. Matrix and Clip are | 
 | ignored.  | 
 |  | 
 | Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). | 
 | Destination Rect corners are (0, 0) and (dstInfo.width(), dstInfo.height()). | 
 | Copies each readable pixel intersecting both rectangles, without scaling, | 
 | converting to dstInfo.colorType() and dstInfo.alphaType() if required. | 
 |  | 
 | Pixels are readable when Device is raster, or backed by a GPU. | 
 | Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, | 
 | returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility | 
 | class like SkDumpCanvas. | 
 |  | 
 | The destination pixel storage must be allocated by the caller. | 
 |  | 
 | Pixel values are converted only if Image_Color_Type and Image_Alpha_Type | 
 | do not match. Only pixels within both source and destination rectangles | 
 | are copied. dstPixels contents outside Rect intersection are unchanged. | 
 |  | 
 | Pass negative values for srcX or srcY to offset pixels across or down destination. | 
 |  | 
 | Does not copy, and returns false if: | 
 |  | 
 | #List | 
 | # Source and destination rectangles do not intersect. ## | 
 | # Canvas pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). ## | 
 | # Canvas pixels are not readable; for instance, Canvas is document-based. ## | 
 | # dstRowBytes is too small to contain one row of pixels. ## | 
 | ## | 
 |  | 
 | #Param dstInfo  width, height, Image_Color_Type, and Image_Alpha_Type of dstPixels ## | 
 | #Param dstPixels  storage for pixels; dstInfo.height() times dstRowBytes, or larger ## | 
 | #Param dstRowBytes  size of one destination row; dstInfo.width() times pixel size, or larger ## | 
 | #Param srcX  offset into readable pixels in x; may be negative ## | 
 | #Param srcY  offset into readable pixels in y; may be negative ## | 
 |  | 
 | #Return  true if pixels were copied ## | 
 |  | 
 | #Example | 
 | #Width 64 | 
 | #Height 64 | 
 | #Description | 
 |     A black circle drawn on a blue background provides an image to copy. | 
 |     readPixels copies one quarter of the canvas into each of the four corners. | 
 |     The copied quarter circles overdraw the original circle. | 
 | ## | 
 |     canvas->clear(SK_ColorBLUE); | 
 |     SkPaint paint; | 
 |     canvas->drawCircle(32, 32, 28, paint); | 
 |     SkImageInfo info = SkImageInfo::Make(64, 64, kBGRA_8888_SkColorType, kPremul_SkAlphaType); | 
 |     sk_sp<SkData> data(SkData::MakeUninitialized(info.minRowBytes() * info.height())); | 
 |     sk_bzero(data->writable_data(), info.minRowBytes() * info.height()); | 
 |     for (int x : { 32, -32 } ) { | 
 |         for (int y : { 32, -32 } ) { | 
 |             canvas->readPixels(info, data->writable_data(), info.minRowBytes(), x, y); | 
 |         }  | 
 |     } | 
 |     sk_sp<SkImage> image = SkImage::MakeRasterData(info, data, info.minRowBytes()); | 
 |     canvas->drawImage(image, 0, 0); | 
 | ## | 
 |  | 
 | #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 multiplied by Color_Alpha | 
 |     to generate Premultiplied value 0x802B5580. readPixels converts pixel back | 
 |     to Unpremultiplied 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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method bool readPixels(const SkPixmap& pixmap, int srcX, int srcY) | 
 |  | 
 | Copies Rect of pixels from Canvas into pixmap. Matrix and Clip are | 
 | ignored. | 
 |  | 
 | Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). | 
 | Destination Rect corners are (0, 0) and (pixmap.width(), pixmap.height()). | 
 | Copies each readable pixel intersecting both rectangles, without scaling, | 
 | converting to pixmap.colorType() and pixmap.alphaType() if required. | 
 |  | 
 | Pixels are readable when Device is raster, or backed by a GPU. | 
 | Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, | 
 | returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility | 
 | class like SkDumpCanvas. | 
 |  | 
 | Caller must allocate pixel storage in pixmap if needed. | 
 |  | 
 | Pixel values are converted only if Image_Color_Type and Image_Alpha_Type | 
 | do not match. Only pixels within both source and destination Rects | 
 | are copied. pixmap pixels contents outside Rect intersection are unchanged. | 
 |  | 
 | Pass negative values for srcX or srcY to offset pixels across or down pixmap. | 
 |  | 
 | Does not copy, and returns false if: | 
 |  | 
 | #List | 
 | # Source and destination rectangles do not intersect. ## | 
 | # Canvas pixels could not be converted to pixmap.colorType() or pixmap.alphaType(). ## | 
 | # Canvas pixels are not readable; for instance, Canvas is document-based. ## | 
 | # Pixmap pixels could not be allocated. ## | 
 | # pixmap.rowBytes() is too small to contain one row of pixels. ## | 
 | ## | 
 |  | 
 | #Param pixmap  storage for pixels copied from Canvas ## | 
 | #Param srcX    offset into readable pixels in x; may be negative ## | 
 | #Param srcY    offset into readable pixels in y; may be negative ## | 
 |  | 
 | #Return  true if pixels were copied ## | 
 |  | 
 | #Example | 
 |     #Description | 
 |         clear() takes Unpremultiplied input with Color_Alpha equal 0x80 | 
 |         and Color_RGB equal 0x55, 0xAA, 0xFF. Color_RGB is multiplied by Color_Alpha | 
 |         to generate Premultiplied value 0x802B5580. | 
 |     ## | 
 |     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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method bool readPixels(const SkBitmap& bitmap, int srcX, int srcY) | 
 |  | 
 | Copies Rect of pixels from Canvas into bitmap. Matrix and Clip are | 
 | ignored. | 
 |  | 
 | Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). | 
 | Destination Rect corners are (0, 0) and (bitmap.width(), bitmap.height()). | 
 | Copies each readable pixel intersecting both rectangles, without scaling, | 
 | converting to bitmap.colorType() and bitmap.alphaType() if required. | 
 |  | 
 | Pixels are readable when Device is raster, or backed by a GPU. | 
 | Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, | 
 | returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility | 
 | class like SkDumpCanvas. | 
 |  | 
 | Caller must allocate pixel storage in bitmap if needed. | 
 |  | 
 | Bitmap values are converted only if Image_Color_Type and Image_Alpha_Type | 
 | do not match. Only pixels within both source and destination rectangles | 
 | are copied. Bitmap pixels outside Rect intersection are unchanged. | 
 |  | 
 | Pass negative values for srcX or srcY to offset pixels across or down bitmap. | 
 |  | 
 | Does not copy, and returns false if: | 
 |  | 
 | #List | 
 | # Source and destination rectangles do not intersect. ## | 
 | # Canvas pixels could not be converted to bitmap.colorType() or bitmap.alphaType(). ## | 
 | # Canvas pixels are not readable; for instance, Canvas is document-based. ## | 
 | # bitmap pixels could not be allocated. ## | 
 | # bitmap.rowBytes() is too small to contain one row of pixels. ## | 
 | ## | 
 |  | 
 | #Param bitmap  storage for pixels copied from Canvas ## | 
 | #Param srcX    offset into readable pixels in x; may be negative ## | 
 | #Param srcY    offset into readable pixels in y; may be negative ## | 
 |  | 
 | #Return  true if pixels were copied ## | 
 |  | 
 | #Example | 
 |     #Description | 
 |         clear() takes Unpremultiplied input with Color_Alpha equal 0x80 | 
 |         and Color_RGB equal 0x55, 0xAA, 0xFF. Color_RGB is multiplied by Color_Alpha | 
 |         to generate Premultiplied value 0x802B5580. | 
 |     ## | 
 | 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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y) | 
 |  | 
 | Copies Rect from pixels to Canvas. Matrix and Clip are ignored. | 
 | Source Rect corners are (0, 0) and (info.width(), info.height()). | 
 | Destination Rect corners are (x, y) and | 
 | (imageInfo().width(), imageInfo().height()). | 
 |  | 
 | Copies each readable pixel intersecting both rectangles, without scaling, | 
 | converting to imageInfo().colorType() and imageInfo().alphaType() if required. | 
 |  | 
 | Pixels are writable when Device is raster, or backed by a GPU. | 
 | Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, | 
 | returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility | 
 | class like SkDumpCanvas. | 
 |  | 
 | Pixel values are converted only if Image_Color_Type and Image_Alpha_Type | 
 | do not match. Only pixels within both source and destination rectangles | 
 | are copied. Canvas pixels outside Rect intersection are unchanged. | 
 |  | 
 | Pass negative values for x or y to offset pixels to the left or | 
 | above Canvas pixels. | 
 |  | 
 | Does not copy, and returns false if: | 
 |  | 
 | #List | 
 | # Source and destination rectangles do not intersect. ## | 
 | # pixels could not be converted to Canvas imageInfo().colorType() or | 
 |   imageInfo().alphaType(). ## | 
 | # Canvas pixels are not writable; for instance, Canvas is document-based. ## | 
 | # rowBytes is too small to contain one row of pixels. ## | 
 | ## | 
 |  | 
 | #Param info  width, height, Image_Color_Type, and Image_Alpha_Type of pixels ## | 
 | #Param pixels  pixels to copy, of size info.height() times rowBytes, or larger ## | 
 | #Param rowBytes  size of one row of pixels; info.width() times pixel size, or larger ## | 
 | #Param x  offset into Canvas writable pixels in x; may be negative ## | 
 | #Param y  offset into Canvas writable pixels in y; may be negative ## | 
 |  | 
 | #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); | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method bool writePixels(const SkBitmap& bitmap, int x, int y) | 
 |  | 
 | Copies Rect from pixels to Canvas. Matrix and Clip are ignored. | 
 | Source Rect corners are (0, 0) and (bitmap.width(), bitmap.height()). | 
 |  | 
 | Destination Rect corners are (x, y) and | 
 | (imageInfo().width(), imageInfo().height()). | 
 |  | 
 | Copies each readable pixel intersecting both rectangles, without scaling, | 
 | converting to imageInfo().colorType() and imageInfo().alphaType() if required. | 
 |  | 
 | Pixels are writable when Device is raster, or backed by a GPU. | 
 | Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, | 
 | returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility | 
 | class like SkDumpCanvas. | 
 |  | 
 | Pixel values are converted only if Image_Color_Type and Image_Alpha_Type | 
 | do not match. Only pixels within both source and destination rectangles | 
 | are copied. Canvas pixels outside Rect intersection are unchanged. | 
 |  | 
 | Pass negative values for x or y to offset pixels to the left or | 
 | above Canvas pixels. | 
 |  | 
 | Does not copy, and returns false if: | 
 |  | 
 | #List | 
 | # Source and destination rectangles do not intersect. ## | 
 | # bitmap does not have allocated pixels. ## | 
 | # bitmap pixels could not be converted to Canvas imageInfo().colorType() or | 
 |   imageInfo().alphaType(). ## | 
 | # Canvas pixels are not writable; for instance, Canvas is document based. ## | 
 | # bitmap pixels are inaccessible; for instance, bitmap wraps a texture. ## | 
 | ## | 
 |  | 
 | #Param bitmap  contains pixels copied to Canvas ## | 
 | #Param x       offset into Canvas writable pixels in x; may be negative ## | 
 | #Param y       offset into Canvas writable pixels in y; may be negative ## | 
 |  | 
 | #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); | 
 |         } | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 | #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(), restoreToCount, and ~SkCanvas() 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha restore() restoreToCount | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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()); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso save() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha restoreToCount | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 | 
 | ## | 
 | ## | 
 |  | 
 | #SeeAlso save() restore() restoreToCount | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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    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 | 
 | ## | 
 | ## | 
 |  | 
 | #SeeAlso restore() getSaveCount save()  | 
 |  | 
 | ## | 
 |  | 
 | #Topic State_Stack ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Topic Layer | 
 | #Substitute layer | 
 | #Alias Layers | 
 |  | 
 | Layer allocates a temporary 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 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 a Bitmap for subsequent drawing. | 
 | Calling restore() discards changes to Matrix, Clip, and Draw_Filter, | 
 | and draws the Bitmap. | 
 |  | 
 | 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 Bitmap 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 returned value to restore this and subsequent saves. | 
 |  | 
 | #Param bounds  hint to limit the size of the Layer; may be nullptr ## | 
 | #Param paint   graphics state for Layer; may be nullptr ## | 
 |  | 
 | #Return        depth of saved stack ## | 
 |  | 
 | #Example | 
 | #Description | 
 | Rectangles are blurred by Image_Filter when restore() draws Layer to main | 
 | Canvas. | 
 | ## | 
 | #Height 128 | 
 | void draw(SkCanvas* canvas) { | 
 |     SkPaint paint, blur; | 
 |     blur.setImageFilter(SkBlurImageFilter::Make(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(); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha SaveLayerRec | 
 |  | 
 | ## | 
 |  | 
 | #Method int saveLayer(const SkRect& bounds, const SkPaint* paint)  | 
 |  | 
 | Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms), | 
 | and allocates a Bitmap for subsequent drawing. | 
 | Calling restore() discards changes to Matrix, Clip, and Draw_Filter, | 
 | and draws the Bitmap. | 
 |  | 
 | 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 Layer 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 returned value to restore this and subsequent saves. | 
 |  | 
 | #Param bounds  hint to limit the size of Layer; may be nullptr ## | 
 | #Param paint   graphics state for Layer; may be nullptr ## | 
 |  | 
 | #Return        depth of saved stack ## | 
 |  | 
 | #Example | 
 | #Description | 
 | Rectangles are blurred by Image_Filter when restore() draws Layer to main Canvas. | 
 | The red rectangle is clipped; it does not fully fit on Layer.  | 
 | Image_Filter blurs past edge of Layer so red rectangle is blurred on all sides. | 
 | ## | 
 | #Height 128 | 
 | void draw(SkCanvas* canvas) { | 
 |     SkPaint paint, blur; | 
 |     blur.setImageFilter(SkBlurImageFilter::Make(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(); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso save() restore() saveLayerPreserveLCDTextRequests saveLayerAlpha SaveLayerRec | 
 |  | 
 | ## | 
 |  | 
 | #Method int saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) | 
 |  | 
 | Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms), | 
 | and allocates a Bitmap for subsequent drawing. | 
 | LCD_Text is preserved when the Layer is drawn to the prior Layer. | 
 |  | 
 | Calling restore() discards changes to Matrix, Clip, and Draw_Filter, | 
 | and draws Layer. | 
 |  | 
 | 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 Layer 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 returned value to restore this and subsequent saves. | 
 |  | 
 | Draw text on an opaque background so that LCD_Text blends correctly with the | 
 | prior Layer. LCD_Text drawn on a background with transparency may result in | 
 | incorrect blending. | 
 |  | 
 | #Param bounds  hint to limit the size of Layer; may be nullptr ## | 
 | #Param paint   graphics state for Layer; 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); | 
 |     } | 
 |     ## | 
 |  | 
 | #SeeAlso save() restore() saveLayer saveLayerAlpha SaveLayerRec | 
 |  | 
 | ## | 
 |  | 
 | #Method int saveLayerAlpha(const SkRect* bounds, U8CPU alpha) | 
 |  | 
 | Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms), | 
 | and allocates Bitmap for subsequent drawing. | 
 |  | 
 | Calling restore() discards changes to Matrix, Clip, and Draw_Filter, | 
 | and blends Layer with alpha opacity onto prior Layer. | 
 |  | 
 | 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 Layer size. To clip drawing to | 
 | a specific rectangle, use clipRect. | 
 |  | 
 | alpha of zero is fully transparent, 255 is fully opaque. | 
 |  | 
 | Call restoreToCount with returned value to restore this and subsequent saves. | 
 |  | 
 | #Param bounds  hint to limit the size of Layer; may be nullptr ## | 
 | #Param alpha   opacity of Layer ## | 
 |  | 
 | #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(); | 
 | ## | 
 |  | 
 | #SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests SaveLayerRec | 
 |  | 
 | ## | 
 |  | 
 | #Enum | 
 |  | 
 | #Code | 
 |     enum { | 
 |         kIsOpaque_SaveLayerFlag = 1 << 0, | 
 |         kPreserveLCDText_SaveLayerFlag = 1 << 1, | 
 |         kInitWithPrevious_SaveLayerFlag = 1 << 2, | 
 |         kDontClipToLayer_Legacy_SaveLayerFlag = kDontClipToLayer_PrivateSaveLayerFlag, | 
 |     }; | 
 | ## | 
 |  | 
 | SaveLayerFlags provides options that may be used in any combination in SaveLayerRec, | 
 | defining how Layer allocated by saveLayer operates. | 
 |  | 
 | #Const kIsOpaque_SaveLayerFlag 1 | 
 |   Creates Layer without transparency. Flag is ignored if Layer Paint contains | 
 |   Image_Filter or Color_Filter. | 
 | ## | 
 |  | 
 | #Const kPreserveLCDText_SaveLayerFlag 2 | 
 |   Creates Layer for LCD text. Flag is ignored if Layer Paint contains | 
 |   Image_Filter or Color_Filter. | 
 | ## | 
 |  | 
 | #Const kInitWithPrevious_SaveLayerFlag 4 | 
 |   Initializes Layer with the contents of the previous Layer. | 
 | ## | 
 |  | 
 | #Const kDontClipToLayer_Legacy_SaveLayerFlag 0x80000000 | 
 | #Private | 
 |   to be deprecated: bug.skia.org/2440 | 
 | ## | 
 |   Only present on Android. | 
 |   Skips setting a clip to the Layer bounds.  | 
 | ## | 
 |  | 
 | #Example | 
 | #Height 160 | 
 | #Description | 
 | Canvas Layer captures red and blue circles scaled up by four. | 
 | scalePaint blends Layer 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(); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha SaveLayerRec | 
 |  | 
 | #Enum ## | 
 |  | 
 | #Typedef uint32_t SaveLayerFlags | 
 |  | 
 | ## | 
 |  | 
 | #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.  | 
 |  | 
 | #Member const SkRect*           fBounds | 
 |     fBounds is used as a hint to limit the size of Layer; may be nullptr. | 
 |     fBounds suggests but does not define Layer size. To clip drawing to | 
 |     a specific rectangle, use clipRect. | 
 | ## | 
 |  | 
 | #Member const SkPaint*          fPaint | 
 |     fPaint modifies how Layer overlays the prior Layer; may be nullptr. | 
 |     Color_Alpha, Blend_Mode, Color_Filter, Draw_Looper, Image_Filter, and | 
 |     Mask_Filter affect Layer draw. | 
 | ## | 
 |  | 
 | #Member const SkImageFilter*    fBackdrop | 
 |     fBackdrop applies Image_Filter to the prior Layer when copying to the Layer; | 
 |     may be nullptr. Use kInitWithPrevious_SaveLayerFlag to copy the | 
 |     prior Layer without an Image_Filter. | 
 | ## | 
 |  | 
 | #Member const SkImage*          fClipMask | 
 |   restore() clips Layer by the Color_Alpha channel of fClipMask when | 
 |   Layer is copied to Device. fClipMask may be nullptr.    . | 
 | ## | 
 |  | 
 | #Member const SkMatrix*         fClipMatrix | 
 |   fClipMatrix transforms fClipMask before it clips Layer. If  | 
 |   fClipMask describes a translucent gradient, it may be scaled and rotated | 
 |   without introducing artifacts. fClipMatrix may be nullptr. | 
 | ## | 
 |  | 
 | #Member SaveLayerFlags          fSaveLayerFlags | 
 |     fSaveLayerFlags are used to create Layer without transparency, | 
 |     create Layer for LCD text, and to create Layer 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 red circle without scaling on top, the Layer 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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha | 
 |  | 
 | ## | 
 |  | 
 | #Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0) | 
 |  | 
 | Sets fBounds, fPaint, and fSaveLayerFlags; sets fBackdrop to nullptr. | 
 |  | 
 | #Param bounds  Layer dimensions; may be nullptr ## | 
 | #Param paint  applied to Layer when overlaying prior Layer; may be nullptr ## | 
 | #Param saveLayerFlags  SaveLayerRec options to modify Layer ## | 
 |  | 
 | #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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha | 
 |  | 
 | ## | 
 |  | 
 | #Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, | 
 |                      SaveLayerFlags saveLayerFlags) | 
 |  | 
 | Sets fBounds, fPaint, fBackdrop, and fSaveLayerFlags. | 
 |  | 
 | #Param bounds          Layer dimensions; may be nullptr ## | 
 | #Param paint           applied to Layer when overlaying prior Layer; | 
 |                        may be nullptr | 
 | ## | 
 | #Param backdrop        prior Layer copied with Image_Filter; may be nullptr | 
 | ## | 
 | #Param saveLayerFlags  SaveLayerRec options to modify Layer ## | 
 |  | 
 | #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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha | 
 |  | 
 | ## | 
 |  | 
 | #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. | 
 | ## | 
 |  | 
 | Sets fBounds, fPaint, fBackdrop, fClipMask, fClipMatrix, and fSaveLayerFlags. | 
 | clipMatrix uses Color_Alpha channel of image, transformed by clipMatrix, to clip | 
 | Layer when drawn to Canvas. | 
 |  | 
 | Implementation is not complete; has no effect if Device is GPU-backed. | 
 |  | 
 | #Param bounds          Layer dimensions; may be nullptr ## | 
 | #Param paint           graphics state applied to Layer when overlaying prior | 
 |                        Layer; may be nullptr | 
 | ## | 
 | #Param backdrop        prior Layer copied with Image_Filter; | 
 |                        may be nullptr | 
 | ## | 
 | #Param clipMask        clip applied to Layer; may be nullptr ## | 
 | #Param clipMatrix      matrix applied to clipMask; may be nullptr to use | 
 |                        identity matrix  | 
 | ## | 
 | #Param saveLayerFlags  SaveLayerRec options to modify Layer ## | 
 |  | 
 | #Return                SaveLayerRec fully specified ## | 
 |  | 
 | #SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha | 
 |  | 
 | ## | 
 |  | 
 | #Struct ## | 
 |  | 
 | #Method int saveLayer(const SaveLayerRec& layerRec) | 
 |  | 
 | Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms), | 
 | and allocates Bitmap for subsequent drawing. | 
 |  | 
 | Calling restore() discards changes to Matrix, Clip, and Draw_Filter, | 
 | and blends Bitmap with Color_Alpha opacity onto the prior Layer. | 
 |  | 
 | 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. | 
 |  | 
 | Call restoreToCount with returned value to restore this and subsequent saves. | 
 |  | 
 | #Param layerRec  Layer 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 Layer and restore with SkBlendMode::kPlus. | 
 | Where Layer was cleared, the original image will draw unchanged. | 
 | Outside of the circle the mandrill is brightened. | 
 | ## | 
 |     #Image 3 | 
 |     // sk_sp<SkImage> image = GetResourceAsImage("images/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 ## | 
 |  | 
 | #SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha | 
 |  | 
 | ## | 
 |  | 
 | #Topic Layer ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 | #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 | 
 | Premultiplied with Matrix.  | 
 |  | 
 | This has the effect of moving the drawing by (dx, dy) before transforming | 
 | the result with Matrix. | 
 |  | 
 | #Param  dx   distance to translate in x ## | 
 | #Param  dy   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) | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso concat() scale() skew() rotate() setMatrix | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 | 
 | Premultiplied with Matrix.  | 
 |  | 
 | This has the effect of scaling the drawing by (sx, sy) before transforming | 
 | the result with Matrix. | 
 |  | 
 | #Param  sx   amount to scale in x ## | 
 | #Param  sy   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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso concat() translate() skew() rotate() setMatrix | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void rotate(SkScalar degrees) | 
 |  | 
 | Rotate Matrix by degrees. Positive degrees rotates clockwise. | 
 |  | 
 | Mathematically, replace Matrix with a rotation matrix | 
 | Premultiplied with Matrix.  | 
 |  | 
 | This has the effect of rotating the drawing by degrees before transforming | 
 | the result with Matrix. | 
 |  | 
 | #Param  degrees  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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso concat() translate() skew() scale() setMatrix | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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. Premultiply the rotation matrix by | 
 | a translation matrix, then replace Matrix with the resulting matrix | 
 | Premultiplied with Matrix.  | 
 |  | 
 | This has the effect of rotating the drawing about a given point before | 
 | transforming the result with Matrix. | 
 |  | 
 | #Param  degrees  amount to rotate, in degrees ## | 
 | #Param  px  x-coordinate of the point to rotate about ## | 
 | #Param  py  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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso concat() translate() skew() scale() setMatrix | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 Premultiplied with Matrix.  | 
 |  | 
 | This has the effect of skewing the drawing by (sx, sy) before transforming | 
 | the result with Matrix. | 
 |  | 
 | #Param  sx   amount to skew in x ## | 
 | #Param  sy   amount to skew in y ## | 
 |  | 
 | #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); | 
 | ## | 
 |  | 
 | #SeeAlso concat() translate() rotate() scale() setMatrix | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void concat(const SkMatrix& matrix) | 
 |  | 
 | Replace Matrix with matrix Premultiplied with existing Matrix. | 
 |  | 
 | This has the effect of transforming the drawn geometry by matrix, before | 
 | transforming the result with existing Matrix. | 
 |  | 
 | #Param  matrix   matrix to Premultiply with existing 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso translate() rotate() scale() skew() setMatrix | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void setMatrix(const SkMatrix& matrix) | 
 |  | 
 | Replace Matrix with matrix. | 
 | Unlike concat(), any prior matrix state is overwritten. | 
 |  | 
 | #Param  matrix  matrix to copy, replacing existing 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso resetMatrix concat() translate() rotate() scale() skew() | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso setMatrix concat() translate() rotate() scale() skew() | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method const SkMatrix& getTotalMatrix() const | 
 |  | 
 | Returns Matrix. | 
 | This does not account for translation by Device or Surface. | 
 |  | 
 | #Return Matrix in Canvas ## | 
 |  | 
 | #Example | 
 |     SkDebugf("isIdentity %s\n", canvas->getTotalMatrix().isIdentity() ? "true" : "false"); | 
 |     #StdOut | 
 |         isIdentity true | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso setMatrix resetMatrix concat() | 
 |  | 
 | ## | 
 |  | 
 | #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, | 
 | rectangular 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  Rect 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRRect clipPath clipRegion | 
 |  | 
 | ## | 
 |  | 
 | #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  Rect 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRRect clipPath clipRegion | 
 |  | 
 | ## | 
 |  | 
 | #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   Rect 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRRect clipPath clipRegion | 
 |  | 
 | ## | 
 |  | 
 | #Method void androidFramework_setDeviceClipRestriction(const SkIRect& rect) | 
 |  | 
 | Sets the maximum clip rectangle, which can be set by clipRect, clipRRect and | 
 | clipPath and intersect the current clip with the specified rect. | 
 | The maximum clip affects only future clipping operations; it is not retroactive. | 
 | The clip restriction is not recorded in pictures. | 
 |  | 
 | Pass an empty rect to disable maximum clip.  | 
 |  | 
 | #Private | 
 | This is private API to be used only by Android framework. | 
 | ## | 
 |  | 
 | #Param  rect   maximum allowed clip in device coordinates | 
 | #Param ## | 
 |  | 
 | ## | 
 |  | 
 | #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 Anti-aliased ## | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRect clipPath clipRegion | 
 |  | 
 | ## | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRect clipPath clipRegion | 
 |  | 
 | ## | 
 |  | 
 | #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 Anti-aliased ## | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRect clipPath clipRegion | 
 |  | 
 | ## | 
 |  | 
 | #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 Anti-aliased ## | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRect clipRRect clipRegion | 
 |  | 
 | ## | 
 |  | 
 | #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 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRect clipRRect clipRegion | 
 |  | 
 | ## | 
 |  | 
 | #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 Anti-aliased ## | 
 |  | 
 | #Example | 
 | #Height 212 | 
 | #Description | 
 | Clip loops over itself covering its center twice. When clip 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRect clipRRect clipRegion | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void setAllowSimplifyClip(bool allow)  | 
 |  | 
 | #Experimental | 
 | Only used for testing. | 
 | ## | 
 |  | 
 | Set to simplify clip stack using PathOps. | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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; iRect is affected by canvas rotation. | 
 |     Both clips are Aliased; this is not noticeable 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clipRect clipRRect clipPath | 
 |  | 
 | ## | 
 |  | 
 | #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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing | 
 |  | 
 | ## | 
 |  | 
 | #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 | 
 |     ## | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing | 
 |  | 
 | ## | 
 |  | 
 | #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  ## | 
 | #SeeAlso getDeviceClipBounds getBaseLayerSize quickReject | 
 |  | 
 | ## | 
 |  | 
 | #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  ## | 
 | #SeeAlso getDeviceClipBounds getBaseLayerSize quickReject | 
 |  | 
 | ## | 
 |  | 
 | #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 ## | 
 | #SeeAlso getLocalClipBounds getBaseLayerSize quickReject | 
 |  | 
 | # 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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso getLocalClipBounds getBaseLayerSize quickReject | 
 |  | 
 | ## | 
 |  | 
 | #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); | 
 | ## | 
 |  | 
 | #SeeAlso clear SkBitmap::erase drawPaint | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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)); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawColor SkBitmap::erase drawPaint | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 ## | 
 | #SeeAlso flush() SkSurface::prepareForExternalIO GrContext::abandonContext | 
 |  | 
 | #NoExample  | 
 | ## | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawPaint(const SkPaint& paint) | 
 |  | 
 | Fill Clip with Paint paint. Paint components Mask_Filter, Shader, | 
 | Color_Filter, Image_Filter, and Blend_Mode affect drawing; | 
 | Path_Effect in paint is ignored. | 
 |  | 
 | # can Path_Effect in paint ever alter drawPaint? | 
 |  | 
 | #Param  paint    graphics state used to fill 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso clear drawColor SkBitmap::erase | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawLine drawPoint drawPath | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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, 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. | 
 |  | 
 | Always draws each element one at a time; 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    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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawLine drawPoint drawPath | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawPoints drawCircle drawRect drawLine drawPath | 
 |  | 
 | ## | 
 |  | 
 | #Method void drawPoint(SkPoint p, const SkPaint& paint) | 
 |  | 
 | Draw point p 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  p        top-left 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::kSquare_Cap); | 
 |   canvas->scale(1, 1.2f); | 
 |   canvas->drawPoint({64, 96}, paint); | 
 |   canvas->scale(.6f, .8f); | 
 |   paint.setColor(SK_ColorWHITE); | 
 |   canvas->drawPoint(106, 120, paint); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawPoints drawCircle drawRect drawLine drawPath | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) | 
 |  | 
 | Draws 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); | 
 | ## | 
 |  | 
 | #SeeAlso drawPoint drawCircle drawRect drawPath | 
 |  | 
 | ## | 
 |  | 
 | #Method void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint) | 
 |  | 
 | Draws line segment from p0 to p1 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  p0    start of line segment ## | 
 | #Param  p1    end of line segment ## | 
 | #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); | 
 | ## | 
 |  | 
 | #SeeAlso drawPoint drawCircle drawRect drawPath | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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     rectangle to draw ## | 
 | #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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawIRect drawRRect drawRoundRect drawRegion drawPath drawLine  | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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     rectangle to draw ## | 
 | #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); | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso drawRect drawRRect drawRoundRect drawRegion drawPath drawLine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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   region to draw ## | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawRect drawIRect drawPath | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawCircle drawPoint drawPath drawRRect drawRoundRect | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawRect drawRoundRect drawDRRect drawCircle drawOval drawPath | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 Round_Rect 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 optimize drawing when 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawRect drawRoundRect drawRRect drawCircle drawOval drawPath | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine | 
 |  | 
 | ## | 
 |  | 
 | #Method void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint) | 
 |  | 
 | Draw Circle at center 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  center   Circle center ## | 
 | #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); | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 |         } | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso SkPath::arcTo drawCircle drawOval drawPath | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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       axis length in x of oval describing rounded corners ## | 
 | #Param  ry       axis length in y of oval describing rounded corners ## | 
 | #Param  paint    stroke, blend, color, and so on, used to draw ## | 
 |  | 
 | #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); | 
 |         } | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso DrawRRect drawRect drawDRRect drawPath drawCircle drawOval drawPoint | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso SkPath drawLine drawArc drawRect drawPoints | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 | #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 = nullptr) | 
 |  | 
 | 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 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top, | 
 |                    const SkPaint* paint = nullptr)  | 
 |  | 
 | 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 edge color when it samples outside of its bounds.  | 
 |  | 
 | #Param  image    uncompressed rectangular map of pixels ## | 
 | #Param  left     left side of image ## | 
 | #Param  top      pop side of image ## | 
 | #Param  paint    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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Enum SrcRectConstraint | 
 |  | 
 | #Code | 
 |     enum SrcRectConstraint { | 
 |         kStrict_SrcRectConstraint,  | 
 |         kFast_SrcRectConstraint,  | 
 |     }; | 
 | ## | 
 |  | 
 | SrcRectConstraint controls the behavior at the edge of source Rect, | 
 | provided to drawImageRect, trading off speed for precision. | 
 |  | 
 | Image_Filter in Paint may sample multiple pixels in the image. Source Rect | 
 | 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 source Rect.  | 
 | SrcRectConstraint specifies whether an Image_Filter is allowed to read pixels | 
 | outside source Rect. | 
 |  | 
 | #Const kStrict_SrcRectConstraint | 
 |     Requires Image_Filter to respect source Rect, | 
 |     sampling only inside of its bounds, possibly with a performance penalty. | 
 | ## | 
 |  | 
 | #Const kFast_SrcRectConstraint | 
 |     Permits Image_Filter to sample outside of source Rect | 
 |     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 checkerboards. | 
 |     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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawImageRect drawImage SkPaint::setImageFilter | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 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 is 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 edge color when it samples outside of its bounds. | 
 |  | 
 | constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to | 
 | sample within isrc; 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 isrc 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 edge color when it samples outside of its bounds. | 
 |  | 
 | constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to | 
 | sample within image; 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 image 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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. | 
 | 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 edge color when it samples outside of its bounds. | 
 |  | 
 | constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to | 
 | sample within image; 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 image 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 edge color when it samples outside of its bounds. | 
 |  | 
 | constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to | 
 | sample within image; 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 image 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, | 
 |                        const SkPaint* paint = nullptr) | 
 |  | 
 | Draw Image image stretched proportionally to fit into Rect dst. | 
 | IRect center divides the image into nine sections: four sides, four corners, and | 
 | the center. Corners are unmodified or scaled down proportionately if their sides | 
 | are larger than dst; center and four sides are scaled to fit remaining space, if any. | 
 |  | 
 | Additionally transform draw using Clip, 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 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 without scaling. | 
 |     The remaining images are larger than center. All corners draw without scaling. | 
 |     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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawImageNine(const sk_sp<SkImage>& image, const SkIRect& center, const SkRect& dst, | 
 |                        const SkPaint* paint = nullptr)  | 
 |  | 
 | Draw Image image stretched proportionally to fit into Rect dst. | 
 | IRect center divides the image into nine sections: four sides, four corners, and | 
 | the center. Corners are not scaled, or scaled down proportionately if their sides | 
 | are larger than dst; center and four sides are scaled to fit remaining space, if any. | 
 |  | 
 | Additionally transform draw using Clip, 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 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 not scaled; 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, | 
 |                     const SkPaint* paint = nullptr) | 
 |  | 
 | Draw Bitmap bitmap, with its top-left corner at (left, top), | 
 | using Clip, Matrix, and optional Paint paint. | 
 |  | 
 | If Paint paint is not nullptr, 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 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawImage drawBitmapLattice drawBitmapNine drawBitmapRect SkBitmap::readPixels SkBitmap::writePixels | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 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 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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. | 
 | 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 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 edge color when it samples | 
 | outside of its bounds. | 
 |  | 
 | constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to | 
 | sample within isrc; 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 sample strictly within isrc, 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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. | 
 | bitmap bounds 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 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 edge color when it samples | 
 | outside of its bounds. | 
 |  | 
 | constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to | 
 | sample within bitmap; 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 bitmap 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, | 
 |                         const SkPaint* paint = nullptr) | 
 |  | 
 | Draw Bitmap bitmap stretched proportionally to fit into Rect dst. | 
 | IRect center divides the bitmap into nine sections: four sides, four corners, | 
 | and the center. Corners are not scaled, or scaled down proportionately if their | 
 | sides are larger than dst; center and four sides are scaled to fit remaining | 
 | space, if any. | 
 |  | 
 | Additionally transform draw using Clip, 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 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 not scaled; 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawImageNine drawBitmap drawBitmapLattice drawBitmapRect | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 | #Struct Lattice | 
 |  | 
 | #Code | 
 |     struct Lattice { | 
 |         enum RectType ... | 
 |  | 
 |         const int*      fXDivs; | 
 |         const int*      fYDivs; | 
 |         const RectType* fRectTypes; | 
 |         int             fXCount; | 
 |         int             fYCount; | 
 |         const SkIRect*  fBounds; | 
 |         const SkColor*  fColors; | 
 |     }; | 
 | ## | 
 |  | 
 |     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. | 
 |  | 
 |     #Enum RectType | 
 |         #Code | 
 |             enum RectType : uint8_t { | 
 |                 kDefault = 0, | 
 |                 kTransparent, | 
 |                 kFixedColor, | 
 |             }; | 
 |         ## | 
 |  | 
 |         Optional setting per rectangular grid entry to make it transparent, | 
 |         or to fill the grid entry with a color. | 
 |  | 
 |         #Const kDefault 0 | 
 |             Draws Bitmap into lattice rectangle. | 
 |         ## | 
 |  | 
 |         #Const kTransparent 1 | 
 |             Skips lattice rectangle by making it transparent. | 
 |         ## | 
 |  | 
 |         #Const kFixedColor 2 | 
 |             Draws one of fColors into lattice rectangle. | 
 |         ## | 
 |     ## | 
 |  | 
 |     #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 RectType* fRectTypes | 
 |         Optional array of fill types, one per rectangular grid entry: | 
 |         array length must be | 
 |     #Formula | 
 |         (fXCount + 1) * (fYCount + 1) | 
 |     ## | 
 |         . | 
 |  | 
 |         Each RectType is one of: kDefault, kTransparent, kFixedColor. | 
 |  | 
 |         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. | 
 |     ## | 
 |  | 
 |     #Member const SkColor*   fColors | 
 |        Optional array of colors, one per rectangular grid entry. | 
 |        Array length must be | 
 |        #Formula | 
 |        (fXCount + 1) * (fYCount + 1) | 
 |        ## | 
 |        . | 
 |  | 
 |        Array entries correspond to the rectangular grid entries, ascending | 
 |        left to right, then top to bottom. | 
 |     ## | 
 |  | 
 | #Struct Lattice ## | 
 |  | 
 | #Method void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst, | 
 |                            const SkPaint* paint = nullptr) | 
 |  | 
 | Draw Bitmap bitmap stretched proportionally 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 | 
 | 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 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 not scaled; 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::RectType fillTypes[3][3]; | 
 |     memset(fillTypes, 0, sizeof(fillTypes)); | 
 |     fillTypes[1][1] = SkCanvas::Lattice::kTransparent; | 
 |     SkColor dummy[9];  // temporary pending bug fix | 
 |     SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], SK_ARRAY_COUNT(xDivs), | 
 |          SK_ARRAY_COUNT(yDivs), nullptr, dummy }; | 
 |     for (auto dest: { 20, 30, 40, 60, 90 } ) { | 
 |         canvas->drawBitmapLattice(bitmap, lattice, SkRect::MakeWH(dest, 110 - dest), nullptr); | 
 |         canvas->translate(dest + 4, 0); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawImageLattice drawBitmap drawBitmapNine Lattice | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, | 
 |                           const SkPaint* paint = nullptr) | 
 |  | 
 | Draw Image image stretched proportionally 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 drawBitmapNine, fixed lattice elements never scale larger than their initial | 
 | size and shrink proportionately when all fixed elements exceed the bitmap | 
 | 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 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 without scaling. | 
 |     The remaining images are larger than center. All corners draw without scaling. 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::RectType fillTypes[3][3]; | 
 |     memset(fillTypes, 0, sizeof(fillTypes));   | 
 |     fillTypes[1][1] = SkCanvas::Lattice::kTransparent; | 
 |     SkColor dummy[9];  // temporary pending bug fix | 
 |     SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], SK_ARRAY_COUNT(xDivs), | 
 |          SK_ARRAY_COUNT(yDivs), nullptr, dummy }; | 
 |     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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawBitmapLattice drawImage drawImageNine Lattice | 
 |  | 
 | ## | 
 |  | 
 | #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 meaning depends on Paint_Text_Encoding; by default, text is encoded as | 
 | 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 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, Mask_Filter, Shader, | 
 | Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws | 
 | filled 12 point black Glyphs. | 
 |  | 
 | #Param  text     character code points or Glyphs drawn ## | 
 | #Param  byteLength   byte length of text array ## | 
 | #Param  x        start of text on x-axis ## | 
 | #Param  y        start of text on y-axis ## | 
 | #Param  paint    text size, blend, color, and so on, used to draw ## | 
 |  | 
 | #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;  | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawString drawPosText drawPosTextH drawTextBlob drawTextOnPath drawTextRSXform | 
 |  | 
 | ## | 
 |  | 
 | #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 meaning depends on Paint_Text_Encoding; by default, strings are encoded | 
 | as 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 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, Mask_Filter, Shader, | 
 | Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws | 
 | filled 12 point black Glyphs. | 
 |  | 
 | #Param  string   character code points or Glyphs drawn, | 
 |                  ending with a char value of zero | 
 | ## | 
 | #Param  x        start of string on x-axis ## | 
 | #Param  y        start of string on y-axis ## | 
 | #Param  paint    text size, blend, color, and so on, used to draw ## | 
 |  | 
 | #Example | 
 |    SkPaint paint; | 
 |    canvas->drawString("a small hello", 20, 20, paint); | 
 | ## | 
 |  | 
 | #SeeAlso drawText drawPosText drawPosTextH drawTextBlob drawTextOnPath drawTextRSXform | 
 |  | 
 | ## | 
 |  | 
 | #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 meaning depends on Paint_Text_Encoding; by default, strings are encoded | 
 | as 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 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, Mask_Filter, Shader, | 
 | Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws | 
 | filled 12 point black Glyphs. | 
 |  | 
 | #Param  string   character code points or Glyphs drawn, | 
 |                  ending with a char value of zero | 
 | ## | 
 | #Param  x        start of string on x-axis ## | 
 | #Param  y        start of string on y-axis ## | 
 | #Param  paint    text size, blend, color, and so on, used to draw ## | 
 |  | 
 | #Example | 
 |    SkPaint paint; | 
 |    SkString string("a small hello"); | 
 |    canvas->drawString(string, 20, 20, paint); | 
 | ## | 
 |  | 
 | #SeeAlso drawText drawPosText drawPosTextH drawTextBlob drawTextOnPath drawTextRSXform | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 meaning depends on Paint_Text_Encoding; by default, text is encoded as | 
 | UTF-8. pos elements' meaning depends on Paint_Text_Align and Paint_Vertical_Text; | 
 | by default each glyph 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, Mask_Filter, Shader, | 
 | Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws | 
 | filled 12 point black Glyphs. | 
 |  | 
 | Layout engines such as Harfbuzz typically position each glyph | 
 | rather than using the font 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawText drawPosTextH drawTextBlob drawTextOnPath drawTextRSXform | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 meaning depends on Paint_Text_Encoding; by default, text is encoded as | 
 | UTF-8. xpos elements' meaning depends on Paint_Text_Align and Paint_Vertical_Text; | 
 | by default each glyph 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, Mask_Filter, Shader, | 
 | Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws | 
 | filled 12 point black Glyphs. | 
 |  | 
 | Layout engines such as Harfbuzz typically position each glyph | 
 | rather than using the font 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); | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso drawText drawPosText drawTextBlob drawTextOnPath drawTextRSXform | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 advance is larger | 
 | than the path length, the excess text is clipped. | 
 |  | 
 | text meaning depends on Paint_Text_Encoding; by default, text is encoded as | 
 | UTF-8. Origin meaning depends on Paint_Text_Align and Paint_Vertical_Text; by | 
 | default text positions the first glyph 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, Mask_Filter, Shader, | 
 | Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws | 
 | filled 12 point black Glyphs. | 
 |  | 
 | #Param  text         character code points or Glyphs drawn ## | 
 | #Param  byteLength   byte length of text array ## | 
 | #Param  path         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); | 
 |         } | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso drawTextOnPath drawText drawPosTextH drawTextBlob drawTextRSXform | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 advance is larger | 
 | than the path length, the excess text is clipped. | 
 |  | 
 | text meaning depends on Paint_Text_Encoding; by default, text is encoded as | 
 | UTF-8. Origin meaning depends on Paint_Text_Align and Paint_Vertical_Text; by | 
 | default text positions the first glyph 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, Mask_Filter, Shader, | 
 | Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws | 
 | filled 12 point black Glyphs. | 
 |  | 
 | #Param  text         character code points or Glyphs drawn ## | 
 | #Param  byteLength   byte length of text array ## | 
 | #Param  path         Path providing text baseline ## | 
 | #Param  matrix       transform of Glyphs before mapping to path; may be nullptr | 
 |                      to use identity Matrix | 
 | ## | 
 | #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); | 
 |         } | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso drawTextOnPathHV drawText drawPosTextH drawTextBlob drawTextRSXform | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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, Mask_Filter, Shader, | 
 | Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws | 
 | filled 12 point black Glyphs. | 
 |  | 
 | #Param  text         character code points or Glyphs drawn ## | 
 | #Param  byteLength   byte length of text array ## | 
 | #Param  xform        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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawTextOnPath drawTextOnPathHV drawText drawPosText drawTextBlob | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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. | 
 |  | 
 | Paint_Text_Encoding must be set to SkPaint::kGlyphID_TextEncoding. | 
 |  | 
 | Elements of paint: Path_Effect, 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); | 
 |         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 
 |         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(&glyphs[glyphIndex], sizeof(glyphs[0]) * runLen, nullptr); | 
 |             glyphIndex += runLen; | 
 |         } | 
 |         sk_sp<const SkTextBlob> blob = textBlobBuilder.make(); | 
 |         paint.reset(); | 
 |         canvas->drawTextBlob(blob.get(), 0, 0, paint); | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso drawText drawPosText drawPosTextH | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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. | 
 |  | 
 | Paint_Text_Encoding must be set to SkPaint::kGlyphID_TextEncoding. | 
 |  | 
 | Elements of paint: Path_Effect, 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); | 
 |         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 
 |         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); | 
 |     } | 
 | ## | 
 |  | 
 | #SeeAlso drawText drawPosText drawPosTextH | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawDrawable SkPicture SkPicture::playback | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawDrawable SkPicture SkPicture::playback | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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   Matrix to rotate, scale, translate, and so on; may be nullptr ## | 
 | #Param  paint    Paint to apply transparency, filtering, and so on; may be 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawDrawable SkPicture SkPicture::playback | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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   Matrix to rotate, scale, translate, and so on; may be nullptr ## | 
 | #Param  paint    Paint to apply transparency, filtering, and so on; may be 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); | 
 |     } | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawDrawable SkPicture SkPicture::playback | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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  triangle mesh to draw ## | 
 | #Param  mode      combines Vertices_Colors with Shader, if both are present ## | 
 | #Param  paint     specifies the Shader, used as Vertices texture; may be nullptr ## | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawPatch drawPicture | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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  triangle mesh to draw ## | 
 | #Param  mode      combines Vertices_Colors with Shader, if both are present ## | 
 | #Param  paint     specifies the Shader, used as Vertices texture, may be nullptr ## | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawPatch drawPicture | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4], | 
 |                    const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint) | 
 |  | 
 | Draws a Coons_Patch: the interpolation of four cubics with shared corners,  | 
 | associating a color, and optionally a texture coordinate, with each corner. | 
 |  | 
 | Coons_Patch uses Clip and Matrix, paint Shader, Color_Filter, | 
 | Color_Alpha, Image_Filter, and Blend_Mode. If Shader is provided it is treated | 
 | as Coons_Patch texture; Blend_Mode mode combines Color colors and Shader if | 
 | both are provided. | 
 |  | 
 | Point array cubics specifies four Cubics starting at the top-left corner,  | 
 | in clockwise order, sharing every fourth point. The last Cubic ends at the | 
 | first point. | 
 |  | 
 | Color array color associates colors with corners in top-left, top-right, | 
 | bottom-right, bottom-left order. | 
 |  | 
 | If paint contains Shader, Point array texCoords maps Shader as texture to | 
 | corners in top-left, top-right, bottom-right, bottom-left order. | 
 |  | 
 | #Param cubics     Path_Cubic array, sharing common points ## | 
 | #Param colors     Color array, one for each corner ## | 
 | #Param texCoords  Point array of texture coordinates, mapping Shader to corners; | 
 |                   may be nullptr  | 
 | #Param ## | 
 | #Param mode       Blend_Mode for colors, and for Shader if paint has one ## | 
 | #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 can patch use image filter? ## | 
 | #SeeAlso SeeAlso drawVertices drawPicture | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4], | 
 |                    const SkPoint texCoords[4], const SkPaint& paint)  | 
 |  | 
 | Draws Cubic Coons_Patch: the interpolation of four cubics with shared corners,  | 
 | associating a color, and optionally a texture coordinate, with each corner. | 
 |  | 
 | Coons_Patch uses Clip and Matrix, paint Shader, Color_Filter, | 
 | Color_Alpha, Image_Filter, and Blend_Mode. If Shader is provided it is treated | 
 | as Coons_Patch texture; Blend_Mode mode combines Color colors and Shader if | 
 | both are provided. | 
 |  | 
 | Point array cubics specifies four Cubics starting at the top-left corner,  | 
 | in clockwise order, sharing every fourth point. The last Cubic ends at the | 
 | first point. | 
 |  | 
 | Color array color associates colors with corners in top-left, top-right, | 
 | bottom-right, bottom-left order. | 
 |  | 
 | If paint contains Shader, Point array texCoords maps Shader as texture to | 
 | corners in top-left, top-right, bottom-right, bottom-left order. | 
 |  | 
 | #Param cubics     Path_Cubic array, sharing common points ## | 
 | #Param colors     Color array, one for each corner ## | 
 | #Param texCoords  Point array of texture coordinates, mapping Shader to corners; | 
 |                   may be nullptr  | 
 | #Param ## | 
 | #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 can patch use image filter? ## | 
 | #SeeAlso SeeAlso drawVertices drawPicture | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 are 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  one per sprite, blended with sprite using Blend_Mode; may be nullptr ## | 
 | #Param count  number of sprites to draw ## | 
 | #Param mode   Blend_Mode combining colors and sprites ## | 
 | #Param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr ## | 
 | #Param paint  Color_Filter, Image_Filter, Blend_Mode, and so on; may be 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawBitmap drawImage | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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  one per sprite, blended with sprite using Blend_Mode; may be nullptr ## | 
 | #Param count  number of sprites to draw ## | 
 | #Param mode   Blend_Mode combining colors and sprites ## | 
 | #Param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr ## | 
 | #Param paint  Color_Filter, Image_Filter, Blend_Mode, and so on; may be 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 ## | 
 |  | 
 | #SeeAlso drawBitmap drawImage | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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  bounds of transformed sprites for efficient clipping; may be nullptr ## | 
 | #Param paint  Color_Filter, Image_Filter, Blend_Mode, and so on; may be 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawBitmap drawImage | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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  bounds of transformed sprites for efficient clipping; may be nullptr ## | 
 | #Param paint  Color_Filter, Image_Filter, Blend_Mode, and so on; may be 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso drawBitmap drawImage | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #Method void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr) | 
 |  | 
 | 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; may be 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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso SkDrawable drawPicture | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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); | 
 | } | 
 | ## | 
 |  | 
 | #SeeAlso SkDrawable drawPicture | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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()); | 
 | ## | 
 |  | 
 | #SeeAlso SkPicture SkDocument | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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()); | 
 | ## | 
 |  | 
 | #SeeAlso SkPicture SkDocument | 
 |  | 
 | ## | 
 |  | 
 | #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. | 
 |  | 
 | 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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso isClipRect getLocalClipBounds getDeviceClipBounds | 
 |  | 
 | ## | 
 |  | 
 | # ------------------------------------------------------------------------------ | 
 |  | 
 | #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 | 
 |     ## | 
 | ## | 
 |  | 
 | #SeeAlso isClipEmpty getLocalClipBounds getDeviceClipBounds | 
 |  | 
 | ## | 
 |  | 
 | #Class SkCanvas ## | 
 |  | 
 | #Topic Canvas ## |