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