Skip to main content

skia_safe/core/
canvas.rs

1use std::{cell::UnsafeCell, ffi::CString, fmt, marker::PhantomData, mem, ops::Deref, ptr, slice};
2
3use sb::SkCanvas_FilterSpan;
4use skia_bindings::{
5    self as sb, SkAutoCanvasRestore, SkCanvas, SkCanvas_SaveLayerRec, SkColorSpace, SkImageFilter,
6    SkPaint, SkRect, U8CPU,
7};
8
9#[cfg(feature = "gpu")]
10use crate::gpu;
11#[cfg(feature = "graphite")]
12use crate::graphite;
13use crate::{Arc, ColorSpace};
14use crate::{
15    Bitmap, BlendMode, ClipOp, Color, Color4f, Data, Drawable, FilterMode, Font, GlyphId, IPoint,
16    IRect, ISize, Image, ImageFilter, ImageInfo, M44, Matrix, Paint, Path, Picture, Pixmap, Point,
17    QuickReject, RRect, RSXform, Rect, Region, SamplingOptions, Shader, Surface, SurfaceProps,
18    TextBlob, TextEncoding, TileMode, Vector, Vertices, prelude::*, scalar,
19};
20
21pub use lattice::Lattice;
22
23bitflags! {
24    /// [`SaveLayerFlags`] provides options that may be used in any combination in [`SaveLayerRec`],
25    /// defining how layer allocated by [`Canvas::save_layer()`] operates. It may be set to zero,
26    /// [`PRESERVE_LCD_TEXT`], [`INIT_WITH_PREVIOUS`], or both flags.
27    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
28    pub struct SaveLayerFlags: u32 {
29        const PRESERVE_LCD_TEXT = sb::SkCanvas_SaveLayerFlagsSet_kPreserveLCDText_SaveLayerFlag as _;
30        /// initializes with previous contents
31        const INIT_WITH_PREVIOUS = sb::SkCanvas_SaveLayerFlagsSet_kInitWithPrevious_SaveLayerFlag as _;
32        const F16_COLOR_TYPE = sb::SkCanvas_SaveLayerFlagsSet_kF16ColorType as _;
33    }
34}
35
36/// [`SaveLayerRec`] contains the state used to create the layer.
37#[repr(C)]
38pub struct SaveLayerRec<'a> {
39    // We _must_ store _references_ to the native types here, because not all of them are native
40    // transmutable, like ImageFilter or Image, which are represented as ref counted pointers and so
41    // we would store a reference to a pointer only.
42    bounds: Option<&'a SkRect>,
43    paint: Option<&'a SkPaint>,
44    filters: SkCanvas_FilterSpan,
45    backdrop: Option<&'a SkImageFilter>,
46    backdrop_tile_mode: sb::SkTileMode,
47    color_space: Option<&'a SkColorSpace>,
48    flags: SaveLayerFlags,
49    experimental_backdrop_scale: scalar,
50}
51
52native_transmutable!(SkCanvas_SaveLayerRec, SaveLayerRec<'_>);
53
54impl Default for SaveLayerRec<'_> {
55    /// Sets [`Self::bounds`], [`Self::paint`], and [`Self::backdrop`] to `None`. Clears
56    /// [`Self::flags`].
57    ///
58    /// Returns empty [`SaveLayerRec`]
59    fn default() -> Self {
60        SaveLayerRec::construct(|slr| unsafe { sb::C_SkCanvas_SaveLayerRec_Construct(slr) })
61    }
62}
63
64impl Drop for SaveLayerRec<'_> {
65    fn drop(&mut self) {
66        unsafe { sb::C_SkCanvas_SaveLayerRec_destruct(self.native_mut()) }
67    }
68}
69
70impl fmt::Debug for SaveLayerRec<'_> {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        f.debug_struct("SaveLayerRec")
73            .field("bounds", &self.bounds.map(Rect::from_native_ref))
74            .field("paint", &self.paint.map(Paint::from_native_ref))
75            .field(
76                "backdrop",
77                &ImageFilter::from_unshared_ptr_ref(&(self.backdrop.as_ptr_or_null() as *mut _)),
78            )
79            .field("backdrop_tile_mode", &self.backdrop_tile_mode)
80            .field(
81                "color_space",
82                &ColorSpace::from_unshared_ptr_ref(&(self.color_space.as_ptr_or_null() as *mut _)),
83            )
84            .field("flags", &self.flags)
85            .field(
86                "experimental_backdrop_scale",
87                &self.experimental_backdrop_scale,
88            )
89            .finish()
90    }
91}
92
93impl<'a> SaveLayerRec<'a> {
94    /// Hints at layer size limit
95    #[must_use]
96    pub fn bounds(mut self, bounds: &'a Rect) -> Self {
97        self.bounds = Some(bounds.native());
98        self
99    }
100
101    /// Modifies overlay
102    #[must_use]
103    pub fn paint(mut self, paint: &'a Paint) -> Self {
104        self.paint = Some(paint.native());
105        self
106    }
107
108    /// If not `None`, this triggers the same initialization behavior as setting
109    /// [`SaveLayerFlags::INIT_WITH_PREVIOUS`] on [`Self::flags`]: the current layer is copied into
110    /// the new layer, rather than initializing the new layer with transparent-black. This is then
111    /// filtered by [`Self::backdrop`] (respecting the current clip).
112    #[must_use]
113    pub fn backdrop(mut self, backdrop: &'a ImageFilter) -> Self {
114        self.backdrop = Some(backdrop.native());
115        self
116    }
117
118    /// If the layer is initialized with prior content (and/or with a backdrop filter) and this
119    /// would require sampling outside of the available backdrop, this is the tilemode applied
120    /// to the boundary of the prior layer's image.
121    #[must_use]
122    pub fn backdrop_tile_mode(mut self, backdrop_tile_mode: TileMode) -> Self {
123        self.backdrop_tile_mode = backdrop_tile_mode;
124        self
125    }
126
127    /// If not `None`, this triggers a color space conversion when the layer is restored. It
128    /// will be as if the layer's contents are drawn in this color space. Filters from
129    /// `backdrop` and `paint` will be applied in this color space.
130    pub fn color_space(mut self, color_space: &'a ColorSpace) -> Self {
131        self.color_space = Some(color_space.native());
132        self
133    }
134
135    /// Preserves LCD text, creates with prior layer contents
136    #[must_use]
137    pub fn flags(mut self, flags: SaveLayerFlags) -> Self {
138        self.flags = flags;
139        self
140    }
141}
142
143/// Selects if an array of points are drawn as discrete points, as lines, or as an open polygon.
144pub use sb::SkCanvas_PointMode as PointMode;
145variant_name!(PointMode::Polygon);
146
147/// [`SrcRectConstraint`] controls the behavior at the edge of source [`Rect`], provided to
148/// [`Canvas::draw_image_rect()`] when there is any filtering. If kStrict is set, then extra code is
149/// used to ensure it nevers samples outside of the src-rect.
150///
151/// [`SrcRectConstraint::Strict`] disables the use of mipmaps and anisotropic filtering.
152pub use sb::SkCanvas_SrcRectConstraint as SrcRectConstraint;
153variant_name!(SrcRectConstraint::Fast);
154
155/// Provides access to Canvas's pixels.
156///
157/// Returned by [`Canvas::access_top_layer_pixels()`]
158#[derive(Debug)]
159pub struct TopLayerPixels<'a> {
160    /// Address of pixels
161    pub pixels: &'a mut [u8],
162    /// Writable pixels' [`ImageInfo`]
163    pub info: ImageInfo,
164    /// Writable pixels' row bytes
165    pub row_bytes: usize,
166    /// [`Canvas`] top layer origin, its top-left corner
167    pub origin: IPoint,
168}
169
170/// Used to pass either a slice of [`Point`] or [`RSXform`] to [`Canvas::draw_glyphs_at`].
171#[derive(Clone, Debug)]
172pub enum GlyphPositions<'a> {
173    Points(&'a [Point]),
174    RSXforms(&'a [RSXform]),
175}
176
177impl<'a> From<&'a [Point]> for GlyphPositions<'a> {
178    fn from(points: &'a [Point]) -> Self {
179        Self::Points(points)
180    }
181}
182
183impl<'a> From<&'a [RSXform]> for GlyphPositions<'a> {
184    fn from(rs_xforms: &'a [RSXform]) -> Self {
185        Self::RSXforms(rs_xforms)
186    }
187}
188
189///  [`Canvas`] provides an interface for drawing, and how the drawing is clipped and transformed.
190///  [`Canvas`] contains a stack of [`Matrix`] and clip values.
191///
192///  [`Canvas`] and [`Paint`] together provide the state to draw into [`Surface`] or `Device`.
193///  Each [`Canvas`] draw call transforms the geometry of the object by the concatenation of all
194///  [`Matrix`] values in the stack. The transformed geometry is clipped by the intersection
195///  of all of clip values in the stack. The [`Canvas`] draw calls use [`Paint`] to supply drawing
196///  state such as color, [`crate::Typeface`], text size, stroke width, [`Shader`] and so on.
197///
198///  To draw to a pixel-based destination, create raster surface or GPU surface.
199///  Request [`Canvas`] from [`Surface`] to obtain the interface to draw.
200///  [`Canvas`] generated by raster surface draws to memory visible to the CPU.
201///  [`Canvas`] generated by GPU surface uses Vulkan or OpenGL to draw to the GPU.
202///
203///  To draw to a document, obtain [`Canvas`] from SVG canvas, document PDF, or
204///  [`crate::PictureRecorder`]. [`crate::Document`] based [`Canvas`] and other [`Canvas`]
205///  subclasses reference Device describing the destination.
206///
207///  [`Canvas`] can be constructed to draw to [`Bitmap`] without first creating raster surface.
208///  This approach may be deprecated in the future.
209#[repr(transparent)]
210pub struct Canvas(UnsafeCell<SkCanvas>);
211
212impl Canvas {
213    pub(self) fn native(&self) -> &SkCanvas {
214        unsafe { &*self.0.get() }
215    }
216
217    #[allow(clippy::mut_from_ref)]
218    pub(crate) fn native_mut(&self) -> &mut SkCanvas {
219        unsafe { &mut (*self.0.get()) }
220    }
221}
222
223impl fmt::Debug for Canvas {
224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225        f.debug_struct("Canvas")
226            .field("image_info", &self.image_info())
227            .field("props", &self.props())
228            .field("base_layer_size", &self.base_layer_size())
229            .field("save_count", &self.save_count())
230            .field("local_clip_bounds", &self.local_clip_bounds())
231            .field("device_clip_bounds", &self.device_clip_bounds())
232            .field("local_to_device", &self.local_to_device())
233            .finish()
234    }
235}
236
237/// Represents a [`Canvas`] that is owned and dropped when it goes out of scope _and_ is bound to
238/// the lifetime of some other value (an array of pixels for example).
239///
240/// Access to the [`Canvas`] functions are resolved with the [`Deref`] trait.
241#[repr(transparent)]
242pub struct OwnedCanvas<'lt>(ptr::NonNull<Canvas>, PhantomData<&'lt ()>);
243
244impl Deref for OwnedCanvas<'_> {
245    type Target = Canvas;
246
247    fn deref(&self) -> &Self::Target {
248        unsafe { self.0.as_ref() }
249    }
250}
251
252impl Drop for OwnedCanvas<'_> {
253    /// Draws saved layers, if any.
254    /// Frees up resources used by [`Canvas`].
255    ///
256    /// example: <https://fiddle.skia.org/c/@Canvas_destructor>
257    fn drop(&mut self) {
258        unsafe { sb::C_SkCanvas_delete(self.native()) }
259    }
260}
261
262impl Default for OwnedCanvas<'_> {
263    /// Creates an empty [`Canvas`] with no backing device or pixels, with
264    /// a width and height of zero.
265    ///
266    /// Returns empty [`Canvas`]
267    ///
268    /// example: <https://fiddle.skia.org/c/@Canvas_empty_constructor>
269    fn default() -> Self {
270        let ptr = unsafe { sb::C_SkCanvas_newEmpty() };
271        Canvas::own_from_native_ptr(ptr).unwrap()
272    }
273}
274
275impl fmt::Debug for OwnedCanvas<'_> {
276    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277        f.debug_tuple("OwnedCanvas").field(self as &Canvas).finish()
278    }
279}
280
281impl Canvas {
282    /// Allocates raster [`Canvas`] that will draw directly into pixels.
283    ///
284    /// [`Canvas`] is returned if all parameters are valid.
285    /// Valid parameters include:
286    /// - `info` dimensions are zero or positive
287    /// - `info` contains [`crate::ColorType`] and [`crate::AlphaType`] supported by raster surface
288    /// - `row_bytes` is `None` or large enough to contain info width pixels of [`crate::ColorType`]
289    ///
290    /// Pass `None` for `row_bytes` to compute `row_bytes` from info width and size of pixel.
291    /// If `row_bytes` is not `None`, it must be equal to or greater than `info` width times
292    /// bytes required for [`crate::ColorType`].
293    ///
294    /// Pixel buffer size should be info height times computed `row_bytes`.
295    /// Pixels are not initialized.
296    /// To access pixels after drawing, call `flush()` or [`Self::peek_pixels()`].
297    ///
298    /// - `info` width, height, [`crate::ColorType`], [`crate::AlphaType`], [`crate::ColorSpace`],
299    ///   of raster surface; width, or height, or both, may be zero
300    /// - `pixels` pointer to destination pixels buffer
301    /// - `row_bytes` interval from one [`Surface`] row to the next, or zero
302    /// - `props` LCD striping orientation and setting for device independent fonts;
303    ///   may be `None`
304    ///
305    /// Returns [`OwnedCanvas`] if all parameters are valid; otherwise, `None`.
306    pub fn from_raster_direct<'pixels>(
307        info: &ImageInfo,
308        pixels: &'pixels mut [u8],
309        row_bytes: impl Into<Option<usize>>,
310        props: Option<&SurfaceProps>,
311    ) -> Option<OwnedCanvas<'pixels>> {
312        let row_bytes = row_bytes.into().unwrap_or_else(|| info.min_row_bytes());
313        if info.valid_pixels(row_bytes, pixels) {
314            let ptr = unsafe {
315                sb::C_SkCanvas_MakeRasterDirect(
316                    info.native(),
317                    pixels.as_mut_ptr() as _,
318                    row_bytes,
319                    props.native_ptr_or_null(),
320                )
321            };
322            Self::own_from_native_ptr(ptr)
323        } else {
324            None
325        }
326    }
327
328    /// Allocates raster [`Canvas`] specified by inline image specification. Subsequent [`Canvas`]
329    /// calls draw into pixels.
330    /// [`crate::ColorType`] is set to [`crate::ColorType::n32()`].
331    /// [`crate::AlphaType`] is set to [`crate::AlphaType::Premul`].
332    /// To access pixels after drawing, call `flush()` or [`Self::peek_pixels()`].
333    ///
334    /// [`OwnedCanvas`] is returned if all parameters are valid.
335    /// Valid parameters include:
336    /// - width and height are zero or positive
337    /// - `row_bytes` is zero or large enough to contain width pixels of [`crate::ColorType::n32()`]
338    ///
339    /// Pass `None` for `row_bytes` to compute `row_bytes` from width and size of pixel.
340    /// If `row_bytes` is greater than zero, it must be equal to or greater than width times bytes
341    /// required for [`crate::ColorType`].
342    ///
343    /// Pixel buffer size should be height times `row_bytes`.
344    ///
345    /// - `size` pixel column and row count on raster surface created; must both be zero or greater
346    /// - `pixels` pointer to destination pixels buffer; buffer size should be height times
347    ///   `row_bytes`
348    /// - `row_bytes` interval from one [`Surface`] row to the next, or zero
349    ///
350    /// Returns [`OwnedCanvas`] if all parameters are valid; otherwise, `None`
351    pub fn from_raster_direct_n32<'pixels>(
352        size: impl Into<ISize>,
353        pixels: &'pixels mut [u32],
354        row_bytes: impl Into<Option<usize>>,
355    ) -> Option<OwnedCanvas<'pixels>> {
356        let info = ImageInfo::new_n32_premul(size, None);
357        let pixels_ptr: *mut u8 = pixels.as_mut_ptr() as _;
358        let pixels_u8: &'pixels mut [u8] =
359            unsafe { slice::from_raw_parts_mut(pixels_ptr, mem::size_of_val(pixels)) };
360        Self::from_raster_direct(&info, pixels_u8, row_bytes, None)
361    }
362
363    /// Creates [`Canvas`] of the specified dimensions without a [`Surface`].
364    /// Used by subclasses with custom implementations for draw member functions.
365    ///
366    /// If props equals `None`, [`SurfaceProps`] are created with `SurfaceProps::InitType` settings,
367    /// which choose the pixel striping direction and order. Since a platform may dynamically change
368    /// its direction when the device is rotated, and since a platform may have multiple monitors
369    /// with different characteristics, it is best not to rely on this legacy behavior.
370    ///
371    /// - `size` with and height zero or greater
372    /// - `props` LCD striping orientation and setting for device independent fonts;
373    ///   may be `None`
374    ///
375    /// Returns [`Canvas`] placeholder with dimensions
376    ///
377    /// example: <https://fiddle.skia.org/c/@Canvas_int_int_const_SkSurfaceProps_star>
378    #[allow(clippy::new_ret_no_self)]
379    pub fn new<'lt>(
380        size: impl Into<ISize>,
381        props: Option<&SurfaceProps>,
382    ) -> Option<OwnedCanvas<'lt>> {
383        let size = size.into();
384        if size.width >= 0 && size.height >= 0 {
385            let ptr = unsafe {
386                sb::C_SkCanvas_newWidthHeightAndProps(
387                    size.width,
388                    size.height,
389                    props.native_ptr_or_null(),
390                )
391            };
392            Canvas::own_from_native_ptr(ptr)
393        } else {
394            None
395        }
396    }
397
398    /// Constructs a canvas that draws into bitmap.
399    /// Use props to match the device characteristics, like LCD striping.
400    ///
401    /// bitmap is copied so that subsequently editing bitmap will not affect constructed [`Canvas`].
402    ///
403    /// - `bitmap` width, height, [`crate::ColorType`], [`crate::AlphaType`], and pixel storage of
404    ///   raster surface
405    /// - `props` order and orientation of RGB striping; and whether to use device independent fonts
406    ///
407    /// Returns [`Canvas`] that can be used to draw into bitmap
408    ///
409    /// example: <https://fiddle.skia.org/c/@Canvas_const_SkBitmap_const_SkSurfaceProps>
410    pub fn from_bitmap<'lt>(
411        bitmap: &Bitmap,
412        props: Option<&SurfaceProps>,
413    ) -> Option<OwnedCanvas<'lt>> {
414        // <https://github.com/rust-skia/rust-skia/issues/669>
415        if !bitmap.is_ready_to_draw() {
416            return None;
417        }
418        let props_ptr = props.native_ptr_or_null();
419        let ptr = if props_ptr.is_null() {
420            unsafe { sb::C_SkCanvas_newFromBitmap(bitmap.native()) }
421        } else {
422            unsafe { sb::C_SkCanvas_newFromBitmapAndProps(bitmap.native(), props_ptr) }
423        };
424        Canvas::own_from_native_ptr(ptr)
425    }
426
427    /// Returns [`ImageInfo`] for [`Canvas`]. If [`Canvas`] is not associated with raster surface or
428    /// GPU surface, returned [`crate::ColorType`] is set to [`crate::ColorType::Unknown`]
429    ///
430    /// Returns dimensions and [`crate::ColorType`] of [`Canvas`]
431    ///
432    /// example: <https://fiddle.skia.org/c/@Canvas_imageInfo>
433    pub fn image_info(&self) -> ImageInfo {
434        let mut ii = ImageInfo::default();
435        unsafe { sb::C_SkCanvas_imageInfo(self.native(), ii.native_mut()) };
436        ii
437    }
438
439    /// Copies [`SurfaceProps`], if [`Canvas`] is associated with raster surface or GPU surface, and
440    /// returns `true`. Otherwise, returns `false` and leave props unchanged.
441    ///
442    /// - `props` storage for writable [`SurfaceProps`]
443    ///
444    /// Returns `true` if [`SurfaceProps`] was copied
445    ///
446    /// example: <https://fiddle.skia.org/c/@Canvas_getProps>
447    pub fn props(&self) -> Option<SurfaceProps> {
448        let mut sp = SurfaceProps::default();
449        unsafe { self.native().getProps(sp.native_mut()) }.then_some(sp)
450    }
451
452    /// Returns the [`SurfaceProps`] associated with the canvas (i.e., at the base of the layer
453    /// stack).
454    pub fn base_props(&self) -> SurfaceProps {
455        SurfaceProps::from_native_c(unsafe { self.native().getBaseProps() })
456    }
457
458    /// Returns the [`SurfaceProps`] associated with the canvas that are currently active (i.e., at
459    /// the top of the layer stack). This can differ from [`Self::base_props`] depending on the flags
460    /// passed to saveLayer (see [`SaveLayerFlags`]).
461    pub fn top_props(&self) -> SurfaceProps {
462        SurfaceProps::from_native_c(unsafe { self.native().getTopProps() })
463    }
464
465    /// Gets the size of the base or root layer in global canvas coordinates. The
466    /// origin of the base layer is always (0,0). The area available for drawing may be
467    /// smaller (due to clipping or saveLayer).
468    ///
469    /// Returns integral size of base layer
470    ///
471    /// example: <https://fiddle.skia.org/c/@Canvas_getBaseLayerSize>
472    pub fn base_layer_size(&self) -> ISize {
473        let mut size = ISize::default();
474        unsafe { sb::C_SkCanvas_getBaseLayerSize(self.native(), size.native_mut()) }
475        size
476    }
477
478    /// Creates [`Surface`] matching info and props, and associates it with [`Canvas`].
479    /// Returns `None` if no match found.
480    ///
481    /// If props is `None`, matches [`SurfaceProps`] in [`Canvas`]. If props is `None` and
482    /// [`Canvas`] does not have [`SurfaceProps`], creates [`Surface`] with default
483    /// [`SurfaceProps`].
484    ///
485    /// - `info` width, height, [`crate::ColorType`], [`crate::AlphaType`], and
486    ///   [`crate::ColorSpace`]
487    /// - `props` [`SurfaceProps`] to match; may be `None` to match [`Canvas`]
488    ///
489    /// Returns [`Surface`] matching info and props, or `None` if no match is available
490    ///
491    /// example: <https://fiddle.skia.org/c/@Canvas_makeSurface>
492    pub fn new_surface(&self, info: &ImageInfo, props: Option<&SurfaceProps>) -> Option<Surface> {
493        Surface::from_ptr(unsafe {
494            sb::C_SkCanvas_makeSurface(self.native_mut(), info.native(), props.native_ptr_or_null())
495        })
496    }
497
498    /// Returns Ganesh context of the GPU surface associated with [`Canvas`].
499    ///
500    /// Returns GPU context, if available; `None` otherwise
501    ///
502    /// example: <https://fiddle.skia.org/c/@Canvas_recordingContext>
503    #[cfg(feature = "gpu")]
504    pub fn recording_context(&self) -> Option<gpu::RecordingContext> {
505        gpu::RecordingContext::from_unshared_ptr(unsafe {
506            sb::C_SkCanvas_recordingContext(self.native())
507        })
508    }
509
510    /// Returns the [`gpu::DirectContext`].
511    /// This is a rust-skia helper for that makes it simpler to call [`Image::encode`].
512    #[cfg(feature = "gpu")]
513    pub fn direct_context(&self) -> Option<gpu::DirectContext> {
514        self.recording_context()
515            .and_then(|mut c| c.as_direct_context())
516    }
517
518    /// Returns the [`graphite::Recorder`] for the GPU surface backing this
519    /// canvas, if it is Graphite-backed.
520    ///
521    /// `SkCanvas::recorder()` returns a *borrowed* pointer — the recorder is
522    /// owned by the surface/canvas — so the result is a
523    /// [`graphite::BorrowedRecorder`] that does not delete the recorder on drop
524    /// and is bound to this canvas's lifetime. Wrapping it in an owning handle
525    /// would double-free the recorder.
526    #[cfg(feature = "graphite")]
527    pub fn recorder(&self) -> Option<graphite::BorrowedRecorder<'_>> {
528        let recorder =
529            graphite::Recorder::from_ptr(unsafe { sb::C_SkCanvas_recorder(self.native()) })?;
530        Some(graphite::BorrowedRecorder::from_canvas(recorder, self))
531    }
532
533    /// Sometimes a canvas is owned by a surface. If it is, [`Self::surface()`] will return a bare
534    /// pointer to that surface, else this will return `None`.
535    ///
536    /// # Safety
537    /// This function is unsafe because it is not clear how exactly the lifetime of the canvas
538    /// relates to surface returned.
539    /// See also [`OwnedCanvas`], [`RCHandle<SkSurface>::canvas()`].
540    pub unsafe fn surface(&self) -> Option<Surface> {
541        unsafe {
542            // TODO: It might be possible to make this safe by returning a _kind of_ reference to the
543            //       Surface that can not be cloned and stays bound to the lifetime of canvas.
544            //       But even then, the Surface might exist twice then, which is confusing, but
545            //       probably safe, because the first instance is borrowed by the canvas.
546            Surface::from_unshared_ptr(self.native().getSurface())
547        }
548    }
549
550    /// Returns the pixel base address, [`ImageInfo`], `row_bytes`, and origin if the pixels
551    /// can be read directly.
552    ///
553    /// - `info` storage for writable pixels' [`ImageInfo`]
554    /// - `row_bytes` storage for writable pixels' row bytes
555    /// - `origin` storage for [`Canvas`] top layer origin, its top-left corner
556    ///
557    /// Returns address of pixels, or `None` if inaccessible
558    ///
559    /// example: <https://fiddle.skia.org/c/@Canvas_accessTopLayerPixels_a>
560    /// example: <https://fiddle.skia.org/c/@Canvas_accessTopLayerPixels_b>
561    pub fn access_top_layer_pixels(&self) -> Option<TopLayerPixels> {
562        let mut info = ImageInfo::default();
563        let mut row_bytes = 0;
564        let mut origin = IPoint::default();
565        let ptr = unsafe {
566            self.native_mut().accessTopLayerPixels(
567                info.native_mut(),
568                &mut row_bytes,
569                origin.native_mut(),
570            )
571        };
572        if !ptr.is_null() {
573            let size = info.compute_byte_size(row_bytes);
574            let pixels = unsafe { slice::from_raw_parts_mut(ptr as _, size) };
575            Some(TopLayerPixels {
576                pixels,
577                info,
578                row_bytes,
579                origin,
580            })
581        } else {
582            None
583        }
584    }
585
586    // TODO: accessTopRasterHandle()
587
588    /// Returns `true` if [`Canvas`] has direct access to its pixels.
589    ///
590    /// Pixels are readable when `Device` is raster. Pixels are not readable when [`Canvas`] is
591    /// returned from GPU surface, returned by [`crate::Document::begin_page()`], returned by
592    /// [`Handle<SkPictureRecorder>::begin_recording()`], or [`Canvas`] is the base of a utility
593    /// class like `DebugCanvas`.
594    ///
595    /// pixmap is valid only while [`Canvas`] is in scope and unchanged. Any [`Canvas`] or
596    /// [`Surface`] call may invalidate the pixmap values.
597    ///
598    /// Returns [`Pixmap`] if [`Canvas`] has direct access to pixels
599    ///
600    /// example: <https://fiddle.skia.org/c/@Canvas_peekPixels>
601    pub fn peek_pixels(&self) -> Option<Pixmap> {
602        let mut pixmap = Pixmap::default();
603        unsafe { self.native_mut().peekPixels(pixmap.native_mut()) }.then_some(pixmap)
604    }
605
606    /// Copies [`Rect`] of pixels from [`Canvas`] into `dst_pixels`. [`Matrix`] and clip are
607    /// ignored.
608    ///
609    /// Source [`Rect`] corners are `src_point` and `(image_info().width(), image_info().height())`.
610    /// Destination [`Rect`] corners are `(0, 0)` and `(dst_Info.width(), dst_info.height())`.
611    /// Copies each readable pixel intersecting both rectangles, without scaling,
612    /// converting to `dst_info.color_type()` and `dst_info.alpha_type()` if required.
613    ///
614    /// Pixels are readable when `Device` is raster, or backed by a GPU.
615    /// Pixels are not readable when [`Canvas`] is returned by [`crate::Document::begin_page()`],
616    /// returned by [`Handle<SkPictureRecorder>::begin_recording()`], or [`Canvas`] is the base of a
617    /// utility class like `DebugCanvas`.
618    ///
619    /// The destination pixel storage must be allocated by the caller.
620    ///
621    /// Pixel values are converted only if [`crate::ColorType`] and [`crate::AlphaType`]
622    /// do not match. Only pixels within both source and destination rectangles
623    /// are copied. `dst_pixels` contents outside [`Rect`] intersection are unchanged.
624    ///
625    /// Pass negative values for `src_point.x` or `src_point.y` to offset pixels across or down
626    /// destination.
627    ///
628    /// Does not copy, and returns `false` if:
629    /// - Source and destination rectangles do not intersect.
630    /// - [`Canvas`] pixels could not be converted to `dst_info.color_type()` or
631    ///   `dst_info.alpha_type()`.
632    /// - [`Canvas`] pixels are not readable; for instance, [`Canvas`] is document-based.
633    /// - `dst_row_bytes` is too small to contain one row of pixels.
634    ///
635    /// - `dst_info` width, height, [`crate::ColorType`], and [`crate::AlphaType`] of dstPixels
636    /// - `dst_pixels` storage for pixels; `dst_info.height()` times `dst_row_bytes`, or larger
637    /// - `dst_row_bytes` size of one destination row; `dst_info.width()` times pixel size, or
638    ///   larger
639    /// - `src_point` offset into readable pixels; may be negative
640    ///
641    /// Returns `true` if pixels were copied
642    #[must_use]
643    pub fn read_pixels(
644        &self,
645        dst_info: &ImageInfo,
646        dst_pixels: &mut [u8],
647        dst_row_bytes: usize,
648        src_point: impl Into<IPoint>,
649    ) -> bool {
650        let src_point = src_point.into();
651        let required_size = dst_info.compute_byte_size(dst_row_bytes);
652        (dst_pixels.len() >= required_size)
653            && unsafe {
654                self.native_mut().readPixels(
655                    dst_info.native(),
656                    dst_pixels.as_mut_ptr() as _,
657                    dst_row_bytes,
658                    src_point.x,
659                    src_point.y,
660                )
661            }
662    }
663
664    /// Copies [`Rect`] of pixels from [`Canvas`] into pixmap. [`Matrix`] and clip are
665    /// ignored.
666    ///
667    /// Source [`Rect`] corners are `(src.x, src.y)` and `(image_info().width(),
668    /// image_info().height())`.
669    /// Destination [`Rect`] corners are `(0, 0)` and `(pixmap.width(), pixmap.height())`.
670    /// Copies each readable pixel intersecting both rectangles, without scaling,
671    /// converting to `pixmap.color_type()` and `pixmap.alpha_type()` if required.
672    ///
673    /// Pixels are readable when `Device` is raster, or backed by a GPU. Pixels are not readable
674    /// when [`Canvas`] is returned by [`crate::Document::begin_page()`], returned by
675    /// [`Handle<SkPictureRecorder>::begin_recording()`], or [`Canvas`] is the base of a utility
676    /// class like `DebugCanvas`.
677    ///
678    /// Caller must allocate pixel storage in pixmap if needed.
679    ///
680    /// Pixel values are converted only if [`crate::ColorType`] and [`crate::AlphaType`] do not
681    /// match. Only pixels within both source and destination [`Rect`] are copied. pixmap pixels
682    /// contents outside [`Rect`] intersection are unchanged.
683    ///
684    /// Pass negative values for `src.x` or `src.y` to offset pixels across or down pixmap.
685    ///
686    /// Does not copy, and returns `false` if:
687    /// - Source and destination rectangles do not intersect.
688    /// - [`Canvas`] pixels could not be converted to `pixmap.color_type()` or
689    ///   `pixmap.alpha_type()`.
690    /// - [`Canvas`] pixels are not readable; for instance, [`Canvas`] is document-based.
691    /// - [`Pixmap`] pixels could not be allocated.
692    /// - `pixmap.row_bytes()` is too small to contain one row of pixels.
693    ///
694    /// - `pixmap` storage for pixels copied from [`Canvas`]
695    /// - `src` offset into readable pixels ; may be negative
696    ///
697    /// Returns `true` if pixels were copied
698    ///
699    /// example: <https://fiddle.skia.org/c/@Canvas_readPixels_2>
700    #[must_use]
701    pub fn read_pixels_to_pixmap(&self, pixmap: &mut Pixmap, src: impl Into<IPoint>) -> bool {
702        let src = src.into();
703        unsafe { self.native_mut().readPixels1(pixmap.native(), src.x, src.y) }
704    }
705
706    /// Copies [`Rect`] of pixels from [`Canvas`] into bitmap. [`Matrix`] and clip are
707    /// ignored.
708    ///
709    /// Source [`Rect`] corners are `(src.x, src.y)` and `(image_info().width(),
710    /// image_info().height())`.
711    /// Destination [`Rect`] corners are `(0, 0)` and `(bitmap.width(), bitmap.height())`.
712    /// Copies each readable pixel intersecting both rectangles, without scaling,
713    /// converting to `bitmap.color_type()` and `bitmap.alpha_type()` if required.
714    ///
715    /// Pixels are readable when `Device` is raster, or backed by a GPU. Pixels are not readable
716    /// when [`Canvas`] is returned by [`crate::Document::begin_page()`], returned by
717    /// [`Handle<SkPictureRecorder>::begin_recording()`], or [`Canvas`] is the base of a utility
718    /// class like DebugCanvas.
719    ///
720    /// Caller must allocate pixel storage in bitmap if needed.
721    ///
722    /// [`Bitmap`] values are converted only if [`crate::ColorType`] and [`crate::AlphaType`]
723    /// do not match. Only pixels within both source and destination rectangles
724    /// are copied. [`Bitmap`] pixels outside [`Rect`] intersection are unchanged.
725    ///
726    /// Pass negative values for srcX or srcY to offset pixels across or down bitmap.
727    ///
728    /// Does not copy, and returns `false` if:
729    /// - Source and destination rectangles do not intersect.
730    /// - [`Canvas`] pixels could not be converted to `bitmap.color_type()` or
731    ///   `bitmap.alpha_type()`.
732    /// - [`Canvas`] pixels are not readable; for instance, [`Canvas`] is document-based.
733    /// - bitmap pixels could not be allocated.
734    /// - `bitmap.row_bytes()` is too small to contain one row of pixels.
735    ///
736    /// - `bitmap` storage for pixels copied from [`Canvas`]
737    /// - `src` offset into readable pixels; may be negative
738    ///
739    /// Returns `true` if pixels were copied
740    ///
741    /// example: <https://fiddle.skia.org/c/@Canvas_readPixels_3>
742    #[must_use]
743    pub fn read_pixels_to_bitmap(&self, bitmap: &mut Bitmap, src: impl Into<IPoint>) -> bool {
744        let src = src.into();
745        unsafe {
746            self.native_mut()
747                .readPixels2(bitmap.native_mut(), src.x, src.y)
748        }
749    }
750
751    /// Copies [`Rect`] from pixels to [`Canvas`]. [`Matrix`] and clip are ignored.
752    /// Source [`Rect`] corners are `(0, 0)` and `(info.width(), info.height())`.
753    /// Destination [`Rect`] corners are `(offset.x, offset.y)` and
754    /// `(image_info().width(), image_info().height())`.
755    ///
756    /// Copies each readable pixel intersecting both rectangles, without scaling,
757    /// converting to `image_info().color_type()` and `image_info().alpha_type()` if required.
758    ///
759    /// Pixels are writable when `Device` is raster, or backed by a GPU.
760    /// Pixels are not writable when [`Canvas`] is returned by [`crate::Document::begin_page()`],
761    /// returned by [`Handle<SkPictureRecorder>::begin_recording()`], or [`Canvas`] is the base of a
762    /// utility class like `DebugCanvas`.
763    ///
764    /// Pixel values are converted only if [`crate::ColorType`] and [`crate::AlphaType`]
765    /// do not match. Only pixels within both source and destination rectangles
766    /// are copied. [`Canvas`] pixels outside [`Rect`] intersection are unchanged.
767    ///
768    /// Pass negative values for `offset.x` or `offset.y` to offset pixels to the left or
769    /// above [`Canvas`] pixels.
770    ///
771    /// Does not copy, and returns `false` if:
772    /// - Source and destination rectangles do not intersect.
773    /// - pixels could not be converted to [`Canvas`] `image_info().color_type()` or
774    ///   `image_info().alpha_type()`.
775    /// - [`Canvas`] pixels are not writable; for instance, [`Canvas`] is document-based.
776    /// - `row_bytes` is too small to contain one row of pixels.
777    ///
778    /// - `info` width, height, [`crate::ColorType`], and [`crate::AlphaType`] of pixels
779    /// - `pixels` pixels to copy, of size `info.height()` times `row_bytes`, or larger
780    /// - `row_bytes` size of one row of pixels; info.width() times pixel size, or larger
781    /// - `offset` offset into [`Canvas`] writable pixels; may be negative
782    ///
783    /// Returns `true` if pixels were written to [`Canvas`]
784    ///
785    /// example: <https://fiddle.skia.org/c/@Canvas_writePixels>
786    #[must_use]
787    pub fn write_pixels(
788        &self,
789        info: &ImageInfo,
790        pixels: &[u8],
791        row_bytes: usize,
792        offset: impl Into<IPoint>,
793    ) -> bool {
794        let offset = offset.into();
795        let required_size = info.compute_byte_size(row_bytes);
796        (pixels.len() >= required_size)
797            && unsafe {
798                self.native_mut().writePixels(
799                    info.native(),
800                    pixels.as_ptr() as _,
801                    row_bytes,
802                    offset.x,
803                    offset.y,
804                )
805            }
806    }
807
808    /// Copies [`Rect`] from pixels to [`Canvas`]. [`Matrix`] and clip are ignored.
809    /// Source [`Rect`] corners are `(0, 0)` and `(bitmap.width(), bitmap.height())`.
810    ///
811    /// Destination [`Rect`] corners are `(offset.x, offset.y)` and
812    /// `(image_info().width(), image_info().height())`.
813    ///
814    /// Copies each readable pixel intersecting both rectangles, without scaling,
815    /// converting to `image_info().color_type()` and `image_info().alpha_type()` if required.
816    ///
817    /// Pixels are writable when `Device` is raster, or backed by a GPU. Pixels are not writable
818    /// when [`Canvas`] is returned by [`crate::Document::begin_page()`], returned by
819    /// [`Handle<SkPictureRecorder>::begin_recording()`], or [`Canvas`] is the base of a utility
820    /// class like `DebugCanvas`.
821    ///
822    /// Pixel values are converted only if [`crate::ColorType`] and [`crate::AlphaType`]
823    /// do not match. Only pixels within both source and destination rectangles
824    /// are copied. [`Canvas`] pixels outside [`Rect`] intersection are unchanged.
825    ///
826    /// Pass negative values for `offset` to offset pixels to the left or
827    /// above [`Canvas`] pixels.
828    ///
829    /// Does not copy, and returns `false` if:
830    /// - Source and destination rectangles do not intersect.
831    /// - bitmap does not have allocated pixels.
832    /// - bitmap pixels could not be converted to [`Canvas`] `image_info().color_type()` or
833    ///   `image_info().alpha_type()`.
834    /// - [`Canvas`] pixels are not writable; for instance, [`Canvas`] is document based.
835    /// - bitmap pixels are inaccessible; for instance, bitmap wraps a texture.
836    ///
837    /// - `bitmap` contains pixels copied to [`Canvas`]
838    /// - `offset` offset into [`Canvas`] writable pixels; may be negative
839    ///
840    /// Returns `true` if pixels were written to [`Canvas`]
841    ///
842    /// example: <https://fiddle.skia.org/c/@Canvas_writePixels_2>
843    /// example: <https://fiddle.skia.org/c/@State_Stack_a>
844    /// example: <https://fiddle.skia.org/c/@State_Stack_b>
845    #[must_use]
846    pub fn write_pixels_from_bitmap(&self, bitmap: &Bitmap, offset: impl Into<IPoint>) -> bool {
847        let offset = offset.into();
848        unsafe {
849            self.native_mut()
850                .writePixels1(bitmap.native(), offset.x, offset.y)
851        }
852    }
853
854    /// Saves [`Matrix`] and clip.
855    /// Calling [`Self::restore()`] discards changes to [`Matrix`] and clip,
856    /// restoring the [`Matrix`] and clip to their state when [`Self::save()`] was called.
857    ///
858    /// [`Matrix`] may be changed by [`Self::translate()`], [`Self::scale()`], [`Self::rotate()`],
859    /// [`Self::skew()`], [`Self::concat()`], [`Self::set_matrix()`], and [`Self::reset_matrix()`].
860    /// Clip may be changed by [`Self::clip_rect()`], [`Self::clip_rrect()`], [`Self::clip_path()`],
861    /// [`Self::clip_region()`].
862    ///
863    /// Saved [`Canvas`] state is put on a stack; multiple calls to [`Self::save()`] should be
864    /// balance by an equal number of calls to [`Self::restore()`].
865    ///
866    /// Call [`Self::restore_to_count()`] with result to restore this and subsequent saves.
867    ///
868    /// Returns depth of saved stack
869    ///
870    /// example: <https://fiddle.skia.org/c/@Canvas_save>
871    pub fn save(&self) -> usize {
872        unsafe { self.native_mut().save().try_into().unwrap() }
873    }
874
875    // The save_layer(bounds, paint) variants have been replaced by SaveLayerRec.
876
877    /// Saves [`Matrix`] and clip, and allocates [`Surface`] for subsequent drawing.
878    ///
879    /// Calling [`Self::restore()`] discards changes to [`Matrix`] and clip, and blends layer with
880    /// alpha opacity onto prior layer.
881    ///
882    /// [`Matrix`] may be changed by [`Self::translate()`], [`Self::scale()`], [`Self::rotate()`],
883    /// [`Self::skew()`], [`Self::concat()`], [`Self::set_matrix()`], and [`Self::reset_matrix()`].
884    /// Clip may be changed by [`Self::clip_rect()`], [`Self::clip_rrect()`], [`Self::clip_path()`],
885    /// [`Self::clip_region()`].
886    ///
887    /// [`Rect`] bounds suggests but does not define layer size. To clip drawing to a specific
888    /// rectangle, use [`Self::clip_rect()`].
889    ///
890    /// alpha of zero is fully transparent, 1.0 is fully opaque.
891    ///
892    /// Call [`Self::restore_to_count()`] with result to restore this and subsequent saves.
893    ///
894    /// - `bounds` hint to limit the size of layer; may be `None`
895    /// - `alpha` opacity of layer
896    ///
897    /// Returns depth of saved stack
898    ///
899    /// example: <https://fiddle.skia.org/c/@Canvas_saveLayerAlpha>
900    pub fn save_layer_alpha_f(&self, bounds: impl Into<Option<Rect>>, alpha: f32) -> usize {
901        unsafe {
902            self.native_mut()
903                .saveLayerAlphaf(bounds.into().native().as_ptr_or_null(), alpha)
904        }
905        .try_into()
906        .unwrap()
907    }
908
909    /// Helper that accepts an int between 0 and 255, and divides it by 255.0
910    pub fn save_layer_alpha(&self, bounds: impl Into<Option<Rect>>, alpha: U8CPU) -> usize {
911        self.save_layer_alpha_f(bounds, alpha as f32 * (1.0 / 255.0))
912    }
913
914    /// Saves [`Matrix`] and clip, and allocates [`Surface`] for subsequent drawing.
915    ///
916    /// Calling [`Self::restore()`] discards changes to [`Matrix`] and clip,
917    /// and blends [`Surface`] with alpha opacity onto the prior layer.
918    ///
919    /// [`Matrix`] may be changed by [`Self::translate()`], [`Self::scale()`], [`Self::rotate()`],
920    /// [`Self::skew()`], [`Self::concat()`], [`Self::set_matrix()`], and [`Self::reset_matrix()`].
921    /// Clip may be changed by [`Self::clip_rect()`], [`Self::clip_rrect()`], [`Self::clip_path()`],
922    /// [`Self::clip_region()`].
923    ///
924    /// [`SaveLayerRec`] contains the state used to create the layer.
925    ///
926    /// Call [`Self::restore_to_count()`] with result to restore this and subsequent saves.
927    ///
928    /// - `layer_rec` layer state
929    ///
930    /// Returns depth of save state stack before this call was made.
931    ///
932    /// example: <https://fiddle.skia.org/c/@Canvas_saveLayer_3>
933    pub fn save_layer(&self, layer_rec: &SaveLayerRec) -> usize {
934        unsafe { self.native_mut().saveLayer1(layer_rec.native()) }
935            .try_into()
936            .unwrap()
937    }
938
939    /// Removes changes to [`Matrix`] and clip since [`Canvas`] state was
940    /// last saved. The state is removed from the stack.
941    ///
942    /// Does nothing if the stack is empty.
943    ///
944    /// example: <https://fiddle.skia.org/c/@AutoCanvasRestore_restore>
945    ///
946    /// example: <https://fiddle.skia.org/c/@Canvas_restore>
947    pub fn restore(&self) -> &Self {
948        unsafe { self.native_mut().restore() };
949        self
950    }
951
952    /// Returns the number of saved states, each containing: [`Matrix`] and clip.
953    /// Equals the number of [`Self::save()`] calls less the number of [`Self::restore()`] calls
954    /// plus one.
955    /// The save count of a new canvas is one.
956    ///
957    /// Returns depth of save state stack
958    ///
959    /// example: <https://fiddle.skia.org/c/@Canvas_getSaveCount>
960    pub fn save_count(&self) -> usize {
961        unsafe { self.native().getSaveCount() }.try_into().unwrap()
962    }
963
964    /// Restores state to [`Matrix`] and clip values when [`Self::save()`], [`Self::save_layer()`],
965    /// or [`Self::save_layer_alpha()`] returned `save_count`.
966    ///
967    /// Does nothing if `save_count` is greater than state stack count.
968    /// Restores state to initial values if `save_count` is less than or equal to one.
969    ///
970    /// - `saveCount` depth of state stack to restore
971    ///
972    /// example: <https://fiddle.skia.org/c/@Canvas_restoreToCount>
973    pub fn restore_to_count(&self, save_count: usize) -> &Self {
974        unsafe {
975            self.native_mut()
976                .restoreToCount(save_count.try_into().unwrap())
977        }
978        self
979    }
980
981    /// Translates [`Matrix`] by `d`.
982    ///
983    /// Mathematically, replaces [`Matrix`] with a translation matrix premultiplied with [`Matrix`].
984    ///
985    /// This has the effect of moving the drawing by `(d.x, d.y)` before transforming the result
986    /// with [`Matrix`].
987    ///
988    /// - `d` distance to translate
989    ///
990    /// example: <https://fiddle.skia.org/c/@Canvas_translate>
991    pub fn translate(&self, d: impl Into<Vector>) -> &Self {
992        let d = d.into();
993        unsafe { self.native_mut().translate(d.x, d.y) }
994        self
995    }
996
997    /// Scales [`Matrix`] by `sx` on the x-axis and `sy` on the y-axis.
998    ///
999    /// Mathematically, replaces [`Matrix`] with a scale matrix premultiplied with [`Matrix`].
1000    ///
1001    /// This has the effect of scaling the drawing by `(sx, sy)` before transforming the result with
1002    /// [`Matrix`].
1003    ///
1004    /// - `sx` amount to scale on x-axis
1005    /// - `sy` amount to scale on y-axis
1006    ///
1007    /// example: <https://fiddle.skia.org/c/@Canvas_scale>
1008    pub fn scale(&self, (sx, sy): (scalar, scalar)) -> &Self {
1009        unsafe { self.native_mut().scale(sx, sy) }
1010        self
1011    }
1012
1013    /// Rotates [`Matrix`] by degrees about a point at `(p.x, p.y)`. Positive degrees rotates
1014    /// clockwise.
1015    ///
1016    /// Mathematically, constructs a rotation matrix; premultiplies the rotation matrix by a
1017    /// translation matrix; then replaces [`Matrix`] with the resulting matrix premultiplied with
1018    /// [`Matrix`].
1019    ///
1020    /// This has the effect of rotating the drawing about a given point before transforming the
1021    /// result with [`Matrix`].
1022    ///
1023    /// - `degrees` amount to rotate, in degrees
1024    /// - `p` the point to rotate about
1025    ///
1026    /// example: <https://fiddle.skia.org/c/@Canvas_rotate_2>
1027    pub fn rotate(&self, degrees: scalar, p: Option<Point>) -> &Self {
1028        unsafe {
1029            match p {
1030                Some(point) => self.native_mut().rotate1(degrees, point.x, point.y),
1031                None => self.native_mut().rotate(degrees),
1032            }
1033        }
1034        self
1035    }
1036
1037    /// Skews [`Matrix`] by `sx` on the x-axis and `sy` on the y-axis. A positive value of `sx`
1038    /// skews the drawing right as y-axis values increase; a positive value of `sy` skews the
1039    /// drawing down as x-axis values increase.
1040    ///
1041    /// Mathematically, replaces [`Matrix`] with a skew matrix premultiplied with [`Matrix`].
1042    ///
1043    /// This has the effect of skewing the drawing by `(sx, sy)` before transforming the result with
1044    /// [`Matrix`].
1045    ///
1046    /// - `sx` amount to skew on x-axis
1047    /// - `sy` amount to skew on y-axis
1048    ///
1049    /// example: <https://fiddle.skia.org/c/@Canvas_skew>
1050    pub fn skew(&self, (sx, sy): (scalar, scalar)) -> &Self {
1051        unsafe { self.native_mut().skew(sx, sy) }
1052        self
1053    }
1054
1055    /// Replaces [`Matrix`] with matrix premultiplied with existing [`Matrix`].
1056    ///
1057    /// This has the effect of transforming the drawn geometry by matrix, before transforming the
1058    /// result with existing [`Matrix`].
1059    ///
1060    /// - `matrix` matrix to premultiply with existing [`Matrix`]
1061    ///
1062    /// example: <https://fiddle.skia.org/c/@Canvas_concat>
1063    pub fn concat(&self, matrix: &Matrix) -> &Self {
1064        unsafe { self.native_mut().concat(matrix.native()) }
1065        self
1066    }
1067
1068    pub fn concat_44(&self, m: &M44) -> &Self {
1069        unsafe { self.native_mut().concat1(m.native()) }
1070        self
1071    }
1072
1073    /// Replaces [`Matrix`] with `matrix`.
1074    /// Unlike [`Self::concat()`], any prior matrix state is overwritten.
1075    ///
1076    /// - `matrix` matrix to copy, replacing existing [`Matrix`]
1077    ///
1078    /// example: <https://fiddle.skia.org/c/@Canvas_setMatrix>
1079    pub fn set_matrix(&self, matrix: &M44) -> &Self {
1080        unsafe { self.native_mut().setMatrix(matrix.native()) }
1081        self
1082    }
1083
1084    /// Sets [`Matrix`] to the identity matrix.
1085    /// Any prior matrix state is overwritten.
1086    ///
1087    /// example: <https://fiddle.skia.org/c/@Canvas_resetMatrix>
1088    pub fn reset_matrix(&self) -> &Self {
1089        unsafe { self.native_mut().resetMatrix() }
1090        self
1091    }
1092
1093    /// Replaces clip with the intersection or difference of clip and `rect`,
1094    /// with an aliased or anti-aliased clip edge. `rect` is transformed by [`Matrix`]
1095    /// before it is combined with clip.
1096    ///
1097    /// - `rect` [`Rect`] to combine with clip
1098    /// - `op` [`ClipOp`] to apply to clip
1099    /// - `do_anti_alias` `true` if clip is to be anti-aliased
1100    ///
1101    /// example: <https://fiddle.skia.org/c/@Canvas_clipRect>
1102    pub fn clip_rect(
1103        &self,
1104        rect: impl AsRef<Rect>,
1105        op: impl Into<Option<ClipOp>>,
1106        do_anti_alias: impl Into<Option<bool>>,
1107    ) -> &Self {
1108        unsafe {
1109            self.native_mut().clipRect(
1110                rect.as_ref().native(),
1111                op.into().unwrap_or_default(),
1112                do_anti_alias.into().unwrap_or_default(),
1113            )
1114        }
1115        self
1116    }
1117
1118    pub fn clip_irect(&self, irect: impl AsRef<IRect>, op: impl Into<Option<ClipOp>>) -> &Self {
1119        let r = Rect::from(*irect.as_ref());
1120        self.clip_rect(r, op, false)
1121    }
1122
1123    /// Replaces clip with the intersection or difference of clip and `rrect`,
1124    /// with an aliased or anti-aliased clip edge.
1125    /// `rrect` is transformed by [`Matrix`]
1126    /// before it is combined with clip.
1127    ///
1128    /// - `rrect` [`RRect`] to combine with clip
1129    /// - `op` [`ClipOp`] to apply to clip
1130    /// - `do_anti_alias` `true` if clip is to be anti-aliased
1131    ///
1132    /// example: <https://fiddle.skia.org/c/@Canvas_clipRRect>
1133    pub fn clip_rrect(
1134        &self,
1135        rrect: impl AsRef<RRect>,
1136        op: impl Into<Option<ClipOp>>,
1137        do_anti_alias: impl Into<Option<bool>>,
1138    ) -> &Self {
1139        unsafe {
1140            self.native_mut().clipRRect(
1141                rrect.as_ref().native(),
1142                op.into().unwrap_or_default(),
1143                do_anti_alias.into().unwrap_or_default(),
1144            )
1145        }
1146        self
1147    }
1148
1149    /// Replaces clip with the intersection or difference of clip and `path`,
1150    /// with an aliased or anti-aliased clip edge. [`crate::PathFillType`] determines if `path`
1151    /// describes the area inside or outside its contours; and if path contour overlaps
1152    /// itself or another path contour, whether the overlaps form part of the area.
1153    /// `path` is transformed by [`Matrix`] before it is combined with clip.
1154    ///
1155    /// - `path` [`Path`] to combine with clip
1156    /// - `op` [`ClipOp`] to apply to clip
1157    /// - `do_anti_alias` `true` if clip is to be anti-aliased
1158    ///
1159    /// example: <https://fiddle.skia.org/c/@Canvas_clipPath>
1160    pub fn clip_path(
1161        &self,
1162        path: &Path,
1163        op: impl Into<Option<ClipOp>>,
1164        do_anti_alias: impl Into<Option<bool>>,
1165    ) -> &Self {
1166        unsafe {
1167            self.native_mut().clipPath(
1168                path.native(),
1169                op.into().unwrap_or_default(),
1170                do_anti_alias.into().unwrap_or_default(),
1171            )
1172        }
1173        self
1174    }
1175
1176    pub fn clip_shader(&self, shader: impl Into<Shader>, op: impl Into<Option<ClipOp>>) -> &Self {
1177        unsafe {
1178            sb::C_SkCanvas_clipShader(
1179                self.native_mut(),
1180                shader.into().into_ptr(),
1181                op.into().unwrap_or(ClipOp::Intersect),
1182            )
1183        }
1184        self
1185    }
1186
1187    /// Replaces clip with the intersection or difference of clip and [`Region`] `device_rgn`.
1188    /// Resulting clip is aliased; pixels are fully contained by the clip.
1189    /// `device_rgn` is unaffected by [`Matrix`].
1190    ///
1191    /// - `device_rgn` [`Region`] to combine with clip
1192    /// - `op` [`ClipOp`] to apply to clip
1193    ///
1194    /// example: <https://fiddle.skia.org/c/@Canvas_clipRegion>
1195    pub fn clip_region(&self, device_rgn: &Region, op: impl Into<Option<ClipOp>>) -> &Self {
1196        unsafe {
1197            self.native_mut()
1198                .clipRegion(device_rgn.native(), op.into().unwrap_or_default())
1199        }
1200        self
1201    }
1202
1203    // quickReject() functions are implemented as a trait.
1204
1205    /// Returns bounds of clip, transformed by inverse of [`Matrix`]. If clip is empty,
1206    /// return [`Rect::new_empty()`], where all [`Rect`] sides equal zero.
1207    ///
1208    /// [`Rect`] returned is outset by one to account for partial pixel coverage if clip
1209    /// is anti-aliased.
1210    ///
1211    /// Returns bounds of clip in local coordinates
1212    ///
1213    /// example: <https://fiddle.skia.org/c/@Canvas_getLocalClipBounds>
1214    pub fn local_clip_bounds(&self) -> Option<Rect> {
1215        let r = Rect::construct(|r| unsafe { sb::C_SkCanvas_getLocalClipBounds(self.native(), r) });
1216        (!r.is_empty()).then_some(r)
1217    }
1218
1219    /// Returns [`IRect`] bounds of clip, unaffected by [`Matrix`]. If clip is empty,
1220    /// return [`Rect::new_empty()`], where all [`Rect`] sides equal zero.
1221    ///
1222    /// Unlike [`Self::local_clip_bounds()`], returned [`IRect`] is not outset.
1223    ///
1224    /// Returns bounds of clip in `Device` coordinates
1225    ///
1226    /// example: <https://fiddle.skia.org/c/@Canvas_getDeviceClipBounds>
1227    pub fn device_clip_bounds(&self) -> Option<IRect> {
1228        let r =
1229            IRect::construct(|r| unsafe { sb::C_SkCanvas_getDeviceClipBounds(self.native(), r) });
1230        (!r.is_empty()).then_some(r)
1231    }
1232
1233    /// Fills clip with color `color`.
1234    /// `mode` determines how ARGB is combined with destination.
1235    ///
1236    /// - `color` [`Color4f`] representing unpremultiplied color.
1237    /// - `mode` [`BlendMode`] used to combine source color and destination
1238    pub fn draw_color(
1239        &self,
1240        color: impl Into<Color4f>,
1241        mode: impl Into<Option<BlendMode>>,
1242    ) -> &Self {
1243        unsafe {
1244            self.native_mut()
1245                .drawColor(&color.into().into_native(), mode.into().unwrap_or_default())
1246        }
1247        self
1248    }
1249
1250    /// Fills clip with color `color` using [`BlendMode::Src`].
1251    /// This has the effect of replacing all pixels contained by clip with `color`.
1252    ///
1253    /// - `color` [`Color4f`] representing unpremultiplied color.
1254    pub fn clear(&self, color: impl Into<Color4f>) -> &Self {
1255        self.draw_color(color, BlendMode::Src)
1256    }
1257
1258    /// Makes [`Canvas`] contents undefined. Subsequent calls that read [`Canvas`] pixels,
1259    /// such as drawing with [`BlendMode`], return undefined results. `discard()` does
1260    /// not change clip or [`Matrix`].
1261    ///
1262    /// `discard()` may do nothing, depending on the implementation of [`Surface`] or `Device`
1263    /// that created [`Canvas`].
1264    ///
1265    /// `discard()` allows optimized performance on subsequent draws by removing
1266    /// cached data associated with [`Surface`] or `Device`.
1267    /// It is not necessary to call `discard()` once done with [`Canvas`];
1268    /// any cached data is deleted when owning [`Surface`] or `Device` is deleted.
1269    pub fn discard(&self) -> &Self {
1270        unsafe { sb::C_SkCanvas_discard(self.native_mut()) }
1271        self
1272    }
1273
1274    /// Fills clip with [`Paint`] `paint`. [`Paint`] components, [`Shader`],
1275    /// [`crate::ColorFilter`], [`ImageFilter`], and [`BlendMode`] affect drawing;
1276    /// [`crate::MaskFilter`] and [`crate::PathEffect`] in `paint` are ignored.
1277    ///
1278    /// - `paint` graphics state used to fill [`Canvas`]
1279    ///
1280    /// example: <https://fiddle.skia.org/c/@Canvas_drawPaint>
1281    pub fn draw_paint(&self, paint: &Paint) -> &Self {
1282        unsafe { self.native_mut().drawPaint(paint.native()) }
1283        self
1284    }
1285
1286    /// Draws `pts` using clip, [`Matrix`] and [`Paint`] `pain`.
1287    /// if the number of points is less than one, has no effect.
1288    /// `mode` may be one of: [`PointMode::Points`], [`PointMode::Lines`], or [`PointMode::Polygon`]
1289    ///
1290    /// If `mode` is [`PointMode::Points`], the shape of point drawn depends on `paint`
1291    /// [`crate::paint::Cap`]. If `paint` is set to [`crate::paint::Cap::Round`], each point draws a
1292    /// circle of diameter [`Paint`] stroke width. If `paint` is set to [`crate::paint::Cap::Square`]
1293    /// or [`crate::paint::Cap::Butt`], each point draws a square of width and height
1294    /// [`Paint`] stroke width.
1295    ///
1296    /// If `mode` is [`PointMode::Lines`], each pair of points draws a line segment.
1297    /// One line is drawn for every two points; each point is used once. If count is odd,
1298    /// the final point is ignored.
1299    ///
1300    /// If mode is [`PointMode::Polygon`], each adjacent pair of points draws a line segment.
1301    /// count minus one lines are drawn; the first and last point are used once.
1302    ///
1303    /// Each line segment respects `paint` [`crate::paint::Cap`] and [`Paint`] stroke width.
1304    /// [`crate::paint::Style`] is ignored, as if were set to [`crate::paint::Style::Stroke`].
1305    ///
1306    /// Always draws each element one at a time; is not affected by
1307    /// [`crate::paint::Join`], and unlike [`Self::draw_path()`], does not create a mask from all points
1308    /// and lines before drawing.
1309    ///
1310    /// - `mode` whether pts draws points or lines
1311    /// - `pts` array of points to draw
1312    /// - `paint` stroke, blend, color, and so on, used to draw
1313    ///
1314    /// example: <https://fiddle.skia.org/c/@Canvas_drawPoints>
1315    pub fn draw_points(&self, mode: PointMode, pts: &[Point], paint: &Paint) -> &Self {
1316        unsafe {
1317            sb::C_SkCanvas_drawPoints(
1318                self.native_mut(),
1319                mode,
1320                pts.native().as_ptr(),
1321                pts.len(),
1322                paint.native(),
1323            )
1324        }
1325        self
1326    }
1327
1328    /// Draws point `p` using clip, [`Matrix`] and [`Paint`] paint.
1329    ///
1330    /// The shape of point drawn depends on `paint` [`crate::paint::Cap`].
1331    /// If `paint` is set to [`crate::paint::Cap::Round`], draw a circle of diameter [`Paint`]
1332    /// stroke width. If `paint` is set to [`crate::paint::Cap::Square`] or
1333    /// [`crate::paint::Cap::Butt`], draw a square of width and height [`Paint`] stroke width.
1334    /// [`crate::paint::Style`] is ignored, as if were set to [`crate::paint::Style::Stroke`].
1335    ///
1336    /// - `p` top-left edge of circle or square
1337    /// - `paint` stroke, blend, color, and so on, used to draw
1338    pub fn draw_point(&self, p: impl Into<Point>, paint: &Paint) -> &Self {
1339        let p = p.into();
1340        unsafe { self.native_mut().drawPoint(p.x, p.y, paint.native()) }
1341        self
1342    }
1343
1344    /// Draws line segment from `p1` to `p2` using clip, [`Matrix`], and [`Paint`] paint.
1345    /// In paint: [`Paint`] stroke width describes the line thickness;
1346    /// [`crate::paint::Cap`] draws the end rounded or square;
1347    /// [`crate::paint::Style`] is ignored, as if were set to [`crate::paint::Style::Stroke`].
1348    ///
1349    /// - `p1` start of line segment
1350    /// - `p2` end of line segment
1351    /// - `paint` stroke, blend, color, and so on, used to draw
1352    pub fn draw_line(&self, p1: impl Into<Point>, p2: impl Into<Point>, paint: &Paint) -> &Self {
1353        let (p1, p2) = (p1.into(), p2.into());
1354        unsafe {
1355            self.native_mut()
1356                .drawLine(p1.x, p1.y, p2.x, p2.y, paint.native())
1357        }
1358        self
1359    }
1360
1361    /// Draws [`Rect`] rect using clip, [`Matrix`], and [`Paint`] `paint`.
1362    /// In paint: [`crate::paint::Style`] determines if rectangle is stroked or filled;
1363    /// if stroked, [`Paint`] stroke width describes the line thickness, and
1364    /// [`crate::paint::Join`] draws the corners rounded or square.
1365    ///
1366    /// - `rect` rectangle to draw
1367    /// - `paint` stroke or fill, blend, color, and so on, used to draw
1368    ///
1369    /// example: <https://fiddle.skia.org/c/@Canvas_drawRect>
1370    pub fn draw_rect(&self, rect: impl AsRef<Rect>, paint: &Paint) -> &Self {
1371        unsafe {
1372            self.native_mut()
1373                .drawRect(rect.as_ref().native(), paint.native())
1374        }
1375        self
1376    }
1377
1378    /// Draws [`IRect`] rect using clip, [`Matrix`], and [`Paint`] `paint`.
1379    /// In `paint`: [`crate::paint::Style`] determines if rectangle is stroked or filled;
1380    /// if stroked, [`Paint`] stroke width describes the line thickness, and
1381    /// [`crate::paint::Join`] draws the corners rounded or square.
1382    ///
1383    /// - `rect` rectangle to draw
1384    /// - `paint` stroke or fill, blend, color, and so on, used to draw
1385    pub fn draw_irect(&self, rect: impl AsRef<IRect>, paint: &Paint) -> &Self {
1386        self.draw_rect(Rect::from(*rect.as_ref()), paint)
1387    }
1388
1389    /// Draws [`Region`] region using clip, [`Matrix`], and [`Paint`] `paint`.
1390    /// In `paint`: [`crate::paint::Style`] determines if rectangle is stroked or filled;
1391    /// if stroked, [`Paint`] stroke width describes the line thickness, and
1392    /// [`crate::paint::Join`] draws the corners rounded or square.
1393    ///
1394    /// - `region` region to draw
1395    /// - `paint` [`Paint`] stroke or fill, blend, color, and so on, used to draw
1396    ///
1397    /// example: <https://fiddle.skia.org/c/@Canvas_drawRegion>
1398    pub fn draw_region(&self, region: &Region, paint: &Paint) -> &Self {
1399        unsafe {
1400            self.native_mut()
1401                .drawRegion(region.native(), paint.native())
1402        }
1403        self
1404    }
1405
1406    /// Draws oval oval using clip, [`Matrix`], and [`Paint`].
1407    /// In `paint`: [`crate::paint::Style`] determines if oval is stroked or filled;
1408    /// if stroked, [`Paint`] stroke width describes the line thickness.
1409    ///
1410    /// - `oval` [`Rect`] bounds of oval
1411    /// - `paint` [`Paint`] stroke or fill, blend, color, and so on, used to draw
1412    ///
1413    /// example: <https://fiddle.skia.org/c/@Canvas_drawOval>
1414    pub fn draw_oval(&self, oval: impl AsRef<Rect>, paint: &Paint) -> &Self {
1415        unsafe {
1416            self.native_mut()
1417                .drawOval(oval.as_ref().native(), paint.native())
1418        }
1419        self
1420    }
1421
1422    /// Draws [`RRect`] rrect using clip, [`Matrix`], and [`Paint`] `paint`.
1423    /// In `paint`: [`crate::paint::Style`] determines if rrect is stroked or filled;
1424    /// if stroked, [`Paint`] stroke width describes the line thickness.
1425    ///
1426    /// `rrect` may represent a rectangle, circle, oval, uniformly rounded rectangle, or
1427    /// may have any combination of positive non-square radii for the four corners.
1428    ///
1429    /// - `rrect` [`RRect`] with up to eight corner radii to draw
1430    /// - `paint` [`Paint`] stroke or fill, blend, color, and so on, used to draw
1431    ///
1432    /// example: <https://fiddle.skia.org/c/@Canvas_drawRRect>
1433    pub fn draw_rrect(&self, rrect: impl AsRef<RRect>, paint: &Paint) -> &Self {
1434        unsafe {
1435            self.native_mut()
1436                .drawRRect(rrect.as_ref().native(), paint.native())
1437        }
1438        self
1439    }
1440
1441    /// Draws [`RRect`] outer and inner
1442    /// using clip, [`Matrix`], and [`Paint`] `paint`.
1443    /// outer must contain inner or the drawing is undefined.
1444    /// In paint: [`crate::paint::Style`] determines if [`RRect`] is stroked or filled;
1445    /// if stroked, [`Paint`] stroke width describes the line thickness.
1446    /// If stroked and [`RRect`] corner has zero length radii, [`crate::paint::Join`] can
1447    /// draw corners rounded or square.
1448    ///
1449    /// GPU-backed platforms optimize drawing when both outer and inner are
1450    /// concave and outer contains inner. These platforms may not be able to draw
1451    /// [`Path`] built with identical data as fast.
1452    ///
1453    /// - `outer` [`RRect`] outer bounds to draw
1454    /// - `inner` [`RRect`] inner bounds to draw
1455    /// - `paint` [`Paint`] stroke or fill, blend, color, and so on, used to draw
1456    ///
1457    /// example: <https://fiddle.skia.org/c/@Canvas_drawDRRect_a>
1458    /// example: <https://fiddle.skia.org/c/@Canvas_drawDRRect_b>
1459    pub fn draw_drrect(
1460        &self,
1461        outer: impl AsRef<RRect>,
1462        inner: impl AsRef<RRect>,
1463        paint: &Paint,
1464    ) -> &Self {
1465        unsafe {
1466            self.native_mut().drawDRRect(
1467                outer.as_ref().native(),
1468                inner.as_ref().native(),
1469                paint.native(),
1470            )
1471        }
1472        self
1473    }
1474
1475    /// Draws circle at center with radius using clip, [`Matrix`], and [`Paint`] `paint`.
1476    /// If radius is zero or less, nothing is drawn.
1477    /// In `paint`: [`crate::paint::Style`] determines if circle is stroked or filled;
1478    /// if stroked, [`Paint`] stroke width describes the line thickness.
1479    ///
1480    /// - `center` circle center
1481    /// - `radius` half the diameter of circle
1482    /// - `paint` [`Paint`] stroke or fill, blend, color, and so on, used to draw
1483    pub fn draw_circle(&self, center: impl Into<Point>, radius: scalar, paint: &Paint) -> &Self {
1484        let center = center.into();
1485        unsafe {
1486            self.native_mut()
1487                .drawCircle(center.x, center.y, radius, paint.native())
1488        }
1489        self
1490    }
1491
1492    /// Draws arc using clip, [`Matrix`], and [`Paint`] paint.
1493    ///
1494    /// Arc is part of oval bounded by oval, sweeping from `start_angle` to `start_angle` plus
1495    /// `sweep_angle`. `start_angle` and `sweep_angle` are in degrees.
1496    ///
1497    /// `start_angle` of zero places start point at the right middle edge of oval.
1498    /// A positive `sweep_angle` places arc end point clockwise from start point;
1499    /// a negative `sweep_angle` places arc end point counterclockwise from start point.
1500    /// `sweep_angle` may exceed 360 degrees, a full circle.
1501    /// If `use_center` is `true`, draw a wedge that includes lines from oval
1502    /// center to arc end points. If `use_center` is `false`, draw arc between end points.
1503    ///
1504    /// If [`Rect`] oval is empty or `sweep_angle` is zero, nothing is drawn.
1505    ///
1506    /// - `oval` [`Rect`] bounds of oval containing arc to draw
1507    /// - `start_angle` angle in degrees where arc begins
1508    /// - `sweep_angle` sweep angle in degrees; positive is clockwise
1509    /// - `use_center` if `true`, include the center of the oval
1510    /// - `paint` [`Paint`] stroke or fill, blend, color, and so on, used to draw
1511    pub fn draw_arc(
1512        &self,
1513        oval: impl AsRef<Rect>,
1514        start_angle: scalar,
1515        sweep_angle: scalar,
1516        use_center: bool,
1517        paint: &Paint,
1518    ) -> &Self {
1519        unsafe {
1520            self.native_mut().drawArc(
1521                oval.as_ref().native(),
1522                start_angle,
1523                sweep_angle,
1524                use_center,
1525                paint.native(),
1526            )
1527        }
1528        self
1529    }
1530
1531    /// Draws arc using clip, [`Matrix`], and [`Paint`] paint.
1532    ///
1533    /// Arc is part of oval bounded by oval, sweeping from `start_angle` to `start_angle` plus
1534    /// `sweep_angle`. `start_angle` and `sweep_angle` are in degrees.
1535    ///
1536    /// `start_angle` of zero places start point at the right middle edge of oval.
1537    /// A positive `sweep_angle` places arc end point clockwise from start point;
1538    /// a negative `sweep_angle` places arc end point counterclockwise from start point.
1539    /// `sweep_angle` may exceed 360 degrees, a full circle.
1540    /// If `use_center` is `true`, draw a wedge that includes lines from oval
1541    /// center to arc end points. If `use_center` is `false`, draw arc between end points.
1542    ///
1543    /// If [`Rect`] oval is empty or `sweep_angle` is zero, nothing is drawn.
1544    ///
1545    /// - `arc` [`Arc`] SkArc specifying oval, startAngle, sweepAngle, and arc-vs-wedge
1546    /// - `paint` [`Paint`] stroke or fill, blend, color, and so on, used to draw
1547    pub fn draw_arc_2(&self, arc: &Arc, paint: &Paint) -> &Self {
1548        self.draw_arc(
1549            arc.oval,
1550            arc.start_angle,
1551            arc.sweep_angle,
1552            arc.is_wedge(),
1553            paint,
1554        );
1555        self
1556    }
1557
1558    /// Draws [`RRect`] bounded by [`Rect`] rect, with corner radii `(rx, ry)` using clip,
1559    /// [`Matrix`], and [`Paint`] `paint`.
1560    ///
1561    /// In `paint`: [`crate::paint::Style`] determines if [`RRect`] is stroked or filled;
1562    /// if stroked, [`Paint`] stroke width describes the line thickness.
1563    /// If `rx` or `ry` are less than zero, they are treated as if they are zero.
1564    /// If `rx` plus `ry` exceeds rect width or rect height, radii are scaled down to fit.
1565    /// If `rx` and `ry` are zero, [`RRect`] is drawn as [`Rect`] and if stroked is affected by
1566    /// [`crate::paint::Join`].
1567    ///
1568    /// - `rect` [`Rect`] bounds of [`RRect`] to draw
1569    /// - `rx` axis length on x-axis of oval describing rounded corners
1570    /// - `ry` axis length on y-axis of oval describing rounded corners
1571    /// - `paint` stroke, blend, color, and so on, used to draw
1572    ///
1573    /// example: <https://fiddle.skia.org/c/@Canvas_drawRoundRect>
1574    pub fn draw_round_rect(
1575        &self,
1576        rect: impl AsRef<Rect>,
1577        rx: scalar,
1578        ry: scalar,
1579        paint: &Paint,
1580    ) -> &Self {
1581        unsafe {
1582            self.native_mut()
1583                .drawRoundRect(rect.as_ref().native(), rx, ry, paint.native())
1584        }
1585        self
1586    }
1587
1588    /// Draws [`Path`] path using clip, [`Matrix`], and [`Paint`] `paint`.
1589    /// [`Path`] contains an array of path contour, each of which may be open or closed.
1590    ///
1591    /// In `paint`: [`crate::paint::Style`] determines if [`RRect`] is stroked or filled:
1592    /// if filled, [`crate::PathFillType`] determines whether path contour describes inside or
1593    /// outside of fill; if stroked, [`Paint`] stroke width describes the line thickness,
1594    /// [`crate::paint::Cap`] describes line ends, and [`crate::paint::Join`] describes how
1595    /// corners are drawn.
1596    ///
1597    /// - `path` [`Path`] to draw
1598    /// - `paint` stroke, blend, color, and so on, used to draw
1599    ///
1600    /// example: <https://fiddle.skia.org/c/@Canvas_drawPath>
1601    pub fn draw_path(&self, path: &Path, paint: &Paint) -> &Self {
1602        unsafe { self.native_mut().drawPath(path.native(), paint.native()) }
1603        self
1604    }
1605
1606    pub fn draw_image(
1607        &self,
1608        image: impl AsRef<Image>,
1609        left_top: impl Into<Point>,
1610        paint: Option<&Paint>,
1611    ) -> &Self {
1612        let left_top = left_top.into();
1613        self.draw_image_with_sampling_options(image, left_top, SamplingOptions::default(), paint)
1614    }
1615
1616    pub fn draw_image_rect(
1617        &self,
1618        image: impl AsRef<Image>,
1619        src: Option<(&Rect, SrcRectConstraint)>,
1620        dst: impl AsRef<Rect>,
1621        paint: &Paint,
1622    ) -> &Self {
1623        self.draw_image_rect_with_sampling_options(
1624            image,
1625            src,
1626            dst,
1627            SamplingOptions::default(),
1628            paint,
1629        )
1630    }
1631
1632    pub fn draw_image_with_sampling_options(
1633        &self,
1634        image: impl AsRef<Image>,
1635        left_top: impl Into<Point>,
1636        sampling: impl Into<SamplingOptions>,
1637        paint: Option<&Paint>,
1638    ) -> &Self {
1639        let left_top = left_top.into();
1640        unsafe {
1641            self.native_mut().drawImage(
1642                image.as_ref().native(),
1643                left_top.x,
1644                left_top.y,
1645                sampling.into().native(),
1646                paint.native_ptr_or_null(),
1647            )
1648        }
1649        self
1650    }
1651
1652    pub fn draw_image_rect_with_sampling_options(
1653        &self,
1654        image: impl AsRef<Image>,
1655        src: Option<(&Rect, SrcRectConstraint)>,
1656        dst: impl AsRef<Rect>,
1657        sampling: impl Into<SamplingOptions>,
1658        paint: &Paint,
1659    ) -> &Self {
1660        let sampling = sampling.into();
1661        match src {
1662            Some((src, constraint)) => unsafe {
1663                self.native_mut().drawImageRect(
1664                    image.as_ref().native(),
1665                    src.native(),
1666                    dst.as_ref().native(),
1667                    sampling.native(),
1668                    paint.native(),
1669                    constraint,
1670                )
1671            },
1672            None => unsafe {
1673                self.native_mut().drawImageRect1(
1674                    image.as_ref().native(),
1675                    dst.as_ref().native(),
1676                    sampling.native(),
1677                    paint.native(),
1678                )
1679            },
1680        }
1681        self
1682    }
1683
1684    /// Draws [`Image`] `image` stretched proportionally to fit into [`Rect`] `dst`.
1685    /// [`IRect`] `center` divides the image into nine sections: four sides, four corners, and
1686    /// the center. Corners are unmodified or scaled down proportionately if their sides
1687    /// are larger than `dst`; center and four sides are scaled to fit remaining space, if any.
1688    ///
1689    /// Additionally transform draw using clip, [`Matrix`], and optional [`Paint`] `paint`.
1690    ///
1691    /// If [`Paint`] `paint` is supplied, apply [`crate::ColorFilter`], alpha, [`ImageFilter`], and
1692    /// [`BlendMode`]. If `image` is [`crate::ColorType::Alpha8`], apply [`Shader`].
1693    /// If `paint` contains [`crate::MaskFilter`], generate mask from `image` bounds.
1694    /// Any [`crate::MaskFilter`] on `paint` is ignored as is paint anti-aliasing state.
1695    ///
1696    /// If generated mask extends beyond image bounds, replicate image edge colors, just
1697    /// as [`Shader`] made from [`RCHandle<Image>::to_shader()`] with [`crate::TileMode::Clamp`] set
1698    /// replicates the image edge color when it samples outside of its bounds.
1699    ///
1700    /// - `image` [`Image`] containing pixels, dimensions, and format
1701    /// - `center` [`IRect`] edge of image corners and sides
1702    /// - `dst` destination [`Rect`] of image to draw to
1703    /// - `filter` what technique to use when sampling the image
1704    /// - `paint` [`Paint`] containing [`BlendMode`], [`crate::ColorFilter`], [`ImageFilter`],
1705    ///    and so on; or `None`
1706    pub fn draw_image_nine(
1707        &self,
1708        image: impl AsRef<Image>,
1709        center: impl AsRef<IRect>,
1710        dst: impl AsRef<Rect>,
1711        filter_mode: FilterMode,
1712        paint: Option<&Paint>,
1713    ) -> &Self {
1714        unsafe {
1715            self.native_mut().drawImageNine(
1716                image.as_ref().native(),
1717                center.as_ref().native(),
1718                dst.as_ref().native(),
1719                filter_mode,
1720                paint.native_ptr_or_null(),
1721            )
1722        }
1723        self
1724    }
1725
1726    /// Draws [`Image`] `image` stretched proportionally to fit into [`Rect`] `dst`.
1727    ///
1728    /// [`lattice::Lattice`] lattice divides image into a rectangular grid.
1729    /// Each intersection of an even-numbered row and column is fixed;
1730    /// fixed lattice elements never scale larger than their initial
1731    /// size and shrink proportionately when all fixed elements exceed the bitmap
1732    /// dimension. All other grid elements scale to fill the available space, if any.
1733    ///
1734    /// Additionally transform draw using clip, [`Matrix`], and optional [`Paint`] `paint`.
1735    ///
1736    /// If [`Paint`] `paint` is supplied, apply [`crate::ColorFilter`], alpha, [`ImageFilter`], and
1737    /// [`BlendMode`]. If image is [`crate::ColorType::Alpha8`], apply [`Shader`].
1738    /// If `paint` contains [`crate::MaskFilter`], generate mask from image bounds.
1739    /// Any [`crate::MaskFilter`] on `paint` is ignored as is `paint` anti-aliasing state.
1740    ///
1741    /// If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
1742    /// just as [`Shader`] made from `SkShader::MakeBitmapShader` with
1743    /// [`crate::TileMode::Clamp`] set replicates the bitmap edge color when it samples
1744    /// outside of its bounds.
1745    ///
1746    /// - `image` [`Image`] containing pixels, dimensions, and format
1747    /// - `lattice` division of bitmap into fixed and variable rectangles
1748    /// - `dst` destination [`Rect`] of image to draw to
1749    /// - `filter` what technique to use when sampling the image
1750    /// - `paint` [`Paint`] containing [`BlendMode`], [`crate::ColorFilter`], [`ImageFilter`],
1751    ///   and so on; or `None`
1752    pub fn draw_image_lattice(
1753        &self,
1754        image: impl AsRef<Image>,
1755        lattice: &Lattice,
1756        dst: impl AsRef<Rect>,
1757        filter: FilterMode,
1758        paint: Option<&Paint>,
1759    ) -> &Self {
1760        unsafe {
1761            self.native_mut().drawImageLattice(
1762                image.as_ref().native(),
1763                &lattice.native().native,
1764                dst.as_ref().native(),
1765                filter,
1766                paint.native_ptr_or_null(),
1767            )
1768        }
1769        self
1770    }
1771
1772    // TODO: drawSimpleText?
1773
1774    /// Draws [`String`], with origin at `(origin.x, origin.y)`, using clip, [`Matrix`], [`Font`]
1775    /// `font`, and [`Paint`] `paint`.
1776    ///
1777    /// This function uses the default character-to-glyph mapping from the [`crate::Typeface`] in
1778    /// font.  It does not perform typeface fallback for characters not found in the
1779    /// [`crate::Typeface`].  It does not perform kerning; glyphs are positioned based on their
1780    /// default advances.
1781    ///
1782    /// Text size is affected by [`Matrix`] and [`Font`] text size. Default text size is 12 point.
1783    ///
1784    /// All elements of `paint`: [`crate::PathEffect`], [`crate::MaskFilter`], [`Shader`],
1785    /// [`crate::ColorFilter`], and [`ImageFilter`]; apply to text. By default, draws filled black
1786    /// glyphs.
1787    ///
1788    /// - `str` character code points drawn,
1789    ///    ending with a char value of zero
1790    /// - `origin` start of string on x,y-axis
1791    /// - `font` typeface, text size and so, used to describe the text
1792    /// - `paint` blend, color, and so on, used to draw
1793    pub fn draw_str(
1794        &self,
1795        str: impl AsRef<str>,
1796        origin: impl Into<Point>,
1797        font: &Font,
1798        paint: &Paint,
1799    ) -> &Self {
1800        // rust specific, based on drawSimpleText with fixed UTF8 encoding,
1801        // implementation is similar to Font's *_str methods.
1802        let origin = origin.into();
1803        let bytes = str.as_ref().as_bytes();
1804        unsafe {
1805            self.native_mut().drawSimpleText(
1806                bytes.as_ptr() as _,
1807                bytes.len(),
1808                TextEncoding::UTF8.into_native(),
1809                origin.x,
1810                origin.y,
1811                font.native(),
1812                paint.native(),
1813            )
1814        }
1815        self
1816    }
1817
1818    /// Draws glyphs at positions relative to `origin` styled with `font` and `paint` with
1819    /// supporting utf8 and cluster information.
1820    ///
1821    /// This function draw glyphs at the given positions relative to the given origin. It does not
1822    /// perform typeface fallback for glyphs not found in the [`crate::Typeface`] in font.
1823    ///
1824    /// The drawing obeys the current transform matrix and clipping.
1825    ///
1826    /// All elements of paint: [`crate::PathEffect`], [`crate::MaskFilter`], [`Shader`],
1827    /// [`crate::ColorFilter`], and [`ImageFilter`]; apply to text. By default, draws filled black
1828    /// glyphs.
1829    ///
1830    /// - `count`           number of glyphs to draw
1831    /// - `glyphs`          the array of glyphIDs to draw
1832    /// - `positions`       where to draw each glyph relative to origin
1833    /// - `clusters`        array of size count of cluster information
1834    /// - `utf8_text`       utf8text supporting information for the glyphs
1835    /// - `origin`          the origin of all the positions
1836    /// - `font`            typeface, text size and so, used to describe the text
1837    /// - `paint`           blend, color, and so on, used to draw
1838    #[allow(clippy::too_many_arguments)]
1839    pub fn draw_glyphs_utf8(
1840        &self,
1841        glyphs: &[GlyphId],
1842        positions: &[Point],
1843        clusters: &[u32],
1844        utf8_text: impl AsRef<str>,
1845        origin: impl Into<Point>,
1846        font: &Font,
1847        paint: &Paint,
1848    ) {
1849        let count = glyphs.len();
1850        if count == 0 {
1851            return;
1852        }
1853        assert_eq!(positions.len(), count);
1854        assert_eq!(clusters.len(), count);
1855        let utf8_text = utf8_text.as_ref().as_bytes();
1856        let origin = origin.into();
1857        unsafe {
1858            sb::C_SkCanvas_drawGlyphs2(
1859                self.native_mut(),
1860                glyphs.as_ptr(),
1861                count,
1862                positions.native().as_ptr(),
1863                clusters.as_ptr(),
1864                utf8_text.as_ptr() as _,
1865                utf8_text.len(),
1866                origin.into_native(),
1867                font.native(),
1868                paint.native(),
1869            )
1870        }
1871    }
1872
1873    /// Draws `count` glyphs, at positions relative to `origin` styled with `font` and `paint`.
1874    ///
1875    /// This function draw glyphs at the given positions relative to the given origin.
1876    /// It does not perform typeface fallback for glyphs not found in the [`crate::Typeface`]] in
1877    /// font.
1878    ///
1879    /// The drawing obeys the current transform matrix and clipping.
1880    ///
1881    /// All elements of paint: [`crate::PathEffect`], [`crate::MaskFilter`], [`Shader`],
1882    /// [`crate::ColorFilter`], and [`ImageFilter`]; apply to text. By default, draws filled black
1883    /// glyphs.
1884    ///
1885    /// - `count`       number of glyphs to draw
1886    /// - `glyphs`      the array of glyphIDs to draw
1887    /// - `positions`   where to draw each glyph relative to origin, either a `&[Point]` or
1888    ///                `&[RSXform]` slice
1889    /// - `origin`      the origin of all the positions
1890    /// - `font`        typeface, text size and so, used to describe the text
1891    /// - `paint`       blend, color, and so on, used to draw
1892    pub fn draw_glyphs_at<'a>(
1893        &self,
1894        glyphs: &[GlyphId],
1895        positions: impl Into<GlyphPositions<'a>>,
1896        origin: impl Into<Point>,
1897        font: &Font,
1898        paint: &Paint,
1899    ) {
1900        let count = glyphs.len();
1901        if count == 0 {
1902            return;
1903        }
1904        let positions: GlyphPositions = positions.into();
1905        let origin = origin.into();
1906
1907        let glyphs = glyphs.as_ptr();
1908        let origin = origin.into_native();
1909        let font = font.native();
1910        let paint = paint.native();
1911
1912        match positions {
1913            GlyphPositions::Points(points) => {
1914                assert_eq!(points.len(), count);
1915                unsafe {
1916                    sb::C_SkCanvas_drawGlyphs(
1917                        self.native_mut(),
1918                        glyphs,
1919                        count,
1920                        points.native().as_ptr(),
1921                        origin,
1922                        font,
1923                        paint,
1924                    )
1925                }
1926            }
1927            GlyphPositions::RSXforms(xforms) => {
1928                assert_eq!(xforms.len(), count);
1929                unsafe {
1930                    sb::C_SkCanvas_drawGlyphsRSXform(
1931                        self.native_mut(),
1932                        glyphs,
1933                        count,
1934                        xforms.native().as_ptr(),
1935                        origin,
1936                        font,
1937                        paint,
1938                    )
1939                }
1940            }
1941        }
1942    }
1943
1944    /// Draws [`TextBlob`] blob at `(origin.x, origin.y)`, using clip, [`Matrix`], and [`Paint`]
1945    /// paint.
1946    ///
1947    /// `blob` contains glyphs, their positions, and paint attributes specific to text:
1948    /// [`crate::Typeface`], [`Paint`] text size, [`Paint`] text scale x, [`Paint`] text skew x,
1949    /// [`Paint`] align, [`Paint`] hinting, anti-alias, [`Paint`] fake bold, [`Paint`] font embedded
1950    /// bitmaps, [`Paint`] full hinting spacing, LCD text, [`Paint`] linear text, and [`Paint`]
1951    /// subpixel text.
1952    ///
1953    /// [`TextEncoding`] must be set to [`TextEncoding::GlyphId`].
1954    ///
1955    /// Elements of `paint`: [`crate::PathEffect`], [`crate::MaskFilter`], [`Shader`],
1956    /// [`crate::ColorFilter`], and [`ImageFilter`]; apply to blob.
1957    ///
1958    /// - `blob` glyphs, positions, and their paints' text size, typeface, and so on
1959    /// - `origin` horizontal and vertical offset applied to blob
1960    /// - `paint` blend, color, stroking, and so on, used to draw
1961    pub fn draw_text_blob(
1962        &self,
1963        blob: impl AsRef<TextBlob>,
1964        origin: impl Into<Point>,
1965        paint: &Paint,
1966    ) -> &Self {
1967        let origin = origin.into();
1968        #[cfg(all(feature = "textlayout", feature = "embed-icudtl"))]
1969        crate::icu::init();
1970        unsafe {
1971            self.native_mut().drawTextBlob(
1972                blob.as_ref().native(),
1973                origin.x,
1974                origin.y,
1975                paint.native(),
1976            )
1977        }
1978        self
1979    }
1980
1981    /// Draws [`Picture`] picture, using clip and [`Matrix`]; transforming picture with
1982    /// [`Matrix`] matrix, if provided; and use [`Paint`] `paint` alpha, [`crate::ColorFilter`],
1983    /// [`ImageFilter`], and [`BlendMode`], if provided.
1984    ///
1985    /// If paint is not `None`, then the picture is always drawn into a temporary layer before
1986    /// actually landing on the canvas. Note that drawing into a layer can also change its
1987    /// appearance if there are any non-associative blend modes inside any of the pictures elements.
1988    ///
1989    /// - `picture` recorded drawing commands to play
1990    /// - `matrix` [`Matrix`] to rotate, scale, translate, and so on; may be `None`
1991    /// - `paint` [`Paint`] to apply transparency, filtering, and so on; may be `None`
1992    pub fn draw_picture(
1993        &self,
1994        picture: impl AsRef<Picture>,
1995        matrix: Option<&Matrix>,
1996        paint: Option<&Paint>,
1997    ) -> &Self {
1998        unsafe {
1999            self.native_mut().drawPicture(
2000                picture.as_ref().native(),
2001                matrix.native_ptr_or_null(),
2002                paint.native_ptr_or_null(),
2003            )
2004        }
2005        self
2006    }
2007
2008    /// Draws [`Vertices`] vertices, a triangle mesh, using clip and [`Matrix`].
2009    /// If `paint` contains an [`Shader`] and vertices does not contain tex coords, the shader is
2010    /// mapped using the vertices' positions.
2011    ///
2012    /// [`BlendMode`] is ignored if [`Vertices`] does not have colors. Otherwise, it combines
2013    ///   - the [`Shader`] if [`Paint`] contains [`Shader`
2014    ///   - or the opaque [`Paint`] color if [`Paint`] does not contain [`Shader`]
2015    ///
2016    /// as the src of the blend and the interpolated vertex colors as the dst.
2017    ///
2018    /// [`crate::MaskFilter`], [`crate::PathEffect`], and antialiasing on [`Paint`] are ignored.
2019    //
2020    /// - `vertices` triangle mesh to draw
2021    /// - `mode` combines vertices' colors with [`Shader`] if present or [`Paint`] opaque color if
2022    ///   not. Ignored if the vertices do not contain color.
2023    /// - `paint` specifies the [`Shader`], used as [`Vertices`] texture, and
2024    ///   [`crate::ColorFilter`].
2025    ///
2026    /// example: <https://fiddle.skia.org/c/@Canvas_drawVertices>
2027    /// example: <https://fiddle.skia.org/c/@Canvas_drawVertices_2>
2028    pub fn draw_vertices(&self, vertices: &Vertices, mode: BlendMode, paint: &Paint) -> &Self {
2029        unsafe {
2030            self.native_mut()
2031                .drawVertices(vertices.native(), mode, paint.native())
2032        }
2033        self
2034    }
2035
2036    /// Draws a Coons patch: the interpolation of four cubics with shared corners,
2037    /// associating a color, and optionally a texture [`Point`], with each corner.
2038    ///
2039    /// [`Point`] array cubics specifies four [`Path`] cubic starting at the top-left corner,
2040    /// in clockwise order, sharing every fourth point. The last [`Path`] cubic ends at the
2041    /// first point.
2042    ///
2043    /// Color array color associates colors with corners in top-left, top-right,
2044    /// bottom-right, bottom-left order.
2045    ///
2046    /// If paint contains [`Shader`], [`Point`] array `tex_coords` maps [`Shader`] as texture to
2047    /// corners in top-left, top-right, bottom-right, bottom-left order. If `tex_coords` is
2048    /// `None`, [`Shader`] is mapped using positions (derived from cubics).
2049    ///
2050    /// [`BlendMode`] is ignored if colors is `None`. Otherwise, it combines
2051    ///   - the [`Shader`] if [`Paint`] contains [`Shader`]
2052    ///   - or the opaque [`Paint`] color if [`Paint`] does not contain [`Shader`]
2053    ///
2054    /// as the src of the blend and the interpolated patch colors as the dst.
2055    ///
2056    /// [`crate::MaskFilter`], [`crate::PathEffect`], and antialiasing on [`Paint`] are ignored.
2057    ///
2058    /// - `cubics` [`Path`] cubic array, sharing common points
2059    /// - `colors` color array, one for each corner
2060    /// - `tex_coords` [`Point`] array of texture coordinates, mapping [`Shader`] to corners;
2061    ///   may be `None`
2062    /// - `mode` combines patch's colors with [`Shader`] if present or [`Paint`] opaque color if
2063    ///    not. Ignored if colors is `None`.
2064    /// - `paint` [`Shader`], [`crate::ColorFilter`], [`BlendMode`], used to draw
2065    pub fn draw_patch<'a>(
2066        &self,
2067        cubics: &[Point; 12],
2068        colors: impl Into<Option<&'a [Color; 4]>>,
2069        tex_coords: Option<&[Point; 4]>,
2070        mode: BlendMode,
2071        paint: &Paint,
2072    ) -> &Self {
2073        let colors = colors
2074            .into()
2075            .map(|c| c.native().as_ptr())
2076            .unwrap_or(ptr::null());
2077        unsafe {
2078            self.native_mut().drawPatch(
2079                cubics.native().as_ptr(),
2080                colors,
2081                tex_coords
2082                    .map(|tc| tc.native().as_ptr())
2083                    .unwrap_or(ptr::null()),
2084                mode,
2085                paint.native(),
2086            )
2087        }
2088        self
2089    }
2090
2091    /// Draws a set of sprites from atlas, using clip, [`Matrix`], and optional [`Paint`] paint.
2092    /// paint uses anti-alias, alpha, [`crate::ColorFilter`], [`ImageFilter`], and [`BlendMode`]
2093    /// to draw, if present. For each entry in the array, [`Rect`] tex locates sprite in
2094    /// atlas, and [`RSXform`] xform transforms it into destination space.
2095    ///
2096    /// [`crate::MaskFilter`] and [`crate::PathEffect`] on paint are ignored.
2097    ///
2098    /// xform, tex, and colors if present, must contain the same number of entries.
2099    /// Optional colors are applied for each sprite using [`BlendMode`] mode, treating
2100    /// sprite as source and colors as destination.
2101    /// Optional `cull_rect` is a conservative bounds of all transformed sprites.
2102    /// If `cull_rect` is outside of clip, canvas can skip drawing.
2103    ///
2104    /// * `atlas` - [`Image`] containing sprites
2105    /// * `xform` - [`RSXform`] mappings for sprites in atlas
2106    /// * `tex` - [`Rect`] locations of sprites in atlas
2107    /// * `colors` - one per sprite, blended with sprite using [`BlendMode`]; may be `None`
2108    /// * `count` - number of sprites to draw
2109    /// * `mode` - [`BlendMode`] combining colors and sprites
2110    /// * `sampling` - [`SamplingOptions`] used when sampling from the atlas image
2111    /// * `cull_rect` - bounds of transformed sprites for efficient clipping; may be `None`
2112    /// * `paint` - [`crate::ColorFilter`], [`ImageFilter`], [`BlendMode`], and so on; may be `None`
2113    #[allow(clippy::too_many_arguments)]
2114    pub fn draw_atlas<'a>(
2115        &self,
2116        atlas: &Image,
2117        xform: &[RSXform],
2118        tex: &[Rect],
2119        colors: impl Into<Option<&'a [Color]>>,
2120        mode: BlendMode,
2121        sampling: impl Into<SamplingOptions>,
2122        cull_rect: impl Into<Option<Rect>>,
2123        paint: impl Into<Option<&'a Paint>>,
2124    ) {
2125        let count = xform.len();
2126        assert_eq!(tex.len(), count);
2127        let colors = colors.into();
2128        if let Some(color_slice) = colors {
2129            assert_eq!(color_slice.len(), count);
2130        }
2131        unsafe {
2132            sb::C_SkCanvas_drawAtlas(
2133                self.native_mut(),
2134                atlas.native(),
2135                xform.native().as_ptr(),
2136                count,
2137                tex.native().as_ptr(),
2138                colors.native().as_ptr_or_null(),
2139                mode,
2140                sampling.into().native(),
2141                cull_rect.into().native().as_ptr_or_null(),
2142                paint.into().native_ptr_or_null(),
2143            )
2144        }
2145    }
2146
2147    /// Draws [`Drawable`] drawable using clip and [`Matrix`], concatenated with
2148    /// optional matrix.
2149    ///
2150    /// If [`Canvas`] has an asynchronous implementation, as is the case when it is recording into
2151    /// [`Picture`], then drawable will be referenced, so that [`RCHandle<Drawable>::draw()`] can be
2152    /// called when the operation is finalized. To force immediate drawing, call
2153    /// [`RCHandle<Drawable>::draw()`] instead.
2154    ///
2155    /// - `drawable` custom struct encapsulating drawing commands
2156    /// - `matrix` transformation applied to drawing; may be `None`
2157    ///
2158    /// example: <https://fiddle.skia.org/c/@Canvas_drawDrawable>
2159    pub fn draw_drawable(&self, drawable: &mut Drawable, matrix: Option<&Matrix>) {
2160        unsafe {
2161            self.native_mut()
2162                .drawDrawable(drawable.native_mut(), matrix.native_ptr_or_null())
2163        }
2164    }
2165
2166    /// Draws [`Drawable`] drawable using clip and [`Matrix`], offset by `(offset.x, offset.y)`.
2167    ///
2168    /// If [`Canvas`] has an asynchronous implementation, as is the case when it is recording into
2169    /// [`Picture`], then drawable will be referenced, so that [`RCHandle<Drawable>::draw()`] can be
2170    /// called when the operation is finalized. To force immediate drawing, call
2171    /// [`RCHandle<Drawable>::draw()`] instead.
2172    ///
2173    /// - `drawable` custom struct encapsulating drawing commands
2174    /// - `offset` offset into [`Canvas`] writable pixels on x,y-axis
2175    ///
2176    /// example: <https://fiddle.skia.org/c/@Canvas_drawDrawable_2>
2177    pub fn draw_drawable_at(&self, drawable: &mut Drawable, offset: impl Into<Point>) {
2178        let offset = offset.into();
2179        unsafe {
2180            self.native_mut()
2181                .drawDrawable1(drawable.native_mut(), offset.x, offset.y)
2182        }
2183    }
2184
2185    /// Associates [`Rect`] on [`Canvas`] when an annotation; a key-value pair, where the key is
2186    /// a UTF-8 string, and optional value is stored as [`Data`].
2187    ///
2188    /// Only some canvas implementations, such as recording to [`Picture`], or drawing to
2189    /// document PDF, use annotations.
2190    ///
2191    /// - `rect` [`Rect`] extent of canvas to annotate
2192    /// - `key` string used for lookup
2193    /// - `value` data holding value stored in annotation
2194    pub fn draw_annotation(&self, rect: impl AsRef<Rect>, key: &str, value: &Data) -> &Self {
2195        let key = CString::new(key).unwrap();
2196        unsafe {
2197            self.native_mut().drawAnnotation(
2198                rect.as_ref().native(),
2199                key.as_ptr(),
2200                value.native_mut_force(),
2201            )
2202        }
2203        self
2204    }
2205
2206    /// Returns `true` if clip is empty; that is, nothing will draw.
2207    ///
2208    /// May do work when called; it should not be called more often than needed. However, once
2209    /// called, subsequent calls perform no work until clip changes.
2210    ///
2211    /// Returns `true` if clip is empty
2212    ///
2213    /// example: <https://fiddle.skia.org/c/@Canvas_isClipEmpty>
2214    pub fn is_clip_empty(&self) -> bool {
2215        unsafe { sb::C_SkCanvas_isClipEmpty(self.native()) }
2216    }
2217
2218    /// Returns `true` if clip is [`Rect`] and not empty.
2219    /// Returns `false` if the clip is empty, or if it is not [`Rect`].
2220    ///
2221    /// Returns `true` if clip is [`Rect`] and not empty
2222    ///
2223    /// example: <https://fiddle.skia.org/c/@Canvas_isClipRect>
2224    pub fn is_clip_rect(&self) -> bool {
2225        unsafe { sb::C_SkCanvas_isClipRect(self.native()) }
2226    }
2227
2228    /// Returns the current transform from local coordinates to the 'device', which for most
2229    /// purposes means pixels.
2230    ///
2231    /// Returns transformation from local coordinates to device / pixels.
2232    pub fn local_to_device(&self) -> M44 {
2233        M44::construct(|m| unsafe { sb::C_SkCanvas_getLocalToDevice(self.native(), m) })
2234    }
2235
2236    /// Throws away the 3rd row and column in the matrix, so be warned.
2237    pub fn local_to_device_as_3x3(&self) -> Matrix {
2238        self.local_to_device().to_m33()
2239    }
2240
2241    /// DEPRECATED
2242    /// Legacy version of [`Self::local_to_device()`], which strips away any Z information, and just
2243    /// returns a 3x3 version.
2244    ///
2245    /// Returns 3x3 version of [`Self::local_to_device()`]
2246    ///
2247    /// example: <https://fiddle.skia.org/c/@Canvas_getTotalMatrix>
2248    /// example: <https://fiddle.skia.org/c/@Clip>
2249    #[deprecated(
2250        since = "0.38.0",
2251        note = "use local_to_device() or local_to_device_as_3x3() instead"
2252    )]
2253    pub fn total_matrix(&self) -> Matrix {
2254        let mut matrix = Matrix::default();
2255        unsafe { sb::C_SkCanvas_getTotalMatrix(self.native(), matrix.native_mut()) };
2256        matrix
2257    }
2258
2259    //
2260    // internal helper
2261    //
2262
2263    pub(crate) fn own_from_native_ptr<'lt>(native: *mut SkCanvas) -> Option<OwnedCanvas<'lt>> {
2264        if !native.is_null() {
2265            Some(OwnedCanvas::<'lt>(
2266                ptr::NonNull::new(
2267                    Self::borrow_from_native(unsafe { &*native }) as *const _ as *mut _
2268                )
2269                .unwrap(),
2270                PhantomData,
2271            ))
2272        } else {
2273            None
2274        }
2275    }
2276
2277    pub(crate) fn borrow_from_native(native: &SkCanvas) -> &Self {
2278        unsafe { transmute_ref(native) }
2279    }
2280}
2281
2282impl QuickReject<Rect> for Canvas {
2283    /// Returns `true` if [`Rect`] `rect`, transformed by [`Matrix`], can be quickly determined to
2284    /// be outside of clip. May return `false` even though rect is outside of clip.
2285    ///
2286    /// Use to check if an area to be drawn is clipped out, to skip subsequent draw calls.
2287    ///
2288    /// - `rect` [`Rect`] to compare with clip
2289    ///
2290    /// Returns `true` if `rect`, transformed by [`Matrix`], does not intersect clip
2291    ///
2292    /// example: <https://fiddle.skia.org/c/@Canvas_quickReject>
2293    fn quick_reject(&self, rect: &Rect) -> bool {
2294        unsafe { self.native().quickReject(rect.native()) }
2295    }
2296}
2297
2298impl QuickReject<Path> for Canvas {
2299    /// Returns `true` if `path`, transformed by [`Matrix`], can be quickly determined to be
2300    /// outside of clip. May return `false` even though `path` is outside of clip.
2301    ///
2302    /// Use to check if an area to be drawn is clipped out, to skip subsequent draw calls.
2303    ///
2304    /// - `path` [`Path`] to compare with clip
2305    ///
2306    /// Returns `true` if `path`, transformed by [`Matrix`], does not intersect clip
2307    ///
2308    /// example: <https://fiddle.skia.org/c/@Canvas_quickReject_2>
2309    fn quick_reject(&self, path: &Path) -> bool {
2310        unsafe { self.native().quickReject1(path.native()) }
2311    }
2312}
2313
2314pub trait SetMatrix {
2315    /// DEPRECATED -- use [`M44`] version
2316    #[deprecated(since = "0.38.0", note = "Use M44 version")]
2317    fn set_matrix(&self, matrix: &Matrix) -> &Self;
2318}
2319
2320impl SetMatrix for Canvas {
2321    /// DEPRECATED -- use [`M44`] version
2322    fn set_matrix(&self, matrix: &Matrix) -> &Self {
2323        unsafe { self.native_mut().setMatrix1(matrix.native()) }
2324        self
2325    }
2326}
2327
2328//
2329// Lattice
2330//
2331
2332pub mod lattice {
2333    use crate::{Color, IRect, prelude::*};
2334    use skia_bindings::{self as sb, SkCanvas_Lattice};
2335    use std::marker::PhantomData;
2336
2337    /// [`Lattice`] divides [`crate::Bitmap`] or [`crate::Image`] into a rectangular grid.
2338    /// Grid entries on even columns and even rows are fixed; these entries are
2339    /// always drawn at their original size if the destination is large enough.
2340    /// If the destination side is too small to hold the fixed entries, all fixed
2341    /// entries are proportionately scaled down to fit.
2342    /// The grid entries not on even columns and rows are scaled to fit the
2343    /// remaining space, if any.
2344    #[derive(Debug)]
2345    pub struct Lattice<'a> {
2346        /// x-axis values dividing bitmap
2347        pub x_divs: &'a [i32],
2348        /// y-axis values dividing bitmap
2349        pub y_divs: &'a [i32],
2350        /// array of fill types
2351        pub rect_types: Option<&'a [RectType]>,
2352        /// source bounds to draw from
2353        pub bounds: Option<IRect>,
2354        /// array of colors
2355        pub colors: Option<&'a [Color]>,
2356    }
2357
2358    #[derive(Debug)]
2359    pub(crate) struct Ref<'a> {
2360        pub native: SkCanvas_Lattice,
2361        pd: PhantomData<&'a Lattice<'a>>,
2362    }
2363
2364    impl Lattice<'_> {
2365        pub(crate) fn native(&self) -> Ref {
2366            if let Some(rect_types) = self.rect_types {
2367                let rect_count = (self.x_divs.len() + 1) * (self.y_divs.len() + 1);
2368                assert_eq!(rect_count, rect_types.len());
2369                // even though rect types may not include any FixedColor refs,
2370                // we expect the colors slice with a proper size here, this
2371                // saves us for going over the types array and looking for FixedColor
2372                // entries.
2373                assert_eq!(rect_count, self.colors.unwrap().len());
2374            }
2375
2376            let native = SkCanvas_Lattice {
2377                fXDivs: self.x_divs.as_ptr(),
2378                fYDivs: self.y_divs.as_ptr(),
2379                fRectTypes: self.rect_types.as_ptr_or_null(),
2380                fXCount: self.x_divs.len().try_into().unwrap(),
2381                fYCount: self.y_divs.len().try_into().unwrap(),
2382                fBounds: self.bounds.native().as_ptr_or_null(),
2383                fColors: self.colors.native().as_ptr_or_null(),
2384            };
2385            Ref {
2386                native,
2387                pd: PhantomData,
2388            }
2389        }
2390    }
2391
2392    /// Optional setting per rectangular grid entry to make it transparent,
2393    /// or to fill the grid entry with a color.
2394    pub use sb::SkCanvas_Lattice_RectType as RectType;
2395    variant_name!(RectType::FixedColor);
2396}
2397
2398#[must_use]
2399#[derive(Debug)]
2400/// Stack helper class calls [`Canvas::restore_to_count()`] when [`AutoCanvasRestore`]
2401/// goes out of scope. Use this to guarantee that the canvas is restored to a known
2402/// state.
2403pub struct AutoRestoredCanvas<'a> {
2404    canvas: &'a Canvas,
2405    restore: SkAutoCanvasRestore,
2406}
2407
2408impl Deref for AutoRestoredCanvas<'_> {
2409    type Target = Canvas;
2410    fn deref(&self) -> &Self::Target {
2411        self.canvas
2412    }
2413}
2414
2415impl NativeAccess for AutoRestoredCanvas<'_> {
2416    type Native = SkAutoCanvasRestore;
2417
2418    fn native(&self) -> &SkAutoCanvasRestore {
2419        &self.restore
2420    }
2421
2422    fn native_mut(&mut self) -> &mut SkAutoCanvasRestore {
2423        &mut self.restore
2424    }
2425}
2426
2427impl Drop for AutoRestoredCanvas<'_> {
2428    /// Restores [`Canvas`] to saved state. Drop is called when container goes out of scope.
2429    fn drop(&mut self) {
2430        unsafe { sb::C_SkAutoCanvasRestore_destruct(self.native_mut()) }
2431    }
2432}
2433
2434impl AutoRestoredCanvas<'_> {
2435    /// Restores [`Canvas`] to saved state immediately. Subsequent calls and [`Self::drop()`] have
2436    /// no effect.
2437    pub fn restore(&mut self) {
2438        unsafe { sb::C_SkAutoCanvasRestore_restore(self.native_mut()) }
2439    }
2440}
2441
2442pub enum AutoCanvasRestore {}
2443
2444impl AutoCanvasRestore {
2445    // TODO: rename to save(), add a method to Canvas, perhaps named auto_restored()?
2446    /// Preserves [`Canvas::save()`] count. Optionally saves [`Canvas`] clip and [`Canvas`] matrix.
2447    ///
2448    /// - `canvas` [`Canvas`] to guard
2449    /// - `do_save` call [`Canvas::save()`]
2450    ///
2451    /// Returns utility to restore [`Canvas`] state on destructor
2452    pub fn guard(canvas: &Canvas, do_save: bool) -> AutoRestoredCanvas {
2453        let restore = construct(|acr| unsafe {
2454            sb::C_SkAutoCanvasRestore_Construct(acr, canvas.native_mut(), do_save)
2455        });
2456
2457        AutoRestoredCanvas { canvas, restore }
2458    }
2459}
2460
2461#[cfg(test)]
2462mod tests {
2463    use crate::{
2464        AlphaType, Canvas, ClipOp, Color, ColorType, ImageInfo, OwnedCanvas, Rect,
2465        canvas::SaveLayerFlags, canvas::SaveLayerRec, surfaces,
2466    };
2467
2468    #[test]
2469    fn test_raster_direct_creation_and_clear_in_memory() {
2470        let info = ImageInfo::new((2, 2), ColorType::RGBA8888, AlphaType::Unpremul, None);
2471        assert_eq!(8, info.min_row_bytes());
2472        let mut bytes: [u8; 8 * 2] = Default::default();
2473        {
2474            let canvas = Canvas::from_raster_direct(&info, bytes.as_mut(), None, None).unwrap();
2475            canvas.clear(Color::RED);
2476        }
2477
2478        assert_eq!(0xff, bytes[0]);
2479        assert_eq!(0x00, bytes[1]);
2480        assert_eq!(0x00, bytes[2]);
2481        assert_eq!(0xff, bytes[3]);
2482    }
2483
2484    #[test]
2485    fn test_raster_direct_n32_creation_and_clear_in_memory() {
2486        let mut pixels: [u32; 4] = Default::default();
2487        {
2488            let canvas = Canvas::from_raster_direct_n32((2, 2), pixels.as_mut(), None).unwrap();
2489            canvas.clear(Color::RED);
2490        }
2491
2492        // TODO: equals to 0xff0000ff on macOS, but why? Endianness should be the same.
2493        // assert_eq!(0xffff0000, pixels[0]);
2494    }
2495
2496    #[test]
2497    fn test_empty_canvas_creation() {
2498        let canvas = OwnedCanvas::default();
2499        drop(canvas)
2500    }
2501
2502    #[test]
2503    fn test_save_layer_rec_lifetimes() {
2504        let rect = Rect::default();
2505        {
2506            let _rec = SaveLayerRec::default()
2507                .flags(SaveLayerFlags::PRESERVE_LCD_TEXT)
2508                .bounds(&rect);
2509        }
2510    }
2511
2512    #[test]
2513    fn test_make_surface() {
2514        let mut pixels: [u32; 4] = Default::default();
2515        let canvas = Canvas::from_raster_direct_n32((2, 2), pixels.as_mut(), None).unwrap();
2516        let ii = canvas.image_info();
2517        let mut surface = canvas.new_surface(&ii, None).unwrap();
2518        dbg!(&canvas as *const _);
2519        drop(canvas);
2520
2521        let canvas = surface.canvas();
2522        dbg!(canvas as *const _);
2523        canvas.clear(Color::RED);
2524    }
2525
2526    #[test]
2527    fn clip_options_overloads() {
2528        let c = OwnedCanvas::default();
2529        // do_anti_alias
2530        c.clip_rect(Rect::default(), None, true);
2531        // clip_op
2532        c.clip_rect(Rect::default(), ClipOp::Difference, None);
2533        // both
2534        c.clip_rect(Rect::default(), ClipOp::Difference, true);
2535    }
2536
2537    /// Regression test for: <https://github.com/rust-skia/rust-skia/issues/427>
2538    #[test]
2539    fn test_local_and_device_clip_bounds() {
2540        let mut surface =
2541            surfaces::raster(&ImageInfo::new_n32_premul((100, 100), None), 0, None).unwrap();
2542        let _ = surface.canvas().device_clip_bounds();
2543        let _ = surface.canvas().local_clip_bounds();
2544        let _ = surface.canvas().local_to_device();
2545    }
2546}