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