SkCanvas_Reference.bmh revision 9ff8c8c073ba553dc8b22bb9aacc23949292f72f
1#Topic Canvas
2#Alias Canvas_Reference
3
4#Subtopic Overview
5    #Subtopic Subtopic
6    #Populate
7    ##
8##
9
10#Class SkCanvas
11
12Canvas provides an interface for drawing, and how the drawing is clipped and transformed.
13Canvas contains a stack of Matrix and Clip values.
14
15Canvas and Paint together provide the state to draw into Surface or Device.
16Each Canvas draw call transforms the geometry of the object by the concatenation of all
17Matrix values in the stack. The transformed geometry is clipped by the intersection
18of all of Clip values in the stack. The Canvas draw calls use Paint to supply drawing
19state such as Color, Typeface, text size, stroke width, Shader and so on.
20
21To draw to a pixel-based destination, create Raster_Surface or GPU_Surface. 
22Request Canvas from Surface to obtain the interface to draw. 
23Canvas generated by Raster_Surface draws to memory visible to the CPU. 
24Canvas generated by GPU_Surface uses Vulkan or OpenGL to draw to the GPU.
25
26To draw to a document, obtain Canvas from SVG_Canvas, Document_PDF, or Picture_Recorder.
27Document based Canvas and other Canvas Subclasses reference Device describing the
28destination.
29
30Canvas can be constructed to draw to Bitmap without first creating Raster_Surface.
31This approach may be deprecated in the future.  
32
33#Subtopic Related_Function
34#Populate
35##
36
37#Subtopic Constant
38#Populate
39##
40
41#Subtopic Class_or_Struct
42#Populate
43##
44
45#Subtopic Constructor
46
47Create the desired type of Surface to obtain its Canvas when possible. Useful
48when no Surface is required, and some helpers implicitly create Raster_Surface.
49
50#Populate
51##
52
53#Subtopic Member_Function
54#Populate
55##
56
57# ------------------------------------------------------------------------------
58
59#Method static std::unique_ptr<SkCanvas> MakeRasterDirect(const SkImageInfo& info, void* pixels,
60                                                          size_t rowBytes,
61                                                          const SkSurfaceProps* props = nullptr)
62#Line # creates from SkImageInfo and Pixel_Storage ##
63
64Allocates raster Canvas that will draw directly into pixels.
65
66Canvas is returned if all parameters are valid.
67Valid parameters include:
68info dimensions are zero or positive;
69info contains Color_Type and Alpha_Type supported by Raster_Surface;
70pixels is not nullptr;
71rowBytes is zero or large enough to contain info width pixels of Color_Type.
72
73Pass zero for rowBytes to compute rowBytes from info width and size of pixel. 
74If rowBytes is greater than zero, it must be equal to or greater than
75info width times bytes required for Color_Type.
76
77Pixel buffer size should be info height times computed rowBytes.
78Pixels are not initialized.
79To access pixels after drawing, call flush() or peekPixels.
80
81#Param info  width, height, Color_Type, Alpha_Type, Color_Space, of Raster_Surface;
82             width, or height, or both, may be zero
83##
84#Param pixels  pointer to destination pixels buffer
85##
86#Param rowBytes  interval from one Surface row to the next, or zero
87##
88#Param props  LCD striping orientation and setting for device independent fonts;
89              may be nullptr
90##
91
92#Return  Canvas if all parameters are valid; otherwise, nullptr ##
93
94#Example
95    #Description
96        Allocates a three by three bitmap, clears it to white, and draws a black pixel
97        in the center.
98    ##
99void draw(SkCanvas* ) {
100    SkImageInfo info = SkImageInfo::MakeN32Premul(3, 3);  // device aligned, 32 bpp, Premultiplied
101    const size_t minRowBytes = info.minRowBytes();  // bytes used by one bitmap row
102    const size_t size = info.computeMinByteSize();  // bytes used by all rows
103    SkAutoTMalloc<SkPMColor> storage(size);  // allocate storage for pixels
104    SkPMColor* pixels = storage.get();  // get pointer to allocated storage
105    // create a SkCanvas backed by a raster device, and delete it when the
106    // function goes out of scope.
107    std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(info, pixels, minRowBytes);
108    canvas->clear(SK_ColorWHITE);  // white is Unpremultiplied, in ARGB order
109    canvas->flush();  // ensure that pixels are cleared
110    SkPMColor pmWhite = pixels[0];  // the Premultiplied format may vary
111    SkPaint paint;  // by default, draws black
112    canvas->drawPoint(1, 1, paint);  // draw in the center
113    canvas->flush();  // ensure that point was drawn
114    for (int y = 0; y < info.height(); ++y) {
115        for (int x = 0; x < info.width(); ++x) {
116            SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
117        }
118        SkDebugf("\n");
119    }
120}
121    #StdOut
122        ---
123        -x-
124        ---
125    ##
126##
127
128#SeeAlso MakeRasterDirectN32 SkSurface::MakeRasterDirect
129
130##
131
132# ------------------------------------------------------------------------------
133
134#Method static std::unique_ptr<SkCanvas> MakeRasterDirectN32(int width, int height, SkPMColor* pixels,
135                                                         size_t rowBytes) 
136#Line # creates from image data and Pixel_Storage ##
137
138Allocates raster Canvas specified by inline image specification. Subsequent Canvas
139calls draw into pixels.
140Color_Type is set to kN32_SkColorType.
141Alpha_Type is set to kPremul_SkAlphaType.
142To access pixels after drawing, call flush() or peekPixels.
143
144Canvas is returned if all parameters are valid.
145Valid parameters include:
146width and height are zero or positive;
147pixels is not nullptr;
148rowBytes is zero or large enough to contain width pixels of kN32_SkColorType.
149
150Pass zero for rowBytes to compute rowBytes from width and size of pixel. 
151If rowBytes is greater than zero, it must be equal to or greater than
152width times bytes required for Color_Type.
153
154Pixel buffer size should be height times rowBytes.
155
156#Param width  pixel column count on Raster_Surface created; must be zero or greater ##
157#Param height  pixel row count on Raster_Surface created; must be zero or greater ##
158#Param pixels  pointer to destination pixels buffer; buffer size should be height
159               times rowBytes
160##
161#Param rowBytes  interval from one Surface row to the next, or zero
162##
163
164#Return  Canvas if all parameters are valid; otherwise, nullptr ##
165
166#Example
167    #Description
168        Allocates a three by three bitmap, clears it to white, and draws a black pixel
169        in the center.
170    ##
171void draw(SkCanvas* ) {
172    const int width = 3;
173    const int height = 3;
174    SkPMColor pixels[height][width];  // allocate a 3x3 Premultiplied bitmap on the stack
175    // create a SkCanvas backed by a raster device, and delete it when the
176    // function goes out of scope.
177    std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirectN32(
178            width,
179            height,
180            pixels[0],  // top-left of the bitmap
181            sizeof(pixels[0]));  // byte width of the each row
182    // write a premultiplied value for white into all pixels in the bitmap
183    canvas->clear(SK_ColorWHITE);
184    SkPMColor pmWhite = pixels[0][0];  // the Premultiplied format may vary
185    SkPaint paint;  // by default, draws black
186    canvas->drawPoint(1, 1, paint);  // draw in the center
187    canvas->flush();  // ensure that pixels is ready to be read
188    for (int y = 0; y < height; ++y) {
189        for (int x = 0; x < width; ++x) {
190            SkDebugf("%c", pixels[y][x] == pmWhite ? '-' : 'x');
191        }
192        SkDebugf("\n");
193    }
194}
195    #StdOut
196        ---
197        -x-
198        ---
199    ##
200##
201
202#SeeAlso MakeRasterDirect SkSurface::MakeRasterDirect SkImageInfo::MakeN32Premul
203
204##
205
206# ------------------------------------------------------------------------------
207
208#Method SkCanvas()
209
210#Line # creates with no Surface, no dimensions ##
211Creates an empty Canvas with no backing device or pixels, with 
212a width and height of zero.
213
214#Return  empty Canvas ##
215
216#Example
217
218#Description
219Passes a placeholder to a function that requires one.
220##
221
222#Function
223// Returns true if either the canvas rotates the text by 90 degrees, or the paint does.
224static void check_for_up_and_down_text(const SkCanvas* canvas, const SkPaint& paint) {
225    bool paintHasVertical = paint.isVerticalText();
226    const SkMatrix& matrix = canvas->getTotalMatrix();
227    bool matrixIsVertical = matrix.preservesRightAngles() && !matrix.isScaleTranslate();
228    SkDebugf("paint draws text %s\n", paintHasVertical != matrixIsVertical ?
229            "top to bottom" : "left to right");
230}
231
232static void check_for_up_and_down_text(const SkPaint& paint) {
233    SkCanvas canvas;  // placeholder only, does not have an associated device
234    check_for_up_and_down_text(&canvas, paint);
235}
236
237##
238void draw(SkCanvas* canvas) {
239    SkPaint paint;
240    check_for_up_and_down_text(paint);  // paint draws text left to right
241    paint.setVerticalText(true);
242    check_for_up_and_down_text(paint);  // paint draws text top to bottom
243    paint.setVerticalText(false);
244    canvas->rotate(90);
245    check_for_up_and_down_text(canvas, paint);  // paint draws text top to bottom
246}
247
248    #StdOut
249        paint draws text left to right
250        paint draws text top to bottom
251        paint draws text top to bottom
252    ##
253##
254
255#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas
256
257##
258
259# ------------------------------------------------------------------------------
260
261#Method SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr)
262
263#Line # no Surface, set dimensions, Surface_Properties ##
264Creates Canvas of the specified dimensions without a Surface.
265Used by Subclasses with custom implementations for draw methods.
266
267If props equals nullptr, Surface_Properties are created with
268Surface_Properties_Legacy_Font_Host settings, which choose the pixel striping 
269direction and order. Since a platform may dynamically change its direction when
270the device is rotated, and since a platform may have multiple monitors with
271different characteristics, it is best not to rely on this legacy behavior.
272
273#Param width  zero or greater ##
274#Param height zero or greater ##
275#Param props  LCD striping orientation and setting for device independent fonts;
276              may be nullptr
277##
278
279#Return       Canvas placeholder with dimensions ##
280
281#Example
282    SkCanvas canvas(10, 20);  // 10 units wide, 20 units high
283    canvas.clipRect(SkRect::MakeXYWH(30, 40, 5, 10));  // clip is outside canvas' device
284    SkDebugf("canvas %s empty\n", canvas.getDeviceClipBounds().isEmpty() ? "is" : "is not");
285
286    #StdOut
287        canvas is empty
288    ##
289##
290
291#SeeAlso MakeRasterDirect SkSurfaceProps SkPixelGeometry SkCreateColorSpaceXformCanvas
292
293##
294
295# ------------------------------------------------------------------------------
296
297#Method explicit SkCanvas(SkBaseDevice* device)
298#Deprecated soon
299##
300
301# ------------------------------------------------------------------------------
302
303#Method explicit SkCanvas(const SkBitmap& bitmap)
304
305#Line # uses existing Bitmap ##
306Construct a canvas that draws into bitmap.
307Sets SkSurfaceProps::kLegacyFontHost_InitType in constructed Surface. 
308
309Bitmap is copied so that subsequently editing bitmap will not affect
310constructed Canvas.
311
312May be deprecated in the future.
313
314#ToDo Should be deprecated? ##
315
316#Param bitmap   width, height, Color_Type, Alpha_Type, and pixel
317                storage of Raster_Surface
318##
319
320#Return         Canvas that can be used to draw into bitmap ##
321
322#Example
323#Description
324The actual output depends on the installed fonts.
325##
326    SkBitmap bitmap;
327    // create a bitmap 5 wide and 11 high
328    bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11));
329    SkCanvas canvas(bitmap);
330    canvas.clear(SK_ColorWHITE);  // white is Unpremultiplied, in ARGB order
331    SkPixmap pixmap;  // provides guaranteed access to the drawn pixels
332    if (!canvas.peekPixels(&pixmap)) {
333        SkDebugf("peekPixels should never fail.\n");
334    }
335    const SkPMColor* pixels = pixmap.addr32();  // points to top-left of bitmap
336    SkPMColor pmWhite = pixels[0];  // the Premultiplied format may vary
337    SkPaint paint;  // by default, draws black, 12 point text
338    canvas.drawString("!", 1, 10, paint);  // 1 char at baseline (1, 10)
339    for (int y = 0; y < bitmap.height(); ++y) {
340        for (int x = 0; x < bitmap.width(); ++x) {
341            SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
342        }
343        SkDebugf("\n");
344    }
345
346    #StdOut
347    -----
348    ---x-
349    ---x-
350    ---x-
351    ---x-
352    ---x-
353    ---x-
354    -----
355    ---x-
356    ---x-
357    -----
358    #StdOut ##
359##
360
361#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas
362
363##
364
365#EnumClass ColorBehavior
366#Line # Android framework only ##
367#Private
368Android framework only.
369##
370
371#Code
372    enum class ColorBehavior {
373        kLegacy,
374    };
375##
376#Const kLegacy 0
377    Is a placeholder to allow specialized constructor; has no meaning.
378##
379##
380
381#Method SkCanvas(const SkBitmap& bitmap, ColorBehavior behavior)
382
383#Line # Android framework only ##
384#Private
385Android framework only.
386##
387
388#Param bitmap    specifies a bitmap for the canvas to draw into ##
389#Param behavior  specializes this constructor; value is unused ##
390#Return          Canvas that can be used to draw into bitmap ##
391
392#NoExample
393##
394##
395
396# ------------------------------------------------------------------------------
397
398#Method SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
399
400#Line # uses existing Bitmap and Surface_Properties ##
401Construct a canvas that draws into bitmap.
402Use props to match the device characteristics, like LCD striping.
403
404bitmap is copied so that subsequently editing bitmap will not affect
405constructed Canvas.
406
407#Param bitmap   width, height, Color_Type, Alpha_Type,
408                and pixel storage of Raster_Surface 
409##
410#Param props    order and orientation of RGB striping; and whether to use
411                device independent fonts
412##
413
414#Return         Canvas that can be used to draw into bitmap ##
415
416#Example
417#Description
418The actual output depends on the installed fonts.
419##
420    SkBitmap bitmap;
421    // create a bitmap 5 wide and 11 high
422    bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11));
423    SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry));
424    canvas.clear(SK_ColorWHITE);  // white is Unpremultiplied, in ARGB order
425    SkPixmap pixmap;  // provides guaranteed access to the drawn pixels
426    if (!canvas.peekPixels(&pixmap)) {
427        SkDebugf("peekPixels should never fail.\n");
428    }
429    const SkPMColor* pixels = pixmap.addr32();  // points to top-left of bitmap
430    SkPMColor pmWhite = pixels[0];  // the Premultiplied format may vary
431    SkPaint paint;  // by default, draws black, 12 point text
432    canvas.drawString("!", 1, 10, paint);  // 1 char at baseline (1, 10)
433    for (int y = 0; y < bitmap.height(); ++y) {
434        for (int x = 0; x < bitmap.width(); ++x) {
435            SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
436        }
437        SkDebugf("\n");
438    }
439
440    #StdOut
441    -----
442    ---x-
443    ---x-
444    ---x-
445    ---x-
446    ---x-
447    ---x-
448    -----
449    ---x-
450    ---x-
451    -----
452    #StdOut ##
453##
454
455#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas
456
457##
458
459# ------------------------------------------------------------------------------
460
461#Method virtual ~SkCanvas()
462
463#Line # draws saved Layers, frees resources ##
464Draws saved Layers, if any.
465Frees up resources used by Canvas.
466
467#Example
468#Description
469Canvas Layer draws into bitmap. saveLayerAlpha sets up an additional
470drawing surface that blends with the bitmap. When Layer goes out of
471scope, Layer Destructor is called. The saved Layer is restored, drawing
472transparent letters.
473##
474void draw(SkCanvas* canvas) {
475    SkBitmap bitmap;
476    bitmap.allocPixels(SkImageInfo::MakeN32Premul(200, 200));
477    {
478        SkCanvas offscreen(bitmap);
479        SkPaint paint;
480        paint.setTextSize(100);
481        offscreen.drawString("ABC", 20, 160, paint);
482        SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192);
483        offscreen.saveLayerAlpha(&layerBounds, 128);
484        offscreen.clear(SK_ColorWHITE);
485        offscreen.drawString("DEF", 20, 160, paint);
486    }
487    canvas->drawBitmap(bitmap, 0, 0, nullptr);
488}
489##
490
491#SeeAlso State_Stack
492
493##
494
495# ------------------------------------------------------------------------------
496
497#Method SkMetaData& getMetaData()
498
499#Line # associates additional data with the canvas ##
500Returns storage to associate additional data with the canvas.
501The storage is freed when Canvas is deleted.
502
503#Return  storage that can be read from and written to ##
504
505#Example
506    const char* kHelloMetaData = "HelloMetaData";
507    SkCanvas canvas;
508    SkMetaData& metaData = canvas.getMetaData();
509    SkDebugf("before: %s\n", metaData.findString(kHelloMetaData));
510    metaData.setString(kHelloMetaData, "Hello!");
511    SkDebugf("during: %s\n", metaData.findString(kHelloMetaData));
512    metaData.removeString(kHelloMetaData);
513    SkDebugf("after: %s\n", metaData.findString(kHelloMetaData));
514
515    #StdOut
516        before: (null)
517        during: Hello!
518        after: (null)
519    #StdOut ##
520##
521
522#SeeAlso SkMetaData
523
524##
525
526# ------------------------------------------------------------------------------
527
528#Method SkImageInfo imageInfo() const
529
530#Line # returns Image_Info for Canvas ##
531Returns Image_Info for Canvas. If Canvas is not associated with Raster_Surface or
532GPU_Surface, returned Color_Type is set to kUnknown_SkColorType.
533
534#Return  dimensions and Color_Type of Canvas ##
535
536#Example
537    SkCanvas emptyCanvas;
538    SkImageInfo canvasInfo = emptyCanvas.imageInfo();
539    SkImageInfo emptyInfo;
540    SkDebugf("emptyInfo %c= canvasInfo\n", emptyInfo == canvasInfo ? '=' : '!');
541
542    #StdOut
543        emptyInfo == canvasInfo
544    ##
545##
546
547#SeeAlso SkImageInfo MakeRasterDirect makeSurface
548
549##
550
551# ------------------------------------------------------------------------------
552
553#Method bool getProps(SkSurfaceProps* props) const
554
555#Line # copies Surface_Properties if available ##
556If Canvas is associated with Raster_Surface or
557GPU_Surface, copies Surface_Properties and returns true. Otherwise,
558return false and leave props unchanged.
559
560#Param props  storage for writable SkSurfaceProps ##
561
562#Return  true if Surface_Properties was copied ##
563
564#ToDo This seems old style. Deprecate? ##
565
566#Example
567    SkBitmap bitmap;
568    SkCanvas canvas(bitmap, SkSurfaceProps(0, kRGB_V_SkPixelGeometry));
569    SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
570    SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry()));
571    if (!canvas.getProps(&surfaceProps)) {
572        SkDebugf("getProps failed unexpectedly.\n");
573    }
574    SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry()));
575
576    #StdOut
577        isRGB:0
578        isRGB:1
579    #StdOut ##
580##
581
582#SeeAlso SkSurfaceProps makeSurface
583
584##
585
586# ------------------------------------------------------------------------------
587
588#Method void flush()
589
590#Line # triggers execution of all pending draw operations ##
591Triggers the immediate execution of all pending draw operations. 
592If Canvas is associated with GPU_Surface, resolves all pending GPU operations.
593If Canvas is associated with Raster_Surface, has no effect; raster draw
594operations are never deferred.
595
596#ToDo
597In an overview section on managing the GPU, include:
598- flush should never change what is drawn
599- call to kick off gpu work
600- calling too much impacts performance
601- some calls (peekPixels, prepareForExternalIO) call it internally
602- canvas call is local, GrContext::flush is global
603- diffentiate between flush, flushAndSignalSemaphores
604- normally never needs to be called
605- call it when sharing gpu resources, feeling memory pressure, swapping out app, and before
606  abandoning context
607- also call to say "I'm finished drawing here", e.g., when drawing to a GPU-backed offscreen surface
608  (created with SkSurface::MakeRenderTarget)
609
610for posterity: this doesn't show a difference: fiddle.skia.org/c/@flushfail
611##
612
613#ToDo haven't thought of a useful example to put here ##
614#NoExample
615##
616
617#SeeAlso peekPixels SkSurface::flush() GrContext::flush() SkSurface::prepareForExternalIO GrContext::abandonContext()
618
619##
620
621# ------------------------------------------------------------------------------
622
623#Method virtual SkISize getBaseLayerSize() const
624
625#Line # returns size of base Layer in global coordinates ##
626Gets the size of the base or root Layer in global canvas coordinates. The
627origin of the base Layer is always (0,0). The area available for drawing may be
628smaller (due to clipping or saveLayer).
629
630#Return  integral width and height of base Layer ##
631
632#Example
633    SkBitmap bitmap;
634    bitmap.allocPixels(SkImageInfo::MakeN32Premul(20, 30));
635    SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry));
636    canvas.clipRect(SkRect::MakeWH(10, 40));
637    SkIRect clipDeviceBounds = canvas.getDeviceClipBounds();
638    if (clipDeviceBounds.isEmpty()) {
639        SkDebugf("Empty clip bounds is unexpected!\n");
640    }
641    SkDebugf("clip=%d,%d\n", clipDeviceBounds.width(), clipDeviceBounds.height());
642    SkISize baseLayerSize = canvas.getBaseLayerSize();
643    SkDebugf("size=%d,%d\n", baseLayerSize.width(), baseLayerSize.height());
644
645    #StdOut
646        clip=10,30
647        size=20,30
648    ##
649##
650
651#ToDo is this the same as the width and height of surface? ##
652
653#SeeAlso getDeviceClipBounds
654
655##
656
657# ------------------------------------------------------------------------------
658
659#Method sk_sp<SkSurface> makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr)
660#In Constructor
661#Line # creates Surface matching SkImageInfo and SkSurfaceProps ##
662Creates Surface matching info and props, and associates it with Canvas.
663Returns nullptr if no match found.
664
665If props is nullptr, matches Surface_Properties in Canvas. If props is nullptr and Canvas
666does not have Surface_Properties, creates Surface with default Surface_Properties.
667
668#Param info  width, height, Color_Type, Alpha_Type, and Color_Space ##
669#Param props  Surface_Properties to match; may be nullptr to match Canvas ##
670
671#Return  Surface matching info and props, or nullptr if no match is available ##
672
673#Example
674    sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(5, 6);
675    SkCanvas* smallCanvas = surface->getCanvas();
676    SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(3, 4);
677    sk_sp<SkSurface> compatible = smallCanvas->makeSurface(imageInfo);
678    SkDebugf("compatible %c= nullptr\n", compatible == nullptr ? '=' : '!');
679    SkDebugf("size = %d, %d\n", compatible->width(), compatible->height());
680
681    #StdOut
682        compatible != nullptr
683        size = 3, 4
684    ##
685##
686
687#SeeAlso SkSurface SkSurface::makeSurface SkImageInfo SkSurfaceProps
688
689##
690
691# ------------------------------------------------------------------------------
692
693#Method virtual GrContext* getGrContext()
694
695#Line # returns GPU_Context of the GPU_Surface ##
696Returns GPU_Context of the GPU_Surface associated with Canvas.
697
698#Return GPU_Context, if available; nullptr otherwise ##
699
700#Example
701void draw(SkCanvas* canvas) {
702    if (canvas->getGrContext()) {
703         canvas->clear(SK_ColorRED);
704    } else {
705         canvas->clear(SK_ColorBLUE);
706    }
707}
708##
709
710#ToDo fiddle should show both CPU and GPU out ##
711
712#SeeAlso GrContext 
713
714##
715
716# ------------------------------------------------------------------------------
717
718#Method void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr)
719
720#Line # returns writable pixel access if available ##
721Returns the pixel base address, Image_Info, rowBytes, and origin if the pixels
722can be read directly. The returned address is only valid
723while Canvas is in scope and unchanged. Any Canvas call or Surface call
724may invalidate the returned address and other returned values.
725
726If pixels are inaccessible, info, rowBytes, and origin are unchanged.
727
728#Param info      storage for writable pixels' Image_Info; may be nullptr ##
729#Param rowBytes  storage for writable pixels' row bytes; may be nullptr ##
730#Param origin    storage for Canvas top Layer origin, its top-left corner;
731                 may be nullptr
732##
733
734#Return  address of pixels, or nullptr if inaccessible ##
735
736#Example
737void draw(SkCanvas* canvas) {
738    if (canvas->accessTopLayerPixels(nullptr, nullptr)) {
739         canvas->clear(SK_ColorRED);
740    } else {
741         canvas->clear(SK_ColorBLUE);
742    }
743}
744##
745
746#Example
747#Description
748Draws "ABC" on the device. Then draws "DEF" in Layer, and reads
749Layer to add a large dotted "DEF". Finally blends Layer with the
750device. 
751
752The Layer and blended result appear on the CPU and GPU but the large dotted
753"DEF" appear only on the CPU.
754##
755void draw(SkCanvas* canvas) {
756  SkPaint paint;
757  paint.setTextSize(100);
758  canvas->drawString("ABC", 20, 160, paint);
759  SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192);
760  canvas->saveLayerAlpha(&layerBounds, 128);
761  canvas->clear(SK_ColorWHITE);
762  canvas->drawString("DEF", 20, 160, paint);
763  SkImageInfo imageInfo;
764  size_t rowBytes;
765  SkIPoint origin;
766  uint32_t* access = (uint32_t*) canvas->accessTopLayerPixels(&imageInfo, &rowBytes, &origin);
767  if (access) {
768    int h = imageInfo.height();
769    int v = imageInfo.width();
770    int rowWords = rowBytes / sizeof(uint32_t);
771    for (int y = 0; y < h; ++y) {
772        int newY = (y - h / 2) * 2 + h / 2;
773        if (newY < 0 || newY >= h) {
774            continue;
775        }
776        for (int x = 0; x < v; ++x) {
777            int newX = (x - v / 2) * 2 + v / 2;
778            if (newX < 0 || newX >= v) {
779                continue;
780            }
781            if (access[y * rowWords + x] == SK_ColorBLACK) {
782                access[newY * rowWords + newX] = SK_ColorGRAY;
783            }
784        }
785    }
786
787  }
788  canvas->restore();
789}
790##
791
792#ToDo there are no callers of this that I can find. Deprecate? ##
793#ToDo fiddle should show both CPU and GPU out ##
794
795#SeeAlso SkImageInfo SkPixmap
796
797##
798
799# ------------------------------------------------------------------------------
800
801#Method SkRasterHandleAllocator::Handle accessTopRasterHandle() const
802
803#Line # returns context that tracks Clip and Matrix ##
804Returns custom context that tracks the Matrix and Clip.
805
806Use Raster_Handle_Allocator to blend Skia drawing with custom drawing, typically performed
807by the host platform user interface. The custom context returned is generated by
808SkRasterHandleAllocator::MakeCanvas, which creates a custom canvas with raster storage for
809the drawing destination.
810
811#Return  context of custom allocation ##
812
813#Example
814#Description
815#ToDo ##
816##
817#Function
818    static void DeleteCallback(void*, void* context) {
819        delete (char*) context;
820    }
821
822    class CustomAllocator : public SkRasterHandleAllocator {
823    public:
824        bool allocHandle(const SkImageInfo& info, Rec* rec) override {
825            char* context = new char[4]{'s', 'k', 'i', 'a'};
826            rec->fReleaseProc = DeleteCallback;
827            rec->fReleaseCtx = context;
828            rec->fHandle = context;
829            rec->fPixels = context;
830            rec->fRowBytes = 4;
831            return true;
832        }
833
834        void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override {
835            // apply canvas matrix and clip to custom environment
836        }
837    };
838
839##
840    void draw(SkCanvas* canvas) {
841        const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
842        std::unique_ptr<SkCanvas> c2 =
843                SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<CustomAllocator>(
844                new CustomAllocator()), info);
845        char* context = (char*) c2->accessTopRasterHandle();
846        SkDebugf("context = %.4s\n", context);
847
848    }
849    #StdOut
850        context = skia
851    ##
852    #ToDo skstd::make_unique could not be used because def is private -- note to fix in c++14? ##
853##
854
855#SeeAlso SkRasterHandleAllocator
856
857##
858
859# ------------------------------------------------------------------------------
860
861#Method bool peekPixels(SkPixmap* pixmap)
862
863#Line # returns if Canvas has direct access to its pixels ##
864Returns true if Canvas has direct access to its pixels.
865
866Pixels are readable when Device is raster. Pixels are not readable when Canvas
867is returned from GPU_Surface, returned by SkDocument::beginPage, returned by
868SkPictureRecorder::beginRecording, or Canvas is the base of a utility class
869like SkDumpCanvas.
870
871pixmap is valid only while Canvas is in scope and unchanged. Any
872Canvas or Surface call may invalidate the pixmap values.
873
874#Param pixmap  storage for pixel state if pixels are readable; otherwise, ignored ##
875
876#Return  true if Canvas has direct access to pixels ##
877
878#Example
879    SkPixmap pixmap;
880    if (canvas->peekPixels(&pixmap)) {
881        SkDebugf("width=%d height=%d\n", pixmap.bounds().width(), pixmap.bounds().height());
882    }
883    #StdOut
884        width=256 height=256
885    ##
886##
887
888#SeeAlso readPixels SkBitmap::peekPixels SkImage::peekPixels SkSurface::peekPixels
889
890##
891
892# ------------------------------------------------------------------------------
893
894#Method bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
895                    int srcX, int srcY)
896#Line # copies and converts rectangle of pixels from Canvas ##
897
898Copies Rect of pixels from Canvas into dstPixels. Matrix and Clip are
899ignored. 
900
901Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
902Destination Rect corners are (0, 0) and (dstInfo.width(), dstInfo.height()).
903Copies each readable pixel intersecting both rectangles, without scaling,
904converting to dstInfo.colorType() and dstInfo.alphaType() if required.
905
906Pixels are readable when Device is raster, or backed by a GPU.
907Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
908returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
909class like SkDumpCanvas.
910
911The destination pixel storage must be allocated by the caller.
912
913Pixel values are converted only if Color_Type and Alpha_Type
914do not match. Only pixels within both source and destination rectangles
915are copied. dstPixels contents outside Rect intersection are unchanged.
916
917Pass negative values for srcX or srcY to offset pixels across or down destination.
918
919Does not copy, and returns false if:
920
921#List
922# Source and destination rectangles do not intersect. ##
923# Canvas pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). ##
924# Canvas pixels are not readable; for instance, Canvas is document-based. ##
925# dstRowBytes is too small to contain one row of pixels. ##
926##
927
928#Param dstInfo  width, height, Color_Type, and Alpha_Type of dstPixels ##
929#Param dstPixels  storage for pixels; dstInfo.height() times dstRowBytes, or larger ##
930#Param dstRowBytes  size of one destination row; dstInfo.width() times pixel size, or larger ##
931#Param srcX  offset into readable pixels in x; may be negative ##
932#Param srcY  offset into readable pixels in y; may be negative ##
933
934#Return  true if pixels were copied ##
935
936#Example
937#Width 64
938#Height 64
939#Description
940    A black circle drawn on a blue background provides an image to copy.
941    readPixels copies one quarter of the canvas into each of the four corners.
942    The copied quarter circles overdraw the original circle.
943##
944    canvas->clear(SK_ColorBLUE);
945    SkPaint paint;
946    canvas->drawCircle(32, 32, 28, paint);
947    SkImageInfo info = SkImageInfo::Make(64, 64, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
948    sk_sp<SkData> data(SkData::MakeUninitialized(info.minRowBytes() * info.height()));
949    sk_bzero(data->writable_data(), info.minRowBytes() * info.height());
950    for (int x : { 32, -32 } ) {
951        for (int y : { 32, -32 } ) {
952            canvas->readPixels(info, data->writable_data(), info.minRowBytes(), x, y);
953        } 
954    }
955    sk_sp<SkImage> image = SkImage::MakeRasterData(info, data, info.minRowBytes());
956    canvas->drawImage(image, 0, 0);
957##
958
959#Example
960#Description
961    Canvas returned by Raster_Surface has Premultiplied pixel values.
962    clear() takes Unpremultiplied input with Color_Alpha equal 0x80
963    and Color_RGB equal 0x55, 0xAA, 0xFF. Color_RGB is multiplied by Color_Alpha
964    to generate Premultiplied value 0x802B5580. readPixels converts pixel back
965    to Unpremultiplied value 0x8056A9FF, introducing error.
966##
967    canvas->clear(0x8055aaff);
968    for (SkAlphaType alphaType : { kPremul_SkAlphaType, kUnpremul_SkAlphaType } ) {
969        uint32_t pixel = 0;
970        SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, alphaType);
971        if (canvas->readPixels(info, &pixel, 4, 0, 0)) {
972            SkDebugf("pixel = %08x\n", pixel);
973        }
974    }
975
976    #StdOut
977        pixel = 802b5580
978        pixel = 8056a9ff
979    ##
980##
981
982#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels
983
984##
985
986# ------------------------------------------------------------------------------
987
988#Method bool readPixels(const SkPixmap& pixmap, int srcX, int srcY)
989
990Copies Rect of pixels from Canvas into pixmap. Matrix and Clip are
991ignored.
992
993Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
994Destination Rect corners are (0, 0) and (pixmap.width(), pixmap.height()).
995Copies each readable pixel intersecting both rectangles, without scaling,
996converting to pixmap.colorType() and pixmap.alphaType() if required.
997
998Pixels are readable when Device is raster, or backed by a GPU.
999Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
1000returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
1001class like SkDumpCanvas.
1002
1003Caller must allocate pixel storage in pixmap if needed.
1004
1005Pixel values are converted only if Color_Type and Alpha_Type
1006do not match. Only pixels within both source and destination Rects
1007are copied. pixmap pixels contents outside Rect intersection are unchanged.
1008
1009Pass negative values for srcX or srcY to offset pixels across or down pixmap.
1010
1011Does not copy, and returns false if:
1012
1013#List
1014# Source and destination rectangles do not intersect. ##
1015# Canvas pixels could not be converted to pixmap.colorType() or pixmap.alphaType(). ##
1016# Canvas pixels are not readable; for instance, Canvas is document-based. ##
1017# Pixmap pixels could not be allocated. ##
1018# pixmap.rowBytes() is too small to contain one row of pixels. ##
1019##
1020
1021#Param pixmap  storage for pixels copied from Canvas ##
1022#Param srcX    offset into readable pixels in x; may be negative ##
1023#Param srcY    offset into readable pixels in y; may be negative ##
1024
1025#Return  true if pixels were copied ##
1026
1027#Example
1028    #Description
1029        clear() takes Unpremultiplied input with Color_Alpha equal 0x80
1030        and Color_RGB equal 0x55, 0xAA, 0xFF. Color_RGB is multiplied by Color_Alpha
1031        to generate Premultiplied value 0x802B5580.
1032    ##
1033    void draw(SkCanvas* canvas) {
1034        canvas->clear(0x8055aaff);
1035        uint32_t pixels[1] = { 0 };
1036        SkPixmap pixmap(SkImageInfo::MakeN32Premul(1, 1), pixels, 4);
1037        canvas->readPixels(pixmap, 0, 0);
1038        SkDebugf("pixel = %08x\n", pixels[0]);
1039    }
1040    #StdOut
1041        pixel = 802b5580
1042    ##
1043##
1044
1045#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels
1046
1047##
1048
1049# ------------------------------------------------------------------------------
1050
1051#Method bool readPixels(const SkBitmap& bitmap, int srcX, int srcY)
1052
1053Copies Rect of pixels from Canvas into bitmap. Matrix and Clip are
1054ignored.
1055
1056Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
1057Destination Rect corners are (0, 0) and (bitmap.width(), bitmap.height()).
1058Copies each readable pixel intersecting both rectangles, without scaling,
1059converting to bitmap.colorType() and bitmap.alphaType() if required.
1060
1061Pixels are readable when Device is raster, or backed by a GPU.
1062Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
1063returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
1064class like SkDumpCanvas.
1065
1066Caller must allocate pixel storage in bitmap if needed.
1067
1068Bitmap values are converted only if Color_Type and Alpha_Type
1069do not match. Only pixels within both source and destination rectangles
1070are copied. Bitmap pixels outside Rect intersection are unchanged.
1071
1072Pass negative values for srcX or srcY to offset pixels across or down bitmap.
1073
1074Does not copy, and returns false if:
1075
1076#List
1077# Source and destination rectangles do not intersect. ##
1078# Canvas pixels could not be converted to bitmap.colorType() or bitmap.alphaType(). ##
1079# Canvas pixels are not readable; for instance, Canvas is document-based. ##
1080# bitmap pixels could not be allocated. ##
1081# bitmap.rowBytes() is too small to contain one row of pixels. ##
1082##
1083
1084#Param bitmap  storage for pixels copied from Canvas ##
1085#Param srcX    offset into readable pixels in x; may be negative ##
1086#Param srcY    offset into readable pixels in y; may be negative ##
1087
1088#Return  true if pixels were copied ##
1089
1090#Example
1091    #Description
1092        clear() takes Unpremultiplied input with Color_Alpha equal 0x80
1093        and Color_RGB equal 0x55, 0xAA, 0xFF. Color_RGB is multiplied by Color_Alpha
1094        to generate Premultiplied value 0x802B5580.
1095    ##
1096void draw(SkCanvas* canvas) {
1097    canvas->clear(0x8055aaff);
1098    SkBitmap bitmap;
1099    bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
1100    canvas->readPixels(bitmap, 0, 0);
1101    SkDebugf("pixel = %08x\n", bitmap.getAddr32(0, 0)[0]);
1102}
1103    #StdOut
1104        pixel = 802b5580
1105    ##
1106##
1107
1108#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels
1109
1110##
1111
1112# ------------------------------------------------------------------------------
1113
1114#Method bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y)
1115
1116#Line # copies and converts rectangle of pixels to Canvas ##
1117Copies Rect from pixels to Canvas. Matrix and Clip are ignored.
1118Source Rect corners are (0, 0) and (info.width(), info.height()).
1119Destination Rect corners are (x, y) and
1120(imageInfo().width(), imageInfo().height()).
1121
1122Copies each readable pixel intersecting both rectangles, without scaling,
1123converting to imageInfo().colorType() and imageInfo().alphaType() if required.
1124
1125Pixels are writable when Device is raster, or backed by a GPU.
1126Pixels are not writable when SkCanvas is returned by SkDocument::beginPage,
1127returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
1128class like SkDumpCanvas.
1129
1130Pixel values are converted only if Color_Type and Alpha_Type
1131do not match. Only pixels within both source and destination rectangles
1132are copied. Canvas pixels outside Rect intersection are unchanged.
1133
1134Pass negative values for x or y to offset pixels to the left or
1135above Canvas pixels.
1136
1137Does not copy, and returns false if:
1138
1139#List
1140# Source and destination rectangles do not intersect. ##
1141# pixels could not be converted to Canvas imageInfo().colorType() or
1142  imageInfo().alphaType(). ##
1143# Canvas pixels are not writable; for instance, Canvas is document-based. ##
1144# rowBytes is too small to contain one row of pixels. ##
1145##
1146
1147#Param info  width, height, Color_Type, and Alpha_Type of pixels ##
1148#Param pixels  pixels to copy, of size info.height() times rowBytes, or larger ##
1149#Param rowBytes  size of one row of pixels; info.width() times pixel size, or larger ##
1150#Param x  offset into Canvas writable pixels in x; may be negative ##
1151#Param y  offset into Canvas writable pixels in y; may be negative ##
1152
1153#Return  true if pixels were written to Canvas ##
1154
1155#Example
1156    SkImageInfo imageInfo = SkImageInfo::MakeN32(256, 1, kPremul_SkAlphaType);
1157    for (int y = 0; y < 256; ++y) {
1158        uint32_t pixels[256];
1159        for (int x = 0; x < 256; ++x) {
1160            pixels[x] = SkColorSetARGB(x, x + y, x, x - y);
1161        }
1162        canvas->writePixels(imageInfo, &pixels, sizeof(pixels), 0, y);
1163    }
1164##
1165
1166#SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels
1167
1168##
1169
1170# ------------------------------------------------------------------------------
1171
1172#Method bool writePixels(const SkBitmap& bitmap, int x, int y)
1173
1174Copies Rect from pixels to Canvas. Matrix and Clip are ignored.
1175Source Rect corners are (0, 0) and (bitmap.width(), bitmap.height()).
1176
1177Destination Rect corners are (x, y) and
1178(imageInfo().width(), imageInfo().height()).
1179
1180Copies each readable pixel intersecting both rectangles, without scaling,
1181converting to imageInfo().colorType() and imageInfo().alphaType() if required.
1182
1183Pixels are writable when Device is raster, or backed by a GPU.
1184Pixels are not writable when SkCanvas is returned by SkDocument::beginPage,
1185returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
1186class like SkDumpCanvas.
1187
1188Pixel values are converted only if Color_Type and Alpha_Type
1189do not match. Only pixels within both source and destination rectangles
1190are copied. Canvas pixels outside Rect intersection are unchanged.
1191
1192Pass negative values for x or y to offset pixels to the left or
1193above Canvas pixels.
1194
1195Does not copy, and returns false if:
1196
1197#List
1198# Source and destination rectangles do not intersect. ##
1199# bitmap does not have allocated pixels. ##
1200# bitmap pixels could not be converted to Canvas imageInfo().colorType() or
1201  imageInfo().alphaType(). ##
1202# Canvas pixels are not writable; for instance, Canvas is document based. ##
1203# bitmap pixels are inaccessible; for instance, bitmap wraps a texture. ##
1204##
1205
1206#Param bitmap  contains pixels copied to Canvas ##
1207#Param x       offset into Canvas writable pixels in x; may be negative ##
1208#Param y       offset into Canvas writable pixels in y; may be negative ##
1209
1210#Return  true if pixels were written to Canvas ##
1211
1212#Example
1213void draw(SkCanvas* canvas) {
1214    SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(2, 2);
1215    SkBitmap bitmap;
1216    bitmap.setInfo(imageInfo);
1217    uint32_t pixels[4];
1218    bitmap.setPixels(pixels);
1219    for (int y = 0; y < 256; y += 2) {
1220        for (int x = 0; x < 256;  x += 2) {
1221            pixels[0] = SkColorSetRGB(x, y, x | y);
1222            pixels[1] = SkColorSetRGB(x ^ y, y, x);
1223            pixels[2] = SkColorSetRGB(x, x & y, y);
1224            pixels[3] = SkColorSetRGB(~x, ~y, x);
1225            canvas->writePixels(bitmap, x, y);
1226        }
1227    }
1228}
1229##
1230
1231#SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels
1232
1233##
1234
1235# ------------------------------------------------------------------------------
1236#Subtopic State_Stack
1237#Line # stack of state for hierarchical drawing ##
1238
1239Canvas maintains a stack of state that allows hierarchical drawing, commonly used
1240to implement windows and views. The initial state has an identity matrix and and
1241an infinite clip. Even with a wide-open clip, drawing is constrained by the
1242bounds of the Canvas Surface or Device.
1243
1244Canvas savable state consists of Clip, Matrix, and Draw_Filter.
1245Clip describes the area that may be drawn to.
1246Matrix transforms the geometry.
1247Draw_Filter (deprecated on most platforms) modifies the paint before drawing.
1248
1249save(), saveLayer, saveLayerPreserveLCDTextRequests, and saveLayerAlpha
1250save state and return the depth of the stack.
1251
1252restore(), restoreToCount, and ~SkCanvas() revert state to its value when saved.
1253
1254Each state on the stack intersects Clip with the previous Clip,
1255and concatenates Matrix with the previous Matrix.
1256The intersected Clip makes the drawing area the same or smaller;
1257the concatenated Matrix may move the origin and potentially scale or rotate
1258the coordinate space.
1259
1260Canvas does not require balancing the state stack but it is a good idea
1261to do so. Calling save() without restore() will eventually cause Skia to fail;
1262mismatched save() and restore() create hard to find bugs.
1263
1264It is not possible to use state to draw outside of the clip defined by the
1265previous state.
1266
1267#Example
1268#Description
1269Draw to ever smaller clips; then restore drawing to full canvas.
1270Note that the second clipRect is not permitted to enlarge Clip.
1271##
1272#Height 160
1273void draw(SkCanvas* canvas) {
1274    SkPaint paint;
1275    canvas->save();                             // records stack depth to restore  
1276    canvas->clipRect(SkRect::MakeWH(100, 100)); // constrains drawing to clip
1277    canvas->clear(SK_ColorRED);                 // draws to limit of clip
1278    canvas->save();                             // records stack depth to restore 
1279    canvas->clipRect(SkRect::MakeWH(50, 150));  // Rect below 100 is ignored
1280    canvas->clear(SK_ColorBLUE);                // draws to smaller clip
1281    canvas->restore();                          // enlarges clip
1282    canvas->drawLine(20, 20, 150, 150, paint);  // line below 100 is not drawn
1283    canvas->restore();                          // enlarges clip
1284    canvas->drawLine(150, 20, 50, 120, paint);  // line below 100 is drawn
1285}
1286## 
1287
1288Each Clip uses the current Matrix for its coordinates.
1289
1290#Example
1291#Description
1292While clipRect is given the same rectangle twice, Matrix makes the second
1293clipRect draw at half the size of the first.
1294##
1295#Height 128
1296void draw(SkCanvas* canvas) {
1297    canvas->clipRect(SkRect::MakeWH(100, 100));
1298    canvas->clear(SK_ColorRED);
1299    canvas->scale(.5, .5);
1300    canvas->clipRect(SkRect::MakeWH(100, 100));
1301    canvas->clear(SK_ColorBLUE);
1302}
1303##
1304
1305#SeeAlso save() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha restore() restoreToCount
1306
1307#Method int save()
1308
1309#In State_Stack
1310#Line # saves Clip and Matrix on stack ##
1311Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms).
1312Calling restore() discards changes to Matrix, Clip, and Draw_Filter,
1313restoring the Matrix, Clip, and Draw_Filter to their state when save() was called.
1314
1315Matrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix,
1316and resetMatrix. Clip may be changed by clipRect, clipRRect, clipPath, clipRegion.
1317
1318Saved Canvas state is put on a stack; multiple calls to save() should be balance
1319by an equal number of calls to restore().
1320
1321Call restoreToCount with result to restore this and subsequent saves.
1322
1323#Return depth of saved stack ##
1324
1325#Example
1326#Description 
1327The black square is translated 50 pixels down and to the right.
1328Restoring Canvas state removes translate() from Canvas stack;
1329the red square is not translated, and is drawn at the origin.
1330##
1331#Height 100
1332void draw(SkCanvas* canvas) {
1333    SkPaint paint;
1334    SkRect rect = { 0, 0, 25, 25 };
1335    canvas->drawRect(rect, paint);
1336    canvas->save();
1337    canvas->translate(50, 50);
1338    canvas->drawRect(rect, paint);
1339    canvas->restore();
1340    paint.setColor(SK_ColorRED);
1341    canvas->drawRect(rect, paint);
1342}
1343##
1344
1345#SeeAlso saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha restore() restoreToCount
1346
1347##
1348
1349# ------------------------------------------------------------------------------
1350
1351#Method void restore()
1352
1353#In State_Stack
1354#Line # restores changes to Clip and Matrix, pops save stack ##
1355Removes changes to Matrix, Clip, and Draw_Filter since Canvas state was
1356last saved. The state is removed from the stack. 
1357
1358Does nothing if the stack is empty. 
1359
1360#Example
1361void draw(SkCanvas* canvas) {
1362    SkCanvas simple;
1363    SkDebugf("depth = %d\n", simple.getSaveCount());
1364    simple.restore();
1365    SkDebugf("depth = %d\n", simple.getSaveCount());
1366}
1367##
1368
1369#SeeAlso save() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha restoreToCount
1370
1371##
1372
1373# ------------------------------------------------------------------------------
1374
1375#Method int getSaveCount() const
1376
1377#In State_Stack
1378#Line # returns depth of stack containing Clip and Matrix ##
1379Returns the number of saved states, each containing: Matrix, Clip, and Draw_Filter.
1380Equals the number of save() calls less the number of restore() calls plus one. 
1381The save count of a new canvas is one.
1382
1383#Return  depth of save state stack ##
1384
1385#Example
1386void draw(SkCanvas* canvas) {
1387    SkCanvas simple;
1388    SkDebugf("depth = %d\n", simple.getSaveCount());
1389    simple.save();
1390    SkDebugf("depth = %d\n", simple.getSaveCount());
1391    simple.restore();
1392    SkDebugf("depth = %d\n", simple.getSaveCount());
1393}
1394#StdOut
1395depth = 1
1396depth = 2
1397depth = 1
1398##
1399##
1400
1401#SeeAlso save() restore() restoreToCount
1402
1403##
1404
1405# ------------------------------------------------------------------------------
1406
1407#Method void restoreToCount(int saveCount)
1408
1409#In State_Stack
1410#Line # restores changes to Clip and Matrix to given depth ##
1411Restores state to Matrix, Clip, and Draw_Filter values when save(), saveLayer,
1412saveLayerPreserveLCDTextRequests, or saveLayerAlpha returned saveCount.
1413
1414Does nothing if saveCount is greater than state stack count. 
1415Restores state to initial values if saveCount is less than or equal to one.
1416
1417#Param saveCount    depth of state stack to restore ##
1418
1419#Example
1420void draw(SkCanvas* canvas) {
1421    SkDebugf("depth = %d\n", canvas->getSaveCount());
1422    canvas->save();
1423    canvas->save();
1424    SkDebugf("depth = %d\n", canvas->getSaveCount());
1425    canvas->restoreToCount(0);
1426    SkDebugf("depth = %d\n", canvas->getSaveCount());
1427}
1428#StdOut
1429depth = 1
1430depth = 3
1431depth = 1
1432##
1433##
1434
1435#SeeAlso restore() getSaveCount save() 
1436
1437##
1438
1439#Subtopic State_Stack ##
1440
1441# ------------------------------------------------------------------------------
1442
1443#Subtopic Layer
1444#Substitute layer
1445#Alias Layers
1446#Line # temporary Bitmap to draw into ##
1447
1448Layer allocates a temporary Bitmap to draw into. When the drawing is
1449complete, the Bitmap is drawn into the Canvas. 
1450
1451Layer is saved in a stack along with other saved state. When state with a Layer
1452is restored, the Bitmap is drawn into the previous Layer.
1453
1454Layer may be initialized with the contents of the previous Layer. When Layer is
1455restored, its Bitmap can be modified by Paint passed to Layer to apply
1456Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode.
1457
1458#Method int saveLayer(const SkRect* bounds, const SkPaint* paint)
1459
1460#In Layer
1461#Line # saves Clip and Matrix on stack; creates Layer ##
1462Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms),
1463and allocates a Bitmap for subsequent drawing.
1464Calling restore() discards changes to Matrix, Clip, and Draw_Filter,
1465and draws the Bitmap.
1466
1467Matrix may be changed by translate(), scale(), rotate(), skew(), concat(),
1468setMatrix, and resetMatrix. Clip may be changed by clipRect, clipRRect, 
1469clipPath, clipRegion.
1470
1471Rect bounds suggests but does not define the Bitmap size. To clip drawing to
1472a specific rectangle, use clipRect.
1473
1474Optional Paint paint applies Color_Alpha, Color_Filter, Image_Filter, and
1475Blend_Mode when restore() is called.
1476
1477Call restoreToCount with returned value to restore this and subsequent saves.
1478
1479#Param bounds  hint to limit the size of the Layer; may be nullptr ##
1480#Param paint   graphics state for Layer; may be nullptr ##
1481
1482#Return        depth of saved stack ##
1483
1484#Example
1485#Description
1486Rectangles are blurred by Image_Filter when restore() draws Layer to main
1487Canvas.
1488##
1489#Height 128
1490void draw(SkCanvas* canvas) {
1491    SkPaint paint, blur;
1492    blur.setImageFilter(SkBlurImageFilter::Make(3, 3, nullptr));
1493    canvas->saveLayer(nullptr, &blur);
1494    SkRect rect = { 25, 25, 50, 50};
1495    canvas->drawRect(rect, paint);
1496    canvas->translate(50, 50);
1497    paint.setColor(SK_ColorRED);
1498    canvas->drawRect(rect, paint);
1499    canvas->restore();
1500}
1501##
1502
1503#SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha SaveLayerRec
1504
1505##
1506
1507#Method int saveLayer(const SkRect& bounds, const SkPaint* paint) 
1508
1509#In Layer
1510Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms),
1511and allocates a Bitmap for subsequent drawing.
1512Calling restore() discards changes to Matrix, Clip, and Draw_Filter,
1513and draws the Bitmap.
1514
1515Matrix may be changed by translate(), scale(), rotate(), skew(), concat(),
1516setMatrix, and resetMatrix. Clip may be changed by clipRect, clipRRect,
1517clipPath, clipRegion.
1518
1519Rect bounds suggests but does not define the Layer size. To clip drawing to
1520a specific rectangle, use clipRect.
1521
1522Optional Paint paint applies Color_Alpha, Color_Filter, Image_Filter, and
1523Blend_Mode when restore() is called.
1524
1525Call restoreToCount with returned value to restore this and subsequent saves.
1526
1527#Param bounds  hint to limit the size of Layer; may be nullptr ##
1528#Param paint   graphics state for Layer; may be nullptr ##
1529
1530#Return        depth of saved stack ##
1531
1532#Example
1533#Description
1534Rectangles are blurred by Image_Filter when restore() draws Layer to main Canvas.
1535The red rectangle is clipped; it does not fully fit on Layer. 
1536Image_Filter blurs past edge of Layer so red rectangle is blurred on all sides.
1537##
1538#Height 128
1539void draw(SkCanvas* canvas) {
1540    SkPaint paint, blur;
1541    blur.setImageFilter(SkBlurImageFilter::Make(3, 3, nullptr));
1542    canvas->saveLayer(SkRect::MakeWH(90, 90), &blur);
1543    SkRect rect = { 25, 25, 50, 50};
1544    canvas->drawRect(rect, paint);
1545    canvas->translate(50, 50);
1546    paint.setColor(SK_ColorRED);
1547    canvas->drawRect(rect, paint);
1548    canvas->restore();
1549}
1550##
1551
1552#SeeAlso save() restore() saveLayerPreserveLCDTextRequests saveLayerAlpha SaveLayerRec
1553
1554##
1555
1556#Method int saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint)
1557
1558#In Layer
1559#Line # saves Clip and Matrix on stack; creates Layer for LCD text ##
1560Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms),
1561and allocates a Bitmap for subsequent drawing.
1562LCD_Text is preserved when the Layer is drawn to the prior Layer.
1563
1564Calling restore() discards changes to Matrix, Clip, and Draw_Filter,
1565and draws Layer.
1566
1567Matrix may be changed by translate(), scale(), rotate(), skew(), concat(),
1568setMatrix, and resetMatrix. Clip may be changed by clipRect, clipRRect,
1569clipPath, clipRegion.
1570  
1571Rect bounds suggests but does not define the Layer size. To clip drawing to
1572a specific rectangle, use clipRect.
1573
1574Optional Paint paint applies Color_Alpha, Color_Filter, Image_Filter, and
1575Blend_Mode when restore() is called.
1576
1577Call restoreToCount with returned value to restore this and subsequent saves.
1578
1579Draw text on an opaque background so that LCD_Text blends correctly with the
1580prior Layer. LCD_Text drawn on a background with transparency may result in
1581incorrect blending.
1582
1583#Param bounds  hint to limit the size of Layer; may be nullptr ##
1584#Param paint   graphics state for Layer; may be nullptr ##
1585
1586#Return        depth of saved stack ##
1587
1588#Example
1589    SkPaint paint;
1590    paint.setAntiAlias(true);
1591    paint.setLCDRenderText(true);
1592    paint.setTextSize(20);
1593    for (auto preserve : { false, true } ) {
1594        preserve ? canvas->saveLayerPreserveLCDTextRequests(nullptr, nullptr)
1595                 : canvas->saveLayer(nullptr, nullptr);
1596        SkPaint p;
1597        p.setColor(SK_ColorWHITE);
1598        // Comment out the next line to draw on a non-opaque background.
1599        canvas->drawRect(SkRect::MakeLTRB(25, 40, 200, 70), p);
1600        canvas->drawString("Hamburgefons", 30, 60, paint);
1601
1602        p.setColor(0xFFCCCCCC);
1603        canvas->drawRect(SkRect::MakeLTRB(25, 70, 200, 100), p);
1604        canvas->drawString("Hamburgefons", 30, 90, paint);
1605
1606        canvas->restore();
1607        canvas->translate(0, 80);
1608    }
1609    ##
1610
1611#SeeAlso save() restore() saveLayer saveLayerAlpha SaveLayerRec
1612
1613##
1614
1615#Method int saveLayerAlpha(const SkRect* bounds, U8CPU alpha)
1616
1617#In Layer
1618#Line # saves Clip and Matrix on stack; creates Layer; sets opacity ##
1619Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms),
1620and allocates Bitmap for subsequent drawing.
1621
1622Calling restore() discards changes to Matrix, Clip, and Draw_Filter,
1623and blends Layer with alpha opacity onto prior Layer.
1624
1625Matrix may be changed by translate(), scale(), rotate(), skew(), concat(),
1626setMatrix, and resetMatrix. Clip may be changed by clipRect, clipRRect,
1627clipPath, clipRegion.
1628
1629Rect bounds suggests but does not define Layer size. To clip drawing to
1630a specific rectangle, use clipRect.
1631
1632alpha of zero is fully transparent, 255 is fully opaque.
1633
1634Call restoreToCount with returned value to restore this and subsequent saves.
1635
1636#Param bounds  hint to limit the size of Layer; may be nullptr ##
1637#Param alpha   opacity of Layer ##
1638
1639#Return  depth of saved stack ##
1640
1641#Example
1642    SkPaint paint;
1643    paint.setColor(SK_ColorRED);
1644    canvas->drawCircle(50, 50, 50, paint);
1645    canvas->saveLayerAlpha(nullptr, 128);
1646    paint.setColor(SK_ColorBLUE);
1647    canvas->drawCircle(100, 50, 50, paint);
1648    paint.setColor(SK_ColorGREEN);
1649    paint.setAlpha(128);
1650    canvas->drawCircle(75, 90, 50, paint);
1651    canvas->restore();
1652##
1653
1654#SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests SaveLayerRec
1655
1656##
1657
1658#ToDo 
1659add new markup to associate typedef SaveLayerFlags with Enum so that, for
1660documentation purposes, this enum is named rather than anonymous
1661##
1662
1663#Enum
1664#Line # sets SaveLayerRec options ##
1665#Code
1666    enum {
1667        kIsOpaque_SaveLayerFlag = 1 << 0,
1668        kPreserveLCDText_SaveLayerFlag = 1 << 1,
1669        kInitWithPrevious_SaveLayerFlag = 1 << 2,
1670        kDontClipToLayer_Legacy_SaveLayerFlag = kDontClipToLayer_PrivateSaveLayerFlag,
1671    };
1672##
1673
1674SaveLayerFlags provides options that may be used in any combination in SaveLayerRec,
1675defining how Layer allocated by saveLayer operates.
1676
1677#Const kIsOpaque_SaveLayerFlag 1
1678  Creates Layer without transparency. Flag is ignored if Layer Paint contains
1679  Image_Filter or Color_Filter.
1680##
1681
1682#Const kPreserveLCDText_SaveLayerFlag 2
1683  Creates Layer for LCD text. Flag is ignored if Layer Paint contains
1684  Image_Filter or Color_Filter.
1685##
1686
1687#Const kInitWithPrevious_SaveLayerFlag 4
1688  Initializes Layer with the contents of the previous Layer.
1689##
1690
1691#Const kDontClipToLayer_Legacy_SaveLayerFlag 0x80000000
1692#Deprecated soon
1693##
1694
1695#Example
1696#Height 160
1697#Description
1698Canvas Layer captures red and blue circles scaled up by four.
1699scalePaint blends Layer back with transparency. 
1700##
1701void draw(SkCanvas* canvas) {
1702    SkPaint redPaint, bluePaint, scalePaint;
1703    redPaint.setColor(SK_ColorRED);
1704    canvas->drawCircle(21, 21, 8, redPaint);
1705    bluePaint.setColor(SK_ColorBLUE);
1706    canvas->drawCircle(31, 21, 8, bluePaint);
1707    SkMatrix matrix;
1708    matrix.setScale(4, 4);
1709    scalePaint.setAlpha(0x40);
1710    scalePaint.setImageFilter(
1711            SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr));
1712    SkCanvas::SaveLayerRec saveLayerRec(nullptr, &scalePaint,
1713            SkCanvas::kInitWithPrevious_SaveLayerFlag); 
1714    canvas->saveLayer(saveLayerRec);
1715    canvas->restore();
1716}
1717##
1718
1719#SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha SaveLayerRec
1720
1721#Enum ##
1722
1723#Typedef uint32_t SaveLayerFlags
1724
1725##
1726
1727#Struct SaveLayerRec
1728#Line # contains the state used to create the Layer ##
1729#Code
1730    struct SaveLayerRec {
1731        SaveLayerRec*(...
1732
1733        const SkRect*           fBounds;
1734        const SkPaint*          fPaint;
1735        const SkImageFilter*    fBackdrop;
1736        SaveLayerFlags          fSaveLayerFlags;
1737    };
1738##
1739
1740SaveLayerRec contains the state used to create the Layer. 
1741
1742#Member const SkRect*           fBounds
1743    fBounds is used as a hint to limit the size of Layer; may be nullptr.
1744    fBounds suggests but does not define Layer size. To clip drawing to
1745    a specific rectangle, use clipRect.
1746##
1747
1748#Member const SkPaint*          fPaint
1749    fPaint modifies how Layer overlays the prior Layer; may be nullptr.
1750    Color_Alpha, Blend_Mode, Color_Filter, Draw_Looper, Image_Filter, and
1751    Mask_Filter affect Layer draw.
1752##
1753
1754#Member const SkImageFilter*    fBackdrop
1755    fBackdrop applies Image_Filter to the prior Layer when copying to the Layer;
1756    may be nullptr. Use kInitWithPrevious_SaveLayerFlag to copy the
1757    prior Layer without an Image_Filter.
1758##
1759
1760#Member const SkImage*          fClipMask
1761  restore() clips Layer by the Color_Alpha channel of fClipMask when
1762  Layer is copied to Device. fClipMask may be nullptr.    .
1763##
1764
1765#Member const SkMatrix*         fClipMatrix
1766  fClipMatrix transforms fClipMask before it clips Layer. If 
1767  fClipMask describes a translucent gradient, it may be scaled and rotated
1768  without introducing artifacts. fClipMatrix may be nullptr.
1769##
1770
1771#Member SaveLayerFlags          fSaveLayerFlags
1772    fSaveLayerFlags are used to create Layer without transparency,
1773    create Layer for LCD text, and to create Layer with the
1774    contents of the previous Layer.
1775##
1776
1777#Example
1778#Height 160
1779#Description
1780Canvas Layer captures a red Anti-aliased circle and a blue Aliased circle scaled
1781up by four. After drawing another red circle without scaling on top, the Layer is
1782transferred to the main canvas. 
1783##
1784void draw(SkCanvas* canvas) {
1785    SkPaint redPaint, bluePaint;
1786    redPaint.setAntiAlias(true);
1787    redPaint.setColor(SK_ColorRED);
1788    canvas->drawCircle(21, 21, 8, redPaint);
1789    bluePaint.setColor(SK_ColorBLUE);
1790    canvas->drawCircle(31, 21, 8, bluePaint);
1791    SkMatrix matrix;
1792    matrix.setScale(4, 4);
1793    auto scaler = SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr);
1794    SkCanvas::SaveLayerRec saveLayerRec(nullptr, nullptr, scaler.get(), 0); 
1795    canvas->saveLayer(saveLayerRec);
1796    canvas->drawCircle(125, 85, 8, redPaint);
1797    canvas->restore();
1798}
1799##
1800
1801#Method SaveLayerRec()
1802
1803Sets fBounds, fPaint, and fBackdrop to nullptr. Clears fSaveLayerFlags.
1804
1805#Return  empty SaveLayerRec ##
1806
1807#Example
1808    SkCanvas::SaveLayerRec rec1;
1809    rec1.fSaveLayerFlags = SkCanvas::kIsOpaque_SaveLayerFlag;
1810    SkCanvas::SaveLayerRec rec2(nullptr, nullptr, SkCanvas::kIsOpaque_SaveLayerFlag);
1811    SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
1812            && rec1.fPaint == rec2.fPaint
1813            && rec1.fBackdrop == rec2.fBackdrop
1814            && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!');
1815    #StdOut
1816        rec1 == rec2
1817    ##
1818##
1819
1820#SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha
1821
1822##
1823
1824#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0)
1825
1826Sets fBounds, fPaint, and fSaveLayerFlags; sets fBackdrop to nullptr.
1827
1828#Param bounds  Layer dimensions; may be nullptr ##
1829#Param paint  applied to Layer when overlaying prior Layer; may be nullptr ##
1830#Param saveLayerFlags  SaveLayerRec options to modify Layer ##
1831
1832#Return  SaveLayerRec with empty backdrop ##
1833
1834#Example
1835    SkCanvas::SaveLayerRec rec1;
1836    SkCanvas::SaveLayerRec rec2(nullptr, nullptr);
1837    SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
1838            && rec1.fPaint == rec2.fPaint
1839            && rec1.fBackdrop == rec2.fBackdrop
1840            && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!');
1841    #StdOut
1842        rec1 == rec2
1843    ##
1844##
1845
1846#SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha
1847
1848##
1849
1850#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop,
1851                     SaveLayerFlags saveLayerFlags)
1852
1853Sets fBounds, fPaint, fBackdrop, and fSaveLayerFlags.
1854
1855#Param bounds          Layer dimensions; may be nullptr ##
1856#Param paint           applied to Layer when overlaying prior Layer;
1857                       may be nullptr
1858##
1859#Param backdrop        prior Layer copied with Image_Filter; may be nullptr
1860##
1861#Param saveLayerFlags  SaveLayerRec options to modify Layer ##
1862
1863#Return  SaveLayerRec fully specified ##
1864
1865#Example
1866    SkCanvas::SaveLayerRec rec1;
1867    SkCanvas::SaveLayerRec rec2(nullptr, nullptr, nullptr, 0);
1868    SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
1869            && rec1.fPaint == rec2.fPaint
1870            && rec1.fBackdrop == rec2.fBackdrop
1871            && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!');
1872    #StdOut
1873        rec1 == rec2
1874    ##
1875##
1876
1877#SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha
1878
1879##
1880
1881#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop,
1882                     const SkImage* clipMask, const SkMatrix* clipMatrix,
1883                     SaveLayerFlags saveLayerFlags)
1884
1885#Experimental
1886Not ready for general use.
1887##
1888
1889Sets fBounds, fPaint, fBackdrop, fClipMask, fClipMatrix, and fSaveLayerFlags.
1890clipMatrix uses Color_Alpha channel of image, transformed by clipMatrix, to clip
1891Layer when drawn to Canvas.
1892
1893Implementation is not complete; has no effect if Device is GPU-backed.
1894
1895#Param bounds          Layer dimensions; may be nullptr ##
1896#Param paint           graphics state applied to Layer when overlaying prior
1897                       Layer; may be nullptr
1898##
1899#Param backdrop        prior Layer copied with Image_Filter;
1900                       may be nullptr
1901##
1902#Param clipMask        clip applied to Layer; may be nullptr ##
1903#Param clipMatrix      matrix applied to clipMask; may be nullptr to use
1904                       identity matrix 
1905##
1906#Param saveLayerFlags  SaveLayerRec options to modify Layer ##
1907
1908#Return                SaveLayerRec fully specified ##
1909
1910#SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha
1911
1912##
1913
1914#Struct ##
1915
1916#Method int saveLayer(const SaveLayerRec& layerRec)
1917
1918#In Layer
1919Saves Matrix, Clip, and Draw_Filter (Draw_Filter deprecated on most platforms),
1920and allocates Bitmap for subsequent drawing.
1921
1922Calling restore() discards changes to Matrix, Clip, and Draw_Filter,
1923and blends Bitmap with Color_Alpha opacity onto the prior Layer.
1924
1925Matrix may be changed by translate(), scale(), rotate(), skew(), concat(),
1926setMatrix, and resetMatrix. Clip may be changed by clipRect, clipRRect,
1927clipPath, clipRegion.
1928
1929SaveLayerRec contains the state used to create the Layer.
1930
1931Call restoreToCount with returned value to restore this and subsequent saves.
1932
1933#Param layerRec  Layer state ##
1934
1935#Return          depth of save state stack ##
1936
1937#Example
1938#Description
1939The example draws an image, and saves it into a Layer with kInitWithPrevious_SaveLayerFlag.
1940Next it punches a hole in Layer and restore with SkBlendMode::kPlus.
1941Where Layer was cleared, the original image will draw unchanged.
1942Outside of the circle the mandrill is brightened.
1943##
1944    #Image 3
1945    // sk_sp<SkImage> image = GetResourceAsImage("images/mandrill_256.png");
1946    canvas->drawImage(image, 0, 0, nullptr);
1947    SkCanvas::SaveLayerRec rec;
1948    SkPaint paint;
1949    paint.setBlendMode(SkBlendMode::kPlus);
1950    rec.fSaveLayerFlags = SkCanvas::kInitWithPrevious_SaveLayerFlag;
1951    rec.fPaint = &paint;
1952    canvas->saveLayer(rec);
1953    paint.setBlendMode(SkBlendMode::kClear);
1954    canvas->drawCircle(128, 128, 96, paint);
1955    canvas->restore();
1956##
1957
1958#ToDo above example needs to replace GetResourceAsImage with way to select image in fiddle ##
1959
1960#SeeAlso save() restore() saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha
1961
1962##
1963
1964#Subtopic Layer ##
1965
1966# ------------------------------------------------------------------------------
1967#Subtopic Matrix
1968#Line # coordinate transformation ##
1969
1970#Method void translate(SkScalar dx, SkScalar dy)
1971
1972#In Matrix
1973#Line # translates Matrix ##
1974Translate Matrix by dx along the x-axis and dy along the y-axis.
1975
1976Mathematically, replace Matrix with a translation matrix
1977Premultiplied with Matrix. 
1978
1979This has the effect of moving the drawing by (dx, dy) before transforming
1980the result with Matrix.
1981
1982#Param  dx   distance to translate in x ##
1983#Param  dy   distance to translate in y ##
1984
1985#Example
1986#Height 128
1987#Description
1988scale() followed by translate() produces different results from translate() followed
1989by scale(). 
1990
1991The blue stroke follows translate of (50, 50); a black
1992fill follows scale of (2, 1/2.f). After restoring the clip, which resets 
1993Matrix, a red frame follows the same scale of (2, 1/2.f); a gray fill
1994follows translate of (50, 50).
1995##
1996void draw(SkCanvas* canvas) {
1997    SkPaint filledPaint;
1998    SkPaint outlinePaint;
1999    outlinePaint.setStyle(SkPaint::kStroke_Style);
2000    outlinePaint.setColor(SK_ColorBLUE);
2001    canvas->save();
2002    canvas->translate(50, 50);
2003    canvas->drawCircle(28, 28, 15, outlinePaint);  // blue center: (50+28, 50+28)
2004    canvas->scale(2, 1/2.f);
2005    canvas->drawCircle(28, 28, 15, filledPaint);   // black center: (50+(28*2), 50+(28/2))
2006    canvas->restore();
2007    filledPaint.setColor(SK_ColorGRAY);
2008    outlinePaint.setColor(SK_ColorRED);
2009    canvas->scale(2, 1/2.f);
2010    canvas->drawCircle(28, 28, 15, outlinePaint);  // red center: (28*2, 28/2)
2011    canvas->translate(50, 50);
2012    canvas->drawCircle(28, 28, 15, filledPaint);   // gray center: ((50+28)*2, (50+28)/2)
2013}
2014##
2015
2016#SeeAlso concat() scale() skew() rotate() setMatrix
2017
2018##
2019
2020# ------------------------------------------------------------------------------
2021
2022#Method void scale(SkScalar sx, SkScalar sy)
2023
2024#In Matrix
2025#Line # scales Matrix ##
2026Scale Matrix by sx on the x-axis and sy on the y-axis.
2027
2028Mathematically, replace Matrix with a scale matrix
2029Premultiplied with Matrix. 
2030
2031This has the effect of scaling the drawing by (sx, sy) before transforming
2032the result with Matrix.
2033
2034#Param  sx   amount to scale in x ##
2035#Param  sy   amount to scale in y ##
2036
2037#Example
2038#Height 160
2039void draw(SkCanvas* canvas) {
2040    SkPaint paint;
2041    SkRect rect = { 10, 20, 60, 120 };
2042    canvas->translate(20, 20);
2043    canvas->drawRect(rect, paint);
2044    canvas->scale(2, .5f);
2045    paint.setColor(SK_ColorGRAY);
2046    canvas->drawRect(rect, paint);
2047}
2048##
2049
2050#SeeAlso concat() translate() skew() rotate() setMatrix
2051
2052##
2053
2054# ------------------------------------------------------------------------------
2055
2056#Method void rotate(SkScalar degrees)
2057
2058#In Matrix
2059#Line # rotates Matrix ##
2060Rotate Matrix by degrees. Positive degrees rotates clockwise.
2061
2062Mathematically, replace Matrix with a rotation matrix
2063Premultiplied with Matrix. 
2064
2065This has the effect of rotating the drawing by degrees before transforming
2066the result with Matrix.
2067
2068#Param  degrees  amount to rotate, in degrees ##
2069
2070#Example
2071#Description
2072Draw clock hands at time 5:10. The hour hand and minute hand point up and
2073are rotated clockwise.
2074##
2075void draw(SkCanvas* canvas) {
2076    SkPaint paint;
2077    paint.setStyle(SkPaint::kStroke_Style);
2078    canvas->translate(128, 128);
2079    canvas->drawCircle(0, 0, 60, paint);
2080    canvas->save();
2081    canvas->rotate(10 * 360 / 60);   // 10 minutes of 60 scaled to 360 degrees
2082    canvas->drawLine(0, 0, 0, -50, paint); 
2083    canvas->restore();
2084    canvas->rotate((5 + 10.f/60) * 360 / 12); // 5 and 10/60 hours of 12 scaled to 360 degrees
2085    canvas->drawLine(0, 0, 0, -30, paint);
2086}
2087##
2088
2089#SeeAlso concat() translate() skew() scale() setMatrix
2090
2091##
2092
2093# ------------------------------------------------------------------------------
2094
2095#Method void rotate(SkScalar degrees, SkScalar px, SkScalar py)
2096
2097#In Matrix
2098Rotate Matrix by degrees about a point at (px, py). Positive degrees rotates
2099clockwise.
2100
2101Mathematically, construct a rotation matrix. Premultiply the rotation matrix by
2102a translation matrix, then replace Matrix with the resulting matrix
2103Premultiplied with Matrix. 
2104
2105This has the effect of rotating the drawing about a given point before
2106transforming the result with Matrix.
2107
2108#Param  degrees  amount to rotate, in degrees ##
2109#Param  px  x-coordinate of the point to rotate about ##
2110#Param  py  y-coordinate of the point to rotate about ##
2111
2112#Example
2113#Height 192
2114void draw(SkCanvas* canvas) {
2115    SkPaint paint;
2116    paint.setTextSize(96);
2117    canvas->drawString("A1", 130, 100, paint);
2118    canvas->rotate(180, 130, 100);
2119    canvas->drawString("A1", 130, 100, paint);
2120}
2121##
2122
2123#SeeAlso concat() translate() skew() scale() setMatrix
2124
2125##
2126
2127# ------------------------------------------------------------------------------
2128
2129#Method void skew(SkScalar sx, SkScalar sy)
2130
2131#In Matrix
2132#Line # skews Matrix ##
2133Skew Matrix by sx on the x-axis and sy on the y-axis. A positive value of sx
2134skews the drawing right as y increases; a positive value of sy skews the drawing
2135down as x increases.
2136
2137Mathematically, replace Matrix with a skew matrix Premultiplied with Matrix. 
2138
2139This has the effect of skewing the drawing by (sx, sy) before transforming
2140the result with Matrix.
2141
2142#Param  sx   amount to skew in x ##
2143#Param  sy   amount to skew in y ##
2144
2145#Example
2146    #Description 
2147        Black text mimics an oblique text style by using a negative skew in x that
2148        shifts the geometry to the right as the y values decrease.
2149        Red text uses a positive skew in y to shift the geometry down as the x values
2150        increase.
2151        Blue text combines x and y skew to rotate and scale.
2152    ##
2153    SkPaint paint;
2154    paint.setTextSize(128);
2155    canvas->translate(30, 130);
2156    canvas->save();
2157    canvas->skew(-.5, 0);
2158    canvas->drawString("A1", 0, 0, paint);
2159    canvas->restore();
2160    canvas->save();
2161    canvas->skew(0, .5);
2162    paint.setColor(SK_ColorRED);
2163    canvas->drawString("A1", 0, 0, paint);
2164    canvas->restore();
2165    canvas->skew(-.5, .5);
2166    paint.setColor(SK_ColorBLUE);
2167    canvas->drawString("A1", 0, 0, paint);
2168##
2169
2170#SeeAlso concat() translate() rotate() scale() setMatrix
2171
2172##
2173
2174# ------------------------------------------------------------------------------
2175
2176#Method void concat(const SkMatrix& matrix)
2177
2178#In Matrix
2179#Line # multiplies Matrix by Matrix ##
2180Replace Matrix with matrix Premultiplied with existing Matrix.
2181
2182This has the effect of transforming the drawn geometry by matrix, before
2183transforming the result with existing Matrix.
2184
2185#Param  matrix   matrix to Premultiply with existing Matrix ##
2186
2187#Example
2188void draw(SkCanvas* canvas) {
2189    SkPaint paint;
2190    paint.setTextSize(80);
2191    paint.setTextScaleX(.3);
2192    SkMatrix matrix;
2193    SkRect rect[2] = {{ 10, 20, 90, 110 }, { 40, 130, 140, 180 }};
2194    matrix.setRectToRect(rect[0], rect[1], SkMatrix::kFill_ScaleToFit);
2195    canvas->drawRect(rect[0], paint);
2196    canvas->drawRect(rect[1], paint);
2197    paint.setColor(SK_ColorWHITE);
2198    canvas->drawString("Here", rect[0].fLeft + 10, rect[0].fBottom - 10, paint);
2199    canvas->concat(matrix);
2200    canvas->drawString("There", rect[0].fLeft + 10, rect[0].fBottom - 10, paint);
2201}
2202##
2203
2204#SeeAlso translate() rotate() scale() skew() setMatrix
2205
2206##
2207
2208# ------------------------------------------------------------------------------
2209
2210#Method void setMatrix(const SkMatrix& matrix)
2211
2212#In Matrix
2213#Line # sets Matrix ##
2214Replace Matrix with matrix.
2215Unlike concat(), any prior matrix state is overwritten.
2216
2217#Param  matrix  matrix to copy, replacing existing Matrix ##
2218
2219#Example
2220#Height 128
2221void draw(SkCanvas* canvas) {
2222    SkPaint paint;
2223    canvas->scale(4, 6);
2224    canvas->drawString("truth", 2, 10, paint);
2225    SkMatrix matrix;
2226    matrix.setScale(2.8f, 6);
2227    canvas->setMatrix(matrix);
2228    canvas->drawString("consequences", 2, 20, paint);
2229}
2230##
2231
2232#SeeAlso resetMatrix concat() translate() rotate() scale() skew()
2233
2234##
2235
2236# ------------------------------------------------------------------------------
2237
2238#Method void resetMatrix()
2239
2240#In Matrix
2241#Line # resets Matrix to identity ##
2242Sets Matrix to the identity matrix.
2243Any prior matrix state is overwritten.
2244
2245#Example
2246#Height 128
2247void draw(SkCanvas* canvas) {
2248    SkPaint paint;
2249    canvas->scale(4, 6);
2250    canvas->drawString("truth", 2, 10, paint);
2251    canvas->resetMatrix();
2252    canvas->scale(2.8f, 6);
2253    canvas->drawString("consequences", 2, 20, paint);
2254}
2255##
2256
2257#SeeAlso setMatrix concat() translate() rotate() scale() skew()
2258
2259##
2260
2261# ------------------------------------------------------------------------------
2262
2263#Method const SkMatrix& getTotalMatrix() const
2264
2265#In Matrix
2266#Line # returns Matrix ##
2267Returns Matrix.
2268This does not account for translation by Device or Surface.
2269
2270#Return Matrix in Canvas ##
2271
2272#Example
2273    SkDebugf("isIdentity %s\n", canvas->getTotalMatrix().isIdentity() ? "true" : "false");
2274    #StdOut
2275        isIdentity true
2276    ##
2277##
2278
2279#SeeAlso setMatrix resetMatrix concat()
2280
2281##
2282
2283#Subtopic Matrix ##
2284
2285# ------------------------------------------------------------------------------
2286#Subtopic Clip
2287#Line # stack of clipping Paths ##
2288
2289Clip is built from a stack of clipping paths. Each Path in the
2290stack can be constructed from one or more Path_Contour elements. The 
2291Path_Contour may be composed of any number of Path_Verb segments. Each
2292Path_Contour forms a closed area; Path_Fill_Type defines the area enclosed
2293by Path_Contour.
2294
2295Clip stack of Path elements successfully restrict the Path area. Each
2296Path is transformed by Matrix, then intersected with or subtracted from the 
2297prior Clip to form the replacement Clip. Use SkClipOp::kDifference
2298to subtract Path from Clip; use SkClipOp::kIntersect to intersect Path
2299with Clip.
2300
2301A clipping Path may be Anti-aliased; if Path, after transformation, is
2302composed of horizontal and vertical lines, clearing Anti-alias allows whole pixels
2303to either be inside or outside the clip. The fastest drawing has a Aliased,
2304rectangular clip.
2305
2306If clipping Path has Anti-alias set, clip may partially clip a pixel, requiring
2307that drawing blend partially with the destination along the edge. A rotated 
2308rectangular Anti-aliased clip looks smoother but draws slower.
2309
2310Clip can combine with Rect and Round_Rect primitives; like
2311Path, these are transformed by Matrix before they are combined with Clip.
2312
2313Clip can combine with Region. Region is assumed to be in Device coordinates
2314and is unaffected by Matrix.
2315
2316#Example
2317#Height 90
2318    #Description
2319        Draw a red circle with an Aliased clip and an Anti-aliased clip.
2320        Use an image filter to zoom into the pixels drawn.
2321        The edge of the Aliased clip fully draws pixels in the red circle.
2322        The edge of the Anti-aliased clip partially draws pixels in the red circle.
2323    ##
2324    SkPaint redPaint, scalePaint;
2325    redPaint.setAntiAlias(true);
2326    redPaint.setColor(SK_ColorRED);
2327    canvas->save();
2328    for (bool antialias : { false, true } ) {
2329        canvas->save();
2330        canvas->clipRect(SkRect::MakeWH(19.5f, 11.5f), antialias);
2331        canvas->drawCircle(17, 11, 8, redPaint);
2332        canvas->restore();
2333        canvas->translate(16, 0);
2334    }
2335    canvas->restore();
2336    SkMatrix matrix;
2337    matrix.setScale(6, 6);
2338    scalePaint.setImageFilter(
2339            SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr));
2340    SkCanvas::SaveLayerRec saveLayerRec(
2341            nullptr, &scalePaint, SkCanvas::kInitWithPrevious_SaveLayerFlag); 
2342    canvas->saveLayer(saveLayerRec);
2343    canvas->restore();
2344##
2345
2346#Method void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias)
2347
2348#In Clip
2349#Line # combines Clip with Rect ##
2350Replace Clip with the intersection or difference of Clip and rect,
2351with an Aliased or Anti-aliased clip edge. rect is transformed by Matrix
2352before it is combined with Clip.
2353
2354#Param  rect  Rect to combine with Clip ##
2355#Param  op    Clip_Op to apply to Clip ##
2356#Param  doAntiAlias  true if Clip is to be Anti-aliased ##
2357
2358#Example
2359#Height 128
2360void draw(SkCanvas* canvas) {
2361    canvas->rotate(10);
2362    SkPaint paint;
2363    paint.setAntiAlias(true);
2364    for (auto alias: { false, true } ) {
2365        canvas->save();
2366        canvas->clipRect(SkRect::MakeWH(90, 80), SkClipOp::kIntersect, alias);
2367        canvas->drawCircle(100, 60, 60, paint);
2368        canvas->restore();
2369        canvas->translate(80, 0);
2370    }
2371}
2372##
2373
2374#SeeAlso clipRRect clipPath clipRegion
2375
2376##
2377
2378#Method void clipRect(const SkRect& rect, SkClipOp op) 
2379
2380#In Clip
2381Replace Clip with the intersection or difference of Clip and rect.
2382Resulting Clip is Aliased; pixels are fully contained by the clip.
2383rect is transformed by Matrix before it is combined with Clip.
2384
2385#Param  rect  Rect to combine with Clip ##
2386#Param  op    Clip_Op to apply to Clip ##
2387
2388#Example
2389#Height 192
2390#Width 280
2391void draw(SkCanvas* canvas) {
2392    SkPaint paint;
2393    for (SkClipOp op: { SkClipOp::kIntersect, SkClipOp::kDifference } ) {
2394        canvas->save();
2395        canvas->clipRect(SkRect::MakeWH(90, 120), op, false);
2396        canvas->drawCircle(100, 100, 60, paint);
2397        canvas->restore();
2398        canvas->translate(80, 0);
2399    }
2400}
2401##
2402
2403#SeeAlso clipRRect clipPath clipRegion
2404
2405##
2406
2407#Method void clipRect(const SkRect& rect, bool doAntiAlias = false) 
2408
2409#In Clip
2410Replace Clip with the intersection of Clip and rect.
2411Resulting Clip is Aliased; pixels are fully contained by the clip.
2412rect is transformed by Matrix
2413before it is combined with Clip.
2414
2415#Param  rect   Rect to combine with Clip ##
2416#Param  doAntiAlias  true if Clip is to be Anti-aliased ##
2417
2418#Example
2419#Height 133
2420    #Description
2421        A circle drawn in pieces looks uniform when drawn Aliased.
2422        The same circle pieces blend with pixels more than once when Anti-aliased,
2423        visible as a thin pair of lines through the right circle.
2424    ##
2425void draw(SkCanvas* canvas) {
2426    canvas->clear(SK_ColorWHITE);
2427    SkPaint paint;
2428    paint.setAntiAlias(true);
2429    paint.setColor(0x8055aaff);
2430    SkRect clipRect = { 0, 0, 87.4f, 87.4f };
2431    for (auto alias: { false, true } ) {
2432        canvas->save();
2433        canvas->clipRect(clipRect, SkClipOp::kIntersect, alias);
2434        canvas->drawCircle(67, 67, 60, paint);
2435        canvas->restore();
2436        canvas->save();
2437        canvas->clipRect(clipRect, SkClipOp::kDifference, alias);
2438        canvas->drawCircle(67, 67, 60, paint);
2439        canvas->restore();
2440        canvas->translate(120, 0);
2441    }
2442}
2443##
2444
2445#SeeAlso clipRRect clipPath clipRegion
2446
2447##
2448
2449#Method void androidFramework_setDeviceClipRestriction(const SkIRect& rect)
2450
2451#In Clip
2452#Line # for use by Android framework ##
2453Sets the maximum clip rectangle, which can be set by clipRect, clipRRect and
2454clipPath and intersect the current clip with the specified rect.
2455The maximum clip affects only future clipping operations; it is not retroactive.
2456The clip restriction is not recorded in pictures.
2457
2458Pass an empty rect to disable maximum clip. 
2459
2460#Private
2461This is private API to be used only by Android framework.
2462##
2463
2464#Param  rect   maximum allowed clip in device coordinates
2465#Param ##
2466
2467##
2468
2469#Method void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias)
2470
2471#In Clip
2472#Line # combines Clip with Round_Rect ##
2473Replace Clip with the intersection or difference of Clip and rrect,
2474with an Aliased or Anti-aliased clip edge.
2475rrect is transformed by Matrix
2476before it is combined with Clip.
2477
2478#Param  rrect  Round_Rect to combine with Clip ##
2479#Param  op  Clip_Op to apply to Clip ##
2480#Param  doAntiAlias  true if Clip is to be Anti-aliased ##
2481
2482#Example
2483#Height 128
2484void draw(SkCanvas* canvas) {
2485    canvas->clear(SK_ColorWHITE);
2486    SkPaint paint;
2487    paint.setAntiAlias(true);
2488    paint.setColor(0x8055aaff);
2489    SkRRect oval;
2490    oval.setOval({10, 20, 90, 100});
2491    canvas->clipRRect(oval, SkClipOp::kIntersect, true);
2492    canvas->drawCircle(70, 100, 60, paint);
2493}
2494##
2495
2496#SeeAlso clipRect clipPath clipRegion
2497
2498##
2499
2500#Method void clipRRect(const SkRRect& rrect, SkClipOp op) 
2501
2502#In Clip
2503Replace Clip with the intersection or difference of Clip and rrect.
2504Resulting Clip is Aliased; pixels are fully contained by the clip.
2505rrect is transformed by Matrix before it is combined with Clip.
2506
2507#Param  rrect  Round_Rect to combine with Clip ##
2508#Param  op  Clip_Op to apply to Clip ##
2509
2510#Example
2511#Height 128
2512void draw(SkCanvas* canvas) {
2513    SkPaint paint;
2514    paint.setColor(0x8055aaff);
2515    auto oval = SkRRect::MakeOval({10, 20, 90, 100});
2516    canvas->clipRRect(oval, SkClipOp::kIntersect);
2517    canvas->drawCircle(70, 100, 60, paint);
2518}
2519##
2520
2521#SeeAlso clipRect clipPath clipRegion
2522
2523##
2524
2525#Method void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) 
2526
2527#In Clip
2528Replace Clip with the intersection of Clip and rrect,
2529with an Aliased or Anti-aliased clip edge.
2530rrect is transformed by Matrix before it is combined with Clip.
2531
2532#Param  rrect  Round_Rect to combine with Clip ##
2533#Param  doAntiAlias  true if Clip is to be Anti-aliased ##
2534
2535#Example
2536#Height 128
2537void draw(SkCanvas* canvas) {
2538    SkPaint paint;
2539    paint.setAntiAlias(true);
2540    auto oval = SkRRect::MakeRectXY({10, 20, 90, 100}, 9, 13);
2541    canvas->clipRRect(oval, true);
2542    canvas->drawCircle(70, 100, 60, paint);
2543}
2544##
2545
2546#SeeAlso clipRect clipPath clipRegion
2547
2548##
2549
2550#Method void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias)
2551
2552#In Clip
2553#Line # combines Clip with Path ##
2554Replace Clip with the intersection or difference of Clip and path,
2555with an Aliased or Anti-aliased clip edge. Path_Fill_Type determines if path
2556describes the area inside or outside its contours; and if Path_Contour overlaps
2557itself or another Path_Contour, whether the overlaps form part of the area.
2558path is transformed by Matrix before it is combined with Clip.
2559
2560#Param  path  Path to combine with Clip ##
2561#Param  op  Clip_Op to apply to Clip ##
2562#Param  doAntiAlias  true if Clip is to be Anti-aliased ##
2563
2564#Example
2565#Description
2566Top figure uses SkPath::kInverseWinding_FillType and SkClipOp::kDifference;
2567area outside clip is subtracted from circle.
2568
2569Bottom figure uses SkPath::kWinding_FillType and SkClipOp::kIntersect;
2570area inside clip is intersected with circle.
2571##
2572void draw(SkCanvas* canvas) {
2573    SkPaint paint;
2574    paint.setAntiAlias(true);
2575    SkPath path;
2576    path.addRect({20, 30, 100, 110});
2577    path.setFillType(SkPath::kInverseWinding_FillType);
2578    canvas->save();
2579    canvas->clipPath(path, SkClipOp::kDifference, false);
2580    canvas->drawCircle(70, 100, 60, paint);
2581    canvas->restore();
2582    canvas->translate(100, 100);
2583    path.setFillType(SkPath::kWinding_FillType);
2584    canvas->clipPath(path, SkClipOp::kIntersect, false);
2585    canvas->drawCircle(70, 100, 60, paint);
2586}
2587##
2588
2589#SeeAlso clipRect clipRRect clipRegion
2590
2591##
2592
2593#Method void clipPath(const SkPath& path, SkClipOp op) 
2594
2595#In Clip
2596Replace Clip with the intersection or difference of Clip and path.
2597Resulting Clip is Aliased; pixels are fully contained by the clip.
2598Path_Fill_Type determines if path
2599describes the area inside or outside its contours; and if Path_Contour overlaps
2600itself or another Path_Contour, whether the overlaps form part of the area.
2601path is transformed by Matrix
2602before it is combined with Clip.
2603
2604#Param  path  Path to combine with Clip ##
2605#Param  op  Clip_Op to apply to Clip ##
2606
2607#Example
2608#Description
2609Overlapping Rects form a clip. When clip Path_Fill_Type is set to
2610SkPath::kWinding_FillType, the overlap is included. Set to 
2611SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole.
2612##
2613void draw(SkCanvas* canvas) {
2614    SkPaint paint;
2615    paint.setAntiAlias(true);
2616    SkPath path;
2617    path.addRect({20, 15, 100, 95});
2618    path.addRect({50, 65, 130, 135});
2619    path.setFillType(SkPath::kWinding_FillType);
2620    canvas->save();
2621    canvas->clipPath(path, SkClipOp::kIntersect);
2622    canvas->drawCircle(70, 85, 60, paint);
2623    canvas->restore();
2624    canvas->translate(100, 100);
2625    path.setFillType(SkPath::kEvenOdd_FillType);
2626    canvas->clipPath(path, SkClipOp::kIntersect);
2627    canvas->drawCircle(70, 85, 60, paint);
2628}
2629##
2630
2631#SeeAlso clipRect clipRRect clipRegion
2632
2633##
2634
2635#Method void clipPath(const SkPath& path, bool doAntiAlias = false) 
2636
2637#In Clip
2638Replace Clip with the intersection of Clip and path.
2639Resulting Clip is Aliased; pixels are fully contained by the clip.
2640Path_Fill_Type determines if path
2641describes the area inside or outside its contours; and if Path_Contour overlaps
2642itself or another Path_Contour, whether the overlaps form part of the area.
2643path is transformed by Matrix before it is combined with Clip.
2644
2645#Param  path  Path to combine with Clip ##
2646#Param  doAntiAlias  true if Clip is to be Anti-aliased ##
2647
2648#Example
2649#Height 212
2650#Description
2651Clip loops over itself covering its center twice. When clip Path_Fill_Type 
2652is set to SkPath::kWinding_FillType, the overlap is included. Set to 
2653SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole.
2654##
2655void draw(SkCanvas* canvas) {
2656    SkPaint paint;
2657    paint.setAntiAlias(true);
2658    SkPath path;
2659    SkPoint poly[] = {{20, 20}, { 80, 20}, { 80,  80}, {40,  80},
2660                      {40, 40}, {100, 40}, {100, 100}, {20, 100}};
2661    path.addPoly(poly, SK_ARRAY_COUNT(poly), true);
2662    path.setFillType(SkPath::kWinding_FillType);
2663    canvas->save();
2664    canvas->clipPath(path, SkClipOp::kIntersect);
2665    canvas->drawCircle(50, 50, 45, paint);
2666    canvas->restore();
2667    canvas->translate(100, 100);
2668    path.setFillType(SkPath::kEvenOdd_FillType);
2669    canvas->clipPath(path, SkClipOp::kIntersect);
2670    canvas->drawCircle(50, 50, 45, paint);
2671}
2672##
2673
2674#SeeAlso clipRect clipRRect clipRegion
2675
2676##
2677
2678# ------------------------------------------------------------------------------
2679
2680#Method void setAllowSimplifyClip(bool allow) 
2681
2682#In Clip
2683#Line # experimental ##
2684#Experimental
2685Only used for testing.
2686##
2687
2688Set to simplify clip stack using PathOps.
2689
2690##
2691
2692# ------------------------------------------------------------------------------
2693
2694#Method void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect)
2695
2696#In Clip
2697#Line # combines Clip with Region ##
2698Replace Clip with the intersection or difference of Clip and Region deviceRgn.
2699Resulting Clip is Aliased; pixels are fully contained by the clip.
2700deviceRgn is unaffected by Matrix.
2701
2702#Param  deviceRgn    Region to combine with Clip ##
2703#Param  op  Clip_Op to apply to Clip ##
2704
2705#Example
2706#Description
2707    region is unaffected by canvas rotation; iRect is affected by canvas rotation.
2708    Both clips are Aliased; this is not noticeable on Region clip because it
2709    aligns to pixel boundaries.
2710##
2711void draw(SkCanvas* canvas) {
2712    SkPaint paint;
2713    paint.setAntiAlias(true);
2714    SkIRect iRect = {30, 40, 120, 130 };
2715    SkRegion region(iRect);
2716    canvas->rotate(10);
2717    canvas->save();
2718    canvas->clipRegion(region, SkClipOp::kIntersect);
2719    canvas->drawCircle(50, 50, 45, paint);
2720    canvas->restore();
2721    canvas->translate(100, 100);
2722    canvas->clipRect(SkRect::Make(iRect), SkClipOp::kIntersect);
2723    canvas->drawCircle(50, 50, 45, paint);
2724}
2725##
2726
2727#SeeAlso clipRect clipRRect clipPath
2728
2729##
2730
2731#Method bool quickReject(const SkRect& rect) const
2732
2733#In Clip
2734#Line # returns if Rect is outside Clip ##
2735Return true if Rect rect, transformed by Matrix, can be quickly determined to be
2736outside of Clip. May return false even though rect is outside of Clip.
2737
2738Use to check if an area to be drawn is clipped out, to skip subsequent draw calls.
2739
2740#Param  rect  Rect to compare with Clip ##
2741
2742#Return  true if rect, transformed by Matrix, does not intersect Clip ##
2743
2744#Example
2745void draw(SkCanvas* canvas) {
2746    SkRect testRect = {30, 30, 120, 129 }; 
2747    SkRect clipRect = {30, 130, 120, 230 }; 
2748    canvas->save();
2749    canvas->clipRect(clipRect);
2750    SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false");
2751    canvas->restore();
2752    canvas->rotate(10);
2753    canvas->clipRect(clipRect);
2754    SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false");
2755}
2756    #StdOut
2757        quickReject true
2758        quickReject false
2759    ##
2760##
2761
2762#SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing
2763
2764##
2765
2766#Method bool quickReject(const SkPath& path) const
2767
2768#In Clip
2769Return true if path, transformed by Matrix, can be quickly determined to be
2770outside of Clip. May return false even though path is outside of Clip.
2771
2772Use to check if an area to be drawn is clipped out, to skip subsequent draw calls.
2773
2774#Param path  Path to compare with Clip ##
2775
2776#Return  true if path, transformed by Matrix, does not intersect Clip ##
2777
2778#Example
2779void draw(SkCanvas* canvas) {
2780    SkPoint testPoints[] = {{30,  30}, {120,  30}, {120, 129} }; 
2781    SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} }; 
2782    SkPath testPath, clipPath;
2783    testPath.addPoly(testPoints, SK_ARRAY_COUNT(testPoints), true);
2784    clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
2785    canvas->save();
2786    canvas->clipPath(clipPath);
2787    SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false");
2788    canvas->restore();
2789    canvas->rotate(10);
2790    canvas->clipPath(clipPath);
2791    SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false");
2792    #StdOut
2793        quickReject true
2794        quickReject false
2795    ##
2796}
2797##
2798
2799#SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing
2800
2801##
2802
2803#Method SkRect getLocalClipBounds() const 
2804
2805#In Clip
2806#Line # returns Clip bounds in source coordinates ##
2807Return bounds of Clip, transformed by inverse of Matrix. If Clip is empty,
2808return SkRect::MakeEmpty, where all Rect sides equal zero.
2809
2810Rect returned is outset by one to account for partial pixel coverage if Clip
2811is Anti-aliased.
2812
2813#Return  bounds of Clip in local coordinates ##
2814
2815#Example
2816    #Description 
2817        Initial bounds is device bounds outset by 1 on all sides.
2818        Clipped bounds is clipPath bounds outset by 1 on all sides.
2819        Scaling the canvas by two in x and y scales the local bounds by 1/2 in x and y.
2820    ##
2821    SkCanvas local(256, 256);
2822    canvas = &local;
2823    SkRect bounds = canvas->getLocalClipBounds();
2824    SkDebugf("left:%g  top:%g  right:%g  bottom:%g\n",
2825            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2826    SkPoint clipPoints[]  = {{30, 130}, {120, 130}, {120, 230} }; 
2827    SkPath clipPath;
2828    clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
2829    canvas->clipPath(clipPath);
2830    bounds = canvas->getLocalClipBounds();
2831    SkDebugf("left:%g  top:%g  right:%g  bottom:%g\n",
2832            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2833    canvas->scale(2, 2);
2834    bounds = canvas->getLocalClipBounds();
2835    SkDebugf("left:%g  top:%g  right:%g  bottom:%g\n",
2836            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2837    #StdOut
2838        left:-1  top:-1  right:257  bottom:257
2839        left:29  top:129  right:121  bottom:231
2840        left:14.5  top:64.5  right:60.5  bottom:115.5
2841    ##
2842##
2843
2844# local canvas in example works around bug in fiddle ##
2845#Bug 6524
2846#SeeAlso getDeviceClipBounds getBaseLayerSize quickReject
2847
2848##
2849
2850#Method bool getLocalClipBounds(SkRect* bounds) const 
2851
2852#In Clip
2853Return bounds of Clip, transformed by inverse of Matrix. If Clip is empty,
2854return false, and set bounds to SkRect::MakeEmpty, where all Rect sides equal zero.
2855
2856bounds is outset by one to account for partial pixel coverage if Clip
2857is Anti-aliased.
2858
2859#Param bounds  Rect of Clip in local coordinates ##
2860
2861#Return  true if Clip bounds is not empty ##
2862
2863#Example
2864    void draw(SkCanvas* canvas) {
2865        SkCanvas local(256, 256);
2866        canvas = &local;
2867        SkRect bounds;
2868        SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds)
2869                 ? "false" : "true");
2870        SkPath path;
2871        canvas->clipPath(path);
2872        SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds)
2873                 ? "false" : "true");
2874    }
2875    #StdOut
2876        local bounds empty = false
2877        local bounds empty = true
2878    ##
2879##
2880
2881# local canvas in example works around bug in fiddle ##
2882#Bug 6524
2883#SeeAlso getDeviceClipBounds getBaseLayerSize quickReject
2884
2885##
2886
2887#Method SkIRect getDeviceClipBounds() const 
2888
2889#In Clip
2890#Line # returns IRect bounds of Clip ##
2891Return IRect bounds of Clip, unaffected by Matrix. If Clip is empty,
2892return SkRect::MakeEmpty, where all Rect sides equal zero.
2893
2894Unlike getLocalClipBounds, returned IRect is not outset. 
2895
2896#Return  bounds of Clip in Device coordinates ##
2897
2898#Example
2899void draw(SkCanvas* canvas) {
2900    #Description
2901        Initial bounds is device bounds, not outset.
2902        Clipped bounds is clipPath bounds, not outset.
2903        Scaling the canvas by 1/2 in x and y scales the device bounds by 1/2 in x and y.
2904    ##
2905    SkCanvas device(256, 256);
2906    canvas = &device;
2907    SkIRect bounds = canvas->getDeviceClipBounds();
2908    SkDebugf("left:%d  top:%d  right:%d  bottom:%d\n",
2909            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2910    SkPoint clipPoints[]  = {{30, 130}, {120, 130}, {120, 230} }; 
2911    SkPath clipPath;
2912    clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
2913    canvas->save();
2914    canvas->clipPath(clipPath);
2915    bounds = canvas->getDeviceClipBounds();
2916    SkDebugf("left:%d  top:%d  right:%d  bottom:%d\n",
2917            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2918    canvas->restore();
2919    canvas->scale(1.f/2, 1.f/2);
2920    canvas->clipPath(clipPath);
2921    bounds = canvas->getDeviceClipBounds();
2922    SkDebugf("left:%d  top:%d  right:%d  bottom:%d\n",
2923            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2924    #StdOut
2925        left:0  top:0  right:256  bottom:256
2926        left:30  top:130  right:120  bottom:230
2927        left:15  top:65  right:60  bottom:115
2928    ##
2929}
2930##
2931
2932#ToDo some confusion on why with an identity Matrix local and device are different ##
2933#SeeAlso getLocalClipBounds getBaseLayerSize quickReject
2934
2935# device canvas in example works around bug in fiddle ##
2936#Bug 6524
2937
2938##
2939
2940#Method bool getDeviceClipBounds(SkIRect* bounds) const 
2941
2942#In Clip
2943Return IRect bounds of Clip, unaffected by Matrix. If Clip is empty,
2944return false, and set bounds to SkRect::MakeEmpty, where all Rect sides equal zero.
2945
2946Unlike getLocalClipBounds, bounds is not outset. 
2947
2948#Param bounds  Rect of Clip in device coordinates ##
2949
2950#Return  true if Clip bounds is not empty ##
2951
2952#Example
2953    void draw(SkCanvas* canvas) {
2954        SkIRect bounds;
2955        SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds)
2956                 ? "false" : "true");
2957        SkPath path;
2958        canvas->clipPath(path);
2959        SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds)
2960                 ? "false" : "true");
2961    }
2962    #StdOut
2963        device bounds empty = false
2964        device bounds empty = true
2965    ##
2966##
2967
2968#SeeAlso getLocalClipBounds getBaseLayerSize quickReject
2969
2970##
2971
2972#Subtopic Clip ##
2973
2974# ------------------------------------------------------------------------------
2975
2976#Method void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver)
2977
2978#Line # fills Clip with Color and Blend_Mode ##
2979Fill Clip with Color color.
2980mode determines how Color_ARGB is combined with destination.
2981
2982#Param color    Unpremultiplied Color_ARGB ##
2983#Param mode  SkBlendMode used to combine source color and destination ##
2984
2985#Example
2986    canvas->drawColor(SK_ColorRED);
2987    canvas->clipRect(SkRect::MakeWH(150, 150));
2988    canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00), SkBlendMode::kPlus);
2989    canvas->clipRect(SkRect::MakeWH(75, 75));
2990    canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF), SkBlendMode::kPlus);
2991##
2992
2993#SeeAlso clear SkBitmap::erase drawPaint
2994
2995##
2996
2997# ------------------------------------------------------------------------------
2998
2999#Method void clear(SkColor color) 
3000
3001#Line # fills Clip with Color ##
3002Fill Clip with Color color using SkBlendMode::kSrc. 
3003This has the effect of replacing all pixels contained by Clip with color.
3004
3005#Param color    Unpremultiplied Color_ARGB ##
3006
3007#Example
3008void draw(SkCanvas* canvas) {
3009    canvas->save();
3010    canvas->clipRect(SkRect::MakeWH(256, 128));
3011    canvas->clear(SkColorSetARGB(0x80, 0xFF, 0x00, 0x00)); 
3012    canvas->restore();
3013    canvas->save();
3014    canvas->clipRect(SkRect::MakeWH(150, 192));
3015    canvas->clear(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00));
3016    canvas->restore();
3017    canvas->clipRect(SkRect::MakeWH(75, 256));
3018    canvas->clear(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF));
3019}
3020##
3021
3022#SeeAlso drawColor SkBitmap::erase drawPaint
3023
3024##
3025
3026# ------------------------------------------------------------------------------
3027
3028#Method void discard() 
3029
3030#Line # makes Canvas contents undefined ##
3031Make Canvas contents undefined. Subsequent calls that read Canvas pixels,
3032such as drawing with SkBlendMode, return undefined results. discard() does
3033not change Clip or Matrix.
3034
3035discard() may do nothing, depending on the implementation of Surface or Device
3036that created Canvas.
3037
3038discard() allows optimized performance on subsequent draws by removing
3039cached data associated with Surface or Device.
3040It is not necessary to call discard() once done with Canvas;
3041any cached data is deleted when owning Surface or Device is deleted.
3042
3043#ToDo example? not sure how to make this meaningful w/o more implementation detail ##
3044#SeeAlso flush() SkSurface::prepareForExternalIO GrContext::abandonContext
3045
3046#NoExample 
3047##
3048
3049##
3050
3051# ------------------------------------------------------------------------------
3052
3053#Method void drawPaint(const SkPaint& paint)
3054
3055#Line # fills Clip with Paint ##
3056Fill Clip with Paint paint. Paint components Mask_Filter, Shader,
3057Color_Filter, Image_Filter, and Blend_Mode affect drawing;
3058Path_Effect in paint is ignored.
3059
3060# can Path_Effect in paint ever alter drawPaint?
3061
3062#Param  paint    graphics state used to fill Canvas ##
3063
3064#Example
3065void draw(SkCanvas* canvas) {
3066    SkColor     colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
3067    SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
3068    SkPaint     paint;
3069    paint.setShader(SkGradientShader::MakeSweep(256, 256, colors, pos, SK_ARRAY_COUNT(colors)));
3070    canvas->drawPaint(paint);
3071}
3072##
3073
3074#SeeAlso clear drawColor SkBitmap::erase
3075
3076##
3077
3078# ------------------------------------------------------------------------------
3079
3080#Enum PointMode
3081#Line # sets drawPoints options ##
3082
3083#Code
3084    enum PointMode {
3085        kPoints_PointMode,
3086        kLines_PointMode,
3087        kPolygon_PointMode,
3088    };
3089##
3090
3091Selects if an array of points are drawn as discrete points, as lines, or as
3092an open polygon.
3093
3094#Const kPoints_PointMode 0
3095    Draw each point separately.
3096##
3097
3098#Const kLines_PointMode 1
3099    Draw each pair of points as a line segment.
3100##
3101
3102#Const kPolygon_PointMode 2
3103    Draw the array of points as a open polygon.
3104##
3105
3106#Example
3107    #Description 
3108        The upper left corner shows three squares when drawn as points.
3109        The upper right corner shows one line; when drawn as lines, two points are required per line.
3110        The lower right corner shows two lines; when draw as polygon, no miter is drawn at the corner.
3111        The lower left corner shows two lines with a miter when path contains polygon.
3112    ##
3113void draw(SkCanvas* canvas) {
3114  SkPaint paint;
3115  paint.setStyle(SkPaint::kStroke_Style);
3116  paint.setStrokeWidth(10);
3117  SkPoint points[] = {{64, 32}, {96, 96}, {32, 96}};
3118  canvas->drawPoints(SkCanvas::kPoints_PointMode, 3, points, paint);
3119  canvas->translate(128, 0);
3120  canvas->drawPoints(SkCanvas::kLines_PointMode, 3, points, paint);
3121  canvas->translate(0, 128);
3122  canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, points, paint);
3123  SkPath path;
3124  path.addPoly(points, 3, false);
3125  canvas->translate(-128, 0);
3126  canvas->drawPath(path, paint);
3127}
3128##
3129
3130#SeeAlso drawLine drawPoint drawPath
3131
3132##
3133
3134# ------------------------------------------------------------------------------
3135
3136#Method void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint)
3137
3138#Line # draws array as points, lines, polygon ##
3139Draw pts using Clip, Matrix and Paint paint.
3140count is the number of points; if count is less than one, has no effect.
3141mode may be one of: kPoints_PointMode, kLines_PointMode, or kPolygon_PointMode.
3142
3143If mode is kPoints_PointMode, the shape of point drawn depends on paint
3144Paint_Stroke_Cap. If paint is set to SkPaint::kRound_Cap, each point draws a
3145circle of diameter Paint_Stroke_Width. If paint is set to SkPaint::kSquare_Cap
3146or SkPaint::kButt_Cap, each point draws a square of width and height
3147Paint_Stroke_Width.
3148
3149If mode is kLines_PointMode, each pair of points draws a line segment.
3150One line is drawn for every two points; each point is used once. If count is odd,
3151the final point is ignored. 
3152
3153If mode is kPolygon_PointMode, each adjacent pair of points draws a line segment.
3154count minus one lines are drawn; the first and last point are used once.
3155
3156Each line segment respects paint Paint_Stroke_Cap and Paint_Stroke_Width.
3157Paint_Style is ignored, as if were set to SkPaint::kStroke_Style.
3158
3159Always draws each element one at a time; is not affected by
3160Paint_Stroke_Join, and unlike drawPath, does not create a mask from all points
3161and lines before drawing. 
3162
3163#Param  mode     whether pts draws points or lines ##
3164#Param  count    number of points in the array ##
3165#Param  pts      array of points to draw ##
3166#Param  paint    stroke, blend, color, and so on, used to draw ##
3167
3168#Example
3169#Height 200
3170    #Description 
3171    #List
3172    # The first column draws points. ##
3173    # The second column draws points as lines. ##
3174    # The third column draws points as a polygon. ##
3175    # The fourth column draws points as a polygonal path. ##
3176    # The first row uses a round cap and round join. ##
3177    # The second row uses a square cap and a miter join. ##
3178    # The third row uses a butt cap and a bevel join. ##
3179    ##
3180    The transparent color makes multiple line draws visible;
3181    the path is drawn all at once.
3182    ##
3183void draw(SkCanvas* canvas) {
3184    SkPaint paint;
3185    paint.setAntiAlias(true);
3186    paint.setStyle(SkPaint::kStroke_Style);
3187    paint.setStrokeWidth(10);
3188    paint.setColor(0x80349a45);
3189    const SkPoint points[] = {{32, 16}, {48, 48}, {16, 32}};
3190    const SkPaint::Join join[] = { SkPaint::kRound_Join, 
3191                                   SkPaint::kMiter_Join,
3192                                   SkPaint::kBevel_Join };
3193    int joinIndex = 0;
3194    SkPath path;
3195    path.addPoly(points, 3, false);
3196    for (const auto cap : { SkPaint::kRound_Cap, SkPaint::kSquare_Cap, SkPaint::kButt_Cap } ) {
3197        paint.setStrokeCap(cap);
3198        paint.setStrokeJoin(join[joinIndex++]);
3199        for (const auto mode : { SkCanvas::kPoints_PointMode,
3200                                 SkCanvas::kLines_PointMode,
3201                                 SkCanvas::kPolygon_PointMode } ) {
3202            canvas->drawPoints(mode, 3, points, paint);
3203            canvas->translate(64, 0);
3204        }
3205        canvas->drawPath(path, paint);
3206        canvas->translate(-192, 64);
3207    }
3208}
3209##
3210
3211#SeeAlso drawLine drawPoint drawPath
3212
3213##
3214
3215# ------------------------------------------------------------------------------
3216
3217#Method void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint)
3218
3219#Line # draws point at (x, y) position ##
3220Draw point at (x, y) using Clip, Matrix and Paint paint.
3221
3222The shape of point drawn depends on paint Paint_Stroke_Cap.
3223If paint is set to SkPaint::kRound_Cap, draw a circle of diameter
3224Paint_Stroke_Width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, 
3225draw a square of width and height Paint_Stroke_Width.
3226Paint_Style is ignored, as if were set to SkPaint::kStroke_Style.
3227
3228#Param  x        left edge of circle or square ##
3229#Param  y        top edge of circle or square ##
3230#Param  paint    stroke, blend, color, and so on, used to draw ##
3231
3232#Example
3233void draw(SkCanvas* canvas) {
3234  SkPaint paint;
3235  paint.setAntiAlias(true);
3236  paint.setColor(0x80349a45);
3237  paint.setStyle(SkPaint::kStroke_Style);
3238  paint.setStrokeWidth(100);
3239  paint.setStrokeCap(SkPaint::kRound_Cap);
3240  canvas->scale(1, 1.2f);
3241  canvas->drawPoint(64, 96, paint);
3242  canvas->scale(.6f, .8f);
3243  paint.setColor(SK_ColorWHITE);
3244  canvas->drawPoint(106, 120, paint);
3245}
3246##
3247
3248#SeeAlso drawPoints drawCircle drawRect drawLine drawPath
3249
3250##
3251
3252#Method void drawPoint(SkPoint p, const SkPaint& paint)
3253
3254Draw point p using Clip, Matrix and Paint paint.
3255
3256The shape of point drawn depends on paint Paint_Stroke_Cap.
3257If paint is set to SkPaint::kRound_Cap, draw a circle of diameter
3258Paint_Stroke_Width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, 
3259draw a square of width and height Paint_Stroke_Width.
3260Paint_Style is ignored, as if were set to SkPaint::kStroke_Style.
3261
3262#Param  p        top-left edge of circle or square ##
3263#Param  paint    stroke, blend, color, and so on, used to draw ##
3264
3265#Example
3266void draw(SkCanvas* canvas) {
3267  SkPaint paint;
3268  paint.setAntiAlias(true);
3269  paint.setColor(0x80349a45);
3270  paint.setStyle(SkPaint::kStroke_Style);
3271  paint.setStrokeWidth(100);
3272  paint.setStrokeCap(SkPaint::kSquare_Cap);
3273  canvas->scale(1, 1.2f);
3274  canvas->drawPoint({64, 96}, paint);
3275  canvas->scale(.6f, .8f);
3276  paint.setColor(SK_ColorWHITE);
3277  canvas->drawPoint(106, 120, paint);
3278}
3279##
3280
3281#SeeAlso drawPoints drawCircle drawRect drawLine drawPath
3282
3283##
3284
3285# ------------------------------------------------------------------------------
3286
3287#Method void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint)
3288
3289#Line # draws line segment between two points ##
3290Draws line segment from (x0, y0) to (x1, y1) using Clip, Matrix, and Paint paint.
3291In paint: Paint_Stroke_Width describes the line thickness;
3292Paint_Stroke_Cap draws the end rounded or square;
3293Paint_Style is ignored, as if were set to SkPaint::kStroke_Style.
3294
3295#Param  x0    start of line segment on x-axis ##
3296#Param  y0    start of line segment on y-axis ##
3297#Param  x1    end of line segment on x-axis ##
3298#Param  y1    end of line segment on y-axis ##
3299#Param  paint stroke, blend, color, and so on, used to draw ##
3300
3301#Example
3302  SkPaint paint;
3303  paint.setAntiAlias(true);
3304  paint.setColor(0xFF9a67be);
3305  paint.setStrokeWidth(20);
3306  canvas->skew(1, 0);
3307  canvas->drawLine(32, 96, 32, 160, paint);
3308  canvas->skew(-2, 0);
3309  canvas->drawLine(288, 96, 288, 160, paint);
3310##
3311
3312#SeeAlso drawPoint drawCircle drawRect drawPath
3313
3314##
3315
3316#Method void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint)
3317
3318Draws line segment from p0 to p1 using Clip, Matrix, and Paint paint.
3319In paint: Paint_Stroke_Width describes the line thickness;
3320Paint_Stroke_Cap draws the end rounded or square;
3321Paint_Style is ignored, as if were set to SkPaint::kStroke_Style.
3322
3323#Param  p0    start of line segment ##
3324#Param  p1    end of line segment ##
3325#Param  paint  stroke, blend, color, and so on, used to draw ##
3326
3327#Example
3328  SkPaint paint;
3329  paint.setAntiAlias(true);
3330  paint.setColor(0xFF9a67be);
3331  paint.setStrokeWidth(20);
3332  canvas->skew(1, 0);
3333  canvas->drawLine({32, 96}, {32, 160}, paint);
3334  canvas->skew(-2, 0);
3335  canvas->drawLine({288, 96}, {288, 160}, paint);
3336##
3337
3338#SeeAlso drawPoint drawCircle drawRect drawPath
3339
3340##
3341
3342# ------------------------------------------------------------------------------
3343
3344#Method void drawRect(const SkRect& rect, const SkPaint& paint)
3345
3346#Line # draws Rect using Clip, Matrix, and Paint ##
3347Draw Rect rect using Clip, Matrix, and Paint paint.
3348In paint: Paint_Style determines if rectangle is stroked or filled; 
3349if stroked, Paint_Stroke_Width describes the line thickness, and
3350Paint_Stroke_Join draws the corners rounded or square.
3351
3352#Param  rect     rectangle to draw ##
3353#Param  paint    stroke or fill, blend, color, and so on, used to draw ##
3354
3355#Example
3356void draw(SkCanvas* canvas) {
3357    SkPoint rectPts[] = { {64, 48}, {192, 160} };
3358    SkPaint paint;
3359    paint.setAntiAlias(true);
3360    paint.setStyle(SkPaint::kStroke_Style);
3361    paint.setStrokeWidth(20);
3362    paint.setStrokeJoin(SkPaint::kRound_Join);
3363    SkMatrix rotator;
3364    rotator.setRotate(30, 128, 128);
3365    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) {
3366        paint.setColor(color);
3367        SkRect rect;
3368        rect.set(rectPts[0], rectPts[1]);
3369        canvas->drawRect(rect, paint);
3370        rotator.mapPoints(rectPts, 2);
3371    }
3372}
3373##
3374
3375#SeeAlso drawIRect drawRRect drawRoundRect drawRegion drawPath drawLine 
3376
3377##
3378
3379# ------------------------------------------------------------------------------
3380
3381#Method void drawIRect(const SkIRect& rect, const SkPaint& paint) 
3382
3383#Line # draws IRect using Clip, Matrix, and Paint ##
3384Draw IRect rect using Clip, Matrix, and Paint paint.
3385In paint: Paint_Style determines if rectangle is stroked or filled; 
3386if stroked, Paint_Stroke_Width describes the line thickness, and
3387Paint_Stroke_Join draws the corners rounded or square.
3388
3389#Param  rect     rectangle to draw ##
3390#Param  paint    stroke or fill, blend, color, and so on, used to draw ##
3391
3392#Example
3393    SkIRect rect = { 64, 48, 192, 160 };
3394    SkPaint paint;
3395    paint.setAntiAlias(true);
3396    paint.setStyle(SkPaint::kStroke_Style);
3397    paint.setStrokeWidth(20);
3398    paint.setStrokeJoin(SkPaint::kRound_Join);
3399    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) {
3400        paint.setColor(color);
3401        canvas->drawIRect(rect, paint);
3402        canvas->rotate(30, 128, 128);
3403    }
3404##
3405
3406#SeeAlso drawRect drawRRect drawRoundRect drawRegion drawPath drawLine
3407
3408##
3409
3410# ------------------------------------------------------------------------------
3411
3412#Method void drawRegion(const SkRegion& region, const SkPaint& paint)
3413
3414#Line # draws Region using Clip, Matrix, and Paint ##
3415Draw Region region using Clip, Matrix, and Paint paint.
3416In paint: Paint_Style determines if rectangle is stroked or filled; 
3417if stroked, Paint_Stroke_Width describes the line thickness, and
3418Paint_Stroke_Join draws the corners rounded or square.
3419
3420#Param  region   region to draw ##
3421#Param  paint    Paint stroke or fill, blend, color, and so on, used to draw ##
3422
3423#Example
3424void draw(SkCanvas* canvas) {
3425    SkRegion region;
3426    region.op( 10, 10, 50, 50, SkRegion::kUnion_Op);
3427    region.op( 10, 50, 90, 90, SkRegion::kUnion_Op);
3428    SkPaint paint;
3429    paint.setAntiAlias(true);
3430    paint.setStyle(SkPaint::kStroke_Style);
3431    paint.setStrokeWidth(20);
3432    paint.setStrokeJoin(SkPaint::kRound_Join);
3433    canvas->drawRegion(region, paint);
3434}
3435##
3436
3437#SeeAlso drawRect drawIRect drawPath
3438
3439##
3440
3441# ------------------------------------------------------------------------------
3442
3443#Method void drawOval(const SkRect& oval, const SkPaint& paint)
3444
3445#Line # draws Oval using Clip, Matrix, and Paint ##
3446Draw Oval oval using Clip, Matrix, and Paint.
3447In paint: Paint_Style determines if Oval is stroked or filled; 
3448if stroked, Paint_Stroke_Width describes the line thickness.
3449
3450#Param  oval     Rect bounds of Oval ##
3451#Param  paint    Paint stroke or fill, blend, color, and so on, used to draw ##
3452
3453#Example
3454void draw(SkCanvas* canvas) {
3455    canvas->clear(0xFF3f5f9f);
3456    SkColor  kColor1 = SkColorSetARGB(0xff, 0xff, 0x7f, 0);
3457    SkColor  g1Colors[] = { kColor1, SkColorSetA(kColor1, 0x20) };
3458    SkPoint  g1Points[] = { { 0, 0 }, { 0, 100 } };
3459    SkScalar pos[] = { 0.2f, 1.0f };
3460    SkRect bounds = SkRect::MakeWH(80, 70);
3461    SkPaint paint;
3462    paint.setAntiAlias(true);
3463    paint.setShader(SkGradientShader::MakeLinear(g1Points, g1Colors, pos, SK_ARRAY_COUNT(g1Colors),
3464            SkShader::kClamp_TileMode));
3465    canvas->drawOval(bounds , paint);
3466}
3467##
3468
3469#SeeAlso drawCircle drawPoint drawPath drawRRect drawRoundRect
3470
3471##
3472
3473# ------------------------------------------------------------------------------
3474
3475#Method void drawRRect(const SkRRect& rrect, const SkPaint& paint)
3476
3477#Line # draws Round_Rect using Clip, Matrix, and Paint ##
3478Draw Round_Rect rrect using Clip, Matrix, and Paint paint.
3479In paint: Paint_Style determines if rrect is stroked or filled; 
3480if stroked, Paint_Stroke_Width describes the line thickness.
3481
3482rrect may represent a rectangle, circle, oval, uniformly rounded rectangle, or
3483may have any combination of positive non-square radii for the four corners.
3484
3485#Param  rrect    Round_Rect with up to eight corner radii to draw ##
3486#Param  paint    Paint stroke or fill, blend, color, and so on, used to draw ##
3487
3488#Example
3489void draw(SkCanvas* canvas) {
3490    SkPaint paint;
3491    paint.setAntiAlias(true);
3492    SkRect outer = {30, 40, 210, 220};
3493    SkRect radii = {30, 50, 70, 90 };
3494    SkRRect rRect;
3495    rRect.setNinePatch(outer, radii.fLeft, radii.fTop, radii.fRight, radii.fBottom);
3496    canvas->drawRRect(rRect, paint);
3497    paint.setColor(SK_ColorWHITE);
3498    canvas->drawLine(outer.fLeft + radii.fLeft, outer.fTop,
3499                     outer.fLeft + radii.fLeft, outer.fBottom, paint);
3500    canvas->drawLine(outer.fRight - radii.fRight, outer.fTop, 
3501                     outer.fRight - radii.fRight, outer.fBottom, paint);
3502    canvas->drawLine(outer.fLeft,  outer.fTop + radii.fTop, 
3503                     outer.fRight, outer.fTop + radii.fTop, paint);
3504    canvas->drawLine(outer.fLeft,  outer.fBottom - radii.fBottom, 
3505                     outer.fRight, outer.fBottom - radii.fBottom, paint);
3506}
3507##
3508
3509#SeeAlso drawRect drawRoundRect drawDRRect drawCircle drawOval drawPath
3510
3511##
3512
3513# ------------------------------------------------------------------------------
3514
3515#Method void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint)
3516
3517#Line # draws double Round_Rect stroked or filled ##
3518Draw Round_Rect outer and inner
3519using Clip, Matrix, and Paint paint. 
3520outer must contain inner or the drawing is undefined.
3521In paint: Paint_Style determines if Round_Rect is stroked or filled; 
3522if stroked, Paint_Stroke_Width describes the line thickness.
3523If stroked and Round_Rect corner has zero length radii, Paint_Stroke_Join can
3524draw corners rounded or square. 
3525
3526GPU-backed platforms optimize drawing when both outer and inner are
3527concave and outer contains inner. These platforms may not be able to draw
3528Path built with identical data as fast. 
3529
3530#Param  outer    Round_Rect outer bounds to draw ##
3531#Param  inner    Round_Rect inner bounds to draw ##
3532#Param  paint    Paint stroke or fill, blend, color, and so on, used to draw ##
3533
3534#Example
3535void draw(SkCanvas* canvas) {
3536   SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200});
3537   SkRRect inner = SkRRect::MakeOval({60, 70, 170, 160});
3538   SkPaint paint;
3539   canvas->drawDRRect(outer, inner, paint);
3540}
3541##
3542
3543#Example
3544#Description
3545    Outer Rect has no corner radii, but stroke join is rounded.
3546    Inner Round_Rect has corner radii; outset stroke increases radii of corners.
3547    Stroke join does not affect inner Round_Rect since it has no sharp corners.
3548##
3549void draw(SkCanvas* canvas) {
3550   SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200});
3551   SkRRect inner = SkRRect::MakeRectXY({60, 70, 170, 160}, 10, 10);
3552   SkPaint paint;
3553   paint.setAntiAlias(true);
3554   paint.setStyle(SkPaint::kStroke_Style);
3555   paint.setStrokeWidth(20);
3556   paint.setStrokeJoin(SkPaint::kRound_Join);
3557   canvas->drawDRRect(outer, inner, paint);
3558   paint.setStrokeWidth(1);
3559   paint.setColor(SK_ColorWHITE);
3560   canvas->drawDRRect(outer, inner, paint);
3561}
3562##
3563
3564#SeeAlso drawRect drawRoundRect drawRRect drawCircle drawOval drawPath
3565
3566##
3567
3568# ------------------------------------------------------------------------------
3569
3570#Method void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint)
3571
3572#Line # draws Circle using Clip, Matrix, and Paint ##
3573Draw Circle at (cx, cy) with radius using Clip, Matrix, and Paint paint.
3574If radius is zero or less, nothing is drawn.
3575In paint: Paint_Style determines if Circle is stroked or filled; 
3576if stroked, Paint_Stroke_Width describes the line thickness.
3577
3578#Param  cx       Circle center on the x-axis ##
3579#Param  cy       Circle center on the y-axis ##
3580#Param  radius   half the diameter of Circle ##
3581#Param  paint    Paint stroke or fill, blend, color, and so on, used to draw ##
3582
3583#Example
3584    void draw(SkCanvas* canvas) {
3585        SkPaint paint;
3586        paint.setAntiAlias(true);
3587        canvas->drawCircle(128, 128, 90, paint);
3588        paint.setColor(SK_ColorWHITE);
3589        canvas->drawCircle(86, 86, 20, paint);
3590        canvas->drawCircle(160, 76, 20, paint);
3591        canvas->drawCircle(140, 150, 35, paint);
3592    }
3593##
3594
3595#SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine
3596
3597##
3598
3599#Method void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint)
3600
3601Draw Circle at center with radius using Clip, Matrix, and Paint paint.
3602If radius is zero or less, nothing is drawn.
3603In paint: Paint_Style determines if Circle is stroked or filled; 
3604if stroked, Paint_Stroke_Width describes the line thickness.
3605
3606#Param  center   Circle center ##
3607#Param  radius   half the diameter of Circle ##
3608#Param  paint    Paint stroke or fill, blend, color, and so on, used to draw ##
3609
3610#Example
3611    void draw(SkCanvas* canvas) {
3612        SkPaint paint;
3613        paint.setAntiAlias(true);
3614        canvas->drawCircle(128, 128, 90, paint);
3615        paint.setColor(SK_ColorWHITE);
3616        canvas->drawCircle({86, 86}, 20, paint);
3617        canvas->drawCircle({160, 76}, 20, paint);
3618        canvas->drawCircle({140, 150}, 35, paint);
3619    }
3620##
3621
3622#SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine
3623
3624##
3625
3626# ------------------------------------------------------------------------------
3627
3628#Method void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
3629                 bool useCenter, const SkPaint& paint)
3630#Line # draws Arc using Clip, Matrix, and Paint ##
3631
3632Draw Arc using Clip, Matrix, and Paint paint.
3633
3634Arc is part of Oval bounded by oval, sweeping from startAngle to startAngle plus
3635sweepAngle. startAngle and sweepAngle are in degrees.
3636
3637startAngle of zero places start point at the right middle edge of oval.
3638A positive sweepAngle places Arc end point clockwise from start point;
3639a negative sweepAngle places Arc end point counterclockwise from start point.
3640sweepAngle may exceed 360 degrees, a full circle.
3641If useCenter is true, draw a wedge that includes lines from oval
3642center to Arc end points. If useCenter is false, draw Arc between end points.
3643
3644If Rect oval is empty or sweepAngle is zero, nothing is drawn.
3645
3646#Param  oval     Rect bounds of Oval containing Arc to draw ##
3647#Param  startAngle angle in degrees where Arc begins ##
3648#Param  sweepAngle sweep angle in degrees; positive is clockwise ##
3649#Param  useCenter if true, include the center of the oval ##
3650#Param  paint    Paint stroke or fill, blend, color, and so on, used to draw ##
3651
3652#Example
3653    void draw(SkCanvas* canvas) {
3654        SkPaint paint;
3655        paint.setAntiAlias(true);
3656        SkRect oval = { 4, 4, 60, 60};
3657        for (auto useCenter : { false, true } ) {
3658            for (auto style : { SkPaint::kFill_Style, SkPaint::kStroke_Style } ) {
3659                paint.setStyle(style);
3660                for (auto degrees : { 45, 90, 180, 360} ) {
3661                    canvas->drawArc(oval, 0, degrees , useCenter, paint);
3662                    canvas->translate(64, 0);
3663                }
3664                canvas->translate(-256, 64);
3665            }
3666        }
3667    }
3668##
3669
3670#Example
3671#Height 64
3672    void draw(SkCanvas* canvas) {
3673        SkPaint paint;
3674        paint.setAntiAlias(true);
3675        paint.setStyle(SkPaint::kStroke_Style);
3676        paint.setStrokeWidth(4);
3677        SkRect oval = { 4, 4, 60, 60};
3678        float intervals[] = { 5, 5 };
3679        paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f));
3680        for (auto degrees : { 270, 360, 540, 720 } ) {
3681            canvas->drawArc(oval, 0, degrees, false, paint);
3682            canvas->translate(64, 0);
3683        }
3684    }
3685##
3686
3687#SeeAlso SkPath::arcTo drawCircle drawOval drawPath
3688
3689##
3690
3691# ------------------------------------------------------------------------------
3692
3693#Method void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint)
3694
3695#Line # draws Round_Rect using Clip, Matrix, and Paint ##
3696Draw Round_Rect bounded by Rect rect, with corner radii (rx, ry) using Clip,
3697Matrix, and Paint paint.
3698
3699In paint: Paint_Style determines if Round_Rect is stroked or filled; 
3700if stroked, Paint_Stroke_Width describes the line thickness.
3701If rx or ry are less than zero, they are treated as if they are zero.
3702If rx plus ry exceeds rect width or rect height, radii are scaled down to fit.
3703If rx and ry are zero, Round_Rect is drawn as Rect and if stroked is affected by
3704Paint_Stroke_Join.
3705
3706#Param  rect     Rect bounds of Round_Rect to draw ##
3707#Param  rx       axis length in x of oval describing rounded corners ##
3708#Param  ry       axis length in y of oval describing rounded corners ##
3709#Param  paint    stroke, blend, color, and so on, used to draw ##
3710
3711#Example
3712#Description
3713    Top row has a zero radius a generates a rectangle.
3714    Second row radii sum to less than sides.
3715    Third row radii sum equals sides.
3716    Fourth row radii sum exceeds sides; radii are scaled to fit.
3717##
3718    void draw(SkCanvas* canvas) {
3719        SkVector radii[] = { {0, 20}, {10, 10}, {10, 20}, {10, 40} };
3720        SkPaint paint;
3721        paint.setStrokeWidth(15);
3722        paint.setStrokeJoin(SkPaint::kRound_Join);
3723        paint.setAntiAlias(true);
3724        for (auto style : { SkPaint::kStroke_Style, SkPaint::kFill_Style  } ) {
3725            paint.setStyle(style );
3726            for (size_t i = 0; i < SK_ARRAY_COUNT(radii); ++i) {
3727               canvas->drawRoundRect({10, 10, 60, 40}, radii[i].fX, radii[i].fY, paint);
3728               canvas->translate(0, 60);
3729            }
3730            canvas->translate(80, -240);
3731        }
3732    }
3733##
3734
3735#SeeAlso DrawRRect drawRect drawDRRect drawPath drawCircle drawOval drawPoint
3736
3737##
3738
3739# ------------------------------------------------------------------------------
3740
3741#Method void drawPath(const SkPath& path, const SkPaint& paint)
3742
3743#Line # draws Path using Clip, Matrix, and Paint ##
3744Draw Path path using Clip, Matrix, and Paint paint.
3745Path contains an array of Path_Contour, each of which may be open or closed.
3746
3747In paint: Paint_Style determines if Round_Rect is stroked or filled:
3748if filled, Path_Fill_Type determines whether Path_Contour describes inside or
3749outside of fill; if stroked, Paint_Stroke_Width describes the line thickness,
3750Paint_Stroke_Cap describes line ends, and Paint_Stroke_Join describes how
3751corners are drawn.
3752
3753#Param  path     Path to draw ##
3754#Param  paint    stroke, blend, color, and so on, used to draw ##
3755
3756#Example
3757#Description
3758    Top rows draw stroked path with combinations of joins and caps. The open contour
3759    is affected by caps; the closed contour is affected by joins.
3760    Bottom row draws fill the same for open and closed contour. 
3761    First bottom column shows winding fills overlap.
3762    Second bottom column shows even odd fills exclude overlap.
3763    Third bottom column shows inverse winding fills area outside both contours.
3764##
3765void draw(SkCanvas* canvas) {
3766    SkPath path;
3767    path.moveTo(20, 20);
3768    path.quadTo(60, 20, 60, 60);
3769    path.close();
3770    path.moveTo(60, 20);
3771    path.quadTo(60, 60, 20, 60);
3772    SkPaint paint;
3773    paint.setStrokeWidth(10);
3774    paint.setAntiAlias(true);
3775    paint.setStyle(SkPaint::kStroke_Style);
3776    for (auto join: { SkPaint::kBevel_Join, SkPaint::kRound_Join, SkPaint::kMiter_Join } ) {
3777        paint.setStrokeJoin(join);
3778        for (auto cap: { SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap  } ) {
3779            paint.setStrokeCap(cap);
3780            canvas->drawPath(path, paint);
3781            canvas->translate(80, 0);
3782        }
3783        canvas->translate(-240, 60);
3784    }
3785    paint.setStyle(SkPaint::kFill_Style);
3786    for (auto fill : { SkPath::kWinding_FillType, 
3787                       SkPath::kEvenOdd_FillType, 
3788                       SkPath::kInverseWinding_FillType } ) {
3789        path.setFillType(fill);
3790        canvas->save();
3791        canvas->clipRect({0, 10, 80, 70});
3792        canvas->drawPath(path, paint);
3793        canvas->restore();
3794        canvas->translate(80, 0);
3795    }
3796}
3797##
3798
3799#SeeAlso SkPath drawLine drawArc drawRect drawPoints
3800
3801##
3802
3803# ------------------------------------------------------------------------------
3804#Subtopic Draw_Image
3805#Line # draws Image to Canvas ##
3806
3807drawImage, drawImageRect, and drawImageNine can be called with a bare pointer or
3808a smart pointer as a convenience. The pairs of calls are otherwise identical.
3809
3810#Method void drawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint = nullptr)
3811
3812#In Draw_Image
3813#Line # draws Image at (x, y) position ##
3814Draw Image image, with its top-left corner at (left, top),
3815using Clip, Matrix, and optional Paint paint.
3816
3817If paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, Blend_Mode,
3818and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
3819If paint contains Mask_Filter, generate mask from image bounds. If generated
3820mask extends beyond image bounds, replicate image edge colors, just as Shader
3821made from SkImage::makeShader with SkShader::kClamp_TileMode set replicates the
3822image edge color when it samples outside of its bounds. 
3823
3824#Param  image    uncompressed rectangular map of pixels ##
3825#Param  left     left side of image ##
3826#Param  top      top side of image ##
3827#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
3828                 and so on; or nullptr
3829##
3830
3831#Example
3832#Height 64
3833#Image 4
3834void draw(SkCanvas* canvas) {
3835   // sk_sp<SkImage> image;
3836   SkImage* imagePtr = image.get();
3837   canvas->drawImage(imagePtr, 0, 0);
3838   SkPaint paint;
3839   canvas->drawImage(imagePtr, 80, 0, &paint);
3840   paint.setAlpha(0x80);
3841   canvas->drawImage(imagePtr, 160, 0, &paint);
3842}
3843##
3844
3845#SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter
3846
3847##
3848
3849# ------------------------------------------------------------------------------
3850
3851#Method void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top,
3852                   const SkPaint* paint = nullptr) 
3853#In Draw_Image
3854
3855Draw Image image, with its top-left corner at (left, top),
3856using Clip, Matrix, and optional Paint paint.
3857
3858If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
3859Blend_Mode, and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
3860If paint contains Mask_Filter, generate mask from image bounds. If generated
3861mask extends beyond image bounds, replicate image edge colors, just as Shader
3862made from SkImage::makeShader with SkShader::kClamp_TileMode set replicates the
3863image edge color when it samples outside of its bounds. 
3864
3865#Param  image    uncompressed rectangular map of pixels ##
3866#Param  left     left side of image ##
3867#Param  top      pop side of image ##
3868#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
3869                 and so on; or nullptr
3870##
3871
3872#Example
3873#Height 64
3874#Image 4
3875void draw(SkCanvas* canvas) {
3876   // sk_sp<SkImage> image;
3877   canvas->drawImage(image, 0, 0);
3878   SkPaint paint;
3879   canvas->drawImage(image, 80, 0, &paint);
3880   paint.setAlpha(0x80);
3881   canvas->drawImage(image, 160, 0, &paint);
3882}
3883##
3884
3885#SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter
3886
3887##
3888
3889# ------------------------------------------------------------------------------
3890
3891#Enum SrcRectConstraint
3892#Line # sets drawImageRect options ##
3893
3894#Code
3895    enum SrcRectConstraint {
3896        kStrict_SrcRectConstraint, 
3897        kFast_SrcRectConstraint, 
3898    };
3899##
3900
3901SrcRectConstraint controls the behavior at the edge of source Rect,
3902provided to drawImageRect, trading off speed for precision.
3903
3904Image_Filter in Paint may sample multiple pixels in the image. Source Rect
3905restricts the bounds of pixels that may be read. Image_Filter may slow down if
3906it cannot read outside the bounds, when sampling near the edge of source Rect. 
3907SrcRectConstraint specifies whether an Image_Filter is allowed to read pixels
3908outside source Rect.
3909
3910#Const kStrict_SrcRectConstraint
3911    Requires Image_Filter to respect source Rect,
3912    sampling only inside of its bounds, possibly with a performance penalty.
3913##
3914
3915#Const kFast_SrcRectConstraint
3916    Permits Image_Filter to sample outside of source Rect
3917    by half the width of Image_Filter, permitting it to run faster but with
3918    error at the image edges.
3919##
3920
3921#Example
3922#Height 64
3923#Description
3924    redBorder contains a black and white checkerboard bordered by red.
3925    redBorder is drawn scaled by 16 on the left.
3926    The middle and right bitmaps are filtered checkerboards.
3927    Drawing the checkerboard with kStrict_SrcRectConstraint shows only a blur of black and white.
3928    Drawing the checkerboard with kFast_SrcRectConstraint allows red to bleed in the corners.
3929##
3930void draw(SkCanvas* canvas) {
3931    SkBitmap redBorder;
3932    redBorder.allocPixels(SkImageInfo::MakeN32Premul(4, 4));
3933    SkCanvas checkRed(redBorder);
3934    checkRed.clear(SK_ColorRED);
3935    uint32_t checkers[][2] = { { SK_ColorBLACK, SK_ColorWHITE },
3936                               { SK_ColorWHITE, SK_ColorBLACK } };
3937    checkRed.writePixels(
3938            SkImageInfo::MakeN32Premul(2, 2), (void*) checkers, sizeof(checkers[0]), 1, 1);
3939    canvas->scale(16, 16);
3940    canvas->drawBitmap(redBorder, 0, 0, nullptr);
3941    canvas->resetMatrix();
3942    sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder);
3943    SkPaint lowPaint;
3944    lowPaint.setFilterQuality(kLow_SkFilterQuality);
3945    for (auto constraint : { SkCanvas::kStrict_SrcRectConstraint,
3946                             SkCanvas::kFast_SrcRectConstraint } ) {
3947        canvas->translate(80, 0);
3948        canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3),
3949                SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint);
3950    }
3951}
3952##
3953
3954#SeeAlso drawImageRect drawImage SkPaint::setImageFilter
3955
3956##
3957
3958# ------------------------------------------------------------------------------
3959
3960#Method void drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
3961                       const SkPaint* paint,
3962                       SrcRectConstraint constraint = kStrict_SrcRectConstraint)
3963#In Draw_Image
3964#Line # draws Image, source Rect to destination Rect ##
3965
3966Draw Rect src of Image image, scaled and translated to fill Rect dst.
3967Additionally transform draw using Clip, Matrix, and optional Paint paint.
3968
3969If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
3970Blend_Mode, and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
3971If paint contains Mask_Filter, generate mask from image bounds.
3972
3973If generated mask extends beyond image bounds, replicate image edge colors, just
3974as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
3975replicates the image edge color when it samples outside of its bounds.
3976
3977constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to
3978sample within src; set to kFast_SrcRectConstraint allows sampling outside to
3979improve performance.
3980
3981#Param  image      Image containing pixels, dimensions, and format ##
3982#Param  src        source Rect of image to draw from ##
3983#Param  dst        destination Rect of image to draw to ##
3984#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
3985                   and so on; or nullptr
3986##
3987#Param  constraint filter strictly within src or draw faster ##
3988
3989#Example
3990#Height 64
3991#Description
3992    The left bitmap draws with Paint default kNone_SkFilterQuality, and stays within
3993    its bounds; there is no bleeding with kFast_SrcRectConstraint.
3994    the middle and right bitmaps draw with kLow_SkFilterQuality; with
3995    kStrict_SrcRectConstraint, the filter remains within the checkerboard, and
3996    with kFast_SrcRectConstraint red bleeds on the edges.
3997##
3998void draw(SkCanvas* canvas) {
3999    uint32_t pixels[][4] = { 
4000            { 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 },
4001            { 0xFFFF0000, 0xFF000000, 0xFFFFFFFF, 0xFFFF0000 },
4002            { 0xFFFF0000, 0xFFFFFFFF, 0xFF000000, 0xFFFF0000 },
4003            { 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 } };
4004    SkBitmap redBorder;
4005    redBorder.installPixels(SkImageInfo::MakeN32Premul(4, 4), 
4006            (void*) pixels, sizeof(pixels[0]));
4007    sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder);
4008    SkPaint lowPaint;
4009    for (auto constraint : {
4010            SkCanvas::kFast_SrcRectConstraint,
4011            SkCanvas::kStrict_SrcRectConstraint,
4012            SkCanvas::kFast_SrcRectConstraint } ) {
4013        canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3),
4014                SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint);
4015        lowPaint.setFilterQuality(kLow_SkFilterQuality);
4016        canvas->translate(80, 0);
4017    }
4018}
4019##
4020
4021#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
4022
4023##
4024
4025# ------------------------------------------------------------------------------
4026
4027#Method void drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
4028                       const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
4029#In Draw_Image
4030
4031Draw IRect isrc of Image image, scaled and translated to fill Rect dst.
4032Note that isrc is on integer pixel boundaries; dst may include fractional
4033boundaries. Additionally transform draw using Clip, Matrix, and optional Paint
4034paint. 
4035
4036If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4037Blend_Mode, and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
4038If paint contains Mask_Filter, generate mask from image bounds.
4039
4040If generated mask extends beyond image bounds, replicate image edge colors, just
4041as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
4042replicates the image edge color when it samples outside of its bounds.
4043
4044constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to
4045sample within isrc; set to kFast_SrcRectConstraint allows sampling outside to
4046improve performance.
4047
4048#Param  image      Image containing pixels, dimensions, and format ##
4049#Param  isrc       source IRect of image to draw from ##
4050#Param  dst        destination Rect of image to draw to ##
4051#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
4052                   and so on; or nullptr
4053##
4054#Param  constraint filter strictly within isrc or draw faster ##
4055
4056#Example
4057#Image 4
4058void draw(SkCanvas* canvas) {
4059    // sk_sp<SkImage> image;
4060    for (auto i : { 1, 2, 4, 8 } ) {
4061        canvas->drawImageRect(image.get(), SkIRect::MakeLTRB(0, 0, 100, 100), 
4062                SkRect::MakeXYWH(i * 20, i * 20, i * 20, i * 20), nullptr);
4063    }
4064}
4065##
4066
4067#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
4068
4069##
4070
4071# ------------------------------------------------------------------------------
4072
4073#Method void drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
4074                       SrcRectConstraint constraint = kStrict_SrcRectConstraint)
4075#In Draw_Image
4076
4077Draw Image image, scaled and translated to fill Rect dst, using Clip, Matrix,
4078and optional Paint paint.
4079
4080If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4081Blend_Mode, and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
4082If paint contains Mask_Filter, generate mask from image bounds.
4083
4084If generated mask extends beyond image bounds, replicate image edge colors, just
4085as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
4086replicates the image edge color when it samples outside of its bounds.
4087
4088constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to
4089sample within image; set to kFast_SrcRectConstraint allows sampling outside to
4090improve performance.
4091
4092#Param  image      Image containing pixels, dimensions, and format ##
4093#Param  dst        destination Rect of image to draw to ##
4094#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
4095                   and so on; or nullptr
4096##
4097#Param  constraint filter strictly within image or draw faster ##
4098
4099#Example
4100#Image 4
4101void draw(SkCanvas* canvas) {
4102    // sk_sp<SkImage> image;
4103    for (auto i : { 20, 40, 80, 160 } ) {
4104        canvas->drawImageRect(image.get(), SkRect::MakeXYWH(i, i, i, i), nullptr);
4105    }
4106}
4107##
4108
4109#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
4110
4111##
4112
4113# ------------------------------------------------------------------------------
4114
4115#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
4116                       const SkPaint* paint,
4117                       SrcRectConstraint constraint = kStrict_SrcRectConstraint) 
4118#In Draw_Image
4119
4120Draw Rect src of Image image, scaled and translated to fill Rect dst.
4121Additionally transform draw using Clip, Matrix, and optional Paint paint.
4122
4123If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4124Blend_Mode, and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
4125If paint contains Mask_Filter, generate mask from image bounds.
4126
4127If generated mask extends beyond image bounds, replicate image edge colors, just
4128as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
4129replicates the image edge color when it samples outside of its bounds.
4130
4131constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to
4132sample within src; set to kFast_SrcRectConstraint allows sampling outside to
4133improve performance.
4134
4135#Param  image      Image containing pixels, dimensions, and format ##
4136#Param  src        source Rect of image to draw from ##
4137#Param  dst        destination Rect of image to draw to ##
4138#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
4139                   and so on; or nullptr
4140##
4141#Param  constraint filter strictly within src or draw faster ##
4142
4143#Example
4144#Height 64
4145#Description
4146    Canvas scales and translates; transformation from src to dst also scales.
4147    The two matrices are concatenated to create the final transformation.
4148##
4149void draw(SkCanvas* canvas) {
4150    uint32_t pixels[][2] = { { SK_ColorBLACK, SK_ColorWHITE },
4151                             { SK_ColorWHITE, SK_ColorBLACK } };
4152    SkBitmap bitmap;
4153    bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2), 
4154            (void*) pixels, sizeof(pixels[0]));
4155    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
4156    SkPaint paint;
4157    canvas->scale(4, 4);
4158    for (auto alpha : { 50, 100, 150, 255 } ) {
4159        paint.setAlpha(alpha);
4160        canvas->drawImageRect(image, SkRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint);
4161        canvas->translate(8, 0);
4162    }
4163}
4164##
4165
4166#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
4167
4168##
4169
4170# ------------------------------------------------------------------------------
4171
4172#Method void drawImageRect(const sk_sp<SkImage>& image, const SkIRect& isrc, const SkRect& dst,
4173                       const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) 
4174#In Draw_Image
4175
4176Draw IRect isrc of Image image, scaled and translated to fill Rect dst.
4177isrc is on integer pixel boundaries; dst may include fractional boundaries.
4178Additionally transform draw using Clip, Matrix, and optional Paint paint.
4179
4180If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4181Blend_Mode, and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
4182If paint contains Mask_Filter, generate mask from image bounds.
4183
4184If generated mask extends beyond image bounds, replicate image edge colors, just
4185as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
4186replicates the image edge color when it samples outside of its bounds.
4187
4188constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to
4189sample within image; set to kFast_SrcRectConstraint allows sampling outside to
4190improve performance.
4191
4192#Param  image      Image containing pixels, dimensions, and format ##
4193#Param  isrc       source IRect of image to draw from ##
4194#Param  dst        destination Rect of image to draw to ##
4195#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
4196                   and so on; or nullptr
4197##
4198#Param  constraint filter strictly within image or draw faster ##
4199
4200#Example
4201#Height 64
4202void draw(SkCanvas* canvas) {
4203    uint32_t pixels[][2] = { { 0x00000000, 0x55555555},
4204                             { 0xAAAAAAAA, 0xFFFFFFFF} };
4205    SkBitmap bitmap;
4206    bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2), 
4207            (void*) pixels, sizeof(pixels[0]));
4208    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
4209    SkPaint paint;
4210    canvas->scale(4, 4);
4211    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
4212        paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
4213        canvas->drawImageRect(image, SkIRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint);
4214        canvas->translate(8, 0);
4215    }
4216}
4217##
4218
4219#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
4220
4221##
4222
4223# ------------------------------------------------------------------------------
4224
4225#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& dst, const SkPaint* paint,
4226                       SrcRectConstraint constraint = kStrict_SrcRectConstraint) 
4227#In Draw_Image
4228
4229Draw Image image, scaled and translated to fill Rect dst,
4230using Clip, Matrix, and optional Paint paint.
4231
4232If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4233Blend_Mode, and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
4234If paint contains Mask_Filter, generate mask from image bounds.
4235
4236If generated mask extends beyond image bounds, replicate image edge colors, just
4237as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
4238replicates the image edge color when it samples outside of its bounds.
4239
4240constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to
4241sample within image; set to kFast_SrcRectConstraint allows sampling outside to
4242improve performance.
4243
4244#Param  image      Image containing pixels, dimensions, and format ##
4245#Param  dst        destination Rect of image to draw to ##
4246#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
4247                   and so on; or nullptr
4248##
4249#Param  constraint filter strictly within image or draw faster ##
4250
4251#Example
4252#Height 64
4253void draw(SkCanvas* canvas) {
4254    uint32_t pixels[][2] = { { 0x00000000, 0x55550000},
4255                             { 0xAAAA0000, 0xFFFF0000} };
4256    SkBitmap bitmap;
4257    bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2), 
4258            (void*) pixels, sizeof(pixels[0]));
4259    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
4260    SkPaint paint;
4261    canvas->scale(4, 4);
4262    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
4263        paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
4264        canvas->drawImageRect(image, SkRect::MakeWH(8, 8), &paint);
4265        canvas->translate(8, 0);
4266    }
4267}
4268##
4269
4270#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
4271
4272##
4273
4274# ------------------------------------------------------------------------------
4275
4276#Method void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
4277                       const SkPaint* paint = nullptr)
4278#In Draw_Image
4279#Line # draws Nine_Patch Image ##
4280
4281Draw Image image stretched proportionally to fit into Rect dst.
4282IRect center divides the image into nine sections: four sides, four corners, and
4283the center. Corners are unmodified or scaled down proportionately if their sides
4284are larger than dst; center and four sides are scaled to fit remaining space, if any.
4285
4286Additionally transform draw using Clip, Matrix, and optional Paint paint.
4287
4288If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4289Blend_Mode, and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
4290If paint contains Mask_Filter, generate mask from image bounds.
4291
4292If generated mask extends beyond image bounds, replicate image edge colors, just
4293as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
4294replicates the image edge color when it samples outside of its bounds.
4295
4296#Param  image      Image containing pixels, dimensions, and format ##
4297#Param  center     IRect edge of image corners and sides ##
4298#Param  dst        destination Rect of image to draw to ##
4299#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
4300                   and so on; or nullptr
4301##
4302
4303#Example
4304#Height 128
4305#Description
4306    The leftmost image is smaller than center; only corners are drawn, all scaled to fit.
4307    The second image equals the size of center; only corners are drawn without scaling.
4308    The remaining images are larger than center. All corners draw without scaling.
4309    The sides and center are scaled if needed to take up the remaining space.
4310##
4311void draw(SkCanvas* canvas) {
4312    SkIRect center = { 20, 10, 50, 40 };
4313    SkBitmap bitmap;
4314    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
4315    SkCanvas bitCanvas(bitmap);
4316    SkPaint paint;
4317    SkColor gray = 0xFF000000;
4318    int left = 0;
4319    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
4320        int top = 0;
4321        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
4322            paint.setColor(gray);
4323            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
4324            gray += 0x001f1f1f;
4325            top = bottom;
4326        }
4327        left = right; 
4328    }
4329    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
4330    SkImage* imagePtr = image.get();
4331    for (auto dest: { 20, 30, 40, 60, 90 } ) {
4332        canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr);
4333        canvas->translate(dest + 4, 0);
4334    }
4335}
4336##
4337
4338#SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect
4339
4340##
4341
4342# ------------------------------------------------------------------------------
4343
4344#Method void drawImageNine(const sk_sp<SkImage>& image, const SkIRect& center, const SkRect& dst,
4345                       const SkPaint* paint = nullptr) 
4346#In Draw_Image
4347
4348Draw Image image stretched proportionally to fit into Rect dst.
4349IRect center divides the image into nine sections: four sides, four corners, and
4350the center. Corners are not scaled, or scaled down proportionately if their sides
4351are larger than dst; center and four sides are scaled to fit remaining space, if any.
4352
4353Additionally transform draw using Clip, Matrix, and optional Paint paint.
4354
4355If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4356Blend_Mode, and Draw_Looper. If image is kAlpha_8_SkColorType, apply Shader.
4357If paint contains Mask_Filter, generate mask from image bounds.
4358
4359If generated mask extends beyond image bounds, replicate image edge colors, just
4360as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
4361replicates the image edge color when it samples outside of its bounds.
4362
4363#Param  image      Image containing pixels, dimensions, and format ##
4364#Param  center     IRect edge of image corners and sides ##
4365#Param  dst        destination Rect of image to draw to ##
4366#Param  paint      Paint containing Blend_Mode, Color_Filter, Image_Filter,
4367                   and so on; or nullptr
4368##
4369
4370#Example
4371#Height 128
4372#Description
4373    The two leftmost images has four corners and sides to the left and right of center.
4374    The leftmost image scales the width of corners proportionately to fit.
4375    The third and fourth image corners are not scaled; the sides and center are scaled to 
4376    fill the remaining space.
4377    The rightmost image has four corners scaled vertically to fit, and uses sides above
4378    and below center to fill the remaining space.
4379##
4380void draw(SkCanvas* canvas) {
4381    SkIRect center = { 20, 10, 50, 40 };
4382    SkBitmap bitmap;
4383    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
4384    SkCanvas bitCanvas(bitmap);
4385    SkPaint paint;
4386    SkColor gray = 0xFF000000;
4387    int left = 0;
4388    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
4389        int top = 0;
4390        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
4391            paint.setColor(gray);
4392            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
4393            gray += 0x001f1f1f;
4394            top = bottom;
4395        }
4396        left = right; 
4397    }
4398    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
4399    for (auto dest: { 20, 30, 40, 60, 90 } ) {
4400        canvas->drawImageNine(image, center, SkRect::MakeWH(dest, 110 - dest), nullptr);
4401        canvas->translate(dest + 4, 0);
4402    }
4403}
4404##
4405
4406#SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect
4407
4408##
4409
4410# ------------------------------------------------------------------------------
4411
4412#Method void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
4413                    const SkPaint* paint = nullptr)
4414#In Draw_Image
4415#Line # draws Bitmap at (x, y) position ##
4416
4417Draw Bitmap bitmap, with its top-left corner at (left, top),
4418using Clip, Matrix, and optional Paint paint.
4419
4420If Paint paint is not nullptr, apply Color_Filter, Color_Alpha, Image_Filter,
4421Blend_Mode, and Draw_Looper. If bitmap is kAlpha_8_SkColorType, apply Shader.
4422If paint contains Mask_Filter, generate mask from bitmap bounds.
4423
4424If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
4425just as Shader made from SkShader::MakeBitmapShader with
4426SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
4427outside of its bounds. 
4428
4429#Param  bitmap   Bitmap containing pixels, dimensions, and format ##
4430#Param  left     left side of bitmap ##
4431#Param  top      top side of bitmap ##
4432#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
4433                 and so on; or nullptr
4434##
4435
4436#Example
4437#Height 64
4438void draw(SkCanvas* canvas) {
4439    uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00},
4440                            { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
4441                            { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00},
4442                            { 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF},
4443                            { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
4444                            { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00},
4445                            { 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00},
4446                            { 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF} };
4447    SkBitmap bitmap;
4448    bitmap.installPixels(SkImageInfo::MakeA8(8, 8), 
4449            (void*) pixels, sizeof(pixels[0]));
4450    SkPaint paint;
4451    canvas->scale(4, 4);
4452    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) {
4453        paint.setColor(color);
4454        canvas->drawBitmap(bitmap, 0, 0, &paint);
4455        canvas->translate(12, 0);
4456    }
4457}
4458##
4459
4460#SeeAlso drawImage drawBitmapLattice drawBitmapNine drawBitmapRect SkBitmap::readPixels SkBitmap::writePixels
4461
4462##
4463
4464# ------------------------------------------------------------------------------
4465
4466#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
4467                        const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
4468#In Draw_Image
4469#Line # draws Bitmap, source Rect to destination Rect ##
4470
4471Draw Rect src of Bitmap bitmap, scaled and translated to fill Rect dst.
4472Additionally transform draw using Clip, Matrix, and optional Paint paint.
4473
4474If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4475Blend_Mode, and Draw_Looper. If bitmap is kAlpha_8_SkColorType, apply Shader.
4476If paint contains Mask_Filter, generate mask from bitmap bounds.
4477
4478If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
4479just as Shader made from SkShader::MakeBitmapShader with
4480SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
4481outside of its bounds.
4482
4483constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to
4484sample within src; set to kFast_SrcRectConstraint allows sampling outside to
4485improve performance.
4486
4487#Param  bitmap   Bitmap containing pixels, dimensions, and format ##
4488#Param  src      source Rect of image to draw from ##
4489#Param  dst      destination Rect of image to draw to ##
4490#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
4491                 and so on; or nullptr
4492##
4493#Param  constraint filter strictly within src or draw faster ##
4494
4495#Example
4496#Height 64
4497void draw(SkCanvas* canvas) {
4498    uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00},
4499                            { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
4500                            { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00},
4501                            { 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF},
4502                            { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
4503                            { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00},
4504                            { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
4505                            { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00} };
4506    SkBitmap bitmap;
4507    bitmap.installPixels(SkImageInfo::MakeA8(8, 8), 
4508            (void*) pixels, sizeof(pixels[0]));
4509    SkPaint paint;
4510    paint.setMaskFilter(SkBlurMaskFilter::Make(kSolid_SkBlurStyle, 6));
4511    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) {
4512        paint.setColor(color);
4513        canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint);
4514        canvas->translate(48, 0);
4515    }
4516}
4517##
4518
4519#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine
4520
4521##
4522
4523# ------------------------------------------------------------------------------
4524
4525#Method void drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
4526                        const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
4527#In Draw_Image
4528
4529Draw IRect isrc of Bitmap bitmap, scaled and translated to fill Rect dst.
4530isrc is on integer pixel boundaries; dst may include fractional boundaries.
4531Additionally transform draw using Clip, Matrix, and optional Paint paint.
4532
4533If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4534Blend_Mode, and Draw_Looper. If bitmap is kAlpha_8_SkColorType, apply Shader.
4535If paint contains Mask_Filter, generate mask from bitmap bounds.
4536
4537If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
4538just as Shader made from SkShader::MakeBitmapShader with
4539SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
4540outside of its bounds.
4541
4542constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to
4543sample within isrc; set to kFast_SrcRectConstraint allows sampling outside to
4544improve performance.
4545
4546#Param  bitmap   Bitmap containing pixels, dimensions, and format ##
4547#Param  isrc     source IRect of image to draw from ##
4548#Param  dst      destination Rect of image to draw to ##
4549#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
4550                 and so on; or nullptr
4551##
4552#Param  constraint sample strictly within isrc, or draw faster ##
4553
4554#Example
4555#Height 64
4556void draw(SkCanvas* canvas) {
4557    uint8_t pixels[][8] = { { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
4558                            { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
4559                            { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF},
4560                            { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF},
4561                            { 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF},
4562                            { 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF},
4563                            { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
4564                            { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00} };
4565    SkBitmap bitmap;
4566    bitmap.installPixels(SkImageInfo::MakeA8(8, 8), 
4567            (void*) pixels, sizeof(pixels[0]));
4568    SkPaint paint;
4569    paint.setFilterQuality(kHigh_SkFilterQuality);
4570    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00, 0xFF7f007f} ) {
4571        paint.setColor(color);
4572        canvas->drawBitmapRect(bitmap, SkIRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint);
4573        canvas->translate(48.25f, 0);
4574    }
4575}
4576##
4577
4578#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine
4579
4580##
4581
4582# ------------------------------------------------------------------------------
4583
4584#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
4585                        SrcRectConstraint constraint = kStrict_SrcRectConstraint)
4586#In Draw_Image
4587
4588Draw Bitmap bitmap, scaled and translated to fill Rect dst.
4589bitmap bounds is on integer pixel boundaries; dst may include fractional boundaries.
4590Additionally transform draw using Clip, Matrix, and optional Paint paint.
4591
4592If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4593Blend_Mode, and Draw_Looper. If bitmap is kAlpha_8_SkColorType, apply Shader.
4594If paint contains Mask_Filter, generate mask from bitmap bounds.
4595
4596If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
4597just as Shader made from SkShader::MakeBitmapShader with
4598SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
4599outside of its bounds.
4600
4601constraint set to kStrict_SrcRectConstraint limits Paint Filter_Quality to
4602sample within bitmap; set to kFast_SrcRectConstraint allows sampling outside to
4603improve performance.
4604
4605#Param  bitmap   Bitmap containing pixels, dimensions, and format ##
4606#Param  dst      destination Rect of image to draw to ##
4607#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
4608                 and so on; or nullptr
4609##
4610#Param  constraint filter strictly within bitmap or draw faster ##
4611
4612#Example
4613#Height 64
4614void draw(SkCanvas* canvas) {
4615    uint32_t pixels[][2] = { { 0x00000000, 0x55550000},
4616                             { 0xAAAA0000, 0xFFFF0000} };
4617    SkBitmap bitmap;
4618    bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2), 
4619            (void*) pixels, sizeof(pixels[0]));
4620    SkPaint paint;
4621    canvas->scale(4, 4);
4622    for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
4623        paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
4624        canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), &paint);
4625        canvas->translate(8, 0);
4626    }
4627}
4628##
4629
4630#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine
4631
4632##
4633
4634# ------------------------------------------------------------------------------
4635
4636#Method void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
4637                        const SkPaint* paint = nullptr)
4638#In Draw_Image
4639#Line # draws Nine_Patch Bitmap ##
4640
4641Draw Bitmap bitmap stretched proportionally to fit into Rect dst.
4642IRect center divides the bitmap into nine sections: four sides, four corners,
4643and the center. Corners are not scaled, or scaled down proportionately if their
4644sides are larger than dst; center and four sides are scaled to fit remaining
4645space, if any.
4646
4647Additionally transform draw using Clip, Matrix, and optional Paint paint.
4648
4649If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4650Blend_Mode, and Draw_Looper. If bitmap is kAlpha_8_SkColorType, apply Shader.
4651If paint contains Mask_Filter, generate mask from bitmap bounds.
4652
4653If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
4654just as Shader made from SkShader::MakeBitmapShader with
4655SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
4656outside of its bounds.
4657
4658#Param  bitmap     Bitmap containing pixels, dimensions, and format ##
4659#Param  center     IRect edge of image corners and sides ##
4660#Param  dst        destination Rect of image to draw to ##
4661#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
4662                 and so on; or nullptr
4663##
4664
4665#Example
4666#Height 128
4667#Description
4668    The two leftmost bitmap draws has four corners and sides to the left and right of center.
4669    The leftmost bitmap draw scales the width of corners proportionately to fit.
4670    The third and fourth draw corners are not scaled; the sides and center are scaled to 
4671    fill the remaining space.
4672    The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above
4673    and below center to fill the remaining space.
4674##
4675void draw(SkCanvas* canvas) {
4676    SkIRect center = { 20, 10, 50, 40 };
4677    SkBitmap bitmap;
4678    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
4679    SkCanvas bitCanvas(bitmap);
4680    SkPaint paint;
4681    SkColor gray = 0xFF000000;
4682    int left = 0;
4683    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
4684        int top = 0;
4685        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
4686            paint.setColor(gray);
4687            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
4688            gray += 0x001f1f1f;
4689            top = bottom;
4690        }
4691        left = right; 
4692    }
4693    for (auto dest: { 20, 30, 40, 60, 90 } ) {
4694        canvas->drawBitmapNine(bitmap, center, SkRect::MakeWH(dest, 110 - dest), nullptr);
4695        canvas->translate(dest + 4, 0);
4696    }
4697}
4698##
4699
4700#SeeAlso drawImageNine drawBitmap drawBitmapLattice drawBitmapRect
4701
4702##
4703
4704# ------------------------------------------------------------------------------
4705#Struct Lattice
4706#Line # divides Bitmap or Image into a rectangular grid ##
4707#Code
4708    struct Lattice {
4709        enum RectType ...
4710
4711        const int*      fXDivs;
4712        const int*      fYDivs;
4713        const RectType* fRectTypes;
4714        int             fXCount;
4715        int             fYCount;
4716        const SkIRect*  fBounds;
4717        const SkColor*  fColors;
4718    };
4719##
4720
4721    Lattice divides Bitmap or Image into a rectangular grid.
4722    Grid entries on even columns and even rows are fixed; these entries are
4723    always drawn at their original size if the destination is large enough.
4724    If the destination side is too small to hold the fixed entries, all fixed
4725    entries are proportionately scaled down to fit.
4726    The grid entries not on even columns and rows are scaled to fit the
4727    remaining space, if any.
4728
4729    #Enum RectType
4730        #Code
4731            enum RectType : uint8_t {
4732                kDefault = 0,
4733                kTransparent,
4734                kFixedColor,
4735            };
4736        ##
4737
4738        Optional setting per rectangular grid entry to make it transparent,
4739        or to fill the grid entry with a color.
4740
4741        #Const kDefault 0
4742            Draws Bitmap into lattice rectangle.
4743        ##
4744
4745        #Const kTransparent 1
4746            Skips lattice rectangle by making it transparent.
4747        ##
4748
4749        #Const kFixedColor 2
4750            Draws one of fColors into lattice rectangle.
4751        ##
4752    ##
4753
4754    #Member const int*   fXDivs
4755        Array of x-coordinates that divide the bitmap vertically.
4756        Array entries must be unique, increasing, greater than or equal to
4757        fBounds left edge, and less than fBounds right edge.
4758        Set the first element to fBounds left to collapse the left column of
4759        fixed grid entries.
4760    ##
4761
4762    #Member const int*   fYDivs
4763        Array of y-coordinates that divide the bitmap horizontally.
4764        Array entries must be unique, increasing, greater than or equal to
4765        fBounds top edge, and less than fBounds bottom edge.
4766        Set the first element to fBounds top to collapse the top row of fixed
4767        grid entries.
4768    ##
4769
4770    #Member const RectType* fRectTypes
4771        Optional array of fill types, one per rectangular grid entry:
4772        array length must be
4773    #Formula
4774        (fXCount + 1) * (fYCount + 1)
4775    ##
4776        .
4777
4778        Each RectType is one of: kDefault, kTransparent, kFixedColor.
4779
4780        Array entries correspond to the rectangular grid entries, ascending
4781        left to right and then top to bottom.
4782    ##
4783
4784    #Member int   fXCount
4785        Number of entries in fXDivs array; one less than the number of
4786        horizontal divisions.
4787    ##
4788
4789    #Member int   fYCount
4790        Number of entries in fYDivs array; one less than the number of vertical
4791        divisions.
4792    ##
4793
4794    #Member const SkIRect*   fBounds
4795       Optional subset IRect source to draw from.
4796       If nullptr, source bounds is dimensions of Bitmap or Image.
4797    ##
4798
4799    #Member const SkColor*   fColors
4800       Optional array of colors, one per rectangular grid entry.
4801       Array length must be
4802       #Formula
4803       (fXCount + 1) * (fYCount + 1)
4804       ##
4805       .
4806
4807       Array entries correspond to the rectangular grid entries, ascending
4808       left to right, then top to bottom.
4809    ##
4810
4811#Struct Lattice ##
4812
4813#Method void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
4814                           const SkPaint* paint = nullptr)
4815#In Draw_Image
4816#Line # draws proportionally stretched Bitmap ##
4817
4818Draw Bitmap bitmap stretched proportionally to fit into Rect dst.
4819
4820Lattice lattice divides bitmap into a rectangular grid.
4821Each intersection of an even-numbered row and column is fixed; like the corners
4822of drawBitmapNine, fixed lattice elements never scale larger than their initial
4823size and shrink proportionately when all fixed elements exceed the bitmap
4824dimension. All other grid elements scale to fill the available space, if any.
4825
4826Additionally transform draw using Clip, Matrix, and optional Paint paint.
4827
4828If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4829Blend_Mode, and Draw_Looper. If bitmap is kAlpha_8_SkColorType, apply Shader.
4830If paint contains Mask_Filter, generate mask from bitmap bounds.
4831
4832If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
4833just as Shader made from SkShader::MakeBitmapShader with
4834SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
4835outside of its bounds.
4836
4837#Param  bitmap     Bitmap containing pixels, dimensions, and format ##
4838#Param  lattice    division of bitmap into fixed and variable rectangles ##
4839#Param  dst        destination Rect of image to draw to ##
4840#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
4841                 and so on; or nullptr
4842##
4843
4844#Example
4845#Height 128
4846#Description
4847    The two leftmost bitmap draws has four corners and sides to the left and right of center.
4848    The leftmost bitmap draw scales the width of corners proportionately to fit.
4849    The third and fourth draw corners are not scaled; the sides are scaled to 
4850    fill the remaining space; the center is transparent.
4851    The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above
4852    and below center to fill the remaining space.
4853##
4854void draw(SkCanvas* canvas) {
4855    SkIRect center = { 20, 10, 50, 40 };
4856    SkBitmap bitmap;
4857    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
4858    SkCanvas bitCanvas(bitmap);
4859    SkPaint paint;
4860    SkColor gray = 0xFF000000;
4861    int left = 0;
4862    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
4863        int top = 0;
4864        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
4865            paint.setColor(gray);
4866            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
4867            gray += 0x001f1f1f;
4868            top = bottom;
4869        }
4870        left = right; 
4871    }
4872    const int xDivs[] = { center.fLeft, center.fRight };
4873    const int yDivs[] = { center.fTop, center.fBottom };
4874    SkCanvas::Lattice::RectType fillTypes[3][3];
4875    memset(fillTypes, 0, sizeof(fillTypes));
4876    fillTypes[1][1] = SkCanvas::Lattice::kTransparent;
4877    SkColor dummy[9];  // temporary pending bug fix
4878    SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], SK_ARRAY_COUNT(xDivs),
4879         SK_ARRAY_COUNT(yDivs), nullptr, dummy };
4880    for (auto dest: { 20, 30, 40, 60, 90 } ) {
4881        canvas->drawBitmapLattice(bitmap, lattice, SkRect::MakeWH(dest, 110 - dest), nullptr);
4882        canvas->translate(dest + 4, 0);
4883    }
4884}
4885##
4886
4887#SeeAlso drawImageLattice drawBitmap drawBitmapNine Lattice
4888
4889##
4890
4891# ------------------------------------------------------------------------------
4892
4893#Method void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
4894                          const SkPaint* paint = nullptr)
4895#In Draw_Image
4896#Line # draws proportionally stretched Image ##
4897
4898Draw Image image stretched proportionally to fit into Rect dst.
4899
4900Lattice lattice divides image into a rectangular grid.
4901Each intersection of an even-numbered row and column is fixed; like the corners
4902of drawBitmapNine, fixed lattice elements never scale larger than their initial
4903size and shrink proportionately when all fixed elements exceed the bitmap
4904dimension. All other grid elements scale to fill the available space, if any.
4905
4906Additionally transform draw using Clip, Matrix, and optional Paint paint.
4907
4908If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
4909Blend_Mode, and Draw_Looper. If bitmap is kAlpha_8_SkColorType, apply Shader.
4910If paint contains Mask_Filter, generate mask from bitmap bounds.
4911
4912If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
4913just as Shader made from SkShader::MakeBitmapShader with
4914SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
4915outside of its bounds.
4916
4917#Param  image      Image containing pixels, dimensions, and format ##
4918#Param  lattice    division of bitmap into fixed and variable rectangles ##
4919#Param  dst        destination Rect of image to draw to ##
4920#Param  paint    Paint containing Blend_Mode, Color_Filter, Image_Filter,
4921                 and so on; or nullptr
4922##
4923
4924#Example
4925#Height 128
4926#Description
4927    The leftmost image is smaller than center; only corners are drawn, all scaled to fit.
4928    The second image equals the size of center; only corners are drawn without scaling.
4929    The remaining images are larger than center. All corners draw without scaling. The sides
4930    are scaled if needed to take up the remaining space; the center is transparent.
4931##
4932void draw(SkCanvas* canvas) {
4933    SkIRect center = { 20, 10, 50, 40 };
4934    SkBitmap bitmap;
4935    bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
4936    SkCanvas bitCanvas(bitmap);
4937    SkPaint paint;
4938    SkColor gray = 0xFF000000;
4939    int left = 0;
4940    for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
4941        int top = 0;
4942        for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
4943            paint.setColor(gray);
4944            bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
4945            gray += 0x001f1f1f;
4946            top = bottom;
4947        }
4948        left = right; 
4949    }
4950    const int xDivs[] = { center.fLeft, center.fRight };
4951    const int yDivs[] = { center.fTop, center.fBottom };
4952    SkCanvas::Lattice::RectType fillTypes[3][3];
4953    memset(fillTypes, 0, sizeof(fillTypes));  
4954    fillTypes[1][1] = SkCanvas::Lattice::kTransparent;
4955    SkColor dummy[9];  // temporary pending bug fix
4956    SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], SK_ARRAY_COUNT(xDivs),
4957         SK_ARRAY_COUNT(yDivs), nullptr, dummy };
4958    sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
4959    SkImage* imagePtr = image.get();
4960    for (auto dest: { 20, 30, 40, 60, 90 } ) {
4961        canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr);
4962        canvas->translate(dest + 4, 0);
4963    }
4964}
4965##
4966
4967#SeeAlso drawBitmapLattice drawImage drawImageNine Lattice
4968
4969##
4970
4971#Subtopic Draw_Image ##
4972
4973# ------------------------------------------------------------------------------
4974
4975#Method void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
4976                  const SkPaint& paint)
4977#Line # draws text at (x, y), using font advance ##
4978
4979Draw text, with origin at (x, y), using Clip, Matrix, and Paint paint.
4980
4981text meaning depends on Paint_Text_Encoding; by default, text is encoded as
4982UTF-8.
4983
4984x and y meaning depends on Paint_Text_Align and Paint_Vertical_Text; by default
4985text draws left to right, positioning the first glyph left side bearing at x
4986and its baseline at y. Text size is affected by Matrix and Paint_Text_Size. 
4987
4988All elements of paint: Path_Effect, Mask_Filter, Shader,
4989Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws
4990filled 12 point black Glyphs.
4991
4992#Param  text     character code points or Glyphs drawn ##
4993#Param  byteLength   byte length of text array ##
4994#Param  x        start of text on x-axis ##
4995#Param  y        start of text on y-axis ##
4996#Param  paint    text size, blend, color, and so on, used to draw ##
4997
4998#Example
4999#Height 200
5000#Description
5001    The same text is drawn varying Paint_Text_Size and varying
5002    Matrix. 
5003##
5004void draw(SkCanvas* canvas) {
5005    SkPaint paint;
5006    paint.setAntiAlias(true);
5007    float textSizes[] = { 12, 18, 24, 36 };
5008    for (auto size: textSizes ) {
5009        paint.setTextSize(size);
5010        canvas->drawText("Aa", 2, 10, 20, paint);
5011        canvas->translate(0, size * 2);
5012    }
5013    paint.reset();
5014    paint.setAntiAlias(true);
5015    float yPos = 20;
5016    for (auto size: textSizes ) {
5017        float scale = size / 12.f;
5018        canvas->resetMatrix();
5019        canvas->translate(100, 0);
5020        canvas->scale(scale, scale);
5021        canvas->drawText("Aa", 2, 10 / scale, yPos / scale, paint);
5022        yPos += size * 2; 
5023    }
5024}
5025##
5026
5027#SeeAlso drawString drawPosText drawPosTextH drawTextBlob drawTextOnPath drawTextRSXform
5028
5029##
5030
5031#Method void drawString(const char* string, SkScalar x, SkScalar y, const SkPaint& paint)
5032
5033#Line # draws null terminated string at (x, y) using font advance ##
5034Draw null terminated string, with origin at (x, y), using Clip, Matrix, and
5035Paint paint.
5036
5037string meaning depends on Paint_Text_Encoding; by default, strings are encoded
5038as UTF-8. Other values of Paint_Text_Encoding are unlikely to produce the desired
5039results, since zero bytes may be embedded in the string.
5040
5041x and y meaning depends on Paint_Text_Align and Paint_Vertical_Text; by default
5042string draws left to right, positioning the first glyph left side bearing at x
5043and its baseline at y. Text size is affected by Matrix and Paint_Text_Size. 
5044
5045All elements of paint: Path_Effect, Mask_Filter, Shader,
5046Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws
5047filled 12 point black Glyphs.
5048
5049#Param  string   character code points or Glyphs drawn,
5050                 ending with a char value of zero
5051##
5052#Param  x        start of string on x-axis ##
5053#Param  y        start of string on y-axis ##
5054#Param  paint    text size, blend, color, and so on, used to draw ##
5055
5056#Example
5057   SkPaint paint;
5058   canvas->drawString("a small hello", 20, 20, paint);
5059##
5060
5061#SeeAlso drawText drawPosText drawPosTextH drawTextBlob drawTextOnPath drawTextRSXform
5062
5063##
5064
5065#Method void drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint)
5066
5067Draw null terminated string, with origin at (x, y), using Clip, Matrix, and
5068Paint paint.
5069
5070string meaning depends on Paint_Text_Encoding; by default, strings are encoded
5071as UTF-8. Other values of Paint_Text_Encoding are unlikely to produce the desired
5072results, since zero bytes may be embedded in the string.
5073
5074x and y meaning depends on Paint_Text_Align and Paint_Vertical_Text; by default
5075string draws left to right, positioning the first glyph left side bearing at x
5076and its baseline at y. Text size is affected by Matrix and Paint_Text_Size. 
5077
5078All elements of paint: Path_Effect, Mask_Filter, Shader,
5079Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws
5080filled 12 point black Glyphs.
5081
5082#Param  string   character code points or Glyphs drawn,
5083                 ending with a char value of zero
5084##
5085#Param  x        start of string on x-axis ##
5086#Param  y        start of string on y-axis ##
5087#Param  paint    text size, blend, color, and so on, used to draw ##
5088
5089#Example
5090   SkPaint paint;
5091   SkString string("a small hello");
5092   canvas->drawString(string, 20, 20, paint);
5093##
5094
5095#SeeAlso drawText drawPosText drawPosTextH drawTextBlob drawTextOnPath drawTextRSXform
5096
5097##
5098
5099# ------------------------------------------------------------------------------
5100
5101#Method void drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
5102                     const SkPaint& paint)
5103#Line # draws text at array of (x, y) positions ##
5104
5105Draw each glyph in text with the origin in pos array, using Clip, Matrix, and
5106Paint paint. The number of entries in pos array must match the number of Glyphs
5107described by byteLength of text.
5108
5109text meaning depends on Paint_Text_Encoding; by default, text is encoded as
5110UTF-8. pos elements' meaning depends on Paint_Text_Align and Paint_Vertical_Text;
5111by default each glyph left side bearing is positioned at x and its
5112baseline is positioned at y. Text size is affected by Matrix and
5113Paint_Text_Size. 
5114
5115All elements of paint: Path_Effect, Mask_Filter, Shader,
5116Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws
5117filled 12 point black Glyphs.
5118
5119Layout engines such as Harfbuzz typically position each glyph
5120rather than using the font advance widths.
5121
5122#Param  text     character code points or Glyphs drawn ##
5123#Param  byteLength   byte length of text array ##
5124#Param  pos      array of glyph origins ##
5125#Param  paint    text size, blend, color, and so on, used to draw ##
5126
5127#Example
5128#Height 120
5129void draw(SkCanvas* canvas) {
5130  const char hello[] = "HeLLo!";
5131  const SkPoint pos[] = { {40, 100}, {82, 95}, {115, 110}, {130, 95}, {145, 85},
5132    {172, 100} };
5133  SkPaint paint;
5134  paint.setTextSize(60);
5135  canvas->drawPosText(hello, strlen(hello), pos, paint);
5136}
5137##
5138
5139#SeeAlso drawText drawPosTextH drawTextBlob drawTextOnPath drawTextRSXform
5140
5141##
5142
5143# ------------------------------------------------------------------------------
5144
5145#Method void drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY,
5146                      const SkPaint& paint)
5147#Line # draws text at x positions with common baseline ##
5148
5149Draw each glyph in text with its (x, y) origin composed from xpos array and
5150constY, using Clip, Matrix, and Paint paint. The number of entries in xpos array
5151must match the number of Glyphs described by byteLength of text.
5152
5153text meaning depends on Paint_Text_Encoding; by default, text is encoded as
5154UTF-8. xpos elements' meaning depends on Paint_Text_Align and Paint_Vertical_Text;
5155by default each glyph left side bearing is positioned at an xpos element and
5156its baseline is positioned at constY. Text size is affected by Matrix and
5157Paint_Text_Size. 
5158
5159All elements of paint: Path_Effect, Mask_Filter, Shader,
5160Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws
5161filled 12 point black Glyphs.
5162
5163Layout engines such as Harfbuzz typically position each glyph
5164rather than using the font advance widths if all Glyphs share the same
5165baseline.
5166
5167#Param  text     character code points or Glyphs drawn ##
5168#Param  byteLength   byte length of text array ##
5169#Param  xpos     array of x positions, used to position each glyph ##
5170#Param  constY   shared y coordinate for all of x positions ##
5171#Param  paint    text size, blend, color, and so on, used to draw ##
5172
5173#Example
5174#Height 40
5175    void draw(SkCanvas* canvas) {
5176        SkScalar xpos[] = { 20, 40, 80, 160 };
5177        SkPaint paint;
5178        canvas->drawPosTextH("XXXX", 4, xpos, 20, paint);
5179    }
5180##
5181
5182#SeeAlso drawText drawPosText drawTextBlob drawTextOnPath drawTextRSXform
5183
5184##
5185
5186# ------------------------------------------------------------------------------
5187
5188#Method void drawTextOnPathHV(const void* text, size_t byteLength, const SkPath& path, SkScalar hOffset,
5189                          SkScalar vOffset, const SkPaint& paint)
5190#Line # draws text following Path with offsets ##
5191
5192Draw text on Path path, using Clip, Matrix, and Paint paint.
5193
5194Origin of text is at distance hOffset along the path, offset by a perpendicular
5195vector of length vOffset. If the path section corresponding the glyph advance is
5196curved, the glyph is drawn curved to match; control points in the glyph are
5197mapped to projected points parallel to the path. If the text advance is larger
5198than the path length, the excess text is clipped.
5199
5200text meaning depends on Paint_Text_Encoding; by default, text is encoded as
5201UTF-8. Origin meaning depends on Paint_Text_Align and Paint_Vertical_Text; by
5202default text positions the first glyph left side bearing at origin x and its
5203baseline at origin y. Text size is affected by Matrix and Paint_Text_Size. 
5204
5205All elements of paint: Path_Effect, Mask_Filter, Shader,
5206Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws
5207filled 12 point black Glyphs.
5208
5209#Param  text         character code points or Glyphs drawn ##
5210#Param  byteLength   byte length of text array ##
5211#Param  path         Path providing text baseline ##
5212#Param  hOffset      distance along path to offset origin ##
5213#Param  vOffset      offset of text above (if negative) or below (if positive) the path ##
5214#Param  paint        text size, blend, color, and so on, used to draw ##
5215
5216#Example
5217    void draw(SkCanvas* canvas) { 
5218        const char aero[] = "correo a" "\xC3" "\xA9" "reo";
5219        const size_t len = sizeof(aero) - 1;
5220        SkPath path;
5221        path.addOval({43-26, 43-26, 43+26, 43+26}, SkPath::kCW_Direction, 3);
5222        SkPaint paint;
5223        paint.setTextSize(24);
5224        for (auto offset : { 0, 10, 20 } ) {
5225            canvas->drawTextOnPathHV(aero, len, path, 0, -offset, paint);
5226            canvas->translate(70 + offset, 70 + offset);
5227        }
5228    }
5229##
5230
5231#SeeAlso drawTextOnPath drawText drawPosTextH drawTextBlob drawTextRSXform
5232
5233##
5234
5235# ------------------------------------------------------------------------------
5236
5237#Method void drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
5238                        const SkMatrix* matrix, const SkPaint& paint)
5239#Line # draws text following Path contour ##
5240
5241Draw text on Path path, using Clip, Matrix, and Paint paint.
5242
5243Origin of text is at beginning of path offset by matrix, if provided, before it
5244is mapped to path. If the path section corresponding the glyph advance is
5245curved, the glyph is drawn curved to match; control points in the glyph are
5246mapped to projected points parallel to the path. If the text advance is larger
5247than the path length, the excess text is clipped.
5248
5249text meaning depends on Paint_Text_Encoding; by default, text is encoded as
5250UTF-8. Origin meaning depends on Paint_Text_Align and Paint_Vertical_Text; by
5251default text positions the first glyph left side bearing at origin x and its
5252baseline at origin y. Text size is affected by Matrix and Paint_Text_Size. 
5253
5254All elements of paint: Path_Effect, Mask_Filter, Shader,
5255Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws
5256filled 12 point black Glyphs.
5257
5258#Param  text         character code points or Glyphs drawn ##
5259#Param  byteLength   byte length of text array ##
5260#Param  path         Path providing text baseline ##
5261#Param  matrix       transform of Glyphs before mapping to path; may be nullptr
5262                     to use identity Matrix
5263##
5264#Param  paint        text size, blend, color, and so on, used to draw ##
5265
5266#Example
5267    void draw(SkCanvas* canvas) { 
5268        const char roller[] = "rollercoaster";
5269        const size_t len = sizeof(roller) - 1;
5270        SkPath path;
5271        path.cubicTo(40, -80, 120, 80, 160, -40);
5272        SkPaint paint;
5273        paint.setTextSize(32);
5274        paint.setStyle(SkPaint::kStroke_Style);
5275        SkMatrix matrix;
5276        matrix.setIdentity();
5277        for (int i = 0; i < 3; ++i) {
5278            canvas->translate(25, 60);
5279            canvas->drawPath(path, paint);
5280            canvas->drawTextOnPath(roller, len, path, &matrix, paint);
5281            matrix.preTranslate(0, 10);
5282        }
5283    }
5284##
5285
5286#SeeAlso drawTextOnPathHV drawText drawPosTextH drawTextBlob drawTextRSXform
5287
5288##
5289
5290# ------------------------------------------------------------------------------
5291
5292#Method void drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
5293                         const SkRect* cullRect, const SkPaint& paint)
5294#Line # draws text with array of RSXform ##
5295
5296Draw text, transforming each glyph by the corresponding SkRSXform,
5297using Clip, Matrix, and Paint paint.
5298
5299RSXform array specifies a separate square scale, rotation, and translation for 
5300each glyph.
5301
5302Optional Rect cullRect is a conservative bounds of text, taking into account
5303RSXform and paint. If cullRect is outside of Clip, canvas can skip drawing.
5304
5305All elements of paint: Path_Effect, Mask_Filter, Shader,
5306Color_Filter, Image_Filter, and Draw_Looper; apply to text. By default, draws
5307filled 12 point black Glyphs.
5308
5309#Param  text         character code points or Glyphs drawn ##
5310#Param  byteLength   byte length of text array ##
5311#Param  xform        RSXform rotates, scales, and translates each glyph individually ##
5312#Param  cullRect     Rect bounds of text for efficient clipping; or nullptr ##
5313#Param  paint        text size, blend, color, and so on, used to draw ##
5314
5315#Example
5316void draw(SkCanvas* canvas) {  
5317    const int iterations = 26;
5318    SkRSXform transforms[iterations];
5319    char alphabet[iterations];
5320    SkScalar angle = 0;
5321    SkScalar scale = 1;
5322    for (size_t i = 0; i < SK_ARRAY_COUNT(transforms); ++i) {
5323        const SkScalar s = SkScalarSin(angle) * scale;
5324        const SkScalar c = SkScalarCos(angle) * scale;
5325        transforms[i] = SkRSXform::Make(-c, -s, -s * 16, c * 16);
5326        angle += .45;
5327        scale += .2;
5328        alphabet[i] = 'A' + i;
5329    }
5330    SkPaint paint;
5331    paint.setTextAlign(SkPaint::kCenter_Align);
5332    canvas->translate(110, 138);
5333    canvas->drawTextRSXform(alphabet, sizeof(alphabet), transforms, nullptr, paint);
5334}
5335##
5336
5337#SeeAlso drawTextOnPath drawTextOnPathHV drawText drawPosText drawTextBlob
5338
5339##
5340
5341# ------------------------------------------------------------------------------
5342
5343#Method void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint)
5344
5345#Line # draws text with arrays of positions and Paint ##
5346Draw Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint.
5347
5348blob contains Glyphs, their positions, and paint attributes specific to text:
5349Typeface, Paint_Text_Size, Paint_Text_Scale_X, Paint_Text_Skew_X,
5350Paint_Text_Align, Paint_Hinting, Anti-alias, Paint_Fake_Bold,
5351Font_Embedded_Bitmaps, Full_Hinting_Spacing, LCD_Text, Linear_Text,
5352Subpixel_Text, and Paint_Vertical_Text.
5353
5354Paint_Text_Encoding must be set to SkPaint::kGlyphID_TextEncoding.
5355
5356Elements of paint: Path_Effect, Mask_Filter, Shader, Color_Filter,
5357Image_Filter, and Draw_Looper; apply to blob.
5358
5359#Param  blob     Glyphs, positions, and their paints' text size, typeface, and so on ##
5360#Param  x        horizontal offset applied to blob ##
5361#Param  y        vertical offset applied to blob ##
5362#Param  paint    blend, color, stroking, and so on, used to draw ##
5363
5364#Example
5365#Height 120
5366    void draw(SkCanvas* canvas) {
5367        SkTextBlobBuilder textBlobBuilder;
5368        const char bunny[] = "/(^x^)\\";
5369        const int len = sizeof(bunny) - 1;
5370        uint16_t glyphs[len];
5371        SkPaint paint;
5372        paint.textToGlyphs(bunny, len, glyphs);
5373        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
5374        int runs[] = { 3, 1, 3 };
5375        SkPoint textPos = { 20, 100 };
5376        int glyphIndex = 0;
5377        for (auto runLen : runs) {
5378            paint.setTextSize(1 == runLen ? 20 : 50);
5379            const SkTextBlobBuilder::RunBuffer& run = 
5380                    textBlobBuilder.allocRun(paint, runLen, textPos.fX, textPos.fY);
5381            memcpy(run.glyphs, &glyphs[glyphIndex], sizeof(glyphs[0]) * runLen);
5382            textPos.fX += paint.measureText(&glyphs[glyphIndex], sizeof(glyphs[0]) * runLen, nullptr);
5383            glyphIndex += runLen;
5384        }
5385        sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
5386        paint.reset();
5387        canvas->drawTextBlob(blob.get(), 0, 0, paint);
5388    }
5389##
5390
5391#SeeAlso drawText drawPosText drawPosTextH
5392
5393##
5394
5395# ------------------------------------------------------------------------------
5396
5397#Method void drawTextBlob(const sk_sp<SkTextBlob>& blob, SkScalar x, SkScalar y, const SkPaint& paint) 
5398
5399Draw Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint.
5400
5401blob contains Glyphs, their positions, and paint attributes specific to text:
5402Typeface, Paint_Text_Size, Paint_Text_Scale_X, Paint_Text_Skew_X,
5403Paint_Text_Align, Paint_Hinting, Anti-alias, Paint_Fake_Bold,
5404Font_Embedded_Bitmaps, Full_Hinting_Spacing, LCD_Text, Linear_Text,
5405Subpixel_Text, and Paint_Vertical_Text.
5406
5407Paint_Text_Encoding must be set to SkPaint::kGlyphID_TextEncoding.
5408
5409Elements of paint: Path_Effect, Mask_Filter, Shader, Color_Filter, 
5410Image_Filter, and Draw_Looper; apply to blob.
5411
5412#Param  blob     Glyphs, positions, and their paints' text size, typeface, and so on ##
5413#Param  x        horizontal offset applied to blob ##
5414#Param  y        vertical offset applied to blob ##
5415#Param  paint    blend, color, stroking, and so on, used to draw ##
5416
5417#Example
5418#Height 120
5419#Description
5420Paint attributes unrelated to text, like color, have no effect on paint in allocated Text_Blob.
5421Paint attributes related to text, like text size, have no effect on paint passed to drawTextBlob.
5422##
5423    void draw(SkCanvas* canvas) {
5424        SkTextBlobBuilder textBlobBuilder;
5425        SkPaint paint;
5426        paint.setTextSize(50);
5427        paint.setColor(SK_ColorRED);
5428        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
5429        const SkTextBlobBuilder::RunBuffer& run = 
5430                textBlobBuilder.allocRun(paint, 1, 20, 100);
5431        run.glyphs[0] = 20;
5432        sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
5433        paint.setTextSize(10);
5434        paint.setColor(SK_ColorBLUE);
5435        canvas->drawTextBlob(blob.get(), 0, 0, paint);
5436    }
5437##
5438
5439#SeeAlso drawText drawPosText drawPosTextH
5440
5441##
5442
5443# ------------------------------------------------------------------------------
5444
5445#Method void drawPicture(const SkPicture* picture) 
5446
5447#Line # draws Picture using Clip and Matrix ##
5448Draw Picture picture, using Clip and Matrix.
5449Clip and Matrix are unchanged by picture contents, as if
5450save() was called before and restore() was called after drawPicture.
5451
5452Picture records a series of draw commands for later playback.
5453
5454#Param  picture  recorded drawing commands to play ##
5455
5456#Example
5457void draw(SkCanvas* canvas) {  
5458    SkPictureRecorder recorder;
5459    SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
5460    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
5461        SkPaint paint;
5462        paint.setColor(color);
5463        recordingCanvas->drawRect({10, 10, 30, 40}, paint);
5464        recordingCanvas->translate(10, 10);
5465        recordingCanvas->scale(1.2f, 1.4f);
5466    }
5467    sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
5468    const SkPicture* playbackPtr = playback.get();
5469    canvas->drawPicture(playback);
5470    canvas->scale(2, 2);
5471    canvas->translate(50, 0);
5472    canvas->drawPicture(playback);
5473}
5474##
5475
5476#SeeAlso drawDrawable SkPicture SkPicture::playback
5477
5478##
5479
5480# ------------------------------------------------------------------------------
5481
5482#Method void drawPicture(const sk_sp<SkPicture>& picture) 
5483
5484Draw Picture picture, using Clip and Matrix.
5485Clip and Matrix are unchanged by picture contents, as if
5486save() was called before and restore() was called after drawPicture.
5487
5488Picture records a series of draw commands for later playback.
5489
5490#Param  picture  recorded drawing commands to play ##
5491
5492#Example
5493void draw(SkCanvas* canvas) {  
5494    SkPictureRecorder recorder;
5495    SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
5496    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
5497        SkPaint paint;
5498        paint.setColor(color);
5499        recordingCanvas->drawRect({10, 10, 30, 40}, paint);
5500        recordingCanvas->translate(10, 10);
5501        recordingCanvas->scale(1.2f, 1.4f);
5502    }
5503    sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
5504    canvas->drawPicture(playback);
5505    canvas->scale(2, 2);
5506    canvas->translate(50, 0);
5507    canvas->drawPicture(playback);
5508}
5509##
5510
5511#SeeAlso drawDrawable SkPicture SkPicture::playback
5512
5513##
5514
5515# ------------------------------------------------------------------------------
5516
5517#Method void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint)
5518
5519Draw Picture picture, using Clip and Matrix; transforming picture with
5520Matrix matrix, if provided; and use Paint paint Color_Alpha, Color_Filter,
5521Image_Filter, and Blend_Mode, if provided.
5522
5523matrix transformation is equivalent to: save(), concat(), drawPicture, restore().
5524paint use is equivalent to: saveLayer, drawPicture, restore().
5525
5526#Param  picture  recorded drawing commands to play ##
5527#Param  matrix   Matrix to rotate, scale, translate, and so on; may be nullptr ##
5528#Param  paint    Paint to apply transparency, filtering, and so on; may be nullptr ##
5529
5530#Example
5531void draw(SkCanvas* canvas) {  
5532    SkPaint paint;
5533    SkPictureRecorder recorder;
5534    SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
5535    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
5536        paint.setColor(color);
5537        recordingCanvas->drawRect({10, 10, 30, 40}, paint);
5538        recordingCanvas->translate(10, 10);
5539        recordingCanvas->scale(1.2f, 1.4f);
5540    }
5541    sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
5542    const SkPicture* playbackPtr = playback.get();
5543    SkMatrix matrix;
5544    matrix.reset();
5545    for (auto alpha : { 70, 140, 210 } ) {
5546    paint.setAlpha(alpha);
5547    canvas->drawPicture(playbackPtr, &matrix, &paint);
5548    matrix.preTranslate(70, 70);
5549    }
5550}
5551##
5552
5553#SeeAlso drawDrawable SkPicture SkPicture::playback
5554
5555##
5556
5557# ------------------------------------------------------------------------------
5558
5559#Method void drawPicture(const sk_sp<SkPicture>& picture, const SkMatrix* matrix, const SkPaint* paint) 
5560
5561Draw Picture picture, using Clip and Matrix; transforming picture with
5562Matrix matrix, if provided; and use Paint paint Color_Alpha, Color_Filter,
5563Image_Filter, and Blend_Mode, if provided.
5564
5565matrix transformation is equivalent to: save(), concat(), drawPicture, restore().
5566paint use is equivalent to: saveLayer, drawPicture, restore().
5567
5568#Param  picture  recorded drawing commands to play ##
5569#Param  matrix   Matrix to rotate, scale, translate, and so on; may be nullptr ##
5570#Param  paint    Paint to apply transparency, filtering, and so on; may be nullptr ##
5571
5572#Example
5573void draw(SkCanvas* canvas) {  
5574    SkPaint paint;
5575    SkPictureRecorder recorder;
5576    SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
5577    for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
5578        paint.setColor(color);
5579        recordingCanvas->drawRect({10, 10, 30, 40}, paint);
5580        recordingCanvas->translate(10, 10);
5581        recordingCanvas->scale(1.2f, 1.4f);
5582    }
5583    sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
5584    SkMatrix matrix;
5585    matrix.reset();
5586    for (auto alpha : { 70, 140, 210 } ) {
5587    paint.setAlpha(alpha);
5588    canvas->drawPicture(playback, &matrix, &paint);
5589    matrix.preTranslate(70, 70);
5590    }
5591}
5592##
5593
5594#SeeAlso drawDrawable SkPicture SkPicture::playback
5595
5596##
5597
5598# ------------------------------------------------------------------------------
5599
5600#Method void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint)
5601
5602#Line # draws Vertices, a triangle mesh ##
5603Draw Vertices vertices, a triangle mesh, using Clip and Matrix.
5604If Vertices_Texs and Vertices_Colors are defined in vertices, and Paint paint
5605contains Shader, Blend_Mode mode combines Vertices_Colors with Shader.
5606
5607#Param  vertices  triangle mesh to draw ##
5608#Param  mode      combines Vertices_Colors with Shader, if both are present ##
5609#Param  paint     specifies the Shader, used as Vertices texture; may be nullptr ##
5610
5611#Example
5612void draw(SkCanvas* canvas) {
5613    SkPaint paint;
5614    SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
5615    SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
5616    auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
5617            SK_ARRAY_COUNT(points), points, nullptr, colors);
5618    canvas->drawVertices(vertices.get(), SkBlendMode::kSrc, paint);
5619}
5620##
5621
5622#SeeAlso drawPatch drawPicture
5623
5624##
5625
5626# ------------------------------------------------------------------------------
5627
5628#Method void drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, const SkPaint& paint)
5629
5630Draw Vertices vertices, a triangle mesh, using Clip and Matrix.
5631If Vertices_Texs and Vertices_Colors are defined in vertices, and Paint paint
5632contains Shader, Blend_Mode mode combines Vertices_Colors with Shader.
5633
5634#Param  vertices  triangle mesh to draw ##
5635#Param  mode      combines Vertices_Colors with Shader, if both are present ##
5636#Param  paint     specifies the Shader, used as Vertices texture, may be nullptr ##
5637
5638#Example
5639void draw(SkCanvas* canvas) {
5640    SkPaint paint;
5641    SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
5642    SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };
5643    SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
5644    paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
5645            SkShader::kClamp_TileMode));
5646    auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
5647            SK_ARRAY_COUNT(points), points, texs, colors);
5648    canvas->drawVertices(vertices.get(), SkBlendMode::kDarken, paint);
5649}
5650##
5651
5652#SeeAlso drawPatch drawPicture
5653
5654##
5655
5656# ------------------------------------------------------------------------------
5657
5658#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
5659                   const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint)
5660#Line # draws Coons_Patch ##
5661
5662Draws a Coons_Patch: the interpolation of four cubics with shared corners, 
5663associating a color, and optionally a texture coordinate, with each corner.
5664
5665Coons_Patch uses Clip and Matrix, paint Shader, Color_Filter,
5666Color_Alpha, Image_Filter, and Blend_Mode. If Shader is provided it is treated
5667as Coons_Patch texture; Blend_Mode mode combines Color colors and Shader if
5668both are provided.
5669
5670Point array cubics specifies four Cubics starting at the top-left corner, 
5671in clockwise order, sharing every fourth point. The last Cubic ends at the
5672first point.
5673
5674Color array color associates colors with corners in top-left, top-right,
5675bottom-right, bottom-left order.
5676
5677If paint contains Shader, Point array texCoords maps Shader as texture to
5678corners in top-left, top-right, bottom-right, bottom-left order.
5679
5680#Param cubics     Path_Cubic array, sharing common points ##
5681#Param colors     Color array, one for each corner ##
5682#Param texCoords  Point array of texture coordinates, mapping Shader to corners;
5683                  may be nullptr 
5684#Param ##
5685#Param mode       Blend_Mode for colors, and for Shader if paint has one ##
5686#Param paint      Shader, Color_Filter, Blend_Mode, used to draw ##
5687
5688#Example
5689#Image 5
5690void draw(SkCanvas* canvas) {
5691    // SkBitmap source = cmbkygk;
5692    SkPaint paint;
5693    paint.setFilterQuality(kLow_SkFilterQuality);
5694    paint.setAntiAlias(true);
5695    SkPoint cubics[] = { { 3, 1 },    { 4, 2 }, { 5, 1 },    { 7, 3 },
5696                      /* { 7, 3 }, */ { 6, 4 }, { 7, 5 },    { 5, 7 },
5697                      /* { 5, 7 }, */ { 4, 6 }, { 3, 7 },    { 1, 5 },
5698                      /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
5699    SkColor colors[] = { 0xbfff0000, 0xbf0000ff, 0xbfff00ff, 0xbf00ffff };
5700    SkPoint texCoords[] = { { -30, -30 }, { 162, -30}, { 162, 162}, { -30, 162} };
5701    paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode,
5702                                                       SkShader::kClamp_TileMode, nullptr));
5703    canvas->scale(15, 15);
5704    for (auto blend : { SkBlendMode::kSrcOver, SkBlendMode::kModulate, SkBlendMode::kXor } ) {
5705        canvas->drawPatch(cubics, colors, texCoords, blend, paint);
5706        canvas->translate(4, 4);
5707    }
5708}
5709##
5710
5711#ToDo can patch use image filter? ##
5712#SeeAlso SeeAlso drawVertices drawPicture
5713
5714##
5715
5716# ------------------------------------------------------------------------------
5717
5718#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
5719                   const SkPoint texCoords[4], const SkPaint& paint) 
5720
5721Draws Cubic Coons_Patch: the interpolation of four cubics with shared corners, 
5722associating a color, and optionally a texture coordinate, with each corner.
5723
5724Coons_Patch uses Clip and Matrix, paint Shader, Color_Filter,
5725Color_Alpha, Image_Filter, and Blend_Mode. If Shader is provided it is treated
5726as Coons_Patch texture; Blend_Mode mode combines Color colors and Shader if
5727both are provided.
5728
5729Point array cubics specifies four Cubics starting at the top-left corner, 
5730in clockwise order, sharing every fourth point. The last Cubic ends at the
5731first point.
5732
5733Color array color associates colors with corners in top-left, top-right,
5734bottom-right, bottom-left order.
5735
5736If paint contains Shader, Point array texCoords maps Shader as texture to
5737corners in top-left, top-right, bottom-right, bottom-left order.
5738
5739#Param cubics     Path_Cubic array, sharing common points ##
5740#Param colors     Color array, one for each corner ##
5741#Param texCoords  Point array of texture coordinates, mapping Shader to corners;
5742                  may be nullptr 
5743#Param ##
5744#Param paint      Shader, Color_Filter, Blend_Mode, used to draw ##
5745
5746#Example
5747void draw(SkCanvas* canvas) {
5748    SkPaint paint;
5749    paint.setAntiAlias(true);
5750    SkPoint cubics[] = { { 3, 1 },    { 4, 2 }, { 5, 1 },    { 7, 3 },
5751                      /* { 7, 3 }, */ { 6, 4 }, { 7, 5 },    { 5, 7 },
5752                      /* { 5, 7 }, */ { 4, 6 }, { 3, 7 },    { 1, 5 },
5753                      /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
5754    SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
5755    canvas->scale(30, 30);
5756    canvas->drawPatch(cubics, colors, nullptr, paint);
5757    SkPoint text[] = { {3,0.9f}, {4,2.5f}, {5,0.9f}, {7.5f,3.2f}, {5.5f,4.2f},
5758            {7.5f,5.2f}, {5,7.5f}, {4,5.9f}, {3,7.5f}, {0.5f,5.2f}, {2.5f,4.2f},
5759            {0.5f,3.2f} };
5760    paint.setTextSize(18.f / 30);
5761    paint.setTextAlign(SkPaint::kCenter_Align);
5762    for (int i = 0; i< 10; ++i) {
5763       char digit = '0' + i;
5764       canvas->drawText(&digit, 1, text[i].fX, text[i].fY, paint);
5765    }
5766    canvas->drawString("10", text[10].fX, text[10].fY, paint);
5767    canvas->drawString("11", text[11].fX, text[11].fY, paint);
5768    paint.setStyle(SkPaint::kStroke_Style);
5769    canvas->drawPoints(SkCanvas::kPolygon_PointMode, 12, cubics, paint);
5770    canvas->drawLine(cubics[11].fX, cubics[11].fY, cubics[0].fX, cubics[0].fY, paint);
5771}
5772##
5773
5774#Example
5775#Image 6
5776void draw(SkCanvas* canvas) {
5777    // SkBitmap source = checkerboard;
5778    SkPaint paint;
5779    paint.setFilterQuality(kLow_SkFilterQuality);
5780    paint.setAntiAlias(true);
5781    SkPoint cubics[] = { { 3, 1 },    { 4, 2 }, { 5, 1 },    { 7, 3 },
5782                      /* { 7, 3 }, */ { 6, 4 }, { 7, 5 },    { 5, 7 },
5783                      /* { 5, 7 }, */ { 4, 6 }, { 3, 7 },    { 1, 5 },
5784                      /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
5785    SkPoint texCoords[] = { { 0, 0 }, { 0, 62}, { 62, 62}, { 62, 0 } };
5786    paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode,
5787                                                       SkShader::kClamp_TileMode, nullptr));
5788    canvas->scale(30, 30);
5789    canvas->drawPatch(cubics, nullptr, texCoords, paint);
5790}
5791##
5792
5793#ToDo can patch use image filter? ##
5794#SeeAlso SeeAlso drawVertices drawPicture
5795
5796##
5797
5798# ------------------------------------------------------------------------------
5799
5800#Method void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
5801                   const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect,
5802                   const SkPaint* paint)
5803#Line # draws sprites using Clip, Matrix, and Paint ##
5804
5805Draw a set of sprites from atlas, using Clip, Matrix, and optional Paint paint.
5806paint uses Anti-alias, Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode
5807to draw, if present. For each entry in the array, Rect tex locates sprite in
5808atlas, and RSXform xform transforms it into destination space.
5809
5810xform, text, and colors if present, must contain count entries.
5811Optional colors are applied for each sprite using Blend_Mode.
5812Optional cullRect is a conservative bounds of all transformed sprites. 
5813If cullRect is outside of Clip, canvas can skip drawing.
5814
5815#Param atlas  Image containing sprites ##
5816#Param xform  RSXform mappings for sprites in atlas ##
5817#Param tex    Rect locations of sprites in atlas ##
5818#Param colors  one per sprite, blended with sprite using Blend_Mode; may be nullptr ##
5819#Param count  number of sprites to draw ##
5820#Param mode   Blend_Mode combining colors and sprites ##
5821#Param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr ##
5822#Param paint  Color_Filter, Image_Filter, Blend_Mode, and so on; may be nullptr ##
5823
5824#Example
5825#Image 3
5826void draw(SkCanvas* canvas) {
5827  // SkBitmap source = mandrill;
5828  SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
5829  SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
5830  SkColor colors[] = { 0x7f55aa00, 0x7f3333bf };
5831  const SkImage* imagePtr = image.get();
5832  canvas->drawAtlas(imagePtr, xforms, tex, colors, 2, SkBlendMode::kSrcOver, nullptr, nullptr);
5833}
5834##
5835
5836#SeeAlso drawBitmap drawImage
5837
5838##
5839
5840# ------------------------------------------------------------------------------
5841
5842#Method void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[],
5843                   const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect,
5844                   const SkPaint* paint) 
5845
5846Draw a set of sprites from atlas, using Clip, Matrix, and optional Paint paint.
5847paint uses Anti-alias, Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode
5848to draw, if present. For each entry in the array, Rect tex locates sprite in
5849atlas, and RSXform xform transforms it into destination space.
5850
5851xform, text, and colors if present, must contain count entries.
5852Optional colors is applied for each sprite using Blend_Mode.
5853Optional cullRect is a conservative bounds of all transformed sprites. 
5854If cullRect is outside of Clip, canvas can skip drawing.
5855
5856#Param atlas  Image containing sprites ##
5857#Param xform  RSXform mappings for sprites in atlas ##
5858#Param tex    Rect locations of sprites in atlas ##
5859#Param colors  one per sprite, blended with sprite using Blend_Mode; may be nullptr ##
5860#Param count  number of sprites to draw ##
5861#Param mode   Blend_Mode combining colors and sprites ##
5862#Param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr ##
5863#Param paint  Color_Filter, Image_Filter, Blend_Mode, and so on; may be nullptr ##
5864
5865#Example
5866#Image 3
5867void draw(SkCanvas* canvas) {
5868  // SkBitmap source = mandrill;
5869  SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
5870  SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
5871  SkColor colors[] = { 0x7f55aa00, 0x7f3333bf };
5872  SkPaint paint;
5873  paint.setAlpha(127);
5874  canvas->drawAtlas(image, xforms, tex, colors, 2, SkBlendMode::kPlus, nullptr, &paint);
5875}
5876##
5877
5878#ToDo bug in example on cpu side, gpu looks ok ##
5879
5880#SeeAlso drawBitmap drawImage
5881
5882##
5883
5884# ------------------------------------------------------------------------------
5885
5886#Method void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count,
5887                   const SkRect* cullRect, const SkPaint* paint) 
5888
5889Draw a set of sprites from atlas, using Clip, Matrix, and optional Paint paint.
5890paint uses Anti-alias, Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode
5891to draw, if present. For each entry in the array, Rect tex locates sprite in
5892atlas, and RSXform xform transforms it into destination space.
5893
5894xform and text must contain count entries.
5895Optional cullRect is a conservative bounds of all transformed sprites. 
5896If cullRect is outside of Clip, canvas can skip drawing.
5897
5898#Param atlas  Image containing sprites ##
5899#Param xform  RSXform mappings for sprites in atlas ##
5900#Param tex    Rect locations of sprites in atlas ##
5901#Param count  number of sprites to draw ##
5902#Param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr ##
5903#Param paint  Color_Filter, Image_Filter, Blend_Mode, and so on; may be nullptr ##
5904
5905#Example
5906#Image 3
5907void draw(SkCanvas* canvas) {
5908  // sk_sp<SkImage> image = mandrill;
5909  SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
5910  SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
5911  const SkImage* imagePtr = image.get();
5912  canvas->drawAtlas(imagePtr, xforms, tex, 2, nullptr, nullptr);
5913}
5914##
5915
5916#SeeAlso drawBitmap drawImage
5917
5918##
5919
5920# ------------------------------------------------------------------------------
5921
5922#Method void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[],
5923                   int count, const SkRect* cullRect, const SkPaint* paint) 
5924
5925Draw a set of sprites from atlas, using Clip, Matrix, and optional Paint paint.
5926paint uses Anti-alias, Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode
5927to draw, if present. For each entry in the array, Rect tex locates sprite in
5928atlas, and RSXform xform transforms it into destination space.
5929
5930xform and text must contain count entries.
5931Optional cullRect is a conservative bounds of all transformed sprites. 
5932If cullRect is outside of Clip, canvas can skip drawing.
5933
5934#Param atlas  Image containing sprites ##
5935#Param xform  RSXform mappings for sprites in atlas ##
5936#Param tex    Rect locations of sprites in atlas ##
5937#Param count  number of sprites to draw ##
5938#Param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr ##
5939#Param paint  Color_Filter, Image_Filter, Blend_Mode, and so on; may be nullptr ##
5940
5941#Example
5942#Image 3
5943void draw(SkCanvas* canvas) {
5944  // sk_sp<SkImage> image = mandrill;
5945  SkRSXform xforms[] = { { 1, 0, 0, 0 }, {0, 1, 300, 100 } };
5946  SkRect tex[] = { { 0, 0, 200, 200 }, { 200, 0, 400, 200 } };
5947  canvas->drawAtlas(image, xforms, tex, 2, nullptr, nullptr);
5948}
5949##
5950
5951#SeeAlso drawBitmap drawImage
5952
5953##
5954
5955# ------------------------------------------------------------------------------
5956
5957#Method void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr)
5958
5959#Line # draws Drawable, encapsulated drawing commands ##
5960Draw Drawable drawable using Clip and Matrix, concatenated with 
5961optional matrix.
5962
5963If Canvas has an asynchronous implementation, as is the case 
5964when it is recording into Picture, then drawable will be referenced,
5965so that SkDrawable::draw() can be called when the operation is finalized. To force
5966immediate drawing, call SkDrawable::draw() instead.
5967
5968#Param drawable  custom struct encapsulating drawing commands ##
5969#Param matrix    transformation applied to drawing; may be nullptr  ##
5970
5971#Example
5972#Height 100
5973#Function
5974struct MyDrawable : public SkDrawable {
5975    SkRect onGetBounds() override { return SkRect::MakeWH(50, 100);  }
5976
5977    void onDraw(SkCanvas* canvas) override {
5978       SkPath path;
5979       path.conicTo(10, 90, 50, 90, 0.9f);
5980       SkPaint paint;
5981       paint.setColor(SK_ColorBLUE);
5982       canvas->drawRect(path.getBounds(), paint);
5983       paint.setAntiAlias(true);
5984       paint.setColor(SK_ColorWHITE);
5985       canvas->drawPath(path, paint);
5986    }
5987};
5988
5989#Function ##
5990void draw(SkCanvas* canvas) {
5991    sk_sp<SkDrawable> drawable(new MyDrawable);
5992  SkMatrix matrix;
5993  matrix.setTranslate(10, 10);
5994  canvas->drawDrawable(drawable.get(), &matrix);
5995}
5996##
5997
5998#SeeAlso SkDrawable drawPicture
5999
6000##
6001
6002# ------------------------------------------------------------------------------
6003
6004#Method void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y)
6005
6006Draw Drawable drawable using Clip and Matrix, offset by (x, y).
6007
6008If Canvas has an asynchronous implementation, as is the case 
6009when it is recording into Picture, then drawable will be referenced,
6010so that SkDrawable::draw() can be called when the operation is finalized. To force
6011immediate drawing, call SkDrawable::draw() instead.
6012
6013#Param drawable  custom struct encapsulating drawing commands ##
6014#Param x  offset into Canvas writable pixels in x ##
6015#Param y  offset into Canvas writable pixels in y ##
6016
6017#Example
6018#Height 100
6019#Function
6020struct MyDrawable : public SkDrawable {
6021    SkRect onGetBounds() override { return SkRect::MakeWH(50, 100);  }
6022
6023    void onDraw(SkCanvas* canvas) override {
6024       SkPath path;
6025       path.conicTo(10, 90, 50, 90, 0.9f);
6026       SkPaint paint;
6027       paint.setColor(SK_ColorBLUE);
6028       canvas->drawRect(path.getBounds(), paint);
6029       paint.setAntiAlias(true);
6030       paint.setColor(SK_ColorWHITE);
6031       canvas->drawPath(path, paint);
6032    }
6033};
6034
6035#Function ##
6036void draw(SkCanvas* canvas) {
6037    sk_sp<SkDrawable> drawable(new MyDrawable);
6038  canvas->drawDrawable(drawable.get(), 10, 10);
6039}
6040##
6041
6042#SeeAlso SkDrawable drawPicture
6043
6044##
6045
6046# ------------------------------------------------------------------------------
6047
6048#Method void drawAnnotation(const SkRect& rect, const char key[], SkData* value)
6049
6050#Line # associates a Rect with a key-value pair ##
6051Associate Rect on Canvas when an annotation; a key-value pair, where the key is
6052a null-terminated utf8 string, and optional value is stored as Data.
6053
6054Only some canvas implementations, such as recording to Picture, or drawing to 
6055Document_PDF, use annotations.
6056
6057#Param rect    Rect extent of canvas to annotate ##
6058#Param key     string used for lookup ##
6059#Param value   data holding value stored in annotation ##
6060
6061#Example
6062    #Height 1
6063    const char text[] = "Click this link!";
6064    SkRect bounds;
6065    SkPaint paint;
6066    paint.setTextSize(40);
6067    (void)paint.measureText(text, strlen(text), &bounds);
6068    const char url[] = "https://www.google.com/";
6069    sk_sp<SkData> urlData(SkData::MakeWithCString(url));
6070    canvas->drawAnnotation(bounds, "url_key", urlData.get());
6071##
6072
6073#SeeAlso SkPicture SkDocument
6074
6075##
6076
6077# ------------------------------------------------------------------------------
6078
6079#Method void drawAnnotation(const SkRect& rect, const char key[], const sk_sp<SkData>& value) 
6080
6081Associate Rect on Canvas when an annotation; a key-value pair, where the key is
6082a null-terminated utf8 string, and optional value is stored as Data.
6083
6084Only some canvas implementations, such as recording to Picture, or drawing to 
6085Document_PDF, use annotations.
6086
6087#Param rect    Rect extent of canvas to annotate ##
6088#Param key     string used for lookup ##
6089#Param value   data holding value stored in annotation ##
6090
6091#Example
6092#Height 1
6093    const char text[] = "Click this link!";
6094    SkRect bounds;
6095    SkPaint paint;
6096    paint.setTextSize(40);
6097    (void)paint.measureText(text, strlen(text), &bounds);
6098    const char url[] = "https://www.google.com/";
6099    sk_sp<SkData> urlData(SkData::MakeWithCString(url));
6100    canvas->drawAnnotation(bounds, "url_key", urlData.get());
6101##
6102
6103#SeeAlso SkPicture SkDocument
6104
6105##
6106
6107#Method SkDrawFilter* getDrawFilter() const
6108#Deprecated soon
6109##
6110
6111#Method virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter)
6112#Deprecated soon
6113##
6114
6115# ------------------------------------------------------------------------------
6116
6117#Method virtual bool isClipEmpty() const
6118
6119#Line # returns if Clip is empty ##
6120Returns true if Clip is empty; that is, nothing will draw.
6121
6122May do work when called; it should not be called
6123more often than needed. However, once called, subsequent calls perform no
6124work until Clip changes.
6125
6126#Return  true if Clip is empty ##
6127
6128#Example
6129    void draw(SkCanvas* canvas) {
6130        SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not");
6131        SkPath path;
6132        canvas->clipPath(path);
6133        SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not");
6134    }
6135    #StdOut
6136        clip is not empty
6137        clip is empty
6138    ##
6139##
6140
6141#SeeAlso isClipRect getLocalClipBounds getDeviceClipBounds
6142
6143##
6144
6145# ------------------------------------------------------------------------------
6146
6147#Method virtual bool isClipRect() const
6148
6149#Line # returns if Clip is Rect and not empty ##
6150Returns true if Clip is Rect and not empty.
6151Returns false if the clip is empty, or if it is not Rect.
6152
6153#Return  true if Clip is Rect and not empty ##
6154
6155#Example
6156    void draw(SkCanvas* canvas) {
6157        SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not");
6158        canvas->clipRect({0, 0, 0, 0});
6159        SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not");
6160    }
6161    #StdOut
6162        clip is rect
6163        clip is not rect
6164    ##
6165##
6166
6167#SeeAlso isClipEmpty getLocalClipBounds getDeviceClipBounds
6168
6169##
6170
6171#Class SkCanvas ##
6172
6173#Topic Canvas ##
6174