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