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