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