• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#Topic Canvas
2#Alias Canvas_Reference ##
3
4#Class SkCanvas
5
6#Code
7#Populate
8##
9
10Canvas provides an interface for drawing, and how the drawing is clipped and transformed.
11Canvas contains a stack of Matrix and Clip values.
12
13Canvas and Paint together provide the state to draw into Surface or Device.
14Each Canvas draw call transforms the geometry of the object by the concatenation of all
15Matrix values in the stack. The transformed geometry is clipped by the intersection
16of all of Clip values in the stack. The Canvas draw calls use Paint to supply drawing
17state such as Color, Typeface, text size, stroke width, Shader and so on.
18
19To draw to a pixel-based destination, create Raster_Surface or GPU_Surface.
20Request Canvas from Surface to obtain the interface to draw.
21Canvas generated by Raster_Surface draws to memory visible to the CPU.
22Canvas generated by GPU_Surface uses Vulkan or OpenGL to draw to the GPU.
23
24To draw to a document, obtain Canvas from SVG_Canvas, Document_PDF, or Picture_Recorder.
25Document based Canvas and other Canvas subclasses reference Device describing the
26destination.
27
28Canvas can be constructed to draw to Bitmap without first creating Raster_Surface.
29This approach may be deprecated in the future.
30
31Canvas may be created directly when no Surface is required; some Canvas methods
32implicitly create Raster_Surface.
33
34# ------------------------------------------------------------------------------
35
36#Method static std::unique_ptr<SkCanvas> MakeRasterDirect(const SkImageInfo& info, void* pixels,
37                                                          size_t rowBytes,
38                                                          const SkSurfaceProps* props = nullptr)
39#In Constructors
40#Line # creates from SkImageInfo and Pixel_Storage ##
41#Populate
42
43#Example
44    #Description
45        Allocates a three by three bitmap, clears it to white, and draws a black pixel
46        in the center.
47    ##
48void draw(SkCanvas* ) {
49    SkImageInfo info = SkImageInfo::MakeN32Premul(3, 3);  // device aligned, 32 bpp, Premultiplied
50    const size_t minRowBytes = info.minRowBytes();  // bytes used by one bitmap row
51    const size_t size = info.computeMinByteSize();  // bytes used by all rows
52    SkAutoTMalloc<SkPMColor> storage(size);  // allocate storage for pixels
53    SkPMColor* pixels = storage.get();  // get pointer to allocated storage
54    // create a SkCanvas backed by a raster device, and delete it when the
55    // function goes out of scope.
56    std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(info, pixels, minRowBytes);
57    canvas->clear(SK_ColorWHITE);  // white is Unpremultiplied, in ARGB order
58    canvas->flush();  // ensure that pixels are cleared
59    SkPMColor pmWhite = pixels[0];  // the Premultiplied format may vary
60    SkPaint paint;  // by default, draws black
61    canvas->drawPoint(1, 1, paint);  // draw in the center
62    canvas->flush();  // ensure that point was drawn
63    for (int y = 0; y < info.height(); ++y) {
64        for (int x = 0; x < info.width(); ++x) {
65            SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
66        }
67        SkDebugf("\n");
68    }
69}
70    #StdOut
71        ---
72        -x-
73        ---
74    ##
75##
76
77#SeeAlso MakeRasterDirectN32 SkSurface::MakeRasterDirect
78
79##
80
81# ------------------------------------------------------------------------------
82
83#Method static std::unique_ptr<SkCanvas> MakeRasterDirectN32(int width, int height, SkPMColor* pixels,
84                                                         size_t rowBytes)
85#In Constructors
86#Line # creates from image data and Pixel_Storage ##
87#Populate
88
89#Example
90    #Description
91        Allocates a three by three bitmap, clears it to white, and draws a black pixel
92        in the center.
93    ##
94void draw(SkCanvas* ) {
95    const int width = 3;
96    const int height = 3;
97    SkPMColor pixels[height][width];  // allocate a 3 by 3 Premultiplied bitmap on the stack
98    // create a SkCanvas backed by a raster device, and delete it when the
99    // function goes out of scope.
100    std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirectN32(
101            width,
102            height,
103            pixels[0],  // top-left of the bitmap
104            sizeof(pixels[0]));  // byte width of the each row
105    // write a Premultiplied value for white into all pixels in the bitmap
106    canvas->clear(SK_ColorWHITE);
107    SkPMColor pmWhite = pixels[0][0];  // the Premultiplied format may vary
108    SkPaint paint;  // by default, draws black
109    canvas->drawPoint(1, 1, paint);  // draw in the center
110    canvas->flush();  // ensure that pixels is ready to be read
111    for (int y = 0; y < height; ++y) {
112        for (int x = 0; x < width; ++x) {
113            SkDebugf("%c", pixels[y][x] == pmWhite ? '-' : 'x');
114        }
115        SkDebugf("\n");
116    }
117}
118    #StdOut
119        ---
120        -x-
121        ---
122    ##
123##
124
125#SeeAlso MakeRasterDirect SkSurface::MakeRasterDirect SkImageInfo::MakeN32Premul
126
127##
128
129# ------------------------------------------------------------------------------
130
131#Method SkCanvas()
132
133#Line # creates with no Surface, no dimensions ##
134#Populate
135
136#Example
137
138#Description
139Passes a placeholder to a function that requires one.
140##
141
142#Function
143static void check_for_rotated_ctm(const SkCanvas* canvas) {
144    const SkMatrix& matrix = canvas->getTotalMatrix();
145    SkDebugf("rect stays rect is %s\n", matrix.rectStaysRect() ? "true" : "false");
146}
147
148##
149void draw(SkCanvas* canvas) {
150    check_for_rotated_ctm(canvas);
151    canvas->rotate(30);
152    check_for_rotated_ctm(canvas);
153
154    SkCanvas defaultCanvas;
155    check_for_rotated_ctm(&defaultCanvas);
156}
157
158    #StdOut
159        rect stays rect is true
160        rect stays rect is false
161        rect stays rect is true
162    ##
163##
164
165#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas
166
167##
168
169# ------------------------------------------------------------------------------
170
171#Method SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr)
172
173#Line # creates with no Surface, set dimensions, Surface_Properties ##
174#Populate
175
176#Example
177    SkCanvas canvas(10, 20);  // 10 units wide, 20 units high
178    canvas.clipRect(SkRect::MakeXYWH(30, 40, 5, 10));  // clip is outside canvas' device
179    SkDebugf("canvas %s empty\n", canvas.getDeviceClipBounds().isEmpty() ? "is" : "is not");
180
181    #StdOut
182        canvas is empty
183    ##
184##
185
186#SeeAlso MakeRasterDirect SkSurfaceProps SkPixelGeometry SkCreateColorSpaceXformCanvas
187
188##
189
190# ------------------------------------------------------------------------------
191
192#Method explicit SkCanvas(const SkBitmap& bitmap)
193
194#Line # uses existing Bitmap ##
195#Populate
196
197#Example
198#Description
199The actual output depends on the installed fonts.
200##
201    SkBitmap bitmap;
202    // create a bitmap 5 wide and 11 high
203    bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11));
204    SkCanvas canvas(bitmap);
205    canvas.clear(SK_ColorWHITE);  // white is Unpremultiplied, in ARGB order
206    SkPixmap pixmap;  // provides guaranteed access to the drawn pixels
207    if (!canvas.peekPixels(&pixmap)) {
208        SkDebugf("peekPixels should never fail.\n");
209    }
210    const SkPMColor* pixels = pixmap.addr32();  // points to top-left of bitmap
211    SkPMColor pmWhite = pixels[0];  // the Premultiplied format may vary
212    SkPaint paint;  // by default, draws black, 12 point text
213    canvas.drawString("!", 1, 10, SkFont(), paint);  // 1 char at baseline (1, 10)
214    for (int y = 0; y < bitmap.height(); ++y) {
215        for (int x = 0; x < bitmap.width(); ++x) {
216            SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
217        }
218        SkDebugf("\n");
219    }
220
221    #StdOut
222    -----
223    ---x-
224    ---x-
225    ---x-
226    ---x-
227    ---x-
228    ---x-
229    -----
230    ---x-
231    ---x-
232    -----
233    #StdOut ##
234##
235
236#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas
237
238##
239
240# ------------------------------------------------------------------------------
241
242#Method SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
243
244#Line # uses existing Bitmap and Surface_Properties ##
245#Populate
246
247#Example
248#Description
249The actual output depends on the installed fonts.
250##
251    SkBitmap bitmap;
252    // create a bitmap 5 wide and 11 high
253    bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11));
254    SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry));
255    canvas.clear(SK_ColorWHITE);  // white is Unpremultiplied, in ARGB order
256    SkPixmap pixmap;  // provides guaranteed access to the drawn pixels
257    if (!canvas.peekPixels(&pixmap)) {
258        SkDebugf("peekPixels should never fail.\n");
259    }
260    const SkPMColor* pixels = pixmap.addr32();  // points to top-left of bitmap
261    SkPMColor pmWhite = pixels[0];  // the Premultiplied format may vary
262    SkPaint paint;  // by default, draws black, 12 point text
263    canvas.drawString("!", 1, 10, SkFont(), paint);  // 1 char at baseline (1, 10)
264    for (int y = 0; y < bitmap.height(); ++y) {
265        for (int x = 0; x < bitmap.width(); ++x) {
266            SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
267        }
268        SkDebugf("\n");
269    }
270
271    #StdOut
272    -----
273    ---x-
274    ---x-
275    ---x-
276    ---x-
277    ---x-
278    ---x-
279    -----
280    ---x-
281    ---x-
282    -----
283    #StdOut ##
284##
285
286#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas
287
288##
289
290# ------------------------------------------------------------------------------
291
292#Method virtual ~SkCanvas()
293
294#Line # draws saved Layers, frees resources ##
295#Populate
296
297#Example
298#Description
299Canvas Layer draws into bitmap. saveLayerAlpha sets up an additional
300drawing surface that blends with the bitmap. When Layer goes out of
301scope, Layer destructor is called. The saved Layer is restored, drawing
302transparent letters.
303##
304void draw(SkCanvas* canvas) {
305    SkBitmap bitmap;
306    bitmap.allocPixels(SkImageInfo::MakeN32Premul(200, 200));
307    {
308        SkCanvas offscreen(bitmap);
309        SkPaint paint;
310        SkFont font(nullptr, 100);
311        offscreen.drawString("ABC", 20, 160, font, paint);
312        SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192);
313        offscreen.saveLayerAlpha(&layerBounds, 128);
314        offscreen.clear(SK_ColorWHITE);
315        offscreen.drawString("DEF", 20, 160, font, paint);
316    }
317    canvas->drawBitmap(bitmap, 0, 0, nullptr);
318}
319##
320
321#SeeAlso State_Stack
322
323##
324
325# ------------------------------------------------------------------------------
326#Subtopic Property
327#Line # metrics and attributes ##
328##
329
330#Method SkMetaData& getMetaData()
331#In Property
332#In Utility
333#Line # associates additional data with the canvas ##
334#Populate
335
336#Example
337    const char* kHelloMetaData = "HelloMetaData";
338    SkCanvas canvas;
339    SkMetaData& metaData = canvas.getMetaData();
340    SkDebugf("before: %s\n", metaData.findString(kHelloMetaData));
341    metaData.setString(kHelloMetaData, "Hello!");
342    SkDebugf("during: %s\n", metaData.findString(kHelloMetaData));
343    metaData.removeString(kHelloMetaData);
344    SkDebugf("after: %s\n", metaData.findString(kHelloMetaData));
345
346    #StdOut
347        before: (null)
348        during: Hello!
349        after: (null)
350    #StdOut ##
351##
352
353#SeeAlso SkMetaData
354
355##
356
357# ------------------------------------------------------------------------------
358
359#Method SkImageInfo imageInfo() const
360#In Property
361#Line # returns Image_Info for Canvas ##
362#Populate
363
364#Example
365    SkCanvas emptyCanvas;
366    SkImageInfo canvasInfo = emptyCanvas.imageInfo();
367    SkImageInfo emptyInfo;
368    SkDebugf("emptyInfo %c= canvasInfo\n", emptyInfo == canvasInfo ? '=' : '!');
369
370    #StdOut
371        emptyInfo == canvasInfo
372    ##
373##
374
375#SeeAlso SkImageInfo MakeRasterDirect makeSurface
376
377##
378
379# ------------------------------------------------------------------------------
380
381#Method bool getProps(SkSurfaceProps* props) const
382#In Property
383#Line # copies Surface_Properties if available ##
384#Populate
385
386#Example
387    SkBitmap bitmap;
388    SkCanvas canvas(bitmap, SkSurfaceProps(0, kRGB_V_SkPixelGeometry));
389    SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
390    SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry()));
391    if (!canvas.getProps(&surfaceProps)) {
392        SkDebugf("getProps failed unexpectedly.\n");
393    }
394    SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry()));
395
396    #StdOut
397        isRGB:0
398        isRGB:1
399    #StdOut ##
400##
401
402#SeeAlso SkSurfaceProps makeSurface
403
404##
405
406# ------------------------------------------------------------------------------
407#Subtopic Utility
408#Line # rarely called management functions ##
409##
410
411#Method void flush()
412#In Utility
413#Line # triggers execution of all pending draw operations ##
414#Populate
415
416#NoExample
417##
418
419#SeeAlso peekPixels SkSurface::flush GrContext::flush GrContext::abandonContext
420
421##
422
423# ------------------------------------------------------------------------------
424
425#Method virtual SkISize getBaseLayerSize() const
426#In Property
427#Line # returns size of base Layer in global coordinates ##
428#Populate
429
430#Example
431    SkBitmap bitmap;
432    bitmap.allocPixels(SkImageInfo::MakeN32Premul(20, 30));
433    SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry));
434    canvas.clipRect(SkRect::MakeWH(10, 40));
435    SkIRect clipDeviceBounds = canvas.getDeviceClipBounds();
436    if (clipDeviceBounds.isEmpty()) {
437        SkDebugf("Empty clip bounds is unexpected!\n");
438    }
439    SkDebugf("clip=%d,%d\n", clipDeviceBounds.width(), clipDeviceBounds.height());
440    SkISize baseLayerSize = canvas.getBaseLayerSize();
441    SkDebugf("size=%d,%d\n", baseLayerSize.width(), baseLayerSize.height());
442
443    #StdOut
444        clip=10,30
445        size=20,30
446    ##
447##
448
449#ToDo is this the same as the width and height of surface? ##
450
451#SeeAlso getDeviceClipBounds
452
453##
454
455# ------------------------------------------------------------------------------
456
457#Method sk_sp<SkSurface> makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr)
458#In Constructors
459#Line # creates Surface matching SkImageInfo and SkSurfaceProps ##
460#Populate
461
462#Example
463    sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(5, 6);
464    SkCanvas* smallCanvas = surface->getCanvas();
465    SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(3, 4);
466    sk_sp<SkSurface> compatible = smallCanvas->makeSurface(imageInfo);
467    SkDebugf("compatible %c= nullptr\n", compatible == nullptr ? '=' : '!');
468    SkDebugf("size = %d, %d\n", compatible->width(), compatible->height());
469
470    #StdOut
471        compatible != nullptr
472        size = 3, 4
473    ##
474##
475
476#SeeAlso SkSurface SkSurface::makeSurface SkImageInfo SkSurfaceProps
477
478##
479
480# ------------------------------------------------------------------------------
481
482#Method virtual GrContext* getGrContext()
483#In Property
484#Line # returns GPU_Context of the GPU_Surface ##
485#Populate
486
487#Example
488void draw(SkCanvas* canvas) {
489    if (canvas->getGrContext()) {
490         canvas->clear(SK_ColorRED);
491    } else {
492         canvas->clear(SK_ColorBLUE);
493    }
494}
495##
496
497#ToDo fiddle should show both CPU and GPU out ##
498
499#SeeAlso GrContext
500
501##
502
503# ------------------------------------------------------------------------------
504
505#Method void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr)
506#In Utility
507#In Property
508#Line # returns writable pixel access if available ##
509#Populate
510
511#Example
512void draw(SkCanvas* canvas) {
513    if (canvas->accessTopLayerPixels(nullptr, nullptr)) {
514         canvas->clear(SK_ColorRED);
515    } else {
516         canvas->clear(SK_ColorBLUE);
517    }
518}
519##
520
521#Example
522#Description
523Draws "ABC" on the device. Then draws "DEF" in Layer, and reads
524Layer to add a large dotted "DEF". Finally blends Layer with the
525device.
526
527The Layer and blended result appear on the CPU and GPU but the large dotted
528"DEF" appear only on the CPU.
529##
530void draw(SkCanvas* canvas) {
531  SkPaint paint;
532  SkFont font(nullptr, 100);
533  canvas->drawString("ABC", 20, 160, font, paint);
534  SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192);
535  canvas->saveLayerAlpha(&layerBounds, 128);
536  canvas->clear(SK_ColorWHITE);
537  canvas->drawString("DEF", 20, 160, font, paint);
538  SkImageInfo imageInfo;
539  size_t rowBytes;
540  SkIPoint origin;
541  uint32_t* access = (uint32_t*) canvas->accessTopLayerPixels(&imageInfo, &rowBytes, &origin);
542  if (access) {
543    int h = imageInfo.height();
544    int v = imageInfo.width();
545    int rowWords = rowBytes / sizeof(uint32_t);
546    for (int y = 0; y < h; ++y) {
547        int newY = (y - h / 2) * 2 + h / 2;
548        if (newY < 0 || newY >= h) {
549            continue;
550        }
551        for (int x = 0; x < v; ++x) {
552            int newX = (x - v / 2) * 2 + v / 2;
553            if (newX < 0 || newX >= v) {
554                continue;
555            }
556            if (access[y * rowWords + x] == SK_ColorBLACK) {
557                access[newY * rowWords + newX] = SK_ColorGRAY;
558            }
559        }
560    }
561
562  }
563  canvas->restore();
564}
565##
566
567#ToDo there are no callers of this that I can find. Deprecate? ##
568#ToDo fiddle should show both CPU and GPU out ##
569
570#SeeAlso SkImageInfo SkPixmap
571
572##
573
574# ------------------------------------------------------------------------------
575
576#Method SkRasterHandleAllocator::Handle accessTopRasterHandle() const
577#In Utility
578#In Property
579#Line # returns context that tracks Clip and Matrix ##
580#Populate
581
582#Example
583#Description
584#ToDo ##
585##
586#Function
587    static void DeleteCallback(void*, void* context) {
588        delete (char*) context;
589    }
590
591    class CustomAllocator : public SkRasterHandleAllocator {
592    public:
593        bool allocHandle(const SkImageInfo& info, Rec* rec) override {
594            char* context = new char[4]{'s', 'k', 'i', 'a'};
595            rec->fReleaseProc = DeleteCallback;
596            rec->fReleaseCtx = context;
597            rec->fHandle = context;
598            rec->fPixels = context;
599            rec->fRowBytes = 4;
600            return true;
601        }
602
603        void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override {
604            // apply canvas matrix and clip to custom environment
605        }
606    };
607
608##
609    void draw(SkCanvas* canvas) {
610        const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
611        std::unique_ptr<SkCanvas> c2 =
612                SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<CustomAllocator>(
613                new CustomAllocator()), info);
614        char* context = (char*) c2->accessTopRasterHandle();
615        SkDebugf("context = %.4s\n", context);
616
617    }
618    #StdOut
619        context = skia
620    ##
621    #ToDo skstd::make_unique could not be used because def is private -- note to fix in c++14? ##
622##
623
624#SeeAlso SkRasterHandleAllocator
625
626##
627
628# ------------------------------------------------------------------------------
629#Subtopic Pixels
630#Line # read and write pixel values ##
631##
632
633#Method bool peekPixels(SkPixmap* pixmap)
634#In Pixels
635#Line # returns if Canvas has direct access to its pixels ##
636#Populate
637
638#Example
639    SkPixmap pixmap;
640    if (canvas->peekPixels(&pixmap)) {
641        SkDebugf("width=%d height=%d\n", pixmap.bounds().width(), pixmap.bounds().height());
642    }
643    #StdOut
644        width=256 height=256
645    ##
646##
647
648#SeeAlso readPixels SkBitmap::peekPixels SkImage::peekPixels SkSurface::peekPixels
649
650##
651
652# ------------------------------------------------------------------------------
653
654#Method bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
655                    int srcX, int srcY)
656#In Pixels
657#Line # copies and converts rectangle of pixels from Canvas ##
658
659Copies Rect of pixels from Canvas into dstPixels. Matrix and Clip are
660ignored.
661
662Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
663Destination Rect corners are (0, 0) and (dstInfo.width(), dstInfo.height()).
664Copies each readable pixel intersecting both rectangles, without scaling,
665converting to dstInfo.colorType() and dstInfo.alphaType() if required.
666
667Pixels are readable when Device is raster, or backed by a GPU.
668Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
669returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
670class like SkDebugCanvas.
671
672The destination pixel storage must be allocated by the caller.
673
674Pixel values are converted only if Color_Type and Alpha_Type
675do not match. Only pixels within both source and destination rectangles
676are copied. dstPixels contents outside Rect intersection are unchanged.
677
678Pass negative values for srcX or srcY to offset pixels across or down destination.
679
680Does not copy, and returns false if:
681
682#List
683# Source and destination rectangles do not intersect. ##
684# Canvas pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). ##
685# Canvas pixels are not readable; for instance, Canvas is document-based. ##
686# dstRowBytes is too small to contain one row of pixels. ##
687##
688
689#Param dstInfo  width, height, Color_Type, and Alpha_Type of dstPixels ##
690#Param dstPixels  storage for pixels; dstInfo.height() times dstRowBytes, or larger ##
691#Param dstRowBytes  size of one destination row; dstInfo.width() times pixel size, or larger ##
692#Param srcX  offset into readable pixels on x-axis; may be negative ##
693#Param srcY  offset into readable pixels on y-axis; may be negative ##
694
695#Return  true if pixels were copied ##
696
697#Example
698#Width 64
699#Height 64
700#Description
701    A black circle drawn on a blue background provides an image to copy.
702    readPixels copies one quarter of the canvas into each of the four corners.
703    The copied quarter circles overdraw the original circle.
704##
705    canvas->clear(SK_ColorBLUE);
706    SkPaint paint;
707    canvas->drawCircle(32, 32, 28, paint);
708    SkImageInfo info = SkImageInfo::Make(64, 64, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
709    sk_sp<SkData> data(SkData::MakeUninitialized(info.minRowBytes() * info.height()));
710    sk_bzero(data->writable_data(), info.minRowBytes() * info.height());
711    for (int x : { 32, -32 } ) {
712        for (int y : { 32, -32 } ) {
713            canvas->readPixels(info, data->writable_data(), info.minRowBytes(), x, y);
714        }
715    }
716    sk_sp<SkImage> image = SkImage::MakeRasterData(info, data, info.minRowBytes());
717    canvas->drawImage(image, 0, 0);
718##
719
720#Example
721#Description
722    Canvas returned by Raster_Surface has Premultiplied pixel values.
723    clear() takes Unpremultiplied input with Color_Alpha equal 0x80
724    and RGB equal 0x55, 0xAA, 0xFF. RGB is multiplied by Color_Alpha
725    to generate Premultiplied value 0x802B5580. readPixels converts pixel back
726    to Unpremultiplied value 0x8056A9FF, introducing error.
727##
728    canvas->clear(0x8055aaff);
729    for (SkAlphaType alphaType : { kPremul_SkAlphaType, kUnpremul_SkAlphaType } ) {
730        uint32_t pixel = 0;
731        SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, alphaType);
732        if (canvas->readPixels(info, &pixel, 4, 0, 0)) {
733            SkDebugf("pixel = %08x\n", pixel);
734        }
735    }
736
737    #StdOut
738        pixel = 802b5580
739        pixel = 8056a9ff
740    ##
741##
742
743#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels
744
745##
746
747# ------------------------------------------------------------------------------
748
749#Method bool readPixels(const SkPixmap& pixmap, int srcX, int srcY)
750
751Copies Rect of pixels from Canvas into pixmap. Matrix and Clip are
752ignored.
753
754Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
755Destination Rect corners are (0, 0) and (pixmap.width(), pixmap.height()).
756Copies each readable pixel intersecting both rectangles, without scaling,
757converting to pixmap.colorType() and pixmap.alphaType() if required.
758
759Pixels are readable when Device is raster, or backed by a GPU.
760Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
761returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
762class like SkDebugCanvas.
763
764Caller must allocate pixel storage in pixmap if needed.
765
766Pixel values are converted only if Color_Type and Alpha_Type
767do not match. Only pixels within both source and destination Rects
768are copied. pixmap pixels contents outside Rect intersection are unchanged.
769
770Pass negative values for srcX or srcY to offset pixels across or down pixmap.
771
772Does not copy, and returns false if:
773
774#List
775# Source and destination rectangles do not intersect. ##
776# Canvas pixels could not be converted to pixmap.colorType() or pixmap.alphaType(). ##
777# Canvas pixels are not readable; for instance, Canvas is document-based. ##
778# Pixmap pixels could not be allocated. ##
779# pixmap.rowBytes() is too small to contain one row of pixels. ##
780##
781
782#Param pixmap  storage for pixels copied from Canvas ##
783#Param srcX    offset into readable pixels on x-axis; may be negative ##
784#Param srcY    offset into readable pixels on y-axis; may be negative ##
785
786#Return  true if pixels were copied ##
787
788#Example
789    #Description
790        clear() takes Unpremultiplied input with Color_Alpha equal 0x80
791        and RGB equal 0x55, 0xAA, 0xFF. RGB is multiplied by Color_Alpha
792        to generate Premultiplied value 0x802B5580.
793    ##
794    void draw(SkCanvas* canvas) {
795        canvas->clear(0x8055aaff);
796        uint32_t pixels[1] = { 0 };
797        SkPixmap pixmap(SkImageInfo::MakeN32Premul(1, 1), pixels, 4);
798        canvas->readPixels(pixmap, 0, 0);
799        SkDebugf("pixel = %08x\n", pixels[0]);
800    }
801    #StdOut
802        pixel = 802b5580
803    ##
804##
805
806#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels
807
808##
809
810# ------------------------------------------------------------------------------
811
812#Method bool readPixels(const SkBitmap& bitmap, int srcX, int srcY)
813
814Copies Rect of pixels from Canvas into bitmap. Matrix and Clip are
815ignored.
816
817Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
818Destination Rect corners are (0, 0) and (bitmap.width(), bitmap.height()).
819Copies each readable pixel intersecting both rectangles, without scaling,
820converting to bitmap.colorType() and bitmap.alphaType() if required.
821
822Pixels are readable when Device is raster, or backed by a GPU.
823Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
824returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
825class like SkDebugCanvas.
826
827Caller must allocate pixel storage in bitmap if needed.
828
829Bitmap values are converted only if Color_Type and Alpha_Type
830do not match. Only pixels within both source and destination rectangles
831are copied. Bitmap pixels outside Rect intersection are unchanged.
832
833Pass negative values for srcX or srcY to offset pixels across or down bitmap.
834
835Does not copy, and returns false if:
836
837#List
838# Source and destination rectangles do not intersect. ##
839# Canvas pixels could not be converted to bitmap.colorType() or bitmap.alphaType(). ##
840# Canvas pixels are not readable; for instance, Canvas is document-based. ##
841# bitmap pixels could not be allocated. ##
842# bitmap.rowBytes() is too small to contain one row of pixels. ##
843##
844
845#Param bitmap  storage for pixels copied from Canvas ##
846#Param srcX    offset into readable pixels on x-axis; may be negative ##
847#Param srcY    offset into readable pixels on y-axis; may be negative ##
848
849#Return  true if pixels were copied ##
850
851#Example
852    #Description
853        clear() takes Unpremultiplied input with Color_Alpha equal 0x80
854        and RGB equal 0x55, 0xAA, 0xFF. RGB is multiplied by Color_Alpha
855        to generate Premultiplied value 0x802B5580.
856    ##
857void draw(SkCanvas* canvas) {
858    canvas->clear(0x8055aaff);
859    SkBitmap bitmap;
860    bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
861    canvas->readPixels(bitmap, 0, 0);
862    SkDebugf("pixel = %08x\n", bitmap.getAddr32(0, 0)[0]);
863}
864    #StdOut
865        pixel = 802b5580
866    ##
867##
868
869#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels
870
871##
872
873# ------------------------------------------------------------------------------
874
875#Method bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y)
876#In Pixels
877#Line # copies and converts rectangle of pixels to Canvas ##
878Copies Rect from pixels to Canvas. Matrix and Clip are ignored.
879Source Rect corners are (0, 0) and (info.width(), info.height()).
880Destination Rect corners are (x, y) and
881(imageInfo().width(), imageInfo().height()).
882
883Copies each readable pixel intersecting both rectangles, without scaling,
884converting to imageInfo().colorType() and imageInfo().alphaType() if required.
885
886Pixels are writable when Device is raster, or backed by a GPU.
887Pixels are not writable when SkCanvas is returned by SkDocument::beginPage,
888returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
889class like SkDebugCanvas.
890
891Pixel values are converted only if Color_Type and Alpha_Type
892do not match. Only pixels within both source and destination rectangles
893are copied. Canvas pixels outside Rect intersection are unchanged.
894
895Pass negative values for x or y to offset pixels to the left or
896above Canvas pixels.
897
898Does not copy, and returns false if:
899
900#List
901# Source and destination rectangles do not intersect. ##
902# pixels could not be converted to Canvas imageInfo().colorType() or
903  imageInfo().alphaType(). ##
904# Canvas pixels are not writable; for instance, Canvas is document-based. ##
905# rowBytes is too small to contain one row of pixels. ##
906##
907
908#Param info  width, height, Color_Type, and Alpha_Type of pixels ##
909#Param pixels  pixels to copy, of size info.height() times rowBytes, or larger ##
910#Param rowBytes  size of one row of pixels; info.width() times pixel size, or larger ##
911#Param x  offset into Canvas writable pixels on x-axis; may be negative ##
912#Param y  offset into Canvas writable pixels on y-axis; may be negative ##
913
914#Return  true if pixels were written to Canvas ##
915
916#Example
917    SkImageInfo imageInfo = SkImageInfo::MakeN32(256, 1, kPremul_SkAlphaType);
918    for (int y = 0; y < 256; ++y) {
919        uint32_t pixels[256];
920        for (int x = 0; x < 256; ++x) {
921            pixels[x] = SkColorSetARGB(x, x + y, x, x - y);
922        }
923        canvas->writePixels(imageInfo, &pixels, sizeof(pixels), 0, y);
924    }
925##
926
927#SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels
928
929##
930
931# ------------------------------------------------------------------------------
932
933#Method bool writePixels(const SkBitmap& bitmap, int x, int y)
934
935Copies Rect from pixels to Canvas. Matrix and Clip are ignored.
936Source Rect corners are (0, 0) and (bitmap.width(), bitmap.height()).
937
938Destination Rect corners are (x, y) and
939(imageInfo().width(), imageInfo().height()).
940
941Copies each readable pixel intersecting both rectangles, without scaling,
942converting to imageInfo().colorType() and imageInfo().alphaType() if required.
943
944Pixels are writable when Device is raster, or backed by a GPU.
945Pixels are not writable when SkCanvas is returned by SkDocument::beginPage,
946returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
947class like SkDebugCanvas.
948
949Pixel values are converted only if Color_Type and Alpha_Type
950do not match. Only pixels within both source and destination rectangles
951are copied. Canvas pixels outside Rect intersection are unchanged.
952
953Pass negative values for x or y to offset pixels to the left or
954above Canvas pixels.
955
956Does not copy, and returns false if:
957
958#List
959# Source and destination rectangles do not intersect. ##
960# bitmap does not have allocated pixels. ##
961# bitmap pixels could not be converted to Canvas imageInfo().colorType() or
962  imageInfo().alphaType(). ##
963# Canvas pixels are not writable; for instance, Canvas is document based. ##
964# bitmap pixels are inaccessible; for instance, bitmap wraps a texture. ##
965##
966
967#Param bitmap  contains pixels copied to Canvas ##
968#Param x       offset into Canvas writable pixels in x; may be negative ##
969#Param y       offset into Canvas writable pixels in y; may be negative ##
970
971#Return  true if pixels were written to Canvas ##
972
973#Example
974void draw(SkCanvas* canvas) {
975    SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(2, 2);
976    SkBitmap bitmap;
977    bitmap.setInfo(imageInfo);
978    uint32_t pixels[4];
979    bitmap.setPixels(pixels);
980    for (int y = 0; y < 256; y += 2) {
981        for (int x = 0; x < 256;  x += 2) {
982            pixels[0] = SkColorSetRGB(x, y, x | y);
983            pixels[1] = SkColorSetRGB(x ^ y, y, x);
984            pixels[2] = SkColorSetRGB(x, x & y, y);
985            pixels[3] = SkColorSetRGB(~x, ~y, x);
986            canvas->writePixels(bitmap, x, y);
987        }
988    }
989}
990##
991
992#SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels
993
994##
995
996# ------------------------------------------------------------------------------
997#Subtopic State_Stack
998#Line # stack of state for hierarchical drawing ##
999
1000Canvas maintains a stack of state that allows hierarchical drawing, commonly used
1001to implement windows and views. The initial state has an identity matrix and and
1002an infinite clip. Even with a wide-open clip, drawing is constrained by the
1003bounds of the Canvas Surface or Device.
1004
1005Canvas savable state consists of Clip and Matrix.
1006Clip describes the area that may be drawn to.
1007Matrix transforms the geometry.
1008
1009save(), saveLayer, and saveLayerAlpha
1010save state and return the depth of the stack.
1011
1012restore(), restoreToCount, and ~SkCanvas() revert state to its value when saved.
1013
1014Each state on the stack intersects Clip with the previous Clip,
1015and concatenates Matrix with the previous Matrix.
1016The intersected Clip makes the drawing area the same or smaller;
1017the concatenated Matrix may move the origin and potentially scale or rotate
1018the coordinate space.
1019
1020Canvas does not require balancing the state stack but it is a good idea
1021to do so. Calling save() without restore() will eventually cause Skia to fail;
1022mismatched save() and restore() create hard to find bugs.
1023
1024It is not possible to use state to draw outside of the clip defined by the
1025previous state.
1026
1027#Example
1028#Description
1029Draw to ever smaller clips; then restore drawing to full canvas.
1030Note that the second clipRect is not permitted to enlarge Clip.
1031##
1032#Height 160
1033void draw(SkCanvas* canvas) {
1034    SkPaint paint;
1035    canvas->save();                             // records stack depth to restore
1036    canvas->clipRect(SkRect::MakeWH(100, 100)); // constrains drawing to clip
1037    canvas->clear(SK_ColorRED);                 // draws to limit of clip
1038    canvas->save();                             // records stack depth to restore
1039    canvas->clipRect(SkRect::MakeWH(50, 150));  // Rect below 100 is ignored
1040    canvas->clear(SK_ColorBLUE);                // draws to smaller clip
1041    canvas->restore();                          // enlarges clip
1042    canvas->drawLine(20, 20, 150, 150, paint);  // line below 100 is not drawn
1043    canvas->restore();                          // enlarges clip
1044    canvas->drawLine(150, 20, 50, 120, paint);  // line below 100 is drawn
1045}
1046##
1047
1048Each Clip uses the current Matrix for its coordinates.
1049
1050#Example
1051#Description
1052While clipRect is given the same rectangle twice, Matrix makes the second
1053clipRect draw at half the size of the first.
1054##
1055#Height 128
1056void draw(SkCanvas* canvas) {
1057    canvas->clipRect(SkRect::MakeWH(100, 100));
1058    canvas->clear(SK_ColorRED);
1059    canvas->scale(.5, .5);
1060    canvas->clipRect(SkRect::MakeWH(100, 100));
1061    canvas->clear(SK_ColorBLUE);
1062}
1063##
1064
1065#SeeAlso save saveLayer saveLayerAlpha restore() restoreToCount
1066
1067#Method int save()
1068
1069#In State_Stack
1070#Line # saves Clip and Matrix on stack ##
1071#Populate
1072
1073#Example
1074#Description
1075The black square is translated 50 pixels down and to the right.
1076Restoring Canvas state removes translate() from Canvas stack;
1077the red square is not translated, and is drawn at the origin.
1078##
1079#Height 100
1080void draw(SkCanvas* canvas) {
1081    SkPaint paint;
1082    SkRect rect = { 0, 0, 25, 25 };
1083    canvas->drawRect(rect, paint);
1084    canvas->save();
1085    canvas->translate(50, 50);
1086    canvas->drawRect(rect, paint);
1087    canvas->restore();
1088    paint.setColor(SK_ColorRED);
1089    canvas->drawRect(rect, paint);
1090}
1091##
1092
1093#SeeAlso saveLayer saveLayerAlpha restore restoreToCount
1094
1095##
1096
1097# ------------------------------------------------------------------------------
1098
1099#Method void restore()
1100
1101#In State_Stack
1102#Line # restores changes to Clip and Matrix, pops save stack ##
1103#Populate
1104
1105#Example
1106void draw(SkCanvas* canvas) {
1107    SkCanvas simple;
1108    SkDebugf("depth = %d\n", simple.getSaveCount());
1109    simple.restore();
1110    SkDebugf("depth = %d\n", simple.getSaveCount());
1111}
1112##
1113
1114#SeeAlso save saveLayer saveLayerAlpha restoreToCount
1115
1116##
1117
1118# ------------------------------------------------------------------------------
1119
1120#Method int getSaveCount() const
1121
1122#In State_Stack
1123#Line # returns depth of stack containing Clip and Matrix ##
1124#Populate
1125
1126#Example
1127void draw(SkCanvas* canvas) {
1128    SkCanvas simple;
1129    SkDebugf("depth = %d\n", simple.getSaveCount());
1130    simple.save();
1131    SkDebugf("depth = %d\n", simple.getSaveCount());
1132    simple.restore();
1133    SkDebugf("depth = %d\n", simple.getSaveCount());
1134}
1135#StdOut
1136depth = 1
1137depth = 2
1138depth = 1
1139##
1140##
1141
1142#SeeAlso save restore restoreToCount
1143
1144##
1145
1146# ------------------------------------------------------------------------------
1147
1148#Method void restoreToCount(int saveCount)
1149
1150#In State_Stack
1151#Line # restores changes to Clip and Matrix to given depth ##
1152#Populate
1153
1154#Example
1155void draw(SkCanvas* canvas) {
1156    SkDebugf("depth = %d\n", canvas->getSaveCount());
1157    canvas->save();
1158    canvas->save();
1159    SkDebugf("depth = %d\n", canvas->getSaveCount());
1160    canvas->restoreToCount(0);
1161    SkDebugf("depth = %d\n", canvas->getSaveCount());
1162}
1163#StdOut
1164depth = 1
1165depth = 3
1166depth = 1
1167##
1168##
1169
1170#SeeAlso restore getSaveCount save
1171
1172##
1173
1174#Subtopic State_Stack ##
1175
1176# ------------------------------------------------------------------------------
1177
1178#Subtopic Layer
1179#Substitute layer
1180#Alias Layers
1181#Substitute layers
1182##
1183#Line # temporary Bitmap to draw into ##
1184
1185Layer allocates a temporary Bitmap to draw into. When the drawing is
1186complete, the Bitmap is drawn into the Canvas.
1187
1188Layer is saved in a stack along with other saved state. When state with a Layer
1189is restored, the Bitmap is drawn into the previous Layer.
1190
1191Layer may be initialized with the contents of the previous Layer. When Layer is
1192restored, its Bitmap can be modified by Paint passed to Layer to apply
1193Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode.
1194
1195#Method int saveLayer(const SkRect* bounds, const SkPaint* paint)
1196
1197#In Layer
1198#Line # saves Clip and Matrix on stack; creates Layer ##
1199#Populate
1200
1201#Example
1202#Description
1203Rectangles are blurred by Image_Filter when restore() draws Layer to main
1204Canvas.
1205##
1206#Height 128
1207#Function
1208###$
1209#include "SkBlurImageFilter.h"
1210$$$#
1211##
1212
1213void draw(SkCanvas* canvas) {
1214    SkPaint paint, blur;
1215    blur.setImageFilter(SkBlurImageFilter::Make(3, 3, nullptr));
1216    canvas->saveLayer(nullptr, &blur);
1217    SkRect rect = { 25, 25, 50, 50};
1218    canvas->drawRect(rect, paint);
1219    canvas->translate(50, 50);
1220    paint.setColor(SK_ColorRED);
1221    canvas->drawRect(rect, paint);
1222    canvas->restore();
1223}
1224##
1225
1226#SeeAlso save restore saveLayer saveLayerAlpha SaveLayerRec
1227
1228##
1229
1230#Method int saveLayer(const SkRect& bounds, const SkPaint* paint)
1231
1232#In Layer
1233#Populate
1234
1235#Example
1236#Description
1237Rectangles are blurred by Image_Filter when restore() draws Layer to main Canvas.
1238The red rectangle is clipped; it does not fully fit on Layer.
1239Image_Filter blurs past edge of Layer so red rectangle is blurred on all sides.
1240##
1241#Height 128
1242#Function
1243###$
1244#include "SkBlurImageFilter.h"
1245$$$#
1246##
1247
1248void draw(SkCanvas* canvas) {
1249    SkPaint paint, blur;
1250    blur.setImageFilter(SkBlurImageFilter::Make(3, 3, nullptr));
1251    canvas->saveLayer(SkRect::MakeWH(90, 90), &blur);
1252    SkRect rect = { 25, 25, 50, 50};
1253    canvas->drawRect(rect, paint);
1254    canvas->translate(50, 50);
1255    paint.setColor(SK_ColorRED);
1256    canvas->drawRect(rect, paint);
1257    canvas->restore();
1258}
1259##
1260
1261#SeeAlso save restore saveLayerAlpha SaveLayerRec
1262
1263##
1264
1265#Method int saveLayerAlpha(const SkRect* bounds, U8CPU alpha)
1266
1267#In Layer
1268#Line # saves Clip and Matrix on stack; creates Layer; sets opacity ##
1269#Populate
1270
1271#Example
1272    SkPaint paint;
1273    paint.setColor(SK_ColorRED);
1274    canvas->drawCircle(50, 50, 50, paint);
1275    canvas->saveLayerAlpha(nullptr, 128);
1276    paint.setColor(SK_ColorBLUE);
1277    canvas->drawCircle(100, 50, 50, paint);
1278    paint.setColor(SK_ColorGREEN);
1279    paint.setAlpha(128);
1280    canvas->drawCircle(75, 90, 50, paint);
1281    canvas->restore();
1282##
1283
1284#SeeAlso save restore saveLayer SaveLayerRec
1285
1286##
1287
1288#Enum SaveLayerFlagsSet
1289#Line # sets SaveLayerRec options ##
1290#Code
1291#Populate
1292##
1293
1294
1295#Typedef uint32_t SaveLayerFlags
1296#Line # options for SaveLayerRec ##
1297##
1298
1299SaveLayerFlags provides options that may be used in any combination in SaveLayerRec,
1300defining how Layer allocated by saveLayer operates. It may be set to zero or
1301kInitWithPrevious_SaveLayerFlag.
1302
1303#Const kInitWithPrevious_SaveLayerFlag 4
1304#Line # initializes with previous contents ##
1305  Initializes Layer with the contents of the previous Layer.
1306##
1307
1308#Example
1309#Height 160
1310#Description
1311Canvas Layer captures red and blue circles scaled up by four.
1312scalePaint blends Layer back with transparency.
1313##
1314void draw(SkCanvas* canvas) {
1315    SkPaint redPaint, bluePaint, scalePaint;
1316    redPaint.setColor(SK_ColorRED);
1317    canvas->drawCircle(21, 21, 8, redPaint);
1318    bluePaint.setColor(SK_ColorBLUE);
1319    canvas->drawCircle(31, 21, 8, bluePaint);
1320    SkMatrix matrix;
1321    matrix.setScale(4, 4);
1322    scalePaint.setAlpha(0x40);
1323    scalePaint.setImageFilter(
1324            SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr));
1325    SkCanvas::SaveLayerRec saveLayerRec(nullptr, &scalePaint,
1326            SkCanvas::kInitWithPrevious_SaveLayerFlag);
1327    canvas->saveLayer(saveLayerRec);
1328    canvas->restore();
1329}
1330##
1331
1332#SeeAlso save restore saveLayer saveLayerAlpha SaveLayerRec
1333
1334#Enum ##
1335
1336#Subtopic SaveLayerRec
1337#Line # contains the state used to create the Layer ##
1338
1339#Struct SaveLayerRec
1340#Line # contains the state used to create the Layer ##
1341
1342#Code
1343#Populate
1344##
1345
1346SaveLayerRec contains the state used to create the Layer.
1347
1348#Member const SkRect*           fBounds
1349#Line # hints at Layer size limit ##
1350    fBounds is used as a hint to limit the size of Layer; may be nullptr.
1351    fBounds suggests but does not define Layer size. To clip drawing to
1352    a specific rectangle, use clipRect.
1353##
1354
1355#Member const SkPaint*          fPaint
1356#Line # modifies overlay ##
1357    fPaint modifies how Layer overlays the prior Layer; may be nullptr.
1358    Color_Alpha, Blend_Mode, Color_Filter, Draw_Looper, Image_Filter, and
1359    Mask_Filter affect Layer draw.
1360##
1361
1362#Member const SkImageFilter*    fBackdrop
1363#Line # applies Image_Filter to prior Layer ##
1364    fBackdrop applies Image_Filter to the prior Layer when copying to the Layer;
1365    may be nullptr. Use kInitWithPrevious_SaveLayerFlag to copy the
1366    prior Layer without an Image_Filter.
1367##
1368
1369#Member const SkImage*          fClipMask
1370#Line # clips Layer with Mask_Alpha ##
1371  restore() clips Layer by the Color_Alpha channel of fClipMask when
1372  Layer is copied to Device. fClipMask may be nullptr.    .
1373##
1374
1375#Member const SkMatrix*         fClipMatrix
1376#Line # transforms Mask_Alpha used to clip ##
1377  fClipMatrix transforms fClipMask before it clips Layer. If
1378  fClipMask describes a translucent gradient, it may be scaled and rotated
1379  without introducing artifacts. fClipMatrix may be nullptr.
1380##
1381
1382#Member SaveLayerFlags          fSaveLayerFlags
1383#Line # creates with prior Layer contents ##
1384    fSaveLayerFlags are used to create Layer without transparency,
1385    and to create Layer with the ontents of the previous Layer.
1386##
1387
1388#Example
1389#Height 160
1390#Description
1391Canvas Layer captures a red Anti_Aliased circle and a blue Aliased circle scaled
1392up by four. After drawing another red circle without scaling on top, the Layer is
1393transferred to the main canvas.
1394##
1395void draw(SkCanvas* canvas) {
1396    SkPaint redPaint, bluePaint;
1397    redPaint.setAntiAlias(true);
1398    redPaint.setColor(SK_ColorRED);
1399    canvas->drawCircle(21, 21, 8, redPaint);
1400    bluePaint.setColor(SK_ColorBLUE);
1401    canvas->drawCircle(31, 21, 8, bluePaint);
1402    SkMatrix matrix;
1403    matrix.setScale(4, 4);
1404    auto scaler = SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr);
1405    SkCanvas::SaveLayerRec saveLayerRec(nullptr, nullptr, scaler.get(), 0);
1406    canvas->saveLayer(saveLayerRec);
1407    canvas->drawCircle(125, 85, 8, redPaint);
1408    canvas->restore();
1409}
1410##
1411
1412#Subtopic Constructors
1413##
1414
1415#Method SaveLayerRec()
1416#Line # constructs SaveLayerRec ##
1417#Populate
1418
1419#Example
1420    SkCanvas::SaveLayerRec rec1;
1421    rec1.fSaveLayerFlags = SkCanvas::kInitWithPrevious_SaveLayerFlag;
1422    SkCanvas::SaveLayerRec rec2(nullptr, nullptr, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1423    SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
1424            && rec1.fPaint == rec2.fPaint
1425            && rec1.fBackdrop == rec2.fBackdrop
1426            && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!');
1427    #StdOut
1428        rec1 == rec2
1429    ##
1430##
1431
1432#SeeAlso save restore saveLayer saveLayerAlpha
1433
1434##
1435
1436#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0)
1437#Populate
1438
1439#Example
1440    SkCanvas::SaveLayerRec rec1;
1441    SkCanvas::SaveLayerRec rec2(nullptr, nullptr);
1442    SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
1443            && rec1.fPaint == rec2.fPaint
1444            && rec1.fBackdrop == rec2.fBackdrop
1445            && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!');
1446    #StdOut
1447        rec1 == rec2
1448    ##
1449##
1450
1451#SeeAlso save restore saveLayer saveLayerAlpha
1452
1453##
1454
1455#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop,
1456                     SaveLayerFlags saveLayerFlags)
1457#Populate
1458
1459#Example
1460    SkCanvas::SaveLayerRec rec1;
1461    SkCanvas::SaveLayerRec rec2(nullptr, nullptr, nullptr, 0);
1462    SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
1463            && rec1.fPaint == rec2.fPaint
1464            && rec1.fBackdrop == rec2.fBackdrop
1465            && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!');
1466    #StdOut
1467        rec1 == rec2
1468    ##
1469##
1470
1471#SeeAlso save restore saveLayer saveLayerAlpha
1472
1473##
1474
1475#Struct ##
1476
1477#Subtopic ##
1478
1479#Method int saveLayer(const SaveLayerRec& layerRec)
1480
1481#In Layer
1482#Populate
1483
1484#Example
1485#Description
1486The example draws an image, and saves it into a Layer with kInitWithPrevious_SaveLayerFlag.
1487Next it punches a hole in Layer and restore with SkBlendMode::kPlus.
1488Where Layer was cleared, the original image will draw unchanged.
1489Outside of the circle the mandrill is brightened.
1490##
1491    #Image 3
1492    // sk_sp<SkImage> image = GetResourceAsImage("images/mandrill_256.png");
1493    canvas->drawImage(image, 0, 0, nullptr);
1494    SkCanvas::SaveLayerRec rec;
1495    SkPaint paint;
1496    paint.setBlendMode(SkBlendMode::kPlus);
1497    rec.fSaveLayerFlags = SkCanvas::kInitWithPrevious_SaveLayerFlag;
1498    rec.fPaint = &paint;
1499    canvas->saveLayer(rec);
1500    paint.setBlendMode(SkBlendMode::kClear);
1501    canvas->drawCircle(128, 128, 96, paint);
1502    canvas->restore();
1503##
1504
1505#ToDo above example needs to replace GetResourceAsImage with way to select image in fiddle ##
1506
1507#SeeAlso save restore saveLayer saveLayerAlpha
1508
1509##
1510
1511#Subtopic Layer ##
1512
1513# ------------------------------------------------------------------------------
1514#Subtopic Matrix
1515#Line # coordinate transformation ##
1516
1517#Method void translate(SkScalar dx, SkScalar dy)
1518
1519#In Matrix
1520#Line # translates Matrix ##
1521#Populate
1522
1523#Example
1524#Height 128
1525#Description
1526scale() followed by translate() produces different results from translate() followed
1527by scale().
1528
1529The blue stroke follows translate of (50, 50); a black
1530fill follows scale of (2, 1/2.f). After restoring the clip, which resets
1531Matrix, a red frame follows the same scale of (2, 1/2.f); a gray fill
1532follows translate of (50, 50).
1533##
1534void draw(SkCanvas* canvas) {
1535    SkPaint filledPaint;
1536    SkPaint outlinePaint;
1537    outlinePaint.setStyle(SkPaint::kStroke_Style);
1538    outlinePaint.setColor(SK_ColorBLUE);
1539    canvas->save();
1540    canvas->translate(50, 50);
1541    canvas->drawCircle(28, 28, 15, outlinePaint);  // blue center: (50+28, 50+28)
1542    canvas->scale(2, 1/2.f);
1543    canvas->drawCircle(28, 28, 15, filledPaint);   // black center: (50+(28*2), 50+(28/2))
1544    canvas->restore();
1545    filledPaint.setColor(SK_ColorGRAY);
1546    outlinePaint.setColor(SK_ColorRED);
1547    canvas->scale(2, 1/2.f);
1548    canvas->drawCircle(28, 28, 15, outlinePaint);  // red center: (28*2, 28/2)
1549    canvas->translate(50, 50);
1550    canvas->drawCircle(28, 28, 15, filledPaint);   // gray center: ((50+28)*2, (50+28)/2)
1551}
1552##
1553
1554#SeeAlso concat() scale() skew() rotate() setMatrix
1555
1556##
1557
1558# ------------------------------------------------------------------------------
1559
1560#Method void scale(SkScalar sx, SkScalar sy)
1561
1562#In Matrix
1563#Line # scales Matrix ##
1564#Populate
1565
1566#Example
1567#Height 160
1568void draw(SkCanvas* canvas) {
1569    SkPaint paint;
1570    SkRect rect = { 10, 20, 60, 120 };
1571    canvas->translate(20, 20);
1572    canvas->drawRect(rect, paint);
1573    canvas->scale(2, .5f);
1574    paint.setColor(SK_ColorGRAY);
1575    canvas->drawRect(rect, paint);
1576}
1577##
1578
1579#SeeAlso concat() translate() skew() rotate() setMatrix
1580
1581##
1582
1583# ------------------------------------------------------------------------------
1584
1585#Method void rotate(SkScalar degrees)
1586
1587#In Matrix
1588#Line # rotates Matrix ##
1589#Populate
1590
1591#Example
1592#Description
1593Draw clock hands at time 5:10. The hour hand and minute hand point up and
1594are rotated clockwise.
1595##
1596void draw(SkCanvas* canvas) {
1597    SkPaint paint;
1598    paint.setStyle(SkPaint::kStroke_Style);
1599    canvas->translate(128, 128);
1600    canvas->drawCircle(0, 0, 60, paint);
1601    canvas->save();
1602    canvas->rotate(10 * 360 / 60);   // 10 minutes of 60 scaled to 360 degrees
1603    canvas->drawLine(0, 0, 0, -50, paint);
1604    canvas->restore();
1605    canvas->rotate((5 + 10.f/60) * 360 / 12); // 5 and 10/60 hours of 12 scaled to 360 degrees
1606    canvas->drawLine(0, 0, 0, -30, paint);
1607}
1608##
1609
1610#SeeAlso concat() translate() skew() scale() setMatrix
1611
1612##
1613
1614# ------------------------------------------------------------------------------
1615
1616#Method void rotate(SkScalar degrees, SkScalar px, SkScalar py)
1617
1618#In Matrix
1619#Populate
1620
1621#Example
1622#Height 192
1623void draw(SkCanvas* canvas) {
1624    SkPaint paint;
1625    SkFont font(nullptr, 96);
1626    canvas->drawString("A1", 130, 100, font, paint);
1627    canvas->rotate(180, 130, 100);
1628    canvas->drawString("A1", 130, 100, font, paint);
1629}
1630##
1631
1632#SeeAlso concat() translate() skew() scale() setMatrix
1633
1634##
1635
1636# ------------------------------------------------------------------------------
1637
1638#Method void skew(SkScalar sx, SkScalar sy)
1639
1640#In Matrix
1641#Line # skews Matrix ##
1642#Populate
1643
1644#Example
1645    #Description
1646        Black text mimics an oblique text style by using a negative skew on x-axis
1647        that shifts the geometry to the right as the y-axis values decrease.
1648        Red text uses a positive skew on y-axis to shift the geometry down
1649        as the x-axis values increase.
1650        Blue text combines sx and sy skew to rotate and scale.
1651    ##
1652    SkPaint paint;
1653    SkFont font(nullptr, 128);
1654    canvas->translate(30, 130);
1655    canvas->save();
1656    canvas->skew(-.5, 0);
1657    canvas->drawString("A1", 0, 0, font, paint);
1658    canvas->restore();
1659    canvas->save();
1660    canvas->skew(0, .5);
1661    paint.setColor(SK_ColorRED);
1662    canvas->drawString("A1", 0, 0, font, paint);
1663    canvas->restore();
1664    canvas->skew(-.5, .5);
1665    paint.setColor(SK_ColorBLUE);
1666    canvas->drawString("A1", 0, 0, font, paint);
1667##
1668
1669#SeeAlso concat() translate() rotate() scale() setMatrix
1670
1671##
1672
1673# ------------------------------------------------------------------------------
1674
1675#Method void concat(const SkMatrix& matrix)
1676
1677#In Matrix
1678#Line # multiplies Matrix by Matrix ##
1679#Populate
1680
1681#Example
1682void draw(SkCanvas* canvas) {
1683    SkPaint paint;
1684    SkFont font(nullptr, 80);
1685    font.setScaleX(.3);
1686    SkMatrix matrix;
1687    SkRect rect[2] = {{ 10, 20, 90, 110 }, { 40, 130, 140, 180 }};
1688    matrix.setRectToRect(rect[0], rect[1], SkMatrix::kFill_ScaleToFit);
1689    canvas->drawRect(rect[0], paint);
1690    canvas->drawRect(rect[1], paint);
1691    paint.setColor(SK_ColorWHITE);
1692    canvas->drawString("Here", rect[0].fLeft + 10, rect[0].fBottom - 10, font, paint);
1693    canvas->concat(matrix);
1694    canvas->drawString("There", rect[0].fLeft + 10, rect[0].fBottom - 10, font, paint);
1695}
1696##
1697
1698#SeeAlso translate() rotate() scale() skew() setMatrix
1699
1700##
1701
1702# ------------------------------------------------------------------------------
1703
1704#Method void setMatrix(const SkMatrix& matrix)
1705
1706#In Matrix
1707#Line # sets Matrix ##
1708#Populate
1709
1710#Example
1711#Height 128
1712void draw(SkCanvas* canvas) {
1713    SkPaint paint;
1714    SkFont font;
1715    canvas->scale(4, 6);
1716    canvas->drawString("truth", 2, 10, font, paint);
1717    SkMatrix matrix;
1718    matrix.setScale(2.8f, 6);
1719    canvas->setMatrix(matrix);
1720    canvas->drawString("consequences", 2, 20, font, paint);
1721}
1722##
1723
1724#SeeAlso resetMatrix concat() translate() rotate() scale() skew()
1725
1726##
1727
1728# ------------------------------------------------------------------------------
1729
1730#Method void resetMatrix()
1731
1732#In Matrix
1733#Line # resets Matrix to identity ##
1734#Populate
1735
1736#Example
1737#Height 128
1738void draw(SkCanvas* canvas) {
1739    SkPaint paint;
1740    SkFont font;
1741    canvas->scale(4, 6);
1742    canvas->drawString("truth", 2, 10, font, paint);
1743    canvas->resetMatrix();
1744    canvas->scale(2.8f, 6);
1745    canvas->drawString("consequences", 2, 20, font, paint);
1746}
1747##
1748
1749#SeeAlso setMatrix concat() translate() rotate() scale() skew()
1750
1751##
1752
1753# ------------------------------------------------------------------------------
1754
1755#Method const SkMatrix& getTotalMatrix() const
1756
1757#In Matrix
1758#Line # returns Matrix ##
1759#Populate
1760
1761#Example
1762    SkDebugf("isIdentity %s\n", canvas->getTotalMatrix().isIdentity() ? "true" : "false");
1763    #StdOut
1764        isIdentity true
1765    ##
1766##
1767
1768#SeeAlso setMatrix resetMatrix concat()
1769
1770##
1771
1772#Subtopic Matrix ##
1773
1774# ------------------------------------------------------------------------------
1775#Subtopic Clip
1776#Line # stack of clipping Paths ##
1777
1778Clip is built from a stack of clipping paths. Each Path in the
1779stack can be constructed from one or more Path_Contour elements. The
1780Path_Contour may be composed of any number of Path_Verb segments. Each
1781Path_Contour forms a closed area; Path_Fill_Type defines the area enclosed
1782by Path_Contour.
1783
1784Clip stack of Path elements successfully restrict the Path area. Each
1785Path is transformed by Matrix, then intersected with or subtracted from the
1786prior Clip to form the replacement Clip. Use SkClipOp::kDifference
1787to subtract Path from Clip; use SkClipOp::kIntersect to intersect Path
1788with Clip.
1789
1790A clipping Path may be Anti_Aliased; if Path, after transformation, is
1791composed of horizontal and vertical lines, clearing Anti_Alias allows whole pixels
1792to either be inside or outside the clip. The fastest drawing has a Aliased,
1793rectangular clip.
1794
1795If clipping Path has Anti_Alias set, clip may partially clip a pixel, requiring
1796that drawing blend partially with the destination along the edge. A rotated
1797rectangular Anti_Aliased clip looks smoother but draws slower.
1798
1799Clip can combine with Rect and Round_Rect primitives; like
1800Path, these are transformed by Matrix before they are combined with Clip.
1801
1802Clip can combine with Region. Region is assumed to be in Device coordinates
1803and is unaffected by Matrix.
1804
1805#Example
1806#Height 90
1807    #Description
1808        Draw a red circle with an Aliased clip and an Anti_Aliased clip.
1809        Use an image filter to zoom into the pixels drawn.
1810        The edge of the Aliased clip fully draws pixels in the red circle.
1811        The edge of the Anti_Aliased clip partially draws pixels in the red circle.
1812    ##
1813    SkPaint redPaint, scalePaint;
1814    redPaint.setAntiAlias(true);
1815    redPaint.setColor(SK_ColorRED);
1816    canvas->save();
1817    for (bool antialias : { false, true } ) {
1818        canvas->save();
1819        canvas->clipRect(SkRect::MakeWH(19.5f, 11.5f), antialias);
1820        canvas->drawCircle(17, 11, 8, redPaint);
1821        canvas->restore();
1822        canvas->translate(16, 0);
1823    }
1824    canvas->restore();
1825    SkMatrix matrix;
1826    matrix.setScale(6, 6);
1827    scalePaint.setImageFilter(
1828            SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr));
1829    SkCanvas::SaveLayerRec saveLayerRec(
1830            nullptr, &scalePaint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1831    canvas->saveLayer(saveLayerRec);
1832    canvas->restore();
1833##
1834
1835#Method void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias)
1836
1837#In Clip
1838#Line # combines Clip with Rect ##
1839#Populate
1840
1841#Example
1842#Height 128
1843void draw(SkCanvas* canvas) {
1844    canvas->rotate(10);
1845    SkPaint paint;
1846    paint.setAntiAlias(true);
1847    for (auto alias: { false, true } ) {
1848        canvas->save();
1849        canvas->clipRect(SkRect::MakeWH(90, 80), SkClipOp::kIntersect, alias);
1850        canvas->drawCircle(100, 60, 60, paint);
1851        canvas->restore();
1852        canvas->translate(80, 0);
1853    }
1854}
1855##
1856
1857#SeeAlso clipRRect clipPath clipRegion
1858
1859##
1860
1861#Method void clipRect(const SkRect& rect, SkClipOp op)
1862
1863#In Clip
1864#Populate
1865
1866#Example
1867#Height 192
1868#Width 280
1869void draw(SkCanvas* canvas) {
1870    SkPaint paint;
1871    for (SkClipOp op: { SkClipOp::kIntersect, SkClipOp::kDifference } ) {
1872        canvas->save();
1873        canvas->clipRect(SkRect::MakeWH(90, 120), op, false);
1874        canvas->drawCircle(100, 100, 60, paint);
1875        canvas->restore();
1876        canvas->translate(80, 0);
1877    }
1878}
1879##
1880
1881#SeeAlso clipRRect clipPath clipRegion
1882
1883##
1884
1885#Method void clipRect(const SkRect& rect, bool doAntiAlias = false)
1886
1887#In Clip
1888#Populate
1889
1890#Example
1891#Height 133
1892    #Description
1893        A circle drawn in pieces looks uniform when drawn Aliased.
1894        The same circle pieces blend with pixels more than once when Anti_Aliased,
1895        visible as a thin pair of lines through the right circle.
1896    ##
1897void draw(SkCanvas* canvas) {
1898    canvas->clear(SK_ColorWHITE);
1899    SkPaint paint;
1900    paint.setAntiAlias(true);
1901    paint.setColor(0x8055aaff);
1902    SkRect clipRect = { 0, 0, 87.4f, 87.4f };
1903    for (auto alias: { false, true } ) {
1904        canvas->save();
1905        canvas->clipRect(clipRect, SkClipOp::kIntersect, alias);
1906        canvas->drawCircle(67, 67, 60, paint);
1907        canvas->restore();
1908        canvas->save();
1909        canvas->clipRect(clipRect, SkClipOp::kDifference, alias);
1910        canvas->drawCircle(67, 67, 60, paint);
1911        canvas->restore();
1912        canvas->translate(120, 0);
1913    }
1914}
1915##
1916
1917#SeeAlso clipRRect clipPath clipRegion
1918
1919##
1920
1921#Method void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias)
1922
1923#In Clip
1924#Line # combines Clip with Round_Rect ##
1925#Populate
1926
1927#Example
1928#Height 128
1929void draw(SkCanvas* canvas) {
1930    canvas->clear(SK_ColorWHITE);
1931    SkPaint paint;
1932    paint.setAntiAlias(true);
1933    paint.setColor(0x8055aaff);
1934    SkRRect oval;
1935    oval.setOval({10, 20, 90, 100});
1936    canvas->clipRRect(oval, SkClipOp::kIntersect, true);
1937    canvas->drawCircle(70, 100, 60, paint);
1938}
1939##
1940
1941#SeeAlso clipRect clipPath clipRegion
1942
1943##
1944
1945#Method void clipRRect(const SkRRect& rrect, SkClipOp op)
1946
1947#In Clip
1948#Populate
1949
1950#Example
1951#Height 128
1952void draw(SkCanvas* canvas) {
1953    SkPaint paint;
1954    paint.setColor(0x8055aaff);
1955    auto oval = SkRRect::MakeOval({10, 20, 90, 100});
1956    canvas->clipRRect(oval, SkClipOp::kIntersect);
1957    canvas->drawCircle(70, 100, 60, paint);
1958}
1959##
1960
1961#SeeAlso clipRect clipPath clipRegion
1962
1963##
1964
1965#Method void clipRRect(const SkRRect& rrect, bool doAntiAlias = false)
1966
1967#In Clip
1968#Populate
1969
1970#Example
1971#Height 128
1972void draw(SkCanvas* canvas) {
1973    SkPaint paint;
1974    paint.setAntiAlias(true);
1975    auto oval = SkRRect::MakeRectXY({10, 20, 90, 100}, 9, 13);
1976    canvas->clipRRect(oval, true);
1977    canvas->drawCircle(70, 100, 60, paint);
1978}
1979##
1980
1981#SeeAlso clipRect clipPath clipRegion
1982
1983##
1984
1985#Method void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias)
1986
1987#In Clip
1988#Line # combines Clip with Path ##
1989#Populate
1990
1991#Example
1992#Description
1993Top figure uses SkPath::kInverseWinding_FillType and SkClipOp::kDifference;
1994area outside clip is subtracted from circle.
1995
1996Bottom figure uses SkPath::kWinding_FillType and SkClipOp::kIntersect;
1997area inside clip is intersected with circle.
1998##
1999void draw(SkCanvas* canvas) {
2000    SkPaint paint;
2001    paint.setAntiAlias(true);
2002    SkPath path;
2003    path.addRect({20, 30, 100, 110});
2004    path.setFillType(SkPath::kInverseWinding_FillType);
2005    canvas->save();
2006    canvas->clipPath(path, SkClipOp::kDifference, false);
2007    canvas->drawCircle(70, 100, 60, paint);
2008    canvas->restore();
2009    canvas->translate(100, 100);
2010    path.setFillType(SkPath::kWinding_FillType);
2011    canvas->clipPath(path, SkClipOp::kIntersect, false);
2012    canvas->drawCircle(70, 100, 60, paint);
2013}
2014##
2015
2016#SeeAlso clipRect clipRRect clipRegion
2017
2018##
2019
2020#Method void clipPath(const SkPath& path, SkClipOp op)
2021
2022#In Clip
2023#Populate
2024
2025#Example
2026#Description
2027Overlapping Rects form a clip. When clip Path_Fill_Type is set to
2028SkPath::kWinding_FillType, the overlap is included. Set to
2029SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole.
2030##
2031void draw(SkCanvas* canvas) {
2032    SkPaint paint;
2033    paint.setAntiAlias(true);
2034    SkPath path;
2035    path.addRect({20, 15, 100, 95});
2036    path.addRect({50, 65, 130, 135});
2037    path.setFillType(SkPath::kWinding_FillType);
2038    canvas->save();
2039    canvas->clipPath(path, SkClipOp::kIntersect);
2040    canvas->drawCircle(70, 85, 60, paint);
2041    canvas->restore();
2042    canvas->translate(100, 100);
2043    path.setFillType(SkPath::kEvenOdd_FillType);
2044    canvas->clipPath(path, SkClipOp::kIntersect);
2045    canvas->drawCircle(70, 85, 60, paint);
2046}
2047##
2048
2049#SeeAlso clipRect clipRRect clipRegion
2050
2051##
2052
2053#Method void clipPath(const SkPath& path, bool doAntiAlias = false)
2054
2055#In Clip
2056#Populate
2057
2058#Example
2059#Height 212
2060#Description
2061Clip loops over itself covering its center twice. When clip Path_Fill_Type
2062is set to SkPath::kWinding_FillType, the overlap is included. Set to
2063SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole.
2064##
2065void draw(SkCanvas* canvas) {
2066    SkPaint paint;
2067    paint.setAntiAlias(true);
2068    SkPath path;
2069    SkPoint poly[] = {{20, 20}, { 80, 20}, { 80,  80}, {40,  80},
2070                      {40, 40}, {100, 40}, {100, 100}, {20, 100}};
2071    path.addPoly(poly, SK_ARRAY_COUNT(poly), true);
2072    path.setFillType(SkPath::kWinding_FillType);
2073    canvas->save();
2074    canvas->clipPath(path, SkClipOp::kIntersect);
2075    canvas->drawCircle(50, 50, 45, paint);
2076    canvas->restore();
2077    canvas->translate(100, 100);
2078    path.setFillType(SkPath::kEvenOdd_FillType);
2079    canvas->clipPath(path, SkClipOp::kIntersect);
2080    canvas->drawCircle(50, 50, 45, paint);
2081}
2082##
2083
2084#SeeAlso clipRect clipRRect clipRegion
2085
2086##
2087
2088# ------------------------------------------------------------------------------
2089
2090#Method void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect)
2091
2092#In Clip
2093#Line # combines Clip with Region ##
2094#Populate
2095
2096#Example
2097#Description
2098    region is unaffected by canvas rotation; iRect is affected by canvas rotation.
2099    Both clips are Aliased; this is not noticeable on Region clip because it
2100    aligns to pixel boundaries.
2101##
2102void draw(SkCanvas* canvas) {
2103    SkPaint paint;
2104    paint.setAntiAlias(true);
2105    SkIRect iRect = {30, 40, 120, 130 };
2106    SkRegion region(iRect);
2107    canvas->rotate(10);
2108    canvas->save();
2109    canvas->clipRegion(region, SkClipOp::kIntersect);
2110    canvas->drawCircle(50, 50, 45, paint);
2111    canvas->restore();
2112    canvas->translate(100, 100);
2113    canvas->clipRect(SkRect::Make(iRect), SkClipOp::kIntersect);
2114    canvas->drawCircle(50, 50, 45, paint);
2115}
2116##
2117
2118#SeeAlso clipRect clipRRect clipPath
2119
2120##
2121
2122#Method bool quickReject(const SkRect& rect) const
2123
2124#In Clip
2125#Line # returns if Rect is outside Clip ##
2126#Populate
2127
2128#Example
2129void draw(SkCanvas* canvas) {
2130    SkRect testRect = {30, 30, 120, 129 };
2131    SkRect clipRect = {30, 130, 120, 230 };
2132    canvas->save();
2133    canvas->clipRect(clipRect);
2134    SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false");
2135    canvas->restore();
2136    canvas->rotate(10);
2137    canvas->clipRect(clipRect);
2138    SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false");
2139}
2140    #StdOut
2141        quickReject true
2142        quickReject false
2143    ##
2144##
2145
2146#SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing
2147
2148##
2149
2150#Method bool quickReject(const SkPath& path) const
2151
2152#In Clip
2153#Populate
2154
2155#Example
2156void draw(SkCanvas* canvas) {
2157    SkPoint testPoints[] = {{30,  30}, {120,  30}, {120, 129} };
2158    SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} };
2159    SkPath testPath, clipPath;
2160    testPath.addPoly(testPoints, SK_ARRAY_COUNT(testPoints), true);
2161    clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
2162    canvas->save();
2163    canvas->clipPath(clipPath);
2164    SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false");
2165    canvas->restore();
2166    canvas->rotate(10);
2167    canvas->clipPath(clipPath);
2168    SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false");
2169    #StdOut
2170        quickReject true
2171        quickReject false
2172    ##
2173}
2174##
2175
2176#SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing
2177
2178##
2179
2180#Method SkRect getLocalClipBounds() const
2181
2182#In Clip
2183#Line # returns Clip bounds in source coordinates ##
2184#Populate
2185
2186#Example
2187    #Description
2188        Initial bounds is device bounds outset by 1 on all sides.
2189        Clipped bounds is clipPath bounds outset by 1 on all sides.
2190        Scaling the canvas by two on both axes scales the local bounds by 1/2
2191        on both axes.
2192    ##
2193    SkCanvas local(256, 256);
2194    canvas = &local;
2195    SkRect bounds = canvas->getLocalClipBounds();
2196    SkDebugf("left:%g  top:%g  right:%g  bottom:%g\n",
2197            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2198    SkPoint clipPoints[]  = {{30, 130}, {120, 130}, {120, 230} };
2199    SkPath clipPath;
2200    clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
2201    canvas->clipPath(clipPath);
2202    bounds = canvas->getLocalClipBounds();
2203    SkDebugf("left:%g  top:%g  right:%g  bottom:%g\n",
2204            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2205    canvas->scale(2, 2);
2206    bounds = canvas->getLocalClipBounds();
2207    SkDebugf("left:%g  top:%g  right:%g  bottom:%g\n",
2208            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2209    #StdOut
2210        left:-1  top:-1  right:257  bottom:257
2211        left:29  top:129  right:121  bottom:231
2212        left:14.5  top:64.5  right:60.5  bottom:115.5
2213    ##
2214##
2215
2216# local canvas in example works around bug in fiddle ##
2217#Bug 6524
2218#SeeAlso getDeviceClipBounds getBaseLayerSize quickReject
2219
2220##
2221
2222#Method bool getLocalClipBounds(SkRect* bounds) const
2223
2224#In Clip
2225#Populate
2226
2227#Example
2228    void draw(SkCanvas* canvas) {
2229        SkCanvas local(256, 256);
2230        canvas = &local;
2231        SkRect bounds;
2232        SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds)
2233                 ? "false" : "true");
2234        SkPath path;
2235        canvas->clipPath(path);
2236        SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds)
2237                 ? "false" : "true");
2238    }
2239    #StdOut
2240        local bounds empty = false
2241        local bounds empty = true
2242    ##
2243##
2244
2245# local canvas in example works around bug in fiddle ##
2246#Bug 6524
2247#SeeAlso getDeviceClipBounds getBaseLayerSize quickReject
2248
2249##
2250
2251#Method SkIRect getDeviceClipBounds() const
2252
2253#In Clip
2254#Line # returns IRect bounds of Clip ##
2255#Populate
2256
2257#Example
2258void draw(SkCanvas* canvas) {
2259    #Description
2260        Initial bounds is device bounds, not outset.
2261        Clipped bounds is clipPath bounds, not outset.
2262        Scaling the canvas by 1/2 on both axes scales the device bounds by 1/2
2263        on both axes.
2264    ##
2265    SkCanvas device(256, 256);
2266    canvas = &device;
2267    SkIRect bounds = canvas->getDeviceClipBounds();
2268    SkDebugf("left:%d  top:%d  right:%d  bottom:%d\n",
2269            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2270    SkPoint clipPoints[]  = {{30, 130}, {120, 130}, {120, 230} };
2271    SkPath clipPath;
2272    clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
2273    canvas->save();
2274    canvas->clipPath(clipPath);
2275    bounds = canvas->getDeviceClipBounds();
2276    SkDebugf("left:%d  top:%d  right:%d  bottom:%d\n",
2277            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2278    canvas->restore();
2279    canvas->scale(1.f/2, 1.f/2);
2280    canvas->clipPath(clipPath);
2281    bounds = canvas->getDeviceClipBounds();
2282    SkDebugf("left:%d  top:%d  right:%d  bottom:%d\n",
2283            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2284    #StdOut
2285        left:0  top:0  right:256  bottom:256
2286        left:30  top:130  right:120  bottom:230
2287        left:15  top:65  right:60  bottom:115
2288    ##
2289}
2290##
2291
2292#ToDo some confusion on why with an identity Matrix local and device are different ##
2293#SeeAlso getLocalClipBounds getBaseLayerSize quickReject
2294
2295# device canvas in example works around bug in fiddle ##
2296#Bug 6524
2297
2298##
2299
2300#Method bool getDeviceClipBounds(SkIRect* bounds) const
2301
2302#In Clip
2303#Populate
2304
2305#Example
2306    void draw(SkCanvas* canvas) {
2307        SkIRect bounds;
2308        SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds)
2309                 ? "false" : "true");
2310        SkPath path;
2311        canvas->clipPath(path);
2312        SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds)
2313                 ? "false" : "true");
2314    }
2315    #StdOut
2316        device bounds empty = false
2317        device bounds empty = true
2318    ##
2319##
2320
2321#SeeAlso getLocalClipBounds getBaseLayerSize quickReject
2322
2323##
2324
2325#Subtopic Clip ##
2326
2327# ------------------------------------------------------------------------------
2328#Subtopic Draw
2329#Line # draws into Canvas ##
2330##
2331
2332#Method void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver)
2333#In Draw
2334#Line # fills Clip with Color and Blend_Mode ##
2335#Populate
2336
2337#Example
2338    canvas->drawColor(SK_ColorRED);
2339    canvas->clipRect(SkRect::MakeWH(150, 150));
2340    canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00), SkBlendMode::kPlus);
2341    canvas->clipRect(SkRect::MakeWH(75, 75));
2342    canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF), SkBlendMode::kPlus);
2343##
2344
2345#SeeAlso clear SkBitmap::erase drawPaint
2346
2347##
2348
2349# ------------------------------------------------------------------------------
2350
2351#Method void clear(SkColor color)
2352#In Draw
2353#Line # fills Clip with Color ##
2354#Populate
2355
2356#Example
2357void draw(SkCanvas* canvas) {
2358    canvas->save();
2359    canvas->clipRect(SkRect::MakeWH(256, 128));
2360    canvas->clear(SkColorSetARGB(0x80, 0xFF, 0x00, 0x00));
2361    canvas->restore();
2362    canvas->save();
2363    canvas->clipRect(SkRect::MakeWH(150, 192));
2364    canvas->clear(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00));
2365    canvas->restore();
2366    canvas->clipRect(SkRect::MakeWH(75, 256));
2367    canvas->clear(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF));
2368}
2369##
2370
2371#SeeAlso drawColor SkBitmap::erase drawPaint
2372
2373##
2374
2375# ------------------------------------------------------------------------------
2376
2377#Method void discard()
2378#In Utility
2379#Line # makes Canvas contents undefined ##
2380#Populate
2381
2382#NoExample
2383##
2384
2385#SeeAlso flush() GrContext::abandonContext
2386
2387##
2388
2389# ------------------------------------------------------------------------------
2390
2391#Method void drawPaint(const SkPaint& paint)
2392#In Draw
2393#Line # fills Clip with Paint ##
2394#Populate
2395
2396#Example
2397void draw(SkCanvas* canvas) {
2398    SkColor     colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
2399    SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
2400    SkPaint     paint;
2401    paint.setShader(SkGradientShader::MakeSweep(256, 256, colors, pos, SK_ARRAY_COUNT(colors)));
2402    canvas->drawPaint(paint);
2403}
2404##
2405
2406#SeeAlso clear drawColor SkBitmap::erase
2407
2408##
2409
2410# ------------------------------------------------------------------------------
2411
2412#Enum PointMode
2413#Line # sets drawPoints options ##
2414
2415#Code
2416#Populate
2417##
2418
2419Selects if an array of points are drawn as discrete points, as lines, or as
2420an open polygon.
2421
2422#Const kPoints_PointMode 0
2423#Line # draw each point separately ##
2424##
2425
2426#Const kLines_PointMode 1
2427#Line # draw each pair of points as a line segment ##
2428##
2429
2430#Const kPolygon_PointMode 2
2431#Line # draw the array of points as a open polygon ##
2432##
2433
2434#Example
2435    #Description
2436        The upper left corner shows three squares when drawn as points.
2437        The upper right corner shows one line; when drawn as lines, two points are required per line.
2438        The lower right corner shows two lines; when draw as polygon, no miter is drawn at the corner.
2439        The lower left corner shows two lines with a miter when path contains polygon.
2440    ##
2441void draw(SkCanvas* canvas) {
2442  SkPaint paint;
2443  paint.setStyle(SkPaint::kStroke_Style);
2444  paint.setStrokeWidth(10);
2445  SkPoint points[] = {{64, 32}, {96, 96}, {32, 96}};
2446  canvas->drawPoints(SkCanvas::kPoints_PointMode, 3, points, paint);
2447  canvas->translate(128, 0);
2448  canvas->drawPoints(SkCanvas::kLines_PointMode, 3, points, paint);
2449  canvas->translate(0, 128);
2450  canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, points, paint);
2451  SkPath path;
2452  path.addPoly(points, 3, false);
2453  canvas->translate(-128, 0);
2454  canvas->drawPath(path, paint);
2455}
2456##
2457
2458#SeeAlso drawLine drawPoint drawPath
2459
2460##
2461
2462# ------------------------------------------------------------------------------
2463
2464#Method void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint)
2465#In Draw
2466#Line # draws array as points, lines, polygon ##
2467#Populate
2468
2469#Example
2470#Height 200
2471    #Description
2472    #List
2473    # The first column draws points. ##
2474    # The second column draws points as lines. ##
2475    # The third column draws points as a polygon. ##
2476    # The fourth column draws points as a polygonal path. ##
2477    # The first row uses a round cap and round join. ##
2478    # The second row uses a square cap and a miter join. ##
2479    # The third row uses a butt cap and a bevel join. ##
2480    ##
2481    The transparent color makes multiple line draws visible;
2482    the path is drawn all at once.
2483    ##
2484void draw(SkCanvas* canvas) {
2485    SkPaint paint;
2486    paint.setAntiAlias(true);
2487    paint.setStyle(SkPaint::kStroke_Style);
2488    paint.setStrokeWidth(10);
2489    paint.setColor(0x80349a45);
2490    const SkPoint points[] = {{32, 16}, {48, 48}, {16, 32}};
2491    const SkPaint::Join join[] = { SkPaint::kRound_Join,
2492                                   SkPaint::kMiter_Join,
2493                                   SkPaint::kBevel_Join };
2494    int joinIndex = 0;
2495    SkPath path;
2496    path.addPoly(points, 3, false);
2497    for (const auto cap : { SkPaint::kRound_Cap, SkPaint::kSquare_Cap, SkPaint::kButt_Cap } ) {
2498        paint.setStrokeCap(cap);
2499        paint.setStrokeJoin(join[joinIndex++]);
2500        for (const auto mode : { SkCanvas::kPoints_PointMode,
2501                                 SkCanvas::kLines_PointMode,
2502                                 SkCanvas::kPolygon_PointMode } ) {
2503            canvas->drawPoints(mode, 3, points, paint);
2504            canvas->translate(64, 0);
2505        }
2506        canvas->drawPath(path, paint);
2507        canvas->translate(-192, 64);
2508    }
2509}
2510##
2511
2512#SeeAlso drawLine drawPoint drawPath
2513
2514##
2515
2516# ------------------------------------------------------------------------------
2517
2518#Method void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint)
2519#In Draw
2520#Line # draws point at (x, y) position ##
2521#Populate
2522
2523#Example
2524void draw(SkCanvas* canvas) {
2525  SkPaint paint;
2526  paint.setAntiAlias(true);
2527  paint.setColor(0x80349a45);
2528  paint.setStyle(SkPaint::kStroke_Style);
2529  paint.setStrokeWidth(100);
2530  paint.setStrokeCap(SkPaint::kRound_Cap);
2531  canvas->scale(1, 1.2f);
2532  canvas->drawPoint(64, 96, paint);
2533  canvas->scale(.6f, .8f);
2534  paint.setColor(SK_ColorWHITE);
2535  canvas->drawPoint(106, 120, paint);
2536}
2537##
2538
2539#SeeAlso drawPoints drawCircle drawRect drawLine drawPath
2540
2541##
2542
2543#Method void drawPoint(SkPoint p, const SkPaint& paint)
2544#Populate
2545
2546#Example
2547void draw(SkCanvas* canvas) {
2548  SkPaint paint;
2549  paint.setAntiAlias(true);
2550  paint.setColor(0x80349a45);
2551  paint.setStyle(SkPaint::kStroke_Style);
2552  paint.setStrokeWidth(100);
2553  paint.setStrokeCap(SkPaint::kSquare_Cap);
2554  canvas->scale(1, 1.2f);
2555  canvas->drawPoint({64, 96}, paint);
2556  canvas->scale(.6f, .8f);
2557  paint.setColor(SK_ColorWHITE);
2558  canvas->drawPoint(106, 120, paint);
2559}
2560##
2561
2562#SeeAlso drawPoints drawCircle drawRect drawLine drawPath
2563
2564##
2565
2566# ------------------------------------------------------------------------------
2567
2568#Method void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint)
2569#In Draw
2570#Line # draws line segment between two points ##
2571#Populate
2572
2573#Example
2574  SkPaint paint;
2575  paint.setAntiAlias(true);
2576  paint.setColor(0xFF9a67be);
2577  paint.setStrokeWidth(20);
2578  canvas->skew(1, 0);
2579  canvas->drawLine(32, 96, 32, 160, paint);
2580  canvas->skew(-2, 0);
2581  canvas->drawLine(288, 96, 288, 160, paint);
2582##
2583
2584#SeeAlso drawPoint drawCircle drawRect drawPath
2585
2586##
2587
2588#Method void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint)
2589#Populate
2590
2591#Example
2592  SkPaint paint;
2593  paint.setAntiAlias(true);
2594  paint.setColor(0xFF9a67be);
2595  paint.setStrokeWidth(20);
2596  canvas->skew(1, 0);
2597  canvas->drawLine({32, 96}, {32, 160}, paint);
2598  canvas->skew(-2, 0);
2599  canvas->drawLine({288, 96}, {288, 160}, paint);
2600##
2601
2602#SeeAlso drawPoint drawCircle drawRect drawPath
2603
2604##
2605
2606# ------------------------------------------------------------------------------
2607
2608#Method void drawRect(const SkRect& rect, const SkPaint& paint)
2609#In Draw
2610#Line # draws Rect using Clip, Matrix, and Paint ##
2611#Populate
2612
2613#Example
2614void draw(SkCanvas* canvas) {
2615    SkPoint rectPts[] = { {64, 48}, {192, 160} };
2616    SkPaint paint;
2617    paint.setAntiAlias(true);
2618    paint.setStyle(SkPaint::kStroke_Style);
2619    paint.setStrokeWidth(20);
2620    paint.setStrokeJoin(SkPaint::kRound_Join);
2621    SkMatrix rotator;
2622    rotator.setRotate(30, 128, 128);
2623    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) {
2624        paint.setColor(color);
2625        SkRect rect;
2626        rect.set(rectPts[0], rectPts[1]);
2627        canvas->drawRect(rect, paint);
2628        rotator.mapPoints(rectPts, 2);
2629    }
2630}
2631##
2632
2633#SeeAlso drawIRect drawRRect drawRoundRect drawRegion drawPath drawLine
2634
2635##
2636
2637# ------------------------------------------------------------------------------
2638
2639#Method void drawIRect(const SkIRect& rect, const SkPaint& paint)
2640#In Draw
2641#Line # draws IRect using Clip, Matrix, and Paint ##
2642#Populate
2643
2644#Example
2645    SkIRect rect = { 64, 48, 192, 160 };
2646    SkPaint paint;
2647    paint.setAntiAlias(true);
2648    paint.setStyle(SkPaint::kStroke_Style);
2649    paint.setStrokeWidth(20);
2650    paint.setStrokeJoin(SkPaint::kRound_Join);
2651    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) {
2652        paint.setColor(color);
2653        canvas->drawIRect(rect, paint);
2654        canvas->rotate(30, 128, 128);
2655    }
2656##
2657
2658#SeeAlso drawRect drawRRect drawRoundRect drawRegion drawPath drawLine
2659
2660##
2661
2662# ------------------------------------------------------------------------------
2663
2664#Method void drawRegion(const SkRegion& region, const SkPaint& paint)
2665#In Draw
2666#Line # draws Region using Clip, Matrix, and Paint ##
2667#Populate
2668
2669#Example
2670void draw(SkCanvas* canvas) {
2671    SkRegion region;
2672    region.op( 10, 10, 50, 50, SkRegion::kUnion_Op);
2673    region.op( 10, 50, 90, 90, SkRegion::kUnion_Op);
2674    SkPaint paint;
2675    paint.setAntiAlias(true);
2676    paint.setStyle(SkPaint::kStroke_Style);
2677    paint.setStrokeWidth(20);
2678    paint.setStrokeJoin(SkPaint::kRound_Join);
2679    canvas->drawRegion(region, paint);
2680}
2681##
2682
2683#SeeAlso drawRect drawIRect drawPath
2684
2685##
2686
2687# ------------------------------------------------------------------------------
2688
2689#Method void drawOval(const SkRect& oval, const SkPaint& paint)
2690#In Draw
2691#Line # draws Oval using Clip, Matrix, and Paint ##
2692#Populate
2693
2694#Example
2695void draw(SkCanvas* canvas) {
2696    canvas->clear(0xFF3f5f9f);
2697    SkColor  kColor1 = SkColorSetARGB(0xff, 0xff, 0x7f, 0);
2698    SkColor  g1Colors[] = { kColor1, SkColorSetA(kColor1, 0x20) };
2699    SkPoint  g1Points[] = { { 0, 0 }, { 0, 100 } };
2700    SkScalar pos[] = { 0.2f, 1.0f };
2701    SkRect bounds = SkRect::MakeWH(80, 70);
2702    SkPaint paint;
2703    paint.setAntiAlias(true);
2704    paint.setShader(SkGradientShader::MakeLinear(g1Points, g1Colors, pos, SK_ARRAY_COUNT(g1Colors),
2705            SkShader::kClamp_TileMode));
2706    canvas->drawOval(bounds , paint);
2707}
2708##
2709
2710#SeeAlso drawCircle drawPoint drawPath drawRRect drawRoundRect
2711
2712##
2713
2714# ------------------------------------------------------------------------------
2715
2716#Method void drawRRect(const SkRRect& rrect, const SkPaint& paint)
2717#In Draw
2718#Line # draws Round_Rect using Clip, Matrix, and Paint ##
2719#Populate
2720
2721#Example
2722void draw(SkCanvas* canvas) {
2723    SkPaint paint;
2724    paint.setAntiAlias(true);
2725    SkRect outer = {30, 40, 210, 220};
2726    SkRect radii = {30, 50, 70, 90 };
2727    SkRRect rRect;
2728    rRect.setNinePatch(outer, radii.fLeft, radii.fTop, radii.fRight, radii.fBottom);
2729    canvas->drawRRect(rRect, paint);
2730    paint.setColor(SK_ColorWHITE);
2731    canvas->drawLine(outer.fLeft + radii.fLeft, outer.fTop,
2732                     outer.fLeft + radii.fLeft, outer.fBottom, paint);
2733    canvas->drawLine(outer.fRight - radii.fRight, outer.fTop,
2734                     outer.fRight - radii.fRight, outer.fBottom, paint);
2735    canvas->drawLine(outer.fLeft,  outer.fTop + radii.fTop,
2736                     outer.fRight, outer.fTop + radii.fTop, paint);
2737    canvas->drawLine(outer.fLeft,  outer.fBottom - radii.fBottom,
2738                     outer.fRight, outer.fBottom - radii.fBottom, paint);
2739}
2740##
2741
2742#SeeAlso drawRect drawRoundRect drawDRRect drawCircle drawOval drawPath
2743
2744##
2745
2746# ------------------------------------------------------------------------------
2747
2748#Method void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint)
2749#In Draw
2750#Line # draws double Round_Rect stroked or filled ##
2751#Populate
2752
2753#Example
2754void draw(SkCanvas* canvas) {
2755   SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200});
2756   SkRRect inner = SkRRect::MakeOval({60, 70, 170, 160});
2757   SkPaint paint;
2758   canvas->drawDRRect(outer, inner, paint);
2759}
2760##
2761
2762#Example
2763#Description
2764    Outer Rect has no corner radii, but stroke join is rounded.
2765    Inner Round_Rect has corner radii; outset stroke increases radii of corners.
2766    Stroke join does not affect inner Round_Rect since it has no sharp corners.
2767##
2768void draw(SkCanvas* canvas) {
2769   SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200});
2770   SkRRect inner = SkRRect::MakeRectXY({60, 70, 170, 160}, 10, 10);
2771   SkPaint paint;
2772   paint.setAntiAlias(true);
2773   paint.setStyle(SkPaint::kStroke_Style);
2774   paint.setStrokeWidth(20);
2775   paint.setStrokeJoin(SkPaint::kRound_Join);
2776   canvas->drawDRRect(outer, inner, paint);
2777   paint.setStrokeWidth(1);
2778   paint.setColor(SK_ColorWHITE);
2779   canvas->drawDRRect(outer, inner, paint);
2780}
2781##
2782
2783#SeeAlso drawRect drawRoundRect drawRRect drawCircle drawOval drawPath
2784
2785##
2786
2787# ------------------------------------------------------------------------------
2788
2789#Method void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint)
2790#In Draw
2791#Line # draws Circle using Clip, Matrix, and Paint ##
2792#Populate
2793
2794#Example
2795    void draw(SkCanvas* canvas) {
2796        SkPaint paint;
2797        paint.setAntiAlias(true);
2798        canvas->drawCircle(128, 128, 90, paint);
2799        paint.setColor(SK_ColorWHITE);
2800        canvas->drawCircle(86, 86, 20, paint);
2801        canvas->drawCircle(160, 76, 20, paint);
2802        canvas->drawCircle(140, 150, 35, paint);
2803    }
2804##
2805
2806#SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine
2807
2808##
2809
2810#Method void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint)
2811#Populate
2812
2813#Example
2814    void draw(SkCanvas* canvas) {
2815        SkPaint paint;
2816        paint.setAntiAlias(true);
2817        canvas->drawCircle(128, 128, 90, paint);
2818        paint.setColor(SK_ColorWHITE);
2819        canvas->drawCircle({86, 86}, 20, paint);
2820        canvas->drawCircle({160, 76}, 20, paint);
2821        canvas->drawCircle({140, 150}, 35, paint);
2822    }
2823##
2824
2825#SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine
2826
2827##
2828
2829# ------------------------------------------------------------------------------
2830
2831#Method void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
2832                 bool useCenter, const SkPaint& paint)
2833#In Draw
2834#Line # draws Arc using Clip, Matrix, and Paint ##
2835#Populate
2836
2837#Example
2838    void draw(SkCanvas* canvas) {
2839        SkPaint paint;
2840        paint.setAntiAlias(true);
2841        SkRect oval = { 4, 4, 60, 60};
2842        for (auto useCenter : { false, true } ) {
2843            for (auto style : { SkPaint::kFill_Style, SkPaint::kStroke_Style } ) {
2844                paint.setStyle(style);
2845                for (auto degrees : { 45, 90, 180, 360} ) {
2846                    canvas->drawArc(oval, 0, degrees , useCenter, paint);
2847                    canvas->translate(64, 0);
2848                }
2849                canvas->translate(-256, 64);
2850            }
2851        }
2852    }
2853##
2854
2855#Example
2856#Height 64
2857    void draw(SkCanvas* canvas) {
2858        SkPaint paint;
2859        paint.setAntiAlias(true);
2860        paint.setStyle(SkPaint::kStroke_Style);
2861        paint.setStrokeWidth(4);
2862        SkRect oval = { 4, 4, 60, 60};
2863        float intervals[] = { 5, 5 };
2864        paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f));
2865        for (auto degrees : { 270, 360, 540, 720 } ) {
2866            canvas->drawArc(oval, 0, degrees, false, paint);
2867            canvas->translate(64, 0);
2868        }
2869    }
2870##
2871
2872#SeeAlso SkPath::arcTo drawCircle drawOval drawPath
2873
2874##
2875
2876# ------------------------------------------------------------------------------
2877
2878#Method void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint)
2879#In Draw
2880#Line # draws Round_Rect using Clip, Matrix, and Paint ##
2881#Populate
2882
2883#Example
2884#Description
2885    Top row has a zero radius a generates a rectangle.
2886    Second row radii sum to less than sides.
2887    Third row radii sum equals sides.
2888    Fourth row radii sum exceeds sides; radii are scaled to fit.
2889##
2890    void draw(SkCanvas* canvas) {
2891        SkVector radii[] = { {0, 20}, {10, 10}, {10, 20}, {10, 40} };
2892        SkPaint paint;
2893        paint.setStrokeWidth(15);
2894        paint.setStrokeJoin(SkPaint::kRound_Join);
2895        paint.setAntiAlias(true);
2896        for (auto style : { SkPaint::kStroke_Style, SkPaint::kFill_Style  } ) {
2897            paint.setStyle(style );
2898            for (size_t i = 0; i < SK_ARRAY_COUNT(radii); ++i) {
2899               canvas->drawRoundRect({10, 10, 60, 40}, radii[i].fX, radii[i].fY, paint);
2900               canvas->translate(0, 60);
2901            }
2902            canvas->translate(80, -240);
2903        }
2904    }
2905##
2906
2907#SeeAlso drawRRect drawRect drawDRRect drawPath drawCircle drawOval drawPoint
2908
2909##
2910
2911# ------------------------------------------------------------------------------
2912
2913#Method void drawPath(const SkPath& path, const SkPaint& paint)
2914#In Draw
2915#Line # draws Path using Clip, Matrix, and Paint ##
2916#Populate
2917
2918#Example
2919#Description
2920    Top rows draw stroked path with combinations of joins and caps. The open contour
2921    is affected by caps; the closed contour is affected by joins.
2922    Bottom row draws fill the same for open and closed contour.
2923    First bottom column shows winding fills overlap.
2924    Second bottom column shows even odd fills exclude overlap.
2925    Third bottom column shows inverse winding fills area outside both contours.
2926##
2927void draw(SkCanvas* canvas) {
2928    SkPath path;
2929    path.moveTo(20, 20);
2930    path.quadTo(60, 20, 60, 60);
2931    path.close();
2932    path.moveTo(60, 20);
2933    path.quadTo(60, 60, 20, 60);
2934    SkPaint paint;
2935    paint.setStrokeWidth(10);
2936    paint.setAntiAlias(true);
2937    paint.setStyle(SkPaint::kStroke_Style);
2938    for (auto join: { SkPaint::kBevel_Join, SkPaint::kRound_Join, SkPaint::kMiter_Join } ) {
2939        paint.setStrokeJoin(join);
2940        for (auto cap: { SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap  } ) {
2941            paint.setStrokeCap(cap);
2942            canvas->drawPath(path, paint);
2943            canvas->translate(80, 0);
2944        }
2945        canvas->translate(-240, 60);
2946    }
2947    paint.setStyle(SkPaint::kFill_Style);
2948    for (auto fill : { SkPath::kWinding_FillType,
2949                       SkPath::kEvenOdd_FillType,
2950                       SkPath::kInverseWinding_FillType } ) {
2951        path.setFillType(fill);
2952        canvas->save();
2953        canvas->clipRect({0, 10, 80, 70});
2954        canvas->drawPath(path, paint);
2955        canvas->restore();
2956        canvas->translate(80, 0);
2957    }
2958}
2959##
2960
2961#SeeAlso SkPath drawLine drawArc drawRect drawPoints
2962
2963##
2964
2965# ------------------------------------------------------------------------------
2966#Subtopic Draw_Image
2967#Line # draws Image to Canvas ##
2968
2969drawImage, drawImageRect, and drawImageNine can be called with a bare pointer or
2970a smart pointer as a convenience. The pairs of calls are otherwise identical.
2971
2972#Method void drawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint = nullptr)
2973#In Draw_Image
2974#In Draw
2975#Line # draws Image at (x, y) position ##
2976#Populate
2977
2978#Example
2979#Height 64
2980#Image 4
2981void draw(SkCanvas* canvas) {
2982   // sk_sp<SkImage> image;
2983   SkImage* imagePtr = image.get();
2984   canvas->drawImage(imagePtr, 0, 0);
2985   SkPaint paint;
2986   canvas->drawImage(imagePtr, 80, 0, &paint);
2987   paint.setAlpha(0x80);
2988   canvas->drawImage(imagePtr, 160, 0, &paint);
2989}
2990##
2991
2992#SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter
2993
2994##
2995
2996# ------------------------------------------------------------------------------
2997
2998#Method void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top,
2999                   const SkPaint* paint = nullptr)
3000#Populate
3001
3002#Example
3003#Height 64
3004#Image 4
3005void draw(SkCanvas* canvas) {
3006   // sk_sp<SkImage> image;
3007   canvas->drawImage(image, 0, 0);
3008   SkPaint paint;
3009   canvas->drawImage(image, 80, 0, &paint);
3010   paint.setAlpha(0x80);
3011   canvas->drawImage(image, 160, 0, &paint);
3012}
3013##
3014
3015#SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter
3016
3017##
3018
3019# ------------------------------------------------------------------------------
3020
3021#Enum SrcRectConstraint
3022#Line # sets drawImageRect options ##
3023
3024#Code
3025#Populate
3026##
3027
3028SrcRectConstraint controls the behavior at the edge of source Rect,
3029provided to drawImageRect, trading off speed for precision.
3030
3031Image_Filter in Paint may sample multiple pixels in the image. Source Rect
3032restricts the bounds of pixels that may be read. Image_Filter may slow down if
3033it cannot read outside the bounds, when sampling near the edge of source Rect.
3034SrcRectConstraint specifies whether an Image_Filter is allowed to read pixels
3035outside source Rect.
3036
3037#Const kStrict_SrcRectConstraint 0
3038#Line # sample only inside bounds; slower ##
3039    Requires Image_Filter to respect source Rect,
3040    sampling only inside of its bounds, possibly with a performance penalty.
3041##
3042
3043#Const kFast_SrcRectConstraint 1
3044#Line # sample outside bounds; faster ##
3045    Permits Image_Filter to sample outside of source Rect
3046    by half the width of Image_Filter, permitting it to run faster but with
3047    error at the image edges.
3048##
3049
3050#Example
3051#Height 64
3052#Description
3053    redBorder contains a black and white checkerboard bordered by red.
3054    redBorder is drawn scaled by 16 on the left.
3055    The middle and right bitmaps are filtered checkerboards.
3056    Drawing the checkerboard with kStrict_SrcRectConstraint shows only a blur of black and white.
3057    Drawing the checkerboard with kFast_SrcRectConstraint allows red to bleed in the corners.
3058##
3059void draw(SkCanvas* canvas) {
3060    SkBitmap redBorder;
3061    redBorder.allocPixels(SkImageInfo::MakeN32Premul(4, 4));
3062    SkCanvas checkRed(redBorder);
3063    checkRed.clear(SK_ColorRED);
3064    uint32_t checkers[][2] = { { SK_ColorBLACK, SK_ColorWHITE },
3065                               { SK_ColorWHITE, SK_ColorBLACK } };
3066    checkRed.writePixels(
3067            SkImageInfo::MakeN32Premul(2, 2), (void*) checkers, sizeof(checkers[0]), 1, 1);
3068    canvas->scale(16, 16);
3069    canvas->drawBitmap(redBorder, 0, 0, nullptr);
3070    canvas->resetMatrix();
3071    sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder);
3072    SkPaint lowPaint;
3073    lowPaint.setFilterQuality(kLow_SkFilterQuality);
3074    for (auto constraint : { SkCanvas::kStrict_SrcRectConstraint,
3075                             SkCanvas::kFast_SrcRectConstraint } ) {
3076        canvas->translate(80, 0);
3077        canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3),
3078                SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint);
3079    }
3080}
3081##
3082
3083#SeeAlso drawImageRect drawImage SkPaint::setImageFilter
3084
3085##
3086
3087# ------------------------------------------------------------------------------
3088
3089#Method void drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
3090                       const SkPaint* paint,
3091                       SrcRectConstraint constraint = kStrict_SrcRectConstraint)
3092#In Draw_Image
3093#In Draw
3094#Line # draws Image, source Rect to destination Rect ##
3095#Populate
3096
3097#Example
3098#Height 64
3099#Description
3100    The left bitmap draws with Paint default kNone_SkFilterQuality, and stays within
3101    its bounds; there is no bleeding with kFast_SrcRectConstraint.
3102    the middle and right bitmaps draw with kLow_SkFilterQuality; with
3103    kStrict_SrcRectConstraint, the filter remains within the checkerboard, and
3104    with kFast_SrcRectConstraint red bleeds on the edges.
3105##
3106void draw(SkCanvas* canvas) {
3107    uint32_t pixels[][4] = {
3108            { 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 },
3109            { 0xFFFF0000, 0xFF000000, 0xFFFFFFFF, 0xFFFF0000 },
3110            { 0xFFFF0000, 0xFFFFFFFF, 0xFF000000, 0xFFFF0000 },
3111            { 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 } };
3112    SkBitmap redBorder;
3113    redBorder.installPixels(SkImageInfo::MakeN32Premul(4, 4),
3114            (void*) pixels, sizeof(pixels[0]));
3115    sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder);
3116    SkPaint lowPaint;
3117    for (auto constraint : {
3118            SkCanvas::kFast_SrcRectConstraint,
3119            SkCanvas::kStrict_SrcRectConstraint,
3120            SkCanvas::kFast_SrcRectConstraint } ) {
3121        canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3),
3122                SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint);
3123        lowPaint.setFilterQuality(kLow_SkFilterQuality);
3124        canvas->translate(80, 0);
3125    }
3126}
3127##
3128
3129#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
3130
3131##
3132
3133# ------------------------------------------------------------------------------
3134
3135#Method void drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
3136                       const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
3137#In Draw_Image
3138#In Draw
3139#Populate
3140
3141#Example
3142#Image 4
3143void draw(SkCanvas* canvas) {
3144    // sk_sp<SkImage> image;
3145    for (auto i : { 1, 2, 4, 8 } ) {
3146        canvas->drawImageRect(image.get(), SkIRect::MakeLTRB(0, 0, 100, 100),
3147                SkRect::MakeXYWH(i * 20, i * 20, i * 20, i * 20), nullptr);
3148    }
3149}
3150##
3151
3152#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
3153
3154##
3155
3156# ------------------------------------------------------------------------------
3157
3158#Method void drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint)
3159#In Draw_Image
3160#In Draw
3161#Populate
3162
3163#Example
3164#Image 4
3165void draw(SkCanvas* canvas) {
3166    // sk_sp<SkImage> image;
3167    for (auto i : { 20, 40, 80, 160 } ) {
3168        canvas->drawImageRect(image.get(), SkRect::MakeXYWH(i, i, i, i), nullptr);
3169    }
3170}
3171##
3172
3173#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
3174
3175##
3176
3177# ------------------------------------------------------------------------------
3178
3179#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
3180                       const SkPaint* paint,
3181                       SrcRectConstraint constraint = kStrict_SrcRectConstraint)
3182#In Draw_Image
3183#In Draw
3184#Populate
3185
3186#Example
3187#Height 64
3188#Description
3189    Canvas scales and translates; transformation from src to dst also scales.
3190    The two matrices are concatenated to create the final transformation.
3191##
3192void draw(SkCanvas* canvas) {
3193    uint32_t pixels[][2] = { { SK_ColorBLACK, SK_ColorWHITE },
3194                             { SK_ColorWHITE, SK_ColorBLACK } };
3195    SkBitmap bitmap;
3196    bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
3197            (void*) pixels, sizeof(pixels[0]));
3198    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
3199    SkPaint paint;
3200    canvas->scale(4, 4);
3201    for (auto alpha : { 50, 100, 150, 255 } ) {
3202        paint.setAlpha(alpha);
3203        canvas->drawImageRect(image, SkRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint);
3204        canvas->translate(8, 0);
3205    }
3206}
3207##
3208
3209#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
3210
3211##
3212
3213# ------------------------------------------------------------------------------
3214
3215#Method void drawImageRect(const sk_sp<SkImage>& image, const SkIRect& isrc, const SkRect& dst,
3216                       const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
3217#In Draw_Image
3218#In Draw
3219#Populate
3220
3221#Example
3222#Height 64
3223void draw(SkCanvas* canvas) {
3224    uint32_t pixels[][2] = { { 0x00000000, 0x55555555},
3225                             { 0xAAAAAAAA, 0xFFFFFFFF} };
3226    SkBitmap bitmap;
3227    bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
3228            (void*) pixels, sizeof(pixels[0]));
3229    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
3230    SkPaint paint;
3231    canvas->scale(4, 4);
3232    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
3233        paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
3234        canvas->drawImageRect(image, SkIRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint);
3235        canvas->translate(8, 0);
3236    }
3237}
3238##
3239
3240#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
3241
3242##
3243
3244# ------------------------------------------------------------------------------
3245
3246#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& dst, const SkPaint* paint)
3247#In Draw_Image
3248#In Draw
3249#Populate
3250
3251#Example
3252#Height 64
3253void draw(SkCanvas* canvas) {
3254    uint32_t pixels[][2] = { { 0x00000000, 0x55550000},
3255                             { 0xAAAA0000, 0xFFFF0000} };
3256    SkBitmap bitmap;
3257    bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
3258            (void*) pixels, sizeof(pixels[0]));
3259    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
3260    SkPaint paint;
3261    canvas->scale(4, 4);
3262    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
3263        paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
3264        canvas->drawImageRect(image, SkRect::MakeWH(8, 8), &paint);
3265        canvas->translate(8, 0);
3266    }
3267}
3268##
3269
3270#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
3271
3272##
3273
3274# ------------------------------------------------------------------------------
3275
3276#Method void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
3277                       const SkPaint* paint = nullptr)
3278#In Draw_Image
3279#In Draw
3280#Line # draws Nine_Patch Image ##
3281
3282Draws Image image stretched proportionally to fit into Rect dst.
3283IRect center divides the image into nine sections: four sides, four corners, and
3284the center. Corners are unmodified or scaled down proportionately if their sides
3285are larger than dst; center and four sides are scaled to fit remaining space, if any.
3286
3287Additionally transform draw using Clip, Matrix, and optional Paint paint.
3288
3289#paint_as_used_by_draw_lattice_or_draw_nine(image)#
3290
3291If generated mask extends beyond image bounds, replicate image edge colors, just
3292as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
3293replicates the image edge color when it samples outside of its bounds.
3294
3295#Param  image      Image containing pixels, dimensions, and format ##
3296#Param  center     IRect edge of image corners and sides ##
3297#Param  dst        destination Rect of image to draw to ##
3298#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
3299                   and so on; or nullptr
3300##
3301
3302#Example
3303#Height 128
3304#Description
3305    The leftmost image is smaller than center; only corners are drawn, all scaled to fit.
3306    The second image equals the size of center; only corners are drawn without scaling.
3307    The remaining images are larger than center. All corners draw without scaling.
3308    The sides and center are scaled if needed to take up the remaining space.
3309##
3310void draw(SkCanvas* canvas) {
3311    SkIRect center = { 20, 10, 50, 40 };
3312    SkBitmap bitmap;
3313    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
3314    SkCanvas bitCanvas(bitmap);
3315    SkPaint paint;
3316    SkColor gray = 0xFF000000;
3317    int left = 0;
3318    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
3319        int top = 0;
3320        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
3321            paint.setColor(gray);
3322            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
3323            gray += 0x001f1f1f;
3324            top = bottom;
3325        }
3326        left = right;
3327    }
3328    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
3329    SkImage* imagePtr = image.get();
3330    for (auto dest: { 20, 30, 40, 60, 90 } ) {
3331        canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr);
3332        canvas->translate(dest + 4, 0);
3333    }
3334}
3335##
3336
3337#SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect
3338
3339##
3340
3341# ------------------------------------------------------------------------------
3342
3343#Method void drawImageNine(const sk_sp<SkImage>& image, const SkIRect& center, const SkRect& dst,
3344                       const SkPaint* paint = nullptr)
3345#In Draw_Image
3346#In Draw
3347Draws Image image stretched proportionally to fit into Rect dst.
3348IRect center divides the image into nine sections: four sides, four corners, and
3349the center. Corners are not scaled, or scaled down proportionately if their sides
3350are larger than dst; center and four sides are scaled to fit remaining space, if any.
3351
3352Additionally transform draw using Clip, Matrix, and optional Paint paint.
3353
3354#paint_as_used_by_draw_lattice_or_draw_nine(image)#
3355
3356If generated mask extends beyond image bounds, replicate image edge colors, just
3357as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
3358replicates the image edge color when it samples outside of its bounds.
3359
3360#Param  image      Image containing pixels, dimensions, and format ##
3361#Param  center     IRect edge of image corners and sides ##
3362#Param  dst        destination Rect of image to draw to ##
3363#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
3364                   and so on; or nullptr
3365##
3366
3367#Example
3368#Height 128
3369#Description
3370    The two leftmost images has four corners and sides to the left and right of center.
3371    The leftmost image scales the width of corners proportionately to fit.
3372    The third and fourth image corners are not scaled; the sides and center are scaled to
3373    fill the remaining space.
3374    The rightmost image has four corners scaled vertically to fit, and uses sides above
3375    and below center to fill the remaining space.
3376##
3377void draw(SkCanvas* canvas) {
3378    SkIRect center = { 20, 10, 50, 40 };
3379    SkBitmap bitmap;
3380    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
3381    SkCanvas bitCanvas(bitmap);
3382    SkPaint paint;
3383    SkColor gray = 0xFF000000;
3384    int left = 0;
3385    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
3386        int top = 0;
3387        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
3388            paint.setColor(gray);
3389            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
3390            gray += 0x001f1f1f;
3391            top = bottom;
3392        }
3393        left = right;
3394    }
3395    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
3396    for (auto dest: { 20, 30, 40, 60, 90 } ) {
3397        canvas->drawImageNine(image, center, SkRect::MakeWH(dest, 110 - dest), nullptr);
3398        canvas->translate(dest + 4, 0);
3399    }
3400}
3401##
3402
3403#SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect
3404
3405##
3406
3407# ------------------------------------------------------------------------------
3408
3409#Method void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
3410                    const SkPaint* paint = nullptr)
3411#In Draw_Image
3412#In Draw
3413#Line # draws Bitmap at (x, y) position ##
3414#Populate
3415
3416#Example
3417#Height 64
3418void draw(SkCanvas* canvas) {
3419    uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00},
3420                            { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
3421                            { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00},
3422                            { 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF},
3423                            { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
3424                            { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00},
3425                            { 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00},
3426                            { 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF} };
3427    SkBitmap bitmap;
3428    bitmap.installPixels(SkImageInfo::MakeA8(8, 8),
3429            (void*) pixels, sizeof(pixels[0]));
3430    SkPaint paint;
3431    canvas->scale(4, 4);
3432    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) {
3433        paint.setColor(color);
3434        canvas->drawBitmap(bitmap, 0, 0, &paint);
3435        canvas->translate(12, 0);
3436    }
3437}
3438##
3439
3440#SeeAlso drawImage drawBitmapLattice drawBitmapNine drawBitmapRect SkBitmap::readPixels SkBitmap::writePixels
3441
3442##
3443
3444# ------------------------------------------------------------------------------
3445
3446#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
3447                        const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
3448#In Draw_Image
3449#In Draw
3450#Line # draws Bitmap, source Rect to destination Rect ##
3451#Populate
3452
3453#Example
3454#Height 64
3455void draw(SkCanvas* canvas) {
3456    uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00},
3457                            { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
3458                            { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00},
3459                            { 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF},
3460                            { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
3461                            { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00},
3462                            { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
3463                            { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00} };
3464    SkBitmap bitmap;
3465    bitmap.installPixels(SkImageInfo::MakeA8(8, 8),
3466            (void*) pixels, sizeof(pixels[0]));
3467    SkPaint paint;
3468    paint.setMaskFilter(SkMaskFilter::MakeBlur(kSolid_SkBlurStyle, 6));
3469    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) {
3470        paint.setColor(color);
3471        canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint);
3472        canvas->translate(48, 0);
3473    }
3474}
3475##
3476
3477#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine
3478
3479##
3480
3481# ------------------------------------------------------------------------------
3482
3483#Method void drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
3484                        const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
3485#In Draw_Image
3486#In Draw
3487#Populate
3488
3489#Example
3490#Height 64
3491void draw(SkCanvas* canvas) {
3492    uint8_t pixels[][8] = { { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
3493                            { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
3494                            { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF},
3495                            { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF},
3496                            { 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF},
3497                            { 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF},
3498                            { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
3499                            { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00} };
3500    SkBitmap bitmap;
3501    bitmap.installPixels(SkImageInfo::MakeA8(8, 8),
3502            (void*) pixels, sizeof(pixels[0]));
3503    SkPaint paint;
3504    paint.setFilterQuality(kHigh_SkFilterQuality);
3505    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00, 0xFF7f007f} ) {
3506        paint.setColor(color);
3507        canvas->drawBitmapRect(bitmap, SkIRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint);
3508        canvas->translate(48.25f, 0);
3509    }
3510}
3511##
3512
3513#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine
3514
3515##
3516
3517# ------------------------------------------------------------------------------
3518
3519#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
3520                        SrcRectConstraint constraint = kStrict_SrcRectConstraint)
3521#In Draw_Image
3522#In Draw
3523#Populate
3524
3525#Example
3526#Height 64
3527void draw(SkCanvas* canvas) {
3528    uint32_t pixels[][2] = { { 0x00000000, 0x55550000},
3529                             { 0xAAAA0000, 0xFFFF0000} };
3530    SkBitmap bitmap;
3531    bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
3532            (void*) pixels, sizeof(pixels[0]));
3533    SkPaint paint;
3534    canvas->scale(4, 4);
3535    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
3536        paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
3537        canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), &paint);
3538        canvas->translate(8, 0);
3539    }
3540}
3541##
3542
3543#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine
3544
3545##
3546
3547# ------------------------------------------------------------------------------
3548
3549#PhraseDef paint_as_used_by_draw_lattice_or_draw_nine(bitmap_or_image)
3550If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
3551Blend_Mode, and Draw_Looper. If #bitmap_or_image# is kAlpha_8_SkColorType, apply Shader.
3552If paint contains Mask_Filter, generate mask from #bitmap_or_image# bounds. If paint
3553Filter_Quality set to kNone_SkFilterQuality, disable pixel filtering. For all
3554other values of paint Filter_Quality, use kLow_SkFilterQuality to filter pixels.
3555Any SkMaskFilter on paint is ignored as is paint Anti_Aliasing state.
3556##
3557
3558#Method void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
3559                        const SkPaint* paint = nullptr)
3560#In Draw_Image
3561#In Draw
3562#Line # draws Nine_Patch Bitmap ##
3563
3564Draws Bitmap bitmap stretched proportionally to fit into Rect dst.
3565IRect center divides the bitmap into nine sections: four sides, four corners,
3566and the center. Corners are not scaled, or scaled down proportionately if their
3567sides are larger than dst; center and four sides are scaled to fit remaining
3568space, if any.
3569
3570Additionally transform draw using Clip, Matrix, and optional Paint paint.
3571
3572#paint_as_used_by_draw_lattice_or_draw_nine(bitmap)#
3573
3574If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
3575just as Shader made from SkShader::MakeBitmapShader with
3576SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
3577outside of its bounds.
3578
3579#Param  bitmap     Bitmap containing pixels, dimensions, and format ##
3580#Param  center     IRect edge of image corners and sides ##
3581#Param  dst        destination Rect of image to draw to ##
3582#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
3583                 and so on; or nullptr
3584##
3585
3586#Example
3587#Height 128
3588#Description
3589    The two leftmost bitmap draws has four corners and sides to the left and right of center.
3590    The leftmost bitmap draw scales the width of corners proportionately to fit.
3591    The third and fourth draw corners are not scaled; the sides and center are scaled to
3592    fill the remaining space.
3593    The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above
3594    and below center to fill the remaining space.
3595##
3596void draw(SkCanvas* canvas) {
3597    SkIRect center = { 20, 10, 50, 40 };
3598    SkBitmap bitmap;
3599    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
3600    SkCanvas bitCanvas(bitmap);
3601    SkPaint paint;
3602    SkColor gray = 0xFF000000;
3603    int left = 0;
3604    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
3605        int top = 0;
3606        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
3607            paint.setColor(gray);
3608            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
3609            gray += 0x001f1f1f;
3610            top = bottom;
3611        }
3612        left = right;
3613    }
3614    for (auto dest: { 20, 30, 40, 60, 90 } ) {
3615        canvas->drawBitmapNine(bitmap, center, SkRect::MakeWH(dest, 110 - dest), nullptr);
3616        canvas->translate(dest + 4, 0);
3617    }
3618}
3619##
3620
3621#SeeAlso drawImageNine drawBitmap drawBitmapLattice drawBitmapRect
3622
3623##
3624
3625# ------------------------------------------------------------------------------
3626#Subtopic Lattice
3627#Line # divides Bitmap or Image into a rectangular grid ##
3628
3629#Struct Lattice
3630#Line # divides Bitmap or Image into a rectangular grid ##
3631
3632#Code
3633#Populate
3634##
3635
3636Lattice divides Bitmap or Image into a rectangular grid.
3637Grid entries on even columns and even rows are fixed; these entries are
3638always drawn at their original size if the destination is large enough.
3639If the destination side is too small to hold the fixed entries, all fixed
3640entries are proportionately scaled down to fit.
3641The grid entries not on even columns and rows are scaled to fit the
3642remaining space, if any.
3643
3644    #Enum RectType
3645    #Line # optional setting per rectangular grid entry ##
3646        #Code
3647        #Populate
3648        ##
3649
3650        Optional setting per rectangular grid entry to make it transparent,
3651        or to fill the grid entry with a color.
3652
3653        #Const kDefault 0
3654        #Line # draws Bitmap into lattice rectangle ##
3655        ##
3656
3657        #Const kTransparent 1
3658        #Line # skips lattice rectangle by making it transparent ##
3659        ##
3660
3661        #Const kFixedColor 2
3662        #Line # draws one of fColors into lattice rectangle ##
3663        ##
3664    ##
3665
3666#Subtopic Members
3667##
3668
3669    #Member const int*   fXDivs
3670    #Line # x-axis values dividing bitmap ##
3671        Array of x-axis values that divide the bitmap vertically.
3672        Array entries must be unique, increasing, greater than or equal to
3673        fBounds left edge, and less than fBounds right edge.
3674        Set the first element to fBounds left to collapse the left column of
3675        fixed grid entries.
3676    ##
3677
3678    #Member const int*   fYDivs
3679    #Line # y-axis values dividing bitmap ##
3680        Array of y-axis values that divide the bitmap horizontally.
3681        Array entries must be unique, increasing, greater than or equal to
3682        fBounds top edge, and less than fBounds bottom edge.
3683        Set the first element to fBounds top to collapse the top row of fixed
3684        grid entries.
3685    ##
3686
3687    #Member const RectType* fRectTypes
3688    #Line # array of fill types ##
3689        Optional array of fill types, one per rectangular grid entry:
3690        array length must be #Formula # (fXCount + 1) * (fYCount + 1) ##.
3691
3692        Each RectType is one of: kDefault, kTransparent, kFixedColor.
3693
3694        Array entries correspond to the rectangular grid entries, ascending
3695        left to right and then top to bottom.
3696    ##
3697
3698    #Member int   fXCount
3699    #Line # number of x-coordinates ##
3700        Number of entries in fXDivs array; one less than the number of
3701        horizontal divisions.
3702    ##
3703
3704    #Member int   fYCount
3705    #Line # number of y-coordinates ##
3706        Number of entries in fYDivs array; one less than the number of vertical
3707        divisions.
3708    ##
3709
3710    #Member const SkIRect*   fBounds
3711    #Line # source bounds to draw from ##
3712       Optional subset IRect source to draw from.
3713       If nullptr, source bounds is dimensions of Bitmap or Image.
3714    ##
3715
3716    #Member const SkColor*   fColors
3717    #Line # array of colors ##
3718       Optional array of colors, one per rectangular grid entry.
3719       Array length must be #Formula # (fXCount + 1) * (fYCount + 1) ##.
3720
3721       Array entries correspond to the rectangular grid entries, ascending
3722       left to right, then top to bottom.
3723    ##
3724
3725#Struct Lattice ##
3726
3727#Method void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
3728                           const SkPaint* paint = nullptr)
3729#In Draw_Image
3730#In Draw
3731#Line # draws proportionally stretched Bitmap ##
3732
3733Draws Bitmap bitmap stretched proportionally to fit into Rect dst.
3734
3735Lattice lattice divides bitmap into a rectangular grid.
3736Each intersection of an even-numbered row and column is fixed; like the corners
3737of drawBitmapNine, fixed lattice elements never scale larger than their initial
3738size and shrink proportionately when all fixed elements exceed the bitmap
3739dimension. All other grid elements scale to fill the available space, if any.
3740
3741Additionally transform draw using Clip, Matrix, and optional Paint paint.
3742
3743#paint_as_used_by_draw_lattice_or_draw_nine(bitmap)#
3744
3745If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
3746just as Shader made from SkShader::MakeBitmapShader with
3747SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
3748outside of its bounds.
3749
3750#Param  bitmap     Bitmap containing pixels, dimensions, and format ##
3751#Param  lattice    division of bitmap into fixed and variable rectangles ##
3752#Param  dst        destination Rect of image to draw to ##
3753#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
3754                 and so on; or nullptr
3755##
3756
3757#Example
3758#Height 128
3759#Description
3760    The two leftmost bitmap draws has four corners and sides to the left and right of center.
3761    The leftmost bitmap draw scales the width of corners proportionately to fit.
3762    The third and fourth draw corners are not scaled; the sides are scaled to
3763    fill the remaining space; the center is transparent.
3764    The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above
3765    and below center to fill the remaining space.
3766##
3767void draw(SkCanvas* canvas) {
3768    SkIRect center = { 20, 10, 50, 40 };
3769    SkBitmap bitmap;
3770    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
3771    SkCanvas bitCanvas(bitmap);
3772    SkPaint paint;
3773    SkColor gray = 0xFF000000;
3774    int left = 0;
3775    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
3776        int top = 0;
3777        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
3778            paint.setColor(gray);
3779            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
3780            gray += 0x001f1f1f;
3781            top = bottom;
3782        }
3783        left = right;
3784    }
3785    const int xDivs[] = { center.fLeft, center.fRight };
3786    const int yDivs[] = { center.fTop, center.fBottom };
3787    SkCanvas::Lattice::RectType fillTypes[3][3];
3788    memset(fillTypes, 0, sizeof(fillTypes));
3789    fillTypes[1][1] = SkCanvas::Lattice::kTransparent;
3790    SkColor dummy[9];  // temporary pending bug fix
3791    SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], SK_ARRAY_COUNT(xDivs),
3792         SK_ARRAY_COUNT(yDivs), nullptr, dummy };
3793    for (auto dest: { 20, 30, 40, 60, 90 } ) {
3794        canvas->drawBitmapLattice(bitmap, lattice, SkRect::MakeWH(dest, 110 - dest), nullptr);
3795        canvas->translate(dest + 4, 0);
3796    }
3797}
3798##
3799
3800#SeeAlso drawImageLattice drawBitmap drawBitmapNine Lattice
3801
3802##
3803
3804# ------------------------------------------------------------------------------
3805
3806#Method void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
3807                          const SkPaint* paint = nullptr)
3808#In Draw_Image
3809#In Draw
3810#Line # draws proportionally stretched Image ##
3811
3812Draws Image image stretched proportionally to fit into Rect dst.
3813
3814Lattice lattice divides image into a rectangular grid.
3815Each intersection of an even-numbered row and column is fixed; like the corners
3816of drawBitmapNine, fixed lattice elements never scale larger than their initial
3817size and shrink proportionately when all fixed elements exceed the bitmap
3818dimension. All other grid elements scale to fill the available space, if any.
3819
3820Additionally transform draw using Clip, Matrix, and optional Paint paint.
3821
3822#paint_as_used_by_draw_lattice_or_draw_nine(image)#
3823
3824If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
3825just as Shader made from SkShader::MakeBitmapShader with
3826SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
3827outside of its bounds.
3828
3829#Param  image      Image containing pixels, dimensions, and format ##
3830#Param  lattice    division of bitmap into fixed and variable rectangles ##
3831#Param  dst        destination Rect of image to draw to ##
3832#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
3833                 and so on; or nullptr
3834##
3835
3836#Example
3837#Height 128
3838#Description
3839    The leftmost image is smaller than center; only corners are drawn, all scaled to fit.
3840    The second image equals the size of center; only corners are drawn without scaling.
3841    The remaining images are larger than center. All corners draw without scaling. The sides
3842    are scaled if needed to take up the remaining space; the center is transparent.
3843##
3844void draw(SkCanvas* canvas) {
3845    SkIRect center = { 20, 10, 50, 40 };
3846    SkBitmap bitmap;
3847    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
3848    SkCanvas bitCanvas(bitmap);
3849    SkPaint paint;
3850    SkColor gray = 0xFF000000;
3851    int left = 0;
3852    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
3853        int top = 0;
3854        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
3855            paint.setColor(gray);
3856            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
3857            gray += 0x001f1f1f;
3858            top = bottom;
3859        }
3860        left = right;
3861    }
3862    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
3863    SkImage* imagePtr = image.get();
3864    for (auto dest: { 20, 30, 40, 60, 90 } ) {
3865        canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr);
3866        canvas->translate(dest + 4, 0);
3867    }
3868}
3869##
3870
3871#SeeAlso drawBitmapLattice drawImage drawImageNine Lattice
3872
3873##
3874
3875#Subtopic Lattice ##
3876
3877#Subtopic Draw_Image ##
3878
3879# ------------------------------------------------------------------------------
3880#Subtopic Draw_Text
3881#Line # draws text into Canvas ##
3882##
3883
3884#Method void drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
3885                            SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint)
3886#In Draw_Text
3887#In Draw
3888#Line # draws text at (x, y), using font advance ##
3889#Populate
3890
3891#Example
3892#Height 200
3893#Description
3894The same text is drawn varying Paint_Text_Size and varying
3895Matrix.
3896##
3897void draw(SkCanvas* canvas) {
3898    SkPaint paint;
3899    SkFont font;
3900    float textSizes[] = { 12, 18, 24, 36 };
3901    for (auto size: textSizes ) {
3902        font.setSize(size);
3903        canvas->drawSimpleText("Aa", 2, kUTF8_SkTextEncoding, 10, 20, font, paint);
3904        canvas->translate(0, size * 2);
3905    }
3906    font.setSize(12);
3907    float yPos = 20;
3908    for (auto size: textSizes ) {
3909        float scale = size / 12.f;
3910        canvas->resetMatrix();
3911        canvas->translate(100, 0);
3912        canvas->scale(scale, scale);
3913        canvas->drawSimpleText("Aa", 2, kUTF8_SkTextEncoding,
3914                               10 / scale, yPos / scale, font, paint);
3915        yPos += size * 2;
3916    }
3917}
3918##
3919
3920#SeeAlso drawString drawTextBlob
3921
3922##
3923
3924# ------------------------------------------------------------------------------
3925
3926#Method void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint)
3927#In Draw_Text
3928#In Draw
3929#Line # draws text with arrays of positions and Paint ##
3930Draws Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint.
3931
3932blob contains Glyphs, their positions, and paint attributes specific to text:
3933#font_metrics#.
3934
3935Paint_Text_Encoding must be set to kGlyphID_SkTextEncoding.
3936
3937Elements of paint: Anti_Alias, Blend_Mode, Color including Color_Alpha,
3938Color_Filter, Paint_Dither, Draw_Looper, Mask_Filter, Path_Effect, Shader, and
3939Paint_Style; apply to blob. If Paint contains SkPaint::kStroke_Style:
3940Paint_Miter_Limit, Paint_Stroke_Cap, Paint_Stroke_Join, and Paint_Stroke_Width;
3941apply to Path created from blob.
3942
3943#Param  blob     Glyphs, positions, and their paints' text size, typeface, and so on ##
3944#Param  x        horizontal offset applied to blob ##
3945#Param  y        vertical offset applied to blob ##
3946#Param  paint    blend, color, stroking, and so on, used to draw ##
3947
3948#Example
3949#Height 120
3950void draw(SkCanvas* canvas) {
3951    SkTextBlobBuilder textBlobBuilder;
3952    const char bunny[] = "/(^x^)\\";
3953    const int len = sizeof(bunny) - 1;
3954    uint16_t glyphs[len];
3955    SkFont font;
3956    font.textToGlyphs(bunny, len, SkTextEncoding::kUTF8, glyphs, len);
3957    int runs[] = { 3, 1, 3 };
3958    SkPoint textPos = { 20, 100 };
3959    int glyphIndex = 0;
3960    for (auto runLen : runs) {
3961        font.setSize(1 == runLen ? 20 : 50);
3962        const SkTextBlobBuilder::RunBuffer& run =
3963                textBlobBuilder.allocRun(font, runLen, textPos.fX, textPos.fY);
3964        memcpy(run.glyphs, &glyphs[glyphIndex], sizeof(glyphs[0]) * runLen);
3965        font.setSize(1 == runLen ? 20 : 50);
3966        textPos.fX += font.measureText(&glyphs[glyphIndex], sizeof(glyphs[0]) * runLen,
3967                SkTextEncoding::kGlyphID);
3968        glyphIndex += runLen;
3969    }
3970    sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
3971    canvas->drawTextBlob(blob.get(), 0, 0, SkPaint());
3972}
3973##
3974
3975#SeeAlso drawText
3976
3977##
3978
3979# ------------------------------------------------------------------------------
3980
3981#Method void drawTextBlob(const sk_sp<SkTextBlob>& blob, SkScalar x, SkScalar y, const SkPaint& paint)
3982
3983Draws Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint.
3984
3985blob contains Glyphs, their positions, and paint attributes specific to text:
3986#font_metrics#.
3987
3988Paint_Text_Encoding must be set to kGlyphID_SkTextEncoding.
3989
3990Elements of paint: Path_Effect, Mask_Filter, Shader, Color_Filter,
3991Image_Filter, and Draw_Looper; apply to blob.
3992
3993#Param  blob     Glyphs, positions, and their paints' text size, typeface, and so on ##
3994#Param  x        horizontal offset applied to blob ##
3995#Param  y        vertical offset applied to blob ##
3996#Param  paint    blend, color, stroking, and so on, used to draw ##
3997
3998#Example
3999#Height 120
4000#Description
4001Paint attributes related to text, like text size, have no effect on paint passed to drawTextBlob.
4002##
4003    void draw(SkCanvas* canvas) {
4004        SkTextBlobBuilder textBlobBuilder;
4005        SkFont font;
4006        font.setSize(50);
4007        const SkTextBlobBuilder::RunBuffer& run =
4008                textBlobBuilder.allocRun(font, 1, 20, 100);
4009        run.glyphs[0] = 20;
4010        sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
4011        SkPaint paint;
4012        paint.setTextSize(10);
4013        paint.setColor(SK_ColorBLUE);
4014        canvas->drawTextBlob(blob.get(), 0, 0, paint);
4015    }
4016##
4017
4018#SeeAlso drawText
4019
4020##
4021
4022# ------------------------------------------------------------------------------
4023
4024#Method void drawPicture(const SkPicture* picture)
4025#In Draw
4026#Line # draws Picture using Clip and Matrix ##
4027#Populate
4028
4029#Example
4030void draw(SkCanvas* canvas) {
4031    SkPictureRecorder recorder;
4032    SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
4033    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
4034        SkPaint paint;
4035        paint.setColor(color);
4036        recordingCanvas->drawRect({10, 10, 30, 40}, paint);
4037        recordingCanvas->translate(10, 10);
4038        recordingCanvas->scale(1.2f, 1.4f);
4039    }
4040    sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
4041    canvas->drawPicture(playback);
4042    canvas->scale(2, 2);
4043    canvas->translate(50, 0);
4044    canvas->drawPicture(playback);
4045}
4046##
4047
4048#SeeAlso drawDrawable SkPicture SkPicture::playback
4049
4050##
4051
4052# ------------------------------------------------------------------------------
4053
4054#Method void drawPicture(const sk_sp<SkPicture>& picture)
4055#Populate
4056
4057#Example
4058void draw(SkCanvas* canvas) {
4059    SkPictureRecorder recorder;
4060    SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
4061    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
4062        SkPaint paint;
4063        paint.setColor(color);
4064        recordingCanvas->drawRect({10, 10, 30, 40}, paint);
4065        recordingCanvas->translate(10, 10);
4066        recordingCanvas->scale(1.2f, 1.4f);
4067    }
4068    sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
4069    canvas->drawPicture(playback);
4070    canvas->scale(2, 2);
4071    canvas->translate(50, 0);
4072    canvas->drawPicture(playback);
4073}
4074##
4075
4076#SeeAlso drawDrawable SkPicture SkPicture::playback
4077
4078##
4079
4080# ------------------------------------------------------------------------------
4081
4082#Method void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint)
4083#Populate
4084
4085#Example
4086void draw(SkCanvas* canvas) {
4087    SkPaint paint;
4088    SkPictureRecorder recorder;
4089    SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
4090    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
4091        paint.setColor(color);
4092        recordingCanvas->drawRect({10, 10, 30, 40}, paint);
4093        recordingCanvas->translate(10, 10);
4094        recordingCanvas->scale(1.2f, 1.4f);
4095    }
4096    sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
4097    const SkPicture* playbackPtr = playback.get();
4098    SkMatrix matrix;
4099    matrix.reset();
4100    for (auto alpha : { 70, 140, 210 } ) {
4101    paint.setAlpha(alpha);
4102    canvas->drawPicture(playbackPtr, &matrix, &paint);
4103    matrix.preTranslate(70, 70);
4104    }
4105}
4106##
4107
4108#SeeAlso drawDrawable SkPicture SkPicture::playback
4109
4110##
4111
4112# ------------------------------------------------------------------------------
4113
4114#Method void drawPicture(const sk_sp<SkPicture>& picture, const SkMatrix* matrix, const SkPaint* paint)
4115#Populate
4116
4117#Example
4118void draw(SkCanvas* canvas) {
4119    SkPaint paint;
4120    SkPictureRecorder recorder;
4121    SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
4122    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
4123        paint.setColor(color);
4124        recordingCanvas->drawRect({10, 10, 30, 40}, paint);
4125        recordingCanvas->translate(10, 10);
4126        recordingCanvas->scale(1.2f, 1.4f);
4127    }
4128    sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
4129    SkMatrix matrix;
4130    matrix.reset();
4131    for (auto alpha : { 70, 140, 210 } ) {
4132    paint.setAlpha(alpha);
4133    canvas->drawPicture(playback, &matrix, &paint);
4134    matrix.preTranslate(70, 70);
4135    }
4136}
4137##
4138
4139#SeeAlso drawDrawable SkPicture SkPicture::playback
4140
4141##
4142
4143# ------------------------------------------------------------------------------
4144
4145#Method void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint)
4146#In Draw
4147#Line # draws Vertices, a triangle mesh ##
4148#Populate
4149
4150#Example
4151void draw(SkCanvas* canvas) {
4152    SkPaint paint;
4153    SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
4154    SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
4155    auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
4156            SK_ARRAY_COUNT(points), points, nullptr, colors);
4157    canvas->drawVertices(vertices.get(), SkBlendMode::kSrc, paint);
4158}
4159##
4160
4161#SeeAlso drawPatch drawPicture
4162
4163##
4164
4165# ------------------------------------------------------------------------------
4166
4167#Method void drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, const SkPaint& paint)
4168#Populate
4169
4170#Example
4171void draw(SkCanvas* canvas) {
4172    SkPaint paint;
4173    SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
4174    SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };
4175    SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
4176    paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
4177            SkShader::kClamp_TileMode));
4178    auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
4179            SK_ARRAY_COUNT(points), points, texs, colors);
4180    canvas->drawVertices(vertices, SkBlendMode::kDarken, paint);
4181}
4182##
4183
4184#SeeAlso drawPatch drawPicture
4185
4186##
4187
4188# ------------------------------------------------------------------------------
4189
4190#Method void drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
4191                          int boneCount, SkBlendMode mode, const SkPaint& paint)
4192#Populate
4193
4194#NoExample
4195void draw(SkCanvas* canvas) {
4196    SkPaint paint;
4197    SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
4198    SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };
4199    SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
4200    SkVertices::BoneIndices boneIndices[] = { { 0, 0, 0, 0 },
4201                                              { 1, 0, 0, 0 },
4202                                              { 2, 0, 0, 0 },
4203                                              { 3, 0, 0, 0 } };
4204    SkVertices::BoneWeights boneWeights[] = { { 0.0f, 0.0f, 0.0f, 0.0f },
4205                                              { 1.0f, 0.0f, 0.0f, 0.0f },
4206                                              { 1.0f, 0.0f, 0.0f, 0.0f },
4207                                              { 1.0f, 0.0f, 0.0f, 0.0f } };
4208    SkVertices::Bone bones[] = { {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }},
4209                                 {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 20.0f }},
4210                                 {{ 1.0f, 0.0f, 0.0f, 1.0f, 50.0f, 50.0f }},
4211                                 {{ 1.0f, 0.0f, 0.0f, 1.0f, 20.0f, 0.0f }} };
4212    paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
4213            SkShader::kClamp_TileMode));
4214    auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
4215            SK_ARRAY_COUNT(points), points, texs, colors, boneIndices, boneWeights);
4216    canvas->drawVertices(vertices.get(), bones, SK_ARRAY_COUNT(bones), SkBlendMode::kDarken, paint);
4217}
4218##
4219
4220#SeeAlso drawPatch drawPicture
4221
4222##
4223
4224# ------------------------------------------------------------------------------
4225
4226#Method void drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
4227                          int boneCount, SkBlendMode mode, const SkPaint& paint)
4228#Populate
4229
4230#NoExample
4231void draw(SkCanvas* canvas) {
4232    SkPaint paint;
4233    SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
4234    SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };
4235    SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
4236    SkVertices::BoneIndices boneIndices[] = { { 0, 0, 0, 0 },
4237                                              { 1, 0, 0, 0 },
4238                                              { 2, 0, 0, 0 },
4239                                              { 3, 0, 0, 0 } };
4240    SkVertices::BoneWeights boneWeights[] = { { 0.0f, 0.0f, 0.0f, 0.0f },
4241                                              { 1.0f, 0.0f, 0.0f, 0.0f },
4242                                              { 1.0f, 0.0f, 0.0f, 0.0f },
4243                                              { 1.0f, 0.0f, 0.0f, 0.0f } };
4244    SkVertices::Bone bones[] = { {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }},
4245                                 {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 20.0f }},
4246                                 {{ 1.0f, 0.0f, 0.0f, 1.0f, 50.0f, 50.0f }},
4247                                 {{ 1.0f, 0.0f, 0.0f, 1.0f, 20.0f, 0.0f }} };
4248    paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
4249            SkShader::kClamp_TileMode));
4250    auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
4251            SK_ARRAY_COUNT(points), points, texs, colors, boneIndices, boneWeights);
4252    canvas->drawVertices(vertices, bones, SK_ARRAY_COUNT(bones), SkBlendMode::kDarken, paint);
4253}
4254##
4255
4256#SeeAlso drawPatch drawPicture
4257
4258##
4259
4260# ------------------------------------------------------------------------------
4261
4262#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
4263                   const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint)
4264#In Draw
4265#Line # draws Coons_Patch ##
4266#Populate
4267
4268#Example
4269#Image 5
4270void draw(SkCanvas* canvas) {
4271    // SkBitmap source = cmbkygk;
4272    SkPaint paint;
4273    paint.setFilterQuality(kLow_SkFilterQuality);
4274    paint.setAntiAlias(true);
4275    SkPoint cubics[] = { { 3, 1 },    { 4, 2 }, { 5, 1 },    { 7, 3 },
4276                      /* { 7, 3 }, */ { 6, 4 }, { 7, 5 },    { 5, 7 },
4277                      /* { 5, 7 }, */ { 4, 6 }, { 3, 7 },    { 1, 5 },
4278                      /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
4279    SkColor colors[] = { 0xbfff0000, 0xbf0000ff, 0xbfff00ff, 0xbf00ffff };
4280    SkPoint texCoords[] = { { -30, -30 }, { 162, -30}, { 162, 162}, { -30, 162} };
4281    paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode,
4282                                                       SkShader::kClamp_TileMode, nullptr));
4283    canvas->scale(15, 15);
4284    for (auto blend : { SkBlendMode::kSrcOver, SkBlendMode::kModulate, SkBlendMode::kXor } ) {
4285        canvas->drawPatch(cubics, colors, texCoords, blend, paint);
4286        canvas->translate(4, 4);
4287    }
4288}
4289##
4290
4291#ToDo can patch use image filter? ##
4292#SeeAlso drawVertices drawPicture
4293
4294##
4295
4296# ------------------------------------------------------------------------------
4297
4298#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
4299                   const SkPoint texCoords[4], const SkPaint& paint)
4300#Populate
4301
4302#Example
4303void draw(SkCanvas* canvas) {
4304    SkPaint paint;
4305    paint.setAntiAlias(true);
4306    SkPoint cubics[] = { { 3, 1 },    { 4, 2 }, { 5, 1 },    { 7, 3 },
4307                      /* { 7, 3 }, */ { 6, 4 }, { 7, 5 },    { 5, 7 },
4308                      /* { 5, 7 }, */ { 4, 6 }, { 3, 7 },    { 1, 5 },
4309                      /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
4310    SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
4311    canvas->scale(30, 30);
4312    canvas->drawPatch(cubics, colors, nullptr, paint);
4313    SkPoint text[] = { {3,0.9f}, {4,2.5f}, {5,0.9f}, {7.5f,3.2f}, {5.5f,4.2f},
4314            {7.5f,5.2f}, {5,7.5f}, {4,5.9f}, {3,7.5f}, {0.5f,5.2f}, {2.5f,4.2f},
4315            {0.5f,3.2f} };
4316
4317    SkFont font(nullptr, 18.f / 30);
4318    for (int i = 0; i< 10; ++i) {
4319       char digit = '0' + i;
4320       canvas->drawSimpleText(&digit, kUTF8_SkTextEncoding, 1, text[i].fX, text[i].fY, font, paint);
4321    }
4322    canvas->drawString("10", text[10].fX, text[10].fY, font, paint);
4323    canvas->drawString("11", text[11].fX, text[11].fY, font, paint);
4324    paint.setStyle(SkPaint::kStroke_Style);
4325    canvas->drawPoints(SkCanvas::kPolygon_PointMode, 12, cubics, paint);
4326    canvas->drawLine(cubics[11].fX, cubics[11].fY, cubics[0].fX, cubics[0].fY, paint);
4327}
4328##
4329
4330#Example
4331#Image 6
4332void draw(SkCanvas* canvas) {
4333    // SkBitmap source = checkerboard;
4334    SkPaint paint;
4335    paint.setFilterQuality(kLow_SkFilterQuality);
4336    paint.setAntiAlias(true);
4337    SkPoint cubics[] = { { 3, 1 },    { 4, 2 }, { 5, 1 },    { 7, 3 },
4338                      /* { 7, 3 }, */ { 6, 4 }, { 7, 5 },    { 5, 7 },
4339                      /* { 5, 7 }, */ { 4, 6 }, { 3, 7 },    { 1, 5 },
4340                      /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
4341    SkPoint texCoords[] = { { 0, 0 }, { 0, 62}, { 62, 62}, { 62, 0 } };
4342    paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode,
4343                                                       SkShader::kClamp_TileMode, nullptr));
4344    canvas->scale(30, 30);
4345    canvas->drawPatch(cubics, nullptr, texCoords, paint);
4346}
4347##
4348
4349#ToDo can patch use image filter? ##
4350#SeeAlso drawVertices drawPicture
4351
4352##
4353
4354# ------------------------------------------------------------------------------
4355
4356#Method void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
4357                   const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect,
4358                   const SkPaint* paint)
4359#In Draw
4360#Line # draws sprites using Clip, Matrix, and Paint ##
4361#Populate
4362
4363#Example
4364#Image 3
4365void draw(SkCanvas* canvas) {
4366  // SkBitmap source = mandrill;
4367  SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
4368  SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
4369  SkColor colors[] = { 0x7f55aa00, 0x7f3333bf };
4370  const SkImage* imagePtr = image.get();
4371  canvas->drawAtlas(imagePtr, xforms, tex, colors, 2, SkBlendMode::kSrcOver, nullptr, nullptr);
4372}
4373##
4374
4375#SeeAlso drawBitmap drawImage
4376
4377##
4378
4379# ------------------------------------------------------------------------------
4380
4381#Method void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[],
4382                   const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect,
4383                   const SkPaint* paint)
4384#Populate
4385
4386#Example
4387#Image 3
4388void draw(SkCanvas* canvas) {
4389  // SkBitmap source = mandrill;
4390  SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
4391  SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
4392  SkColor colors[] = { 0x7f55aa00, 0x7f3333bf };
4393  SkPaint paint;
4394  paint.setAlpha(127);
4395  canvas->drawAtlas(image, xforms, tex, colors, 2, SkBlendMode::kPlus, nullptr, &paint);
4396}
4397##
4398
4399#ToDo bug in example on cpu side, gpu looks ok ##
4400
4401#SeeAlso drawBitmap drawImage
4402
4403##
4404
4405# ------------------------------------------------------------------------------
4406
4407#Method void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count,
4408                   const SkRect* cullRect, const SkPaint* paint)
4409#Populate
4410
4411#Example
4412#Image 3
4413void draw(SkCanvas* canvas) {
4414  // sk_sp<SkImage> image = mandrill;
4415  SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
4416  SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
4417  const SkImage* imagePtr = image.get();
4418  canvas->drawAtlas(imagePtr, xforms, tex, 2, nullptr, nullptr);
4419}
4420##
4421
4422#SeeAlso drawBitmap drawImage
4423
4424##
4425
4426# ------------------------------------------------------------------------------
4427
4428#Method void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[],
4429                   int count, const SkRect* cullRect, const SkPaint* paint)
4430#Populate
4431
4432#Example
4433#Image 3
4434void draw(SkCanvas* canvas) {
4435  // sk_sp<SkImage> image = mandrill;
4436  SkRSXform xforms[] = { { 1, 0, 0, 0 }, {0, 1, 300, 100 } };
4437  SkRect tex[] = { { 0, 0, 200, 200 }, { 200, 0, 400, 200 } };
4438  canvas->drawAtlas(image, xforms, tex, 2, nullptr, nullptr);
4439}
4440##
4441
4442#SeeAlso drawBitmap drawImage
4443
4444##
4445
4446# ------------------------------------------------------------------------------
4447
4448#Method void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr)
4449#In Draw
4450#Line # draws Drawable, encapsulated drawing commands ##
4451#Populate
4452
4453#Example
4454#Height 100
4455#Function
4456struct MyDrawable : public SkDrawable {
4457    SkRect onGetBounds() override { return SkRect::MakeWH(50, 100);  }
4458
4459    void onDraw(SkCanvas* canvas) override {
4460       SkPath path;
4461       path.conicTo(10, 90, 50, 90, 0.9f);
4462       SkPaint paint;
4463       paint.setColor(SK_ColorBLUE);
4464       canvas->drawRect(path.getBounds(), paint);
4465       paint.setAntiAlias(true);
4466       paint.setColor(SK_ColorWHITE);
4467       canvas->drawPath(path, paint);
4468    }
4469};
4470
4471#Function ##
4472void draw(SkCanvas* canvas) {
4473    sk_sp<SkDrawable> drawable(new MyDrawable);
4474  SkMatrix matrix;
4475  matrix.setTranslate(10, 10);
4476  canvas->drawDrawable(drawable.get(), &matrix);
4477}
4478##
4479
4480#SeeAlso SkDrawable drawPicture
4481
4482##
4483
4484# ------------------------------------------------------------------------------
4485
4486#Method void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y)
4487#Populate
4488
4489#Example
4490#Height 100
4491#Function
4492struct MyDrawable : public SkDrawable {
4493    SkRect onGetBounds() override { return SkRect::MakeWH(50, 100);  }
4494
4495    void onDraw(SkCanvas* canvas) override {
4496       SkPath path;
4497       path.conicTo(10, 90, 50, 90, 0.9f);
4498       SkPaint paint;
4499       paint.setColor(SK_ColorBLUE);
4500       canvas->drawRect(path.getBounds(), paint);
4501       paint.setAntiAlias(true);
4502       paint.setColor(SK_ColorWHITE);
4503       canvas->drawPath(path, paint);
4504    }
4505};
4506
4507#Function ##
4508void draw(SkCanvas* canvas) {
4509    sk_sp<SkDrawable> drawable(new MyDrawable);
4510  canvas->drawDrawable(drawable.get(), 10, 10);
4511}
4512##
4513
4514#SeeAlso SkDrawable drawPicture
4515
4516##
4517
4518# ------------------------------------------------------------------------------
4519
4520#Method void drawAnnotation(const SkRect& rect, const char key[], SkData* value)
4521#In Draw
4522#In Utility
4523#Line # associates a Rect with a key-value pair ##
4524#Populate
4525
4526#Example
4527    #Height 1
4528    const char text[] = "Click this link!";
4529    SkRect bounds;
4530    SkPaint paint;
4531    SkFont font(nullptr, 40);
4532    (void)font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
4533    const char url[] = "https://www.google.com/";
4534    sk_sp<SkData> urlData(SkData::MakeWithCString(url));
4535    canvas->drawAnnotation(bounds, "url_key", urlData.get());
4536##
4537
4538#SeeAlso SkPicture SkDocument
4539
4540##
4541
4542# ------------------------------------------------------------------------------
4543
4544#Method void drawAnnotation(const SkRect& rect, const char key[], const sk_sp<SkData>& value)
4545#Populate
4546
4547#Example
4548#Height 1
4549    const char text[] = "Click this link!";
4550    SkRect bounds;
4551    SkPaint paint;
4552    SkFont font(nullptr, 40);
4553    (void)font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
4554    const char url[] = "https://www.google.com/";
4555    sk_sp<SkData> urlData(SkData::MakeWithCString(url));
4556    canvas->drawAnnotation(bounds, "url_key", urlData.get());
4557##
4558
4559#SeeAlso SkPicture SkDocument
4560
4561##
4562
4563# ------------------------------------------------------------------------------
4564
4565#Method virtual bool isClipEmpty() const
4566#In Property
4567#Line # returns if Clip is empty ##
4568#Populate
4569
4570#Example
4571    void draw(SkCanvas* canvas) {
4572        SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not");
4573        SkPath path;
4574        canvas->clipPath(path);
4575        SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not");
4576    }
4577    #StdOut
4578        clip is not empty
4579        clip is empty
4580    ##
4581##
4582
4583#SeeAlso isClipRect getLocalClipBounds getDeviceClipBounds
4584
4585##
4586
4587# ------------------------------------------------------------------------------
4588
4589#Method virtual bool isClipRect() const
4590#In Property
4591#Line # returns if Clip is Rect and not empty ##
4592#Populate
4593
4594#Example
4595    void draw(SkCanvas* canvas) {
4596        SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not");
4597        canvas->clipRect({0, 0, 0, 0});
4598        SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not");
4599    }
4600    #StdOut
4601        clip is rect
4602        clip is not rect
4603    ##
4604##
4605
4606#SeeAlso isClipEmpty getLocalClipBounds getDeviceClipBounds
4607
4608##
4609
4610#Class SkCanvas ##
4611
4612#Topic Canvas ##
4613