cairo-rs-0.20.1/.cargo_vcs_info.json0000644000000001430000000000100126310ustar { "git": { "sha1": "6f481a26fd6ba257e3af7acb83d1c090630de969" }, "path_in_vcs": "cairo" }cairo-rs-0.20.1/COPYRIGHT000064400000000000000000000012131046102023000127130ustar 00000000000000The gtk-rs Project is licensed under the MIT license, see the LICENSE file or . Copyrights in the gtk-rs Project project are retained by their contributors. No copyright assignment is required to contribute to the gtk-rs Project project. For full authorship information, see the version control history. This project provides interoperability with various GNOME libraries but doesn't distribute any parts of them. Distributing compiled libraries and executables that link to those libraries may be subject to terms of the GNU LGPL or other licenses. For more information check the license of each GNOME library. cairo-rs-0.20.1/Cargo.toml0000644000000040040000000000100106270ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.70" name = "cairo-rs" version = "0.20.1" authors = ["The gtk-rs Project Developers"] build = false exclude = ["gir-files/*"] autobins = false autoexamples = false autotests = false autobenches = false description = "Rust bindings for the Cairo library" homepage = "https://gtk-rs.org/" documentation = "https://gtk-rs.org/gtk-rs-core/stable/latest/docs/cairo/" readme = "README.md" keywords = [ "cairo", "gtk-rs", "gnome", "GUI", ] license = "MIT" repository = "https://github.com/gtk-rs/gtk-rs-core" [package.metadata.docs.rs] all-features = true rustc-args = [ "--cfg", "docsrs", ] rustdoc-args = [ "--cfg", "docsrs", "--generate-link-to-definition", ] [lib] name = "cairo" path = "src/lib.rs" [dependencies.bitflags] version = "2.6" [dependencies.cairo-sys-rs] version = "0.20" [dependencies.freetype-rs] version = "0.37" optional = true [dependencies.glib] version = "0.20" optional = true [dependencies.libc] version = "0.2" [dev-dependencies.float_eq] version = "1" [dev-dependencies.tempfile] version = "3.10" [features] default = ["use_glib"] freetype = [ "cairo-sys-rs/freetype", "freetype-rs", ] pdf = ["cairo-sys-rs/pdf"] png = ["cairo-sys-rs/png"] ps = ["cairo-sys-rs/ps"] script = ["cairo-sys-rs/script"] svg = ["cairo-sys-rs/svg"] use_glib = [ "glib", "cairo-sys-rs/use_glib", ] v1_16 = ["cairo-sys-rs/v1_16"] v1_18 = [ "v1_16", "cairo-sys-rs/v1_18", ] win32-surface = ["cairo-sys-rs/win32-surface"] xcb = ["cairo-sys-rs/xcb"] xlib = ["cairo-sys-rs/xlib"] cairo-rs-0.20.1/Cargo.toml.orig000064400000000000000000000024251046102023000143150ustar 00000000000000[package] name = "cairo-rs" keywords = ["cairo", "gtk-rs", "gnome", "GUI"] readme = "README.md" documentation = "https://gtk-rs.org/gtk-rs-core/stable/latest/docs/cairo/" description = "Rust bindings for the Cairo library" authors.workspace = true edition.workspace = true exclude.workspace = true homepage.workspace = true license.workspace = true repository.workspace = true rust-version.workspace = true version.workspace = true [lib] name = "cairo" [features] png = ["cairo-sys-rs/png"] pdf = ["cairo-sys-rs/pdf"] svg = ["cairo-sys-rs/svg"] ps = ["cairo-sys-rs/ps"] use_glib = ["glib", "cairo-sys-rs/use_glib"] v1_16 = ["cairo-sys-rs/v1_16"] v1_18 = ["v1_16", "cairo-sys-rs/v1_18"] default = ["use_glib"] freetype = ["cairo-sys-rs/freetype", "freetype-rs"] script = ["cairo-sys-rs/script"] xcb = ["cairo-sys-rs/xcb"] xlib = ["cairo-sys-rs/xlib"] win32-surface = ["cairo-sys-rs/win32-surface"] [dependencies.glib] optional = true workspace = true [dependencies] cairo-sys-rs.workspace = true libc.workspace = true bitflags.workspace = true freetype-rs = { version = "0.37", optional = true } [dev-dependencies] tempfile = "3.10" float_eq = "1" [package.metadata.docs.rs] all-features = true rustc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] cairo-rs-0.20.1/LICENSE000064400000000000000000000020001046102023000124200ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cairo-rs-0.20.1/README.md000064400000000000000000000036271046102023000127120ustar 00000000000000# Cairo bindings __Rust__ bindings for Rust and wrappers for [Cairo](https://www.cairographics.org/), part of [gtk-rs-core](https://github.com/gtk-rs/gtk-rs-core). ![screenshot](https://guillaume-gomez.fr/image/cairo.png) Cairo __1.14__ is the lowest supported version for the underlying library. ## Minimum supported Rust version Currently, the minimum supported Rust version is `1.70.0`. ## Default-on features * **use_glib** - Use with [glib](mod@glib) ## Fileformat features * **png** - Reading and writing PNG images * **pdf** - Rendering PDF documents * **svg** - Rendering SVG documents * **ps** - Rendering PostScript documents ## Cairo API version features * **v1_16** - Use Cairo 1.16 APIs ## Documentation * [Rust API - Stable](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/cairo) * [Rust API - Development](https://gtk-rs.org/gtk-rs-core/git/docs/cairo) * [C API](https://www.cairographics.org/documentation/) ## X Window features * **xcb** - X Window System rendering using the XCB library * **xlib** - X Window System rendering using XLib ## Windows API features * **win32-surface** - Microsoft Windows surface support ## Documentation rustdoc attributes * **docsrs** - Used to keep system dependent items in documentation ## Using We recommend using [crates from crates.io](https://crates.io/keywords/gtk-rs), as [demonstrated here](https://gtk-rs.org/#using). If you want to track the bleeding edge, use the git dependency instead: ```toml [dependencies] cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs-core.git", package = "cairo-rs" } ``` Avoid mixing versioned and git crates like this: ```toml # This will not compile [dependencies] cairo-rs = "0.13" cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs-core.git", package = "cairo-rs" } ``` ### See Also * [glib](https://crates.io/crates/glib) ## License __cairo__ is available under the MIT License, please refer to it. cairo-rs-0.20.1/src/constants.rs000064400000000000000000000026761046102023000146070ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. pub const MIME_TYPE_JPEG: &str = "image/jpeg"; pub const MIME_TYPE_PNG: &str = "image/png"; pub const MIME_TYPE_JP2: &str = "image/jp2"; pub const MIME_TYPE_URI: &str = "text/x-uri"; pub const MIME_TYPE_UNIQUE_ID: &str = "application/x-cairo.uuid"; pub const MIME_TYPE_JBIG2: &str = "application/x-cairo.jbig2"; pub const MIME_TYPE_JBIG2_GLOBAL: &str = "application/x-cairo.jbig2-global"; pub const MIME_TYPE_JBIG2_GLOBAL_ID: &str = "application/x-cairo.jbig2-global-id"; #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] pub const MIME_TYPE_CCITT_FAX: &str = "image/g3fax"; #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] pub const MIME_TYPE_CCITT_FAX_PARAMS: &str = "application/x-cairo.ccitt.params"; #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] pub const MIME_TYPE_EPS: &str = "application/postscript"; #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] pub const MIME_TYPE_EPS_PARAMS: &str = "application/x-cairo.eps.params"; #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] pub const PDF_OUTLINE_ROOT: i32 = 0; #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] pub const CAIRO_TAG_DEST: &str = "cairo.dest"; #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] pub const CAIRO_TAG_LINK: &str = "Link"; cairo-rs-0.20.1/src/context.rs000064400000000000000000000754351046102023000142620ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(feature = "use_glib")] use std::marker::PhantomData; use std::{ffi::CString, fmt, mem::MaybeUninit, ops, ptr, slice}; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ ffi, utils::status_to_result, Antialias, Content, Error, FillRule, FontExtents, FontFace, FontOptions, FontSlant, FontWeight, Glyph, LineCap, LineJoin, Matrix, Operator, Path, Pattern, Rectangle, ScaledFont, Surface, TextCluster, TextClusterFlags, TextExtents, }; pub struct RectangleList { ptr: *mut ffi::cairo_rectangle_list_t, } impl ops::Deref for RectangleList { type Target = [Rectangle]; #[inline] fn deref(&self) -> &[Rectangle] { unsafe { let ptr = (*self.ptr).rectangles as *mut Rectangle; let len = (*self.ptr).num_rectangles; if ptr.is_null() || len == 0 { &[] } else { slice::from_raw_parts(ptr, len as usize) } } } } impl Drop for RectangleList { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_rectangle_list_destroy(self.ptr); } } } impl fmt::Debug for RectangleList { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use std::ops::Deref; f.debug_tuple("RectangleList").field(&self.deref()).finish() } } #[derive(Debug)] #[repr(transparent)] #[doc(alias = "cairo_t")] pub struct Context(ptr::NonNull); #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl IntoGlibPtr<*mut ffi::cairo_t> for Context { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::cairo_t { (&*std::mem::ManuallyDrop::new(self)).to_glib_none().0 } } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl<'a> ToGlibPtr<'a, *mut ffi::cairo_t> for &'a Context { type Storage = PhantomData<&'a Context>; #[inline] fn to_glib_none(&self) -> Stash<'a, *mut ffi::cairo_t, &'a Context> { Stash(self.0.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *mut ffi::cairo_t { unsafe { ffi::cairo_reference(self.0.as_ptr()) } } } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl FromGlibPtrNone<*mut ffi::cairo_t> for Context { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::cairo_t) -> Context { Self::from_raw_none(ptr) } } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl FromGlibPtrBorrow<*mut ffi::cairo_t> for Context { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_t) -> crate::Borrowed { Self::from_raw_borrow(ptr) } } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl FromGlibPtrFull<*mut ffi::cairo_t> for Context { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::cairo_t) -> Context { Self::from_raw_full(ptr) } } #[cfg(feature = "use_glib")] gvalue_impl!( Context, ffi::cairo_t, ffi::gobject::cairo_gobject_context_get_type ); impl Clone for Context { #[inline] fn clone(&self) -> Context { unsafe { Self::from_raw_none(self.to_raw_none()) } } } impl Drop for Context { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_destroy(self.0.as_ptr()); } } } impl Context { #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_t) -> Context { debug_assert!(!ptr.is_null()); ffi::cairo_reference(ptr); Context(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_t) -> crate::Borrowed { debug_assert!(!ptr.is_null()); crate::Borrowed::new(Context(ptr::NonNull::new_unchecked(ptr))) } #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_t) -> Context { debug_assert!(!ptr.is_null()); Context(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_t { self.0.as_ptr() } #[doc(alias = "cairo_status")] #[inline] pub fn status(&self) -> Result<(), Error> { let status = unsafe { ffi::cairo_status(self.0.as_ptr()) }; status_to_result(status) } pub fn new(target: impl AsRef) -> Result { let ctx = unsafe { Self::from_raw_full(ffi::cairo_create(target.as_ref().to_raw_none())) }; ctx.status().map(|_| ctx) } #[doc(alias = "cairo_save")] pub fn save(&self) -> Result<(), Error> { unsafe { ffi::cairo_save(self.0.as_ptr()) } self.status() } #[doc(alias = "cairo_restore")] pub fn restore(&self) -> Result<(), Error> { unsafe { ffi::cairo_restore(self.0.as_ptr()) } self.status() } #[doc(alias = "get_target")] #[doc(alias = "cairo_get_target")] pub fn target(&self) -> Surface { unsafe { Surface::from_raw_none(ffi::cairo_get_target(self.0.as_ptr())) } } #[doc(alias = "cairo_push_group")] pub fn push_group(&self) { unsafe { ffi::cairo_push_group(self.0.as_ptr()) } } #[doc(alias = "cairo_push_group_with_content")] pub fn push_group_with_content(&self, content: Content) { unsafe { ffi::cairo_push_group_with_content(self.0.as_ptr(), content.into()) } } #[doc(alias = "cairo_pop_group")] pub fn pop_group(&self) -> Result { let pattern = unsafe { Pattern::from_raw_full(ffi::cairo_pop_group(self.0.as_ptr())) }; self.status().map(|_| pattern) } #[doc(alias = "cairo_pop_group_to_source")] pub fn pop_group_to_source(&self) -> Result<(), Error> { unsafe { ffi::cairo_pop_group_to_source(self.0.as_ptr()) }; self.status() } #[doc(alias = "get_group_target")] #[doc(alias = "cairo_get_group_target")] pub fn group_target(&self) -> Surface { unsafe { Surface::from_raw_none(ffi::cairo_get_group_target(self.0.as_ptr())) } } #[doc(alias = "cairo_set_source_rgb")] pub fn set_source_rgb(&self, red: f64, green: f64, blue: f64) { unsafe { ffi::cairo_set_source_rgb(self.0.as_ptr(), red, green, blue) } } #[doc(alias = "cairo_set_source_rgba")] pub fn set_source_rgba(&self, red: f64, green: f64, blue: f64, alpha: f64) { unsafe { ffi::cairo_set_source_rgba(self.0.as_ptr(), red, green, blue, alpha) } } #[doc(alias = "cairo_set_source")] pub fn set_source(&self, source: impl AsRef) -> Result<(), Error> { let source = source.as_ref(); source.status()?; unsafe { ffi::cairo_set_source(self.0.as_ptr(), source.to_raw_none()); } self.status() } #[doc(alias = "get_source")] #[doc(alias = "cairo_get_source")] pub fn source(&self) -> Pattern { unsafe { Pattern::from_raw_none(ffi::cairo_get_source(self.0.as_ptr())) } } #[doc(alias = "cairo_set_source_surface")] pub fn set_source_surface( &self, surface: impl AsRef, x: f64, y: f64, ) -> Result<(), Error> { let surface = surface.as_ref(); surface.status()?; unsafe { ffi::cairo_set_source_surface(self.0.as_ptr(), surface.to_raw_none(), x, y); } self.status() } #[doc(alias = "cairo_set_antialias")] pub fn set_antialias(&self, antialias: Antialias) { unsafe { ffi::cairo_set_antialias(self.0.as_ptr(), antialias.into()) } } #[doc(alias = "get_antialias")] #[doc(alias = "cairo_get_antialias")] pub fn antialias(&self) -> Antialias { unsafe { Antialias::from(ffi::cairo_get_antialias(self.0.as_ptr())) } } #[doc(alias = "cairo_set_dash")] pub fn set_dash(&self, dashes: &[f64], offset: f64) { unsafe { ffi::cairo_set_dash( self.0.as_ptr(), dashes.as_ptr(), dashes.len() as i32, offset, ) } } #[doc(alias = "get_dash_count")] #[doc(alias = "cairo_get_dash_count")] pub fn dash_count(&self) -> i32 { unsafe { ffi::cairo_get_dash_count(self.0.as_ptr()) } } #[doc(alias = "get_dash")] #[doc(alias = "cairo_get_dash")] pub fn dash(&self) -> (Vec, f64) { let dash_count = self.dash_count() as usize; let mut dashes: Vec = Vec::with_capacity(dash_count); let mut offset: f64 = 0.0; unsafe { ffi::cairo_get_dash(self.0.as_ptr(), dashes.as_mut_ptr(), &mut offset); dashes.set_len(dash_count); (dashes, offset) } } #[doc(alias = "get_dash_dashes")] pub fn dash_dashes(&self) -> Vec { let (dashes, _) = self.dash(); dashes } #[doc(alias = "get_dash_offset")] pub fn dash_offset(&self) -> f64 { let (_, offset) = self.dash(); offset } #[doc(alias = "cairo_set_fill_rule")] pub fn set_fill_rule(&self, fill_rule: FillRule) { unsafe { ffi::cairo_set_fill_rule(self.0.as_ptr(), fill_rule.into()); } } #[doc(alias = "get_fill_rule")] #[doc(alias = "cairo_get_fill_rule")] pub fn fill_rule(&self) -> FillRule { unsafe { FillRule::from(ffi::cairo_get_fill_rule(self.0.as_ptr())) } } #[doc(alias = "cairo_set_line_cap")] pub fn set_line_cap(&self, arg: LineCap) { unsafe { ffi::cairo_set_line_cap(self.0.as_ptr(), arg.into()) } } #[doc(alias = "get_line_cap")] #[doc(alias = "cairo_get_line_cap")] pub fn line_cap(&self) -> LineCap { unsafe { LineCap::from(ffi::cairo_get_line_cap(self.0.as_ptr())) } } #[doc(alias = "cairo_set_line_join")] pub fn set_line_join(&self, arg: LineJoin) { unsafe { ffi::cairo_set_line_join(self.0.as_ptr(), arg.into()) } } #[doc(alias = "get_line_join")] #[doc(alias = "cairo_get_line_join")] pub fn line_join(&self) -> LineJoin { unsafe { LineJoin::from(ffi::cairo_get_line_join(self.0.as_ptr())) } } #[doc(alias = "cairo_set_line_width")] pub fn set_line_width(&self, arg: f64) { unsafe { ffi::cairo_set_line_width(self.0.as_ptr(), arg) } } #[doc(alias = "get_line_width")] #[doc(alias = "cairo_get_line_width")] pub fn line_width(&self) -> f64 { unsafe { ffi::cairo_get_line_width(self.0.as_ptr()) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "cairo_set_hairline")] pub fn set_hairline(&self, set_hairline: bool) { unsafe { ffi::cairo_set_hairline(self.0.as_ptr(), set_hairline.into()) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "get_hairline")] #[doc(alias = "cairo_get_hairline")] pub fn hairline(&self) -> bool { unsafe { ffi::cairo_get_hairline(self.0.as_ptr()) }.as_bool() } #[doc(alias = "cairo_set_miter_limit")] pub fn set_miter_limit(&self, arg: f64) { unsafe { ffi::cairo_set_miter_limit(self.0.as_ptr(), arg) } } #[doc(alias = "get_miter_limit")] #[doc(alias = "cairo_get_miter_limit")] pub fn miter_limit(&self) -> f64 { unsafe { ffi::cairo_get_miter_limit(self.0.as_ptr()) } } #[doc(alias = "cairo_set_operator")] pub fn set_operator(&self, op: Operator) { unsafe { ffi::cairo_set_operator(self.0.as_ptr(), op.into()); } } #[doc(alias = "get_operator")] #[doc(alias = "cairo_get_operator")] pub fn operator(&self) -> Operator { unsafe { Operator::from(ffi::cairo_get_operator(self.0.as_ptr())) } } #[doc(alias = "cairo_set_tolerance")] pub fn set_tolerance(&self, arg: f64) { unsafe { ffi::cairo_set_tolerance(self.0.as_ptr(), arg) } } #[doc(alias = "get_tolerance")] #[doc(alias = "cairo_get_tolerance")] pub fn tolerance(&self) -> f64 { unsafe { ffi::cairo_get_tolerance(self.0.as_ptr()) } } #[doc(alias = "cairo_clip")] pub fn clip(&self) { unsafe { ffi::cairo_clip(self.0.as_ptr()) } } #[doc(alias = "cairo_clip_preserve")] pub fn clip_preserve(&self) { unsafe { ffi::cairo_clip_preserve(self.0.as_ptr()) } } #[doc(alias = "cairo_clip_extents")] pub fn clip_extents(&self) -> Result<(f64, f64, f64, f64), Error> { let mut x1: f64 = 0.0; let mut y1: f64 = 0.0; let mut x2: f64 = 0.0; let mut y2: f64 = 0.0; unsafe { ffi::cairo_clip_extents(self.0.as_ptr(), &mut x1, &mut y1, &mut x2, &mut y2); } self.status().map(|_| (x1, y1, x2, y2)) } #[doc(alias = "cairo_in_clip")] pub fn in_clip(&self, x: f64, y: f64) -> Result { let in_clip = unsafe { ffi::cairo_in_clip(self.0.as_ptr(), x, y).as_bool() }; self.status().map(|_| in_clip) } #[doc(alias = "cairo_reset_clip")] pub fn reset_clip(&self) { unsafe { ffi::cairo_reset_clip(self.0.as_ptr()) } } #[doc(alias = "cairo_copy_clip_rectangle_list")] pub fn copy_clip_rectangle_list(&self) -> Result { unsafe { let rectangle_list = ffi::cairo_copy_clip_rectangle_list(self.0.as_ptr()); status_to_result((*rectangle_list).status)?; Ok(RectangleList { ptr: rectangle_list, }) } } #[doc(alias = "cairo_fill")] pub fn fill(&self) -> Result<(), Error> { unsafe { ffi::cairo_fill(self.0.as_ptr()) }; self.status() } #[doc(alias = "cairo_fill_preserve")] pub fn fill_preserve(&self) -> Result<(), Error> { unsafe { ffi::cairo_fill_preserve(self.0.as_ptr()) }; self.status() } #[doc(alias = "cairo_fill_extents")] pub fn fill_extents(&self) -> Result<(f64, f64, f64, f64), Error> { let mut x1: f64 = 0.0; let mut y1: f64 = 0.0; let mut x2: f64 = 0.0; let mut y2: f64 = 0.0; unsafe { ffi::cairo_fill_extents(self.0.as_ptr(), &mut x1, &mut y1, &mut x2, &mut y2); } self.status().map(|_| (x1, y1, x2, y2)) } #[doc(alias = "cairo_in_fill")] pub fn in_fill(&self, x: f64, y: f64) -> Result { let in_fill = unsafe { ffi::cairo_in_fill(self.0.as_ptr(), x, y).as_bool() }; self.status().map(|_| in_fill) } #[doc(alias = "cairo_mask")] pub fn mask(&self, pattern: impl AsRef) -> Result<(), Error> { let pattern = pattern.as_ref(); pattern.status()?; unsafe { ffi::cairo_mask(self.0.as_ptr(), pattern.to_raw_none()) }; self.status() } #[doc(alias = "cairo_mask_surface")] pub fn mask_surface(&self, surface: impl AsRef, x: f64, y: f64) -> Result<(), Error> { let surface = surface.as_ref(); surface.status()?; unsafe { ffi::cairo_mask_surface(self.0.as_ptr(), surface.to_raw_none(), x, y); }; self.status() } #[doc(alias = "cairo_paint")] pub fn paint(&self) -> Result<(), Error> { unsafe { ffi::cairo_paint(self.0.as_ptr()) }; self.status() } #[doc(alias = "cairo_paint_with_alpha")] pub fn paint_with_alpha(&self, alpha: f64) -> Result<(), Error> { unsafe { ffi::cairo_paint_with_alpha(self.0.as_ptr(), alpha) }; self.status() } #[doc(alias = "cairo_stroke")] pub fn stroke(&self) -> Result<(), Error> { unsafe { ffi::cairo_stroke(self.0.as_ptr()) }; self.status() } #[doc(alias = "cairo_stroke_preserve")] pub fn stroke_preserve(&self) -> Result<(), Error> { unsafe { ffi::cairo_stroke_preserve(self.0.as_ptr()) }; self.status() } #[doc(alias = "cairo_stroke_extents")] pub fn stroke_extents(&self) -> Result<(f64, f64, f64, f64), Error> { let mut x1: f64 = 0.0; let mut y1: f64 = 0.0; let mut x2: f64 = 0.0; let mut y2: f64 = 0.0; unsafe { ffi::cairo_stroke_extents(self.0.as_ptr(), &mut x1, &mut y1, &mut x2, &mut y2); } self.status().map(|_| (x1, y1, x2, y2)) } #[doc(alias = "cairo_in_stroke")] pub fn in_stroke(&self, x: f64, y: f64) -> Result { let in_stroke = unsafe { ffi::cairo_in_stroke(self.0.as_ptr(), x, y).as_bool() }; self.status().map(|_| in_stroke) } #[doc(alias = "cairo_copy_page")] pub fn copy_page(&self) -> Result<(), Error> { unsafe { ffi::cairo_copy_page(self.0.as_ptr()) }; self.status() } #[doc(alias = "cairo_show_page")] pub fn show_page(&self) -> Result<(), Error> { unsafe { ffi::cairo_show_page(self.0.as_ptr()) }; self.status() } #[doc(alias = "get_reference_count")] pub fn reference_count(&self) -> u32 { unsafe { ffi::cairo_get_reference_count(self.0.as_ptr()) } } // transformations stuff #[doc(alias = "cairo_translate")] pub fn translate(&self, tx: f64, ty: f64) { unsafe { ffi::cairo_translate(self.0.as_ptr(), tx, ty) } } #[doc(alias = "cairo_scale")] pub fn scale(&self, sx: f64, sy: f64) { unsafe { ffi::cairo_scale(self.0.as_ptr(), sx, sy) } } #[doc(alias = "cairo_rotate")] pub fn rotate(&self, angle: f64) { unsafe { ffi::cairo_rotate(self.0.as_ptr(), angle) } } #[doc(alias = "cairo_transform")] pub fn transform(&self, matrix: Matrix) { unsafe { ffi::cairo_transform(self.0.as_ptr(), matrix.ptr()); } } #[doc(alias = "cairo_set_matrix")] pub fn set_matrix(&self, matrix: Matrix) { unsafe { ffi::cairo_set_matrix(self.0.as_ptr(), matrix.ptr()); } } #[doc(alias = "get_matrix")] #[doc(alias = "cairo_get_matrix")] pub fn matrix(&self) -> Matrix { let mut matrix = Matrix::null(); unsafe { ffi::cairo_get_matrix(self.0.as_ptr(), matrix.mut_ptr()); } matrix } #[doc(alias = "cairo_identity_matrix")] pub fn identity_matrix(&self) { unsafe { ffi::cairo_identity_matrix(self.0.as_ptr()) } } #[doc(alias = "cairo_user_to_device")] pub fn user_to_device(&self, mut x: f64, mut y: f64) -> (f64, f64) { unsafe { ffi::cairo_user_to_device(self.0.as_ptr(), &mut x, &mut y); (x, y) } } #[doc(alias = "cairo_user_to_device_distance")] pub fn user_to_device_distance(&self, mut dx: f64, mut dy: f64) -> Result<(f64, f64), Error> { unsafe { ffi::cairo_user_to_device_distance(self.0.as_ptr(), &mut dx, &mut dy); }; self.status().map(|_| (dx, dy)) } #[doc(alias = "cairo_device_to_user")] pub fn device_to_user(&self, mut x: f64, mut y: f64) -> Result<(f64, f64), Error> { unsafe { ffi::cairo_device_to_user(self.0.as_ptr(), &mut x, &mut y); } self.status().map(|_| (x, y)) } #[doc(alias = "cairo_device_to_user_distance")] pub fn device_to_user_distance(&self, mut dx: f64, mut dy: f64) -> Result<(f64, f64), Error> { unsafe { ffi::cairo_device_to_user_distance(self.0.as_ptr(), &mut dx, &mut dy); } self.status().map(|_| (dx, dy)) } // font stuff #[doc(alias = "cairo_select_font_face")] pub fn select_font_face(&self, family: &str, slant: FontSlant, weight: FontWeight) { unsafe { let family = CString::new(family).unwrap(); ffi::cairo_select_font_face( self.0.as_ptr(), family.as_ptr(), slant.into(), weight.into(), ) } } #[doc(alias = "cairo_set_font_size")] pub fn set_font_size(&self, size: f64) { unsafe { ffi::cairo_set_font_size(self.0.as_ptr(), size) } } // FIXME probably needs a heap allocation #[doc(alias = "cairo_set_font_matrix")] pub fn set_font_matrix(&self, matrix: Matrix) { unsafe { ffi::cairo_set_font_matrix(self.0.as_ptr(), matrix.ptr()) } } #[doc(alias = "get_font_matrix")] #[doc(alias = "cairo_get_font_matrix")] pub fn font_matrix(&self) -> Matrix { let mut matrix = Matrix::null(); unsafe { ffi::cairo_get_font_matrix(self.0.as_ptr(), matrix.mut_ptr()); } matrix } #[doc(alias = "cairo_set_font_options")] pub fn set_font_options(&self, options: &FontOptions) { unsafe { ffi::cairo_set_font_options(self.0.as_ptr(), options.to_raw_none()) } } #[doc(alias = "get_font_options")] #[doc(alias = "cairo_get_font_options")] pub fn font_options(&self) -> Result { let out = FontOptions::new()?; unsafe { ffi::cairo_get_font_options(self.0.as_ptr(), out.to_raw_none()); } Ok(out) } #[doc(alias = "cairo_set_font_face")] pub fn set_font_face(&self, font_face: &FontFace) { unsafe { ffi::cairo_set_font_face(self.0.as_ptr(), font_face.to_raw_none()) } } #[doc(alias = "get_font_face")] #[doc(alias = "cairo_get_font_face")] pub fn font_face(&self) -> FontFace { unsafe { FontFace::from_raw_none(ffi::cairo_get_font_face(self.0.as_ptr())) } } #[doc(alias = "cairo_set_scaled_font")] pub fn set_scaled_font(&self, scaled_font: &ScaledFont) { unsafe { ffi::cairo_set_scaled_font(self.0.as_ptr(), scaled_font.to_raw_none()) } } #[doc(alias = "get_scaled_font")] #[doc(alias = "cairo_get_scaled_font")] pub fn scaled_font(&self) -> ScaledFont { unsafe { ScaledFont::from_raw_none(ffi::cairo_get_scaled_font(self.0.as_ptr())) } } #[doc(alias = "cairo_show_text")] pub fn show_text(&self, text: &str) -> Result<(), Error> { unsafe { let text = CString::new(text).unwrap(); ffi::cairo_show_text(self.0.as_ptr(), text.as_ptr()) }; self.status() } #[doc(alias = "cairo_show_glyphs")] pub fn show_glyphs(&self, glyphs: &[Glyph]) -> Result<(), Error> { unsafe { ffi::cairo_show_glyphs( self.0.as_ptr(), glyphs.as_ptr() as *const _, glyphs.len() as _, ) }; self.status() } #[doc(alias = "cairo_show_text_glyphs")] pub fn show_text_glyphs( &self, text: &str, glyphs: &[Glyph], clusters: &[TextCluster], cluster_flags: TextClusterFlags, ) -> Result<(), Error> { unsafe { let text = CString::new(text).unwrap(); ffi::cairo_show_text_glyphs( self.0.as_ptr(), text.as_ptr(), -1_i32, //NULL terminated glyphs.as_ptr() as *const _, glyphs.len() as _, clusters.as_ptr() as *const _, clusters.len() as _, cluster_flags.into(), ) }; self.status() } #[doc(alias = "cairo_font_extents")] pub fn font_extents(&self) -> Result { let mut extents = MaybeUninit::::uninit(); unsafe { ffi::cairo_font_extents(self.0.as_ptr(), extents.as_mut_ptr() as *mut _); self.status().map(|_| extents.assume_init() as _) } } #[doc(alias = "cairo_text_extents")] pub fn text_extents(&self, text: &str) -> Result { let mut extents = MaybeUninit::::uninit(); unsafe { let text = CString::new(text).unwrap(); ffi::cairo_text_extents( self.0.as_ptr(), text.as_ptr(), extents.as_mut_ptr() as *mut _, ); self.status().map(|_| extents.assume_init()) } } #[doc(alias = "cairo_glyph_extents")] pub fn glyph_extents(&self, glyphs: &[Glyph]) -> Result { let mut extents = MaybeUninit::::uninit(); unsafe { ffi::cairo_glyph_extents( self.0.as_ptr(), glyphs.as_ptr() as *const _, glyphs.len() as _, extents.as_mut_ptr() as *mut _, ); self.status().map(|_| extents.assume_init()) } } // paths stuff #[doc(alias = "cairo_copy_path")] pub fn copy_path(&self) -> Result { let path = unsafe { Path::from_raw_full(ffi::cairo_copy_path(self.0.as_ptr())) }; self.status().map(|_| path) } #[doc(alias = "cairo_copy_path_flat")] pub fn copy_path_flat(&self) -> Result { let path = unsafe { Path::from_raw_full(ffi::cairo_copy_path_flat(self.0.as_ptr())) }; self.status().map(|_| path) } #[doc(alias = "cairo_append_path")] pub fn append_path(&self, path: &Path) { unsafe { ffi::cairo_append_path(self.0.as_ptr(), path.as_ptr()) } } #[doc(alias = "cairo_has_current_point")] pub fn has_current_point(&self) -> Result { let has_current_point = unsafe { ffi::cairo_has_current_point(self.0.as_ptr()).as_bool() }; self.status().map(|_| has_current_point) } #[doc(alias = "get_current_point")] #[doc(alias = "cairo_get_current_point")] pub fn current_point(&self) -> Result<(f64, f64), Error> { unsafe { let mut x = 0.0; let mut y = 0.0; ffi::cairo_get_current_point(self.0.as_ptr(), &mut x, &mut y); self.status().map(|_| (x, y)) } } #[doc(alias = "cairo_new_path")] pub fn new_path(&self) { unsafe { ffi::cairo_new_path(self.0.as_ptr()) } } #[doc(alias = "cairo_new_sub_path")] pub fn new_sub_path(&self) { unsafe { ffi::cairo_new_sub_path(self.0.as_ptr()) } } #[doc(alias = "cairo_close_path")] pub fn close_path(&self) { unsafe { ffi::cairo_close_path(self.0.as_ptr()) } } #[doc(alias = "cairo_arc")] pub fn arc(&self, xc: f64, yc: f64, radius: f64, angle1: f64, angle2: f64) { unsafe { ffi::cairo_arc(self.0.as_ptr(), xc, yc, radius, angle1, angle2) } } #[doc(alias = "cairo_arc_negative")] pub fn arc_negative(&self, xc: f64, yc: f64, radius: f64, angle1: f64, angle2: f64) { unsafe { ffi::cairo_arc_negative(self.0.as_ptr(), xc, yc, radius, angle1, angle2) } } #[doc(alias = "cairo_curve_to")] pub fn curve_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) { unsafe { ffi::cairo_curve_to(self.0.as_ptr(), x1, y1, x2, y2, x3, y3) } } #[doc(alias = "cairo_line_to")] pub fn line_to(&self, x: f64, y: f64) { unsafe { ffi::cairo_line_to(self.0.as_ptr(), x, y) } } #[doc(alias = "cairo_move_to")] pub fn move_to(&self, x: f64, y: f64) { unsafe { ffi::cairo_move_to(self.0.as_ptr(), x, y) } } #[doc(alias = "cairo_rectangle")] pub fn rectangle(&self, x: f64, y: f64, width: f64, height: f64) { unsafe { ffi::cairo_rectangle(self.0.as_ptr(), x, y, width, height) } } #[doc(alias = "cairo_text_path")] pub fn text_path(&self, str_: &str) { unsafe { let str_ = CString::new(str_).unwrap(); ffi::cairo_text_path(self.0.as_ptr(), str_.as_ptr()) } } #[doc(alias = "cairo_glyph_path")] pub fn glyph_path(&self, glyphs: &[Glyph]) { unsafe { ffi::cairo_glyph_path( self.0.as_ptr(), glyphs.as_ptr() as *const _, glyphs.len() as _, ) } } #[doc(alias = "cairo_rel_curve_to")] pub fn rel_curve_to(&self, dx1: f64, dy1: f64, dx2: f64, dy2: f64, dx3: f64, dy3: f64) { unsafe { ffi::cairo_rel_curve_to(self.0.as_ptr(), dx1, dy1, dx2, dy2, dx3, dy3) } } #[doc(alias = "cairo_rel_line_to")] pub fn rel_line_to(&self, dx: f64, dy: f64) { unsafe { ffi::cairo_rel_line_to(self.0.as_ptr(), dx, dy) } } #[doc(alias = "cairo_rel_move_to")] pub fn rel_move_to(&self, dx: f64, dy: f64) { unsafe { ffi::cairo_rel_move_to(self.0.as_ptr(), dx, dy) } } #[doc(alias = "cairo_path_extents")] pub fn path_extents(&self) -> Result<(f64, f64, f64, f64), Error> { let mut x1: f64 = 0.0; let mut y1: f64 = 0.0; let mut x2: f64 = 0.0; let mut y2: f64 = 0.0; unsafe { ffi::cairo_path_extents(self.0.as_ptr(), &mut x1, &mut y1, &mut x2, &mut y2); } self.status().map(|_| (x1, y1, x2, y2)) } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "cairo_tag_begin")] pub fn tag_begin(&self, tag_name: &str, attributes: &str) { unsafe { let tag_name = CString::new(tag_name).unwrap(); let attributes = CString::new(attributes).unwrap(); ffi::cairo_tag_begin(self.0.as_ptr(), tag_name.as_ptr(), attributes.as_ptr()) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "cairo_tag_end")] pub fn tag_end(&self, tag_name: &str) { unsafe { let tag_name = CString::new(tag_name).unwrap(); ffi::cairo_tag_end(self.0.as_ptr(), tag_name.as_ptr()) } } } #[cfg(test)] mod tests { use float_eq::float_eq; use super::*; use crate::{enums::Format, image_surface::ImageSurface, patterns::LinearGradient}; fn create_ctx() -> Context { let surface = ImageSurface::create(Format::ARgb32, 10, 10).unwrap(); Context::new(&surface).expect("Can't create a Cairo context") } #[test] fn invalid_surface_cant_create_context() { unsafe { // The size here will create an image surface in an error state let image_surf = ffi::cairo_image_surface_create(Format::ARgb32.into(), 100_000, 100_000); // from_raw_none() as from_raw_full() checks the surface status, and we *want* // a surface in an error state. let wrapped = Surface::from_raw_none(image_surf); assert!(Context::new(&wrapped).is_err()); ffi::cairo_surface_destroy(image_surf); } } #[test] fn drop_non_reference_pattern_from_ctx() { let ctx = create_ctx(); ctx.source(); } #[test] fn drop_non_reference_pattern() { let ctx = create_ctx(); let pattern = LinearGradient::new(1.0f64, 2.0f64, 3.0f64, 4.0f64); ctx.set_source(&pattern).expect("Invalid surface state"); } #[test] fn clip_rectangle() { let ctx = create_ctx(); let rect = ctx .copy_clip_rectangle_list() .expect("Failed to copy rectangle list"); let first_rect = rect[0]; assert!(float_eq!(first_rect.x(), 0.0, abs <= 0.000_1)); assert!(float_eq!(first_rect.y(), 0.0, abs <= 0.000_1)); assert!(float_eq!(first_rect.width(), 10.0, abs <= 0.000_1)); assert!(float_eq!(first_rect.height(), 10.0, abs <= 0.000_1)); } } cairo-rs-0.20.1/src/device.rs000064400000000000000000000306421046102023000140240ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(feature = "script")] use std::ffi::CString; #[cfg(feature = "use_glib")] use std::marker::PhantomData; #[cfg(feature = "script")] use std::path::Path; use std::ptr; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, utils::status_to_result, DeviceType, Error}; #[cfg(feature = "script")] use crate::{Content, RecordingSurface, ScriptMode, Surface}; #[derive(Debug)] #[must_use = "if unused the Device will immediately be released"] pub struct DeviceAcquireGuard<'a>(&'a Device); impl<'a> Drop for DeviceAcquireGuard<'a> { #[inline] fn drop(&mut self) { self.0.release(); } } #[derive(Debug)] #[doc(alias = "cairo_device_t")] #[repr(transparent)] pub struct Device(ptr::NonNull); impl Device { #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_device_t) -> Device { debug_assert!(!ptr.is_null()); ffi::cairo_device_reference(ptr); Device(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_device_t) -> crate::Borrowed { debug_assert!(!ptr.is_null()); crate::Borrowed::new(Device(ptr::NonNull::new_unchecked(ptr))) } #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_device_t) -> Device { debug_assert!(!ptr.is_null()); Device(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_device_t { self.0.as_ptr() } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[doc(alias = "cairo_script_create")] pub fn create>(filename: P) -> Option { unsafe { let filename = filename.as_ref().to_string_lossy().into_owned(); let filename = CString::new(filename).unwrap(); let p = ffi::cairo_script_create(filename.as_ptr()); if p.is_null() { None } else { Some(Self::from_raw_full(p)) } } } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[doc(alias = "cairo_script_from_recording_surface")] pub fn from_recording_surface(&self, surface: &RecordingSurface) -> Result<(), Error> { unsafe { let status = ffi::cairo_script_from_recording_surface(self.to_raw_none(), surface.to_raw_none()); status_to_result(status) } } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[doc(alias = "cairo_script_get_mode")] #[doc(alias = "get_mode")] pub fn mode(&self) -> ScriptMode { unsafe { ScriptMode::from(ffi::cairo_script_get_mode(self.to_raw_none())) } } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[doc(alias = "cairo_script_set_mode")] pub fn set_mode(&self, mode: ScriptMode) { unsafe { ffi::cairo_script_set_mode(self.to_raw_none(), mode.into()) } } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[doc(alias = "cairo_script_surface_create")] pub fn surface_create( &self, content: Content, width: f64, height: f64, ) -> Result { unsafe { Surface::from_raw_full(ffi::cairo_script_surface_create( self.to_raw_none(), content.into(), width, height, )) } } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[doc(alias = "cairo_script_surface_create_for_target")] pub fn surface_create_for_target(&self, target: impl AsRef) -> Result { let target = target.as_ref(); target.status()?; unsafe { Surface::from_raw_full(ffi::cairo_script_surface_create_for_target( self.to_raw_none(), target.to_raw_none(), )) } } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[doc(alias = "cairo_script_write_comment")] pub fn write_comment(&self, comment: &str) { unsafe { let len = comment.len(); let comment = CString::new(comment).unwrap(); ffi::cairo_script_write_comment(self.to_raw_none(), comment.as_ptr(), len as i32) } } #[doc(alias = "cairo_device_finish")] pub fn finish(&self) { unsafe { ffi::cairo_device_finish(self.to_raw_none()) } } #[doc(alias = "cairo_device_flush")] pub fn flush(&self) { unsafe { ffi::cairo_device_flush(self.to_raw_none()) } } #[doc(alias = "cairo_device_get_type")] #[doc(alias = "get_type")] pub fn type_(&self) -> DeviceType { unsafe { DeviceType::from(ffi::cairo_device_get_type(self.to_raw_none())) } } #[doc(alias = "cairo_device_acquire")] pub fn acquire(&self) -> Result { unsafe { let status = ffi::cairo_device_acquire(self.to_raw_none()); status_to_result(status)?; } Ok(DeviceAcquireGuard(self)) } #[doc(alias = "cairo_device_release")] fn release(&self) { unsafe { ffi::cairo_device_release(self.to_raw_none()) } } #[doc(alias = "cairo_device_observer_elapsed")] pub fn observer_elapsed(&self) -> f64 { unsafe { ffi::cairo_device_observer_elapsed(self.to_raw_none()) } } #[doc(alias = "cairo_device_observer_fill_elapsed")] pub fn observer_fill_elapsed(&self) -> f64 { unsafe { ffi::cairo_device_observer_fill_elapsed(self.to_raw_none()) } } #[doc(alias = "cairo_device_observer_glyphs_elapsed")] pub fn observer_glyphs_elapsed(&self) -> f64 { unsafe { ffi::cairo_device_observer_glyphs_elapsed(self.to_raw_none()) } } #[doc(alias = "cairo_device_observer_mask_elapsed")] pub fn observer_mask_elapsed(&self) -> f64 { unsafe { ffi::cairo_device_observer_mask_elapsed(self.to_raw_none()) } } #[doc(alias = "cairo_device_observer_paint_elapsed")] pub fn observer_paint_elapsed(&self) -> f64 { unsafe { ffi::cairo_device_observer_paint_elapsed(self.to_raw_none()) } } #[doc(alias = "cairo_device_observer_stroke_elapsed")] pub fn observer_stroke_elapsed(&self) -> f64 { unsafe { ffi::cairo_device_observer_stroke_elapsed(self.to_raw_none()) } } #[cfg(any(feature = "xlib", feature = "xcb"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "xlib", feature = "xcb"))))] #[doc(alias = "cairo_xlib_device_debug_cap_xrender_version")] #[doc(alias = "cairo_xcb_device_debug_cap_xrender_version")] pub fn debug_cap_xrender_version(&self, _major_version: i32, _minor_version: i32) { match self.type_() { DeviceType::Xlib => { #[cfg(feature = "xlib")] unsafe { ffi::cairo_xlib_device_debug_cap_xrender_version( self.to_raw_none(), _major_version, _minor_version, ) } #[cfg(not(feature = "xlib"))] { panic!("you need to enable \"xlib\" feature") } } DeviceType::Xcb => { #[cfg(feature = "xcb")] unsafe { ffi::cairo_xcb_device_debug_cap_xrender_version( self.to_raw_none(), _major_version, _minor_version, ) } #[cfg(not(feature = "xcb"))] { panic!("you need to enable \"xcb\" feature") } } d => panic!("invalid device type: {:#?}", d), } } #[cfg(any(feature = "xlib", feature = "xcb"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "xlib", feature = "xcb"))))] #[doc(alias = "cairo_xlib_device_debug_get_precision")] #[doc(alias = "cairo_xcb_device_debug_get_precision")] pub fn debug_get_precision(&self) -> i32 { match self.type_() { DeviceType::Xlib => { #[cfg(feature = "xlib")] unsafe { ffi::cairo_xlib_device_debug_get_precision(self.to_raw_none()) } #[cfg(not(feature = "xlib"))] { panic!("you need to enable \"xlib\" feature") } } DeviceType::Xcb => { #[cfg(feature = "xcb")] unsafe { ffi::cairo_xcb_device_debug_get_precision(self.to_raw_none()) } #[cfg(not(feature = "xcb"))] { panic!("you need to enable \"xcb\" feature") } } d => panic!("invalid device type: {:#?}", d), } } #[cfg(any(feature = "xlib", feature = "xcb"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "xlib", feature = "xcb"))))] #[doc(alias = "cairo_xlib_device_debug_set_precision")] #[doc(alias = "cairo_xcb_device_debug_set_precision")] pub fn debug_set_precision(&self, _precision: i32) { match self.type_() { DeviceType::Xlib => { #[cfg(feature = "xlib")] unsafe { ffi::cairo_xlib_device_debug_set_precision(self.to_raw_none(), _precision) } #[cfg(not(feature = "xlib"))] { panic!("you need to enable \"xlib\" feature") } } DeviceType::Xcb => { #[cfg(feature = "xcb")] unsafe { ffi::cairo_xcb_device_debug_set_precision(self.to_raw_none(), _precision) } #[cfg(not(feature = "xcb"))] { panic!("you need to enable \"xcb\" feature") } } d => panic!("invalid device type: {:#?}", d), } } #[doc(alias = "cairo_device_status")] #[inline] pub fn status(&self) -> Result<(), Error> { let status = unsafe { ffi::cairo_device_status(self.to_raw_none()) }; status_to_result(status) } user_data_methods! { ffi::cairo_device_get_user_data, ffi::cairo_device_set_user_data, } } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl IntoGlibPtr<*mut ffi::cairo_device_t> for Device { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::cairo_device_t { std::mem::ManuallyDrop::new(self).to_glib_none().0 } } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl<'a> ToGlibPtr<'a, *mut ffi::cairo_device_t> for Device { type Storage = PhantomData<&'a Device>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_device_t, Self> { Stash(self.to_raw_none(), PhantomData) } #[inline] fn to_glib_full(&self) -> *mut ffi::cairo_device_t { unsafe { ffi::cairo_device_reference(self.to_raw_none()) } } } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl FromGlibPtrNone<*mut ffi::cairo_device_t> for Device { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::cairo_device_t) -> Device { Self::from_raw_none(ptr) } } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl FromGlibPtrBorrow<*mut ffi::cairo_device_t> for Device { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_device_t) -> crate::Borrowed { Self::from_raw_borrow(ptr) } } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] impl FromGlibPtrFull<*mut ffi::cairo_device_t> for Device { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::cairo_device_t) -> Device { Self::from_raw_full(ptr) } } #[cfg(feature = "use_glib")] gvalue_impl!( Device, ffi::cairo_device_t, ffi::gobject::cairo_gobject_device_get_type ); impl Clone for Device { #[inline] fn clone(&self) -> Device { unsafe { Self::from_raw_none(ffi::cairo_device_reference(self.0.as_ptr())) } } } impl Drop for Device { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_device_destroy(self.0.as_ptr()); } } } cairo-rs-0.20.1/src/enums.rs000064400000000000000000001460251046102023000137170ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::fmt::Debug; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, Error}; // Helper macro for our GValue related trait impls #[cfg(feature = "use_glib")] macro_rules! gvalue_impl { ($name:ty, $get_type:expr) => { impl glib::prelude::StaticType for $name { #[inline] fn static_type() -> glib::Type { unsafe { from_glib($get_type()) } } } impl glib::value::ValueType for $name { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for $name { type Checker = glib::value::GenericValueTypeChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { Self::from(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl glib::value::ToValue for $name { fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, (*self).into()); } value } fn value_type(&self) -> glib::Type { ::static_type() } } impl From<$name> for glib::Value { #[inline] fn from(v: $name) -> Self { glib::value::ToValue::to_value(&v) } } }; } #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_antialias_t")] pub enum Antialias { #[doc(alias = "ANTIALIAS_DEFAULT")] Default, /* method */ #[doc(alias = "ANTIALIAS_NONE")] None, #[doc(alias = "ANTIALIAS_GRAY")] Gray, #[doc(alias = "ANTIALIAS_SUBPIXEL")] Subpixel, /* hints */ #[doc(alias = "ANTIALIAS_FAST")] Fast, #[doc(alias = "ANTIALIAS_GOOD")] Good, #[doc(alias = "ANTIALIAS_BEST")] Best, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_antialias_t { fn from(val: Antialias) -> ffi::cairo_antialias_t { match val { Antialias::Default => ffi::ANTIALIAS_DEFAULT, Antialias::None => ffi::ANTIALIAS_NONE, Antialias::Gray => ffi::ANTIALIAS_GRAY, Antialias::Subpixel => ffi::ANTIALIAS_SUBPIXEL, Antialias::Fast => ffi::ANTIALIAS_FAST, Antialias::Good => ffi::ANTIALIAS_GOOD, Antialias::Best => ffi::ANTIALIAS_BEST, Antialias::__Unknown(value) => value, } } } #[doc(hidden)] impl From for Antialias { fn from(value: ffi::cairo_antialias_t) -> Self { match value { ffi::ANTIALIAS_DEFAULT => Self::Default, ffi::ANTIALIAS_NONE => Self::None, ffi::ANTIALIAS_GRAY => Self::Gray, ffi::ANTIALIAS_SUBPIXEL => Self::Subpixel, ffi::ANTIALIAS_FAST => Self::Fast, ffi::ANTIALIAS_GOOD => Self::Good, ffi::ANTIALIAS_BEST => Self::Best, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(Antialias, ffi::gobject::cairo_gobject_antialias_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_fill_rule_t")] pub enum FillRule { #[doc(alias = "FILL_RULE_WINDING")] Winding, #[doc(alias = "FILL_RULE_EVEN_ODD")] EvenOdd, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_fill_rule_t { fn from(val: FillRule) -> ffi::cairo_fill_rule_t { match val { FillRule::Winding => ffi::FILL_RULE_WINDING, FillRule::EvenOdd => ffi::FILL_RULE_EVEN_ODD, FillRule::__Unknown(value) => value, } } } #[doc(hidden)] impl From for FillRule { fn from(value: ffi::cairo_fill_rule_t) -> Self { match value { ffi::FILL_RULE_WINDING => Self::Winding, ffi::FILL_RULE_EVEN_ODD => Self::EvenOdd, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(FillRule, ffi::gobject::cairo_gobject_fill_rule_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_line_cap_t")] pub enum LineCap { #[doc(alias = "LINE_CAP_BUTT")] Butt, #[doc(alias = "LINE_CAP_ROUND")] Round, #[doc(alias = "LINE_CAP_SQUARE")] Square, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_line_cap_t { fn from(val: LineCap) -> ffi::cairo_line_cap_t { match val { LineCap::Butt => ffi::LINE_CAP_BUTT, LineCap::Round => ffi::LINE_CAP_ROUND, LineCap::Square => ffi::LINE_CAP_SQUARE, LineCap::__Unknown(value) => value, } } } #[doc(hidden)] impl From for LineCap { fn from(value: ffi::cairo_line_cap_t) -> Self { match value { ffi::LINE_CAP_BUTT => Self::Butt, ffi::LINE_CAP_ROUND => Self::Round, ffi::LINE_CAP_SQUARE => Self::Square, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(LineCap, ffi::gobject::cairo_gobject_line_cap_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_line_join_t")] pub enum LineJoin { #[doc(alias = "LINE_JOIN_MITER")] Miter, #[doc(alias = "LINE_JOIN_ROUND")] Round, #[doc(alias = "LINE_JOIN_BEVEL")] Bevel, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_line_join_t { fn from(val: LineJoin) -> ffi::cairo_line_join_t { match val { LineJoin::Miter => ffi::LINE_JOIN_MITER, LineJoin::Round => ffi::LINE_JOIN_ROUND, LineJoin::Bevel => ffi::LINE_JOIN_BEVEL, LineJoin::__Unknown(value) => value, } } } #[doc(hidden)] impl From for LineJoin { fn from(value: ffi::cairo_line_join_t) -> Self { match value { ffi::LINE_JOIN_MITER => Self::Miter, ffi::LINE_JOIN_ROUND => Self::Round, ffi::LINE_JOIN_BEVEL => Self::Bevel, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(LineJoin, ffi::gobject::cairo_gobject_line_join_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_operator_t")] pub enum Operator { #[doc(alias = "OPERATOR_CLEAR")] Clear, #[doc(alias = "OPERATOR_SOURCE")] Source, #[doc(alias = "OPERATOR_OVER")] Over, #[doc(alias = "OPERATOR_IN")] In, #[doc(alias = "OPERATOR_OUT")] Out, #[doc(alias = "OPERATOR_ATOP")] Atop, #[doc(alias = "OPERATOR_DEST")] Dest, #[doc(alias = "OPERATOR_DEST_OVER")] DestOver, #[doc(alias = "OPERATOR_DEST_IN")] DestIn, #[doc(alias = "OPERATOR_DEST_OUT")] DestOut, #[doc(alias = "OPERATOR_DEST_ATOP")] DestAtop, #[doc(alias = "OPERATOR_XOR")] Xor, #[doc(alias = "OPERATOR_ADD")] Add, #[doc(alias = "OPERATOR_SATURATE")] Saturate, #[doc(alias = "OPERATOR_MULTIPLY")] Multiply, #[doc(alias = "OPERATOR_SCREEN")] Screen, #[doc(alias = "OPERATOR_OVERLAY")] Overlay, #[doc(alias = "OPERATOR_DARKEN")] Darken, #[doc(alias = "OPERATOR_LIGHTEN")] Lighten, #[doc(alias = "OPERATOR_COLOR_DODGE")] ColorDodge, #[doc(alias = "OPERATOR_COLOR_BURN")] ColorBurn, #[doc(alias = "OPERATOR_HARD_LIGHT")] HardLight, #[doc(alias = "OPERATOR_SOFT_LIGHT")] SoftLight, #[doc(alias = "OPERATOR_DIFFERENCE")] Difference, #[doc(alias = "OPERATOR_EXCLUSION")] Exclusion, #[doc(alias = "OPERATOR_HSL_HUE")] HslHue, #[doc(alias = "OPERATOR_HSL_SATURATION")] HslSaturation, #[doc(alias = "OPERATOR_HSL_COLOR")] HslColor, #[doc(alias = "OPERATOR_HSL_LUMINOSITY")] HslLuminosity, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_operator_t { fn from(val: Operator) -> ffi::cairo_operator_t { match val { Operator::Clear => ffi::OPERATOR_CLEAR, Operator::Source => ffi::OPERATOR_SOURCE, Operator::Over => ffi::OPERATOR_OVER, Operator::In => ffi::OPERATOR_IN, Operator::Out => ffi::OPERATOR_OUT, Operator::Atop => ffi::OPERATOR_ATOP, Operator::Dest => ffi::OPERATOR_DEST, Operator::DestOver => ffi::OPERATOR_DEST_OVER, Operator::DestIn => ffi::OPERATOR_DEST_IN, Operator::DestOut => ffi::OPERATOR_DEST_OUT, Operator::DestAtop => ffi::OPERATOR_DEST_ATOP, Operator::Xor => ffi::OPERATOR_XOR, Operator::Add => ffi::OPERATOR_ADD, Operator::Saturate => ffi::OPERATOR_SATURATE, Operator::Multiply => ffi::OPERATOR_MULTIPLY, Operator::Screen => ffi::OPERATOR_SCREEN, Operator::Overlay => ffi::OPERATOR_OVERLAY, Operator::Darken => ffi::OPERATOR_DARKEN, Operator::Lighten => ffi::OPERATOR_LIGHTEN, Operator::ColorDodge => ffi::OPERATOR_COLOR_DODGE, Operator::ColorBurn => ffi::OPERATOR_COLOR_BURN, Operator::HardLight => ffi::OPERATOR_HARD_LIGHT, Operator::SoftLight => ffi::OPERATOR_SOFT_LIGHT, Operator::Difference => ffi::OPERATOR_DIFFERENCE, Operator::Exclusion => ffi::OPERATOR_EXCLUSION, Operator::HslHue => ffi::OPERATOR_HSL_HUE, Operator::HslSaturation => ffi::OPERATOR_HSL_SATURATION, Operator::HslColor => ffi::OPERATOR_HSL_COLOR, Operator::HslLuminosity => ffi::OPERATOR_HSL_LUMINOSITY, Operator::__Unknown(value) => value, } } } #[doc(hidden)] impl From for Operator { fn from(value: ffi::cairo_operator_t) -> Self { match value { ffi::OPERATOR_CLEAR => Self::Clear, ffi::OPERATOR_SOURCE => Self::Source, ffi::OPERATOR_OVER => Self::Over, ffi::OPERATOR_IN => Self::In, ffi::OPERATOR_OUT => Self::Out, ffi::OPERATOR_ATOP => Self::Atop, ffi::OPERATOR_DEST => Self::Dest, ffi::OPERATOR_DEST_OVER => Self::DestOver, ffi::OPERATOR_DEST_IN => Self::DestIn, ffi::OPERATOR_DEST_OUT => Self::DestOut, ffi::OPERATOR_DEST_ATOP => Self::DestAtop, ffi::OPERATOR_XOR => Self::Xor, ffi::OPERATOR_ADD => Self::Add, ffi::OPERATOR_SATURATE => Self::Saturate, ffi::OPERATOR_MULTIPLY => Self::Multiply, ffi::OPERATOR_SCREEN => Self::Screen, ffi::OPERATOR_OVERLAY => Self::Overlay, ffi::OPERATOR_DARKEN => Self::Darken, ffi::OPERATOR_LIGHTEN => Self::Lighten, ffi::OPERATOR_COLOR_DODGE => Self::ColorDodge, ffi::OPERATOR_COLOR_BURN => Self::ColorBurn, ffi::OPERATOR_HARD_LIGHT => Self::HardLight, ffi::OPERATOR_SOFT_LIGHT => Self::SoftLight, ffi::OPERATOR_DIFFERENCE => Self::Difference, ffi::OPERATOR_EXCLUSION => Self::Exclusion, ffi::OPERATOR_HSL_HUE => Self::HslHue, ffi::OPERATOR_HSL_SATURATION => Self::HslSaturation, ffi::OPERATOR_HSL_COLOR => Self::HslColor, ffi::OPERATOR_HSL_LUMINOSITY => Self::HslLuminosity, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(Operator, ffi::gobject::cairo_gobject_operator_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_path_data_type_t")] pub enum PathDataType { #[doc(alias = "PATH_DATA_TYPE_MOVE_TO")] MoveTo, #[doc(alias = "PATH_DATA_TYPE_LINE_TO")] LineTo, #[doc(alias = "PATH_DATA_TYPE_CURVE_TO")] CurveTo, #[doc(alias = "PATH_DATA_TYPE_CLOSE_PATH")] ClosePath, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_path_data_type_t { fn from(val: PathDataType) -> ffi::cairo_path_data_type_t { match val { PathDataType::MoveTo => ffi::PATH_DATA_TYPE_MOVE_TO, PathDataType::LineTo => ffi::PATH_DATA_TYPE_LINE_TO, PathDataType::CurveTo => ffi::PATH_DATA_TYPE_CURVE_TO, PathDataType::ClosePath => ffi::PATH_DATA_TYPE_CLOSE_PATH, PathDataType::__Unknown(value) => value, } } } #[doc(hidden)] impl From for PathDataType { fn from(value: ffi::cairo_path_data_type_t) -> Self { match value { ffi::PATH_DATA_TYPE_MOVE_TO => Self::MoveTo, ffi::PATH_DATA_TYPE_LINE_TO => Self::LineTo, ffi::PATH_DATA_TYPE_CURVE_TO => Self::CurveTo, ffi::PATH_DATA_TYPE_CLOSE_PATH => Self::ClosePath, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!( PathDataType, ffi::gobject::cairo_gobject_path_data_type_get_type ); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_content_t")] pub enum Content { #[doc(alias = "CONTENT_COLOR")] Color, #[doc(alias = "CONTENT_ALPHA")] Alpha, #[doc(alias = "CONTENT_COLOR_ALPHA")] ColorAlpha, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_content_t { fn from(val: Content) -> ffi::cairo_content_t { match val { Content::Color => ffi::CONTENT_COLOR, Content::Alpha => ffi::CONTENT_ALPHA, Content::ColorAlpha => ffi::CONTENT_COLOR_ALPHA, Content::__Unknown(value) => value, } } } #[doc(hidden)] impl From for Content { fn from(value: ffi::cairo_content_t) -> Self { match value { ffi::CONTENT_COLOR => Self::Color, ffi::CONTENT_ALPHA => Self::Alpha, ffi::CONTENT_COLOR_ALPHA => Self::ColorAlpha, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(Content, ffi::gobject::cairo_gobject_content_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_extend_t")] pub enum Extend { #[doc(alias = "EXTEND_NONE")] None, #[doc(alias = "EXTEND_REPEAT")] Repeat, #[doc(alias = "EXTEND_REFLECT")] Reflect, #[doc(alias = "EXTEND_PAD")] Pad, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_extend_t { fn from(val: Extend) -> ffi::cairo_extend_t { match val { Extend::None => ffi::EXTEND_NONE, Extend::Repeat => ffi::EXTEND_REPEAT, Extend::Reflect => ffi::EXTEND_REFLECT, Extend::Pad => ffi::EXTEND_PAD, Extend::__Unknown(value) => value, } } } #[doc(hidden)] impl From for Extend { fn from(value: ffi::cairo_extend_t) -> Self { match value { ffi::EXTEND_NONE => Self::None, ffi::EXTEND_REPEAT => Self::Repeat, ffi::EXTEND_REFLECT => Self::Reflect, ffi::EXTEND_PAD => Self::Pad, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(Extend, ffi::gobject::cairo_gobject_extend_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_filter_t")] pub enum Filter { #[doc(alias = "FILTER_FAST")] Fast, #[doc(alias = "FILTER_GOOD")] Good, #[doc(alias = "FILTER_BEST")] Best, #[doc(alias = "FILTER_NEAREST")] Nearest, #[doc(alias = "FILTER_BILINEAR")] Bilinear, #[doc(alias = "FILTER_GAUSSIAN")] Gaussian, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_filter_t { fn from(val: Filter) -> ffi::cairo_filter_t { match val { Filter::Fast => ffi::FILTER_FAST, Filter::Good => ffi::FILTER_GOOD, Filter::Best => ffi::FILTER_BEST, Filter::Nearest => ffi::FILTER_NEAREST, Filter::Bilinear => ffi::FILTER_BILINEAR, Filter::Gaussian => ffi::FILTER_GAUSSIAN, Filter::__Unknown(value) => value, } } } #[doc(hidden)] impl From for Filter { fn from(value: ffi::cairo_filter_t) -> Self { match value { ffi::FILTER_FAST => Self::Fast, ffi::FILTER_GOOD => Self::Good, ffi::FILTER_BEST => Self::Best, ffi::FILTER_NEAREST => Self::Nearest, ffi::FILTER_BILINEAR => Self::Bilinear, ffi::FILTER_GAUSSIAN => Self::Gaussian, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(Filter, ffi::gobject::cairo_gobject_filter_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_pattern_type_t")] pub enum PatternType { #[doc(alias = "PATTERN_TYPE_SOLID")] Solid, #[doc(alias = "PATTERN_TYPE_SURFACE")] Surface, #[doc(alias = "PATTERN_TYPE_LINEAR_GRADIENT")] LinearGradient, #[doc(alias = "PATTERN_TYPE_RADIAL_GRADIENT")] RadialGradient, #[doc(alias = "PATTERN_TYPE_MESH")] Mesh, #[doc(alias = "PATTERN_TYPE_RASTER_SOURCE")] RasterSource, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_pattern_type_t { fn from(val: PatternType) -> ffi::cairo_pattern_type_t { match val { PatternType::Solid => ffi::PATTERN_TYPE_SOLID, PatternType::Surface => ffi::PATTERN_TYPE_SURFACE, PatternType::LinearGradient => ffi::PATTERN_TYPE_LINEAR_GRADIENT, PatternType::RadialGradient => ffi::PATTERN_TYPE_RADIAL_GRADIENT, PatternType::Mesh => ffi::PATTERN_TYPE_MESH, PatternType::RasterSource => ffi::PATTERN_TYPE_RASTER_SOURCE, PatternType::__Unknown(value) => value, } } } #[doc(hidden)] impl From for PatternType { fn from(value: ffi::cairo_pattern_type_t) -> Self { match value { ffi::PATTERN_TYPE_SOLID => Self::Solid, ffi::PATTERN_TYPE_SURFACE => Self::Surface, ffi::PATTERN_TYPE_LINEAR_GRADIENT => Self::LinearGradient, ffi::PATTERN_TYPE_RADIAL_GRADIENT => Self::RadialGradient, ffi::PATTERN_TYPE_MESH => Self::Mesh, ffi::PATTERN_TYPE_RASTER_SOURCE => Self::RasterSource, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!( PatternType, ffi::gobject::cairo_gobject_pattern_type_get_type ); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_font_slant_t")] pub enum FontSlant { #[doc(alias = "FONT_SLANT_NORMAL")] Normal, #[doc(alias = "FONT_SLANT_ITALIC")] Italic, #[doc(alias = "FONT_SLANT_OBLIQUE")] Oblique, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_font_slant_t { fn from(val: FontSlant) -> ffi::cairo_font_slant_t { match val { FontSlant::Normal => ffi::FONT_SLANT_NORMAL, FontSlant::Italic => ffi::FONT_SLANT_ITALIC, FontSlant::Oblique => ffi::FONT_SLANT_OBLIQUE, FontSlant::__Unknown(value) => value, } } } #[doc(hidden)] impl From for FontSlant { fn from(value: ffi::cairo_font_slant_t) -> Self { match value { ffi::FONT_SLANT_NORMAL => Self::Normal, ffi::FONT_SLANT_ITALIC => Self::Italic, ffi::FONT_SLANT_OBLIQUE => Self::Oblique, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(FontSlant, ffi::gobject::cairo_gobject_font_slant_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_font_weight_t")] pub enum FontWeight { #[doc(alias = "FONT_WEIGHT_NORMAL")] Normal, #[doc(alias = "FONT_WEIGHT_BOLD")] Bold, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_font_weight_t { fn from(val: FontWeight) -> ffi::cairo_font_weight_t { match val { FontWeight::Normal => ffi::FONT_WEIGHT_NORMAL, FontWeight::Bold => ffi::FONT_WEIGHT_BOLD, FontWeight::__Unknown(value) => value, } } } #[doc(hidden)] impl From for FontWeight { fn from(value: ffi::cairo_font_weight_t) -> Self { match value { ffi::FONT_WEIGHT_NORMAL => Self::Normal, ffi::FONT_WEIGHT_BOLD => Self::Bold, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(FontWeight, ffi::gobject::cairo_gobject_font_weight_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_text_cluster_flags_t")] pub enum TextClusterFlags { #[doc(alias = "TEXT_CLUSTER_FLAGS_NONE")] None, #[doc(alias = "TEXT_CLUSTER_FLAGS_BACKWARD")] Backward, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_text_cluster_flags_t { fn from(val: TextClusterFlags) -> ffi::cairo_text_cluster_flags_t { match val { TextClusterFlags::None => ffi::TEXT_CLUSTER_FLAGS_NONE, TextClusterFlags::Backward => ffi::TEXT_CLUSTER_FLAGS_BACKWARD, TextClusterFlags::__Unknown(value) => value, } } } #[doc(hidden)] impl From for TextClusterFlags { fn from(value: ffi::cairo_text_cluster_flags_t) -> Self { match value { ffi::TEXT_CLUSTER_FLAGS_NONE => Self::None, ffi::TEXT_CLUSTER_FLAGS_BACKWARD => Self::Backward, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!( TextClusterFlags, ffi::gobject::cairo_gobject_text_cluster_flags_get_type ); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_font_type_t")] pub enum FontType { #[doc(alias = "FONT_TYPE_FONT_TYPE_TOY")] FontTypeToy, #[doc(alias = "FONT_TYPE_FONT_TYPE_FT")] FontTypeFt, #[doc(alias = "FONT_TYPE_FONT_TYPE_WIN32")] FontTypeWin32, #[doc(alias = "FONT_TYPE_FONT_TYPE_QUARTZ")] FontTypeQuartz, #[doc(alias = "FONT_TYPE_FONT_TYPE_USER")] FontTypeUser, #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "FONT_TYPE_FONT_TYPE_DWRITE")] FontTypeDwrite, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_font_type_t { fn from(val: FontType) -> ffi::cairo_font_type_t { match val { FontType::FontTypeToy => ffi::FONT_TYPE_FONT_TYPE_TOY, FontType::FontTypeFt => ffi::FONT_TYPE_FONT_TYPE_FT, FontType::FontTypeWin32 => ffi::FONT_TYPE_FONT_TYPE_WIN32, FontType::FontTypeQuartz => ffi::FONT_TYPE_FONT_TYPE_QUARTZ, FontType::FontTypeUser => ffi::FONT_TYPE_FONT_TYPE_USER, #[cfg(feature = "v1_18")] FontType::FontTypeDwrite => ffi::FONT_TYPE_FONT_TYPE_DWRITE, FontType::__Unknown(value) => value, } } } #[doc(hidden)] impl From for FontType { fn from(value: ffi::cairo_font_type_t) -> Self { match value { ffi::FONT_TYPE_FONT_TYPE_TOY => Self::FontTypeToy, ffi::FONT_TYPE_FONT_TYPE_FT => Self::FontTypeFt, ffi::FONT_TYPE_FONT_TYPE_WIN32 => Self::FontTypeWin32, ffi::FONT_TYPE_FONT_TYPE_QUARTZ => Self::FontTypeQuartz, ffi::FONT_TYPE_FONT_TYPE_USER => Self::FontTypeUser, #[cfg(feature = "v1_18")] ffi::FONT_TYPE_FONT_TYPE_DWRITE => Self::FontTypeDwrite, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(FontType, ffi::gobject::cairo_gobject_font_type_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_subpixel_order_t")] pub enum SubpixelOrder { #[doc(alias = "SUBPIXEL_ORDER_DEFAULT")] Default, #[doc(alias = "SUBPIXEL_ORDER_RGB")] Rgb, #[doc(alias = "SUBPIXEL_ORDER_BGR")] Bgr, #[doc(alias = "SUBPIXEL_ORDER_VRGB")] Vrgb, #[doc(alias = "SUBPIXEL_ORDER_VBGR")] Vbgr, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_subpixel_order_t { fn from(val: SubpixelOrder) -> ffi::cairo_subpixel_order_t { match val { SubpixelOrder::Default => ffi::SUBPIXEL_ORDER_DEFAULT, SubpixelOrder::Rgb => ffi::SUBPIXEL_ORDER_RGB, SubpixelOrder::Bgr => ffi::SUBPIXEL_ORDER_BGR, SubpixelOrder::Vrgb => ffi::SUBPIXEL_ORDER_VRGB, SubpixelOrder::Vbgr => ffi::SUBPIXEL_ORDER_VBGR, SubpixelOrder::__Unknown(value) => value, } } } #[doc(hidden)] impl From for SubpixelOrder { fn from(value: ffi::cairo_subpixel_order_t) -> Self { match value { ffi::SUBPIXEL_ORDER_DEFAULT => Self::Default, ffi::SUBPIXEL_ORDER_RGB => Self::Rgb, ffi::SUBPIXEL_ORDER_BGR => Self::Bgr, ffi::SUBPIXEL_ORDER_VRGB => Self::Vrgb, ffi::SUBPIXEL_ORDER_VBGR => Self::Vbgr, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!( SubpixelOrder, ffi::gobject::cairo_gobject_subpixel_order_get_type ); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_hint_style_t")] pub enum HintStyle { #[doc(alias = "HINT_STYLE_DEFAULT")] Default, #[doc(alias = "HINT_STYLE_NONE")] None, #[doc(alias = "HINT_STYLE_SLIGHT")] Slight, #[doc(alias = "HINT_STYLE_MEDIUM")] Medium, #[doc(alias = "HINT_STYLE_FULL")] Full, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_hint_style_t { fn from(val: HintStyle) -> ffi::cairo_hint_style_t { match val { HintStyle::Default => ffi::HINT_STYLE_DEFAULT, HintStyle::None => ffi::HINT_STYLE_NONE, HintStyle::Slight => ffi::HINT_STYLE_SLIGHT, HintStyle::Medium => ffi::HINT_STYLE_MEDIUM, HintStyle::Full => ffi::HINT_STYLE_FULL, HintStyle::__Unknown(value) => value, } } } #[doc(hidden)] impl From for HintStyle { fn from(value: ffi::cairo_hint_style_t) -> Self { match value { ffi::HINT_STYLE_DEFAULT => Self::Default, ffi::HINT_STYLE_NONE => Self::None, ffi::HINT_STYLE_SLIGHT => Self::Slight, ffi::HINT_STYLE_MEDIUM => Self::Medium, ffi::HINT_STYLE_FULL => Self::Full, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(HintStyle, ffi::gobject::cairo_gobject_hint_style_get_type); #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_hint_metrics_t")] pub enum HintMetrics { #[doc(alias = "HINT_METRICS_DEFAULT")] Default, #[doc(alias = "HINT_METRICS_OFF")] Off, #[doc(alias = "HINT_METRICS_ON")] On, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_hint_metrics_t { fn from(val: HintMetrics) -> ffi::cairo_hint_metrics_t { match val { HintMetrics::Default => ffi::HINT_METRICS_DEFAULT, HintMetrics::Off => ffi::HINT_METRICS_OFF, HintMetrics::On => ffi::HINT_METRICS_ON, HintMetrics::__Unknown(value) => value, } } } #[doc(hidden)] impl From for HintMetrics { fn from(value: ffi::cairo_hint_metrics_t) -> Self { match value { ffi::HINT_METRICS_DEFAULT => Self::Default, ffi::HINT_METRICS_OFF => Self::Off, ffi::HINT_METRICS_ON => Self::On, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!( HintMetrics, ffi::gobject::cairo_gobject_hint_metrics_get_type ); #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[non_exhaustive] #[doc(alias = "cairo_surface_type_t")] pub enum SurfaceType { #[doc(alias = "SURFACE_TYPE_IMAGE")] Image, #[doc(alias = "SURFACE_TYPE_PDF")] Pdf, #[doc(alias = "SURFACE_TYPE_PS")] Ps, #[doc(alias = "SURFACE_TYPE_XLIB")] Xlib, #[doc(alias = "SURFACE_TYPE_XCB")] Xcb, #[doc(alias = "SURFACE_TYPE_GLITZ")] Glitz, #[doc(alias = "SURFACE_TYPE_QUARTZ")] Quartz, #[doc(alias = "SURFACE_TYPE_WIN32")] Win32, #[doc(alias = "SURFACE_TYPE_BE_OS")] BeOs, #[doc(alias = "SURFACE_TYPE_DIRECT_FB")] DirectFb, #[doc(alias = "SURFACE_TYPE_SVG")] Svg, #[doc(alias = "SURFACE_TYPE_OS2")] Os2, #[doc(alias = "SURFACE_TYPE_WIN32_PRINTING")] Win32Printing, #[doc(alias = "SURFACE_TYPE_QUARTZ_IMAGE")] QuartzImage, #[doc(alias = "SURFACE_TYPE_SCRIPT")] Script, #[doc(alias = "SURFACE_TYPE_QT")] Qt, #[doc(alias = "SURFACE_TYPE_RECORDING")] Recording, #[doc(alias = "SURFACE_TYPE_VG")] Vg, #[doc(alias = "SURFACE_TYPE_GL")] Gl, #[doc(alias = "SURFACE_TYPE_DRM")] Drm, #[doc(alias = "SURFACE_TYPE_TEE")] Tee, #[doc(alias = "SURFACE_TYPE_XML")] Xml, #[doc(alias = "SURFACE_TYPE_SKIA")] Skia, #[doc(alias = "SURFACE_TYPE_SUBSURFACE")] Subsurface, #[doc(alias = "SURFACE_TYPE_COGL")] Cogl, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_surface_type_t { fn from(val: SurfaceType) -> ffi::cairo_surface_type_t { match val { SurfaceType::Image => ffi::SURFACE_TYPE_IMAGE, SurfaceType::Pdf => ffi::SURFACE_TYPE_PDF, SurfaceType::Ps => ffi::SURFACE_TYPE_PS, SurfaceType::Xlib => ffi::SURFACE_TYPE_XLIB, SurfaceType::Xcb => ffi::SURFACE_TYPE_XCB, SurfaceType::Glitz => ffi::SURFACE_TYPE_GLITZ, SurfaceType::Quartz => ffi::SURFACE_TYPE_QUARTZ, SurfaceType::Win32 => ffi::SURFACE_TYPE_WIN32, SurfaceType::BeOs => ffi::SURFACE_TYPE_BE_OS, SurfaceType::DirectFb => ffi::SURFACE_TYPE_DIRECT_FB, SurfaceType::Svg => ffi::SURFACE_TYPE_SVG, SurfaceType::Os2 => ffi::SURFACE_TYPE_OS2, SurfaceType::Win32Printing => ffi::SURFACE_TYPE_WIN32_PRINTING, SurfaceType::QuartzImage => ffi::SURFACE_TYPE_QUARTZ_IMAGE, SurfaceType::Script => ffi::SURFACE_TYPE_SCRIPT, SurfaceType::Qt => ffi::SURFACE_TYPE_QT, SurfaceType::Recording => ffi::SURFACE_TYPE_RECORDING, SurfaceType::Vg => ffi::SURFACE_TYPE_VG, SurfaceType::Gl => ffi::SURFACE_TYPE_GL, SurfaceType::Drm => ffi::SURFACE_TYPE_DRM, SurfaceType::Tee => ffi::SURFACE_TYPE_TEE, SurfaceType::Xml => ffi::SURFACE_TYPE_XML, SurfaceType::Skia => ffi::SURFACE_TYPE_SKIA, SurfaceType::Subsurface => ffi::SURFACE_TYPE_SUBSURFACE, SurfaceType::Cogl => ffi::SURFACE_TYPE_COGL, SurfaceType::__Unknown(value) => value, } } } #[doc(hidden)] impl From for SurfaceType { fn from(value: ffi::cairo_surface_type_t) -> Self { match value { ffi::SURFACE_TYPE_IMAGE => Self::Image, ffi::SURFACE_TYPE_PDF => Self::Pdf, ffi::SURFACE_TYPE_PS => Self::Ps, ffi::SURFACE_TYPE_XLIB => Self::Xlib, ffi::SURFACE_TYPE_XCB => Self::Xcb, ffi::SURFACE_TYPE_GLITZ => Self::Glitz, ffi::SURFACE_TYPE_QUARTZ => Self::Quartz, ffi::SURFACE_TYPE_WIN32 => Self::Win32, ffi::SURFACE_TYPE_BE_OS => Self::BeOs, ffi::SURFACE_TYPE_DIRECT_FB => Self::DirectFb, ffi::SURFACE_TYPE_SVG => Self::Svg, ffi::SURFACE_TYPE_OS2 => Self::Os2, ffi::SURFACE_TYPE_WIN32_PRINTING => Self::Win32Printing, ffi::SURFACE_TYPE_QUARTZ_IMAGE => Self::QuartzImage, ffi::SURFACE_TYPE_SCRIPT => Self::Script, ffi::SURFACE_TYPE_QT => Self::Qt, ffi::SURFACE_TYPE_RECORDING => Self::Recording, ffi::SURFACE_TYPE_VG => Self::Vg, ffi::SURFACE_TYPE_GL => Self::Gl, ffi::SURFACE_TYPE_DRM => Self::Drm, ffi::SURFACE_TYPE_TEE => Self::Tee, ffi::SURFACE_TYPE_XML => Self::Xml, ffi::SURFACE_TYPE_SKIA => Self::Skia, ffi::SURFACE_TYPE_SUBSURFACE => Self::Subsurface, ffi::SURFACE_TYPE_COGL => Self::Cogl, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!( SurfaceType, ffi::gobject::cairo_gobject_surface_type_get_type ); #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg(all(feature = "svg", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "svg", feature = "v1_16"))))] #[non_exhaustive] #[doc(alias = "cairo_svg_unit_t")] pub enum SvgUnit { #[doc(alias = "SVG_UNIT_USER")] User, #[doc(alias = "SVG_UNIT_EM")] Em, #[doc(alias = "SVG_UNIT_EX")] Ex, #[doc(alias = "SVG_UNIT_PX")] Px, #[doc(alias = "SVG_UNIT_IN")] In, #[doc(alias = "SVG_UNIT_CM")] Cm, #[doc(alias = "SVG_UNIT_MM")] Mm, #[doc(alias = "SVG_UNIT_PT")] Pt, #[doc(alias = "SVG_UNIT_PC")] Pc, #[doc(alias = "SVG_UNIT_PERCENT")] Percent, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] #[cfg(all(feature = "svg", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "svg", feature = "v1_16"))))] impl From for ffi::cairo_svg_unit_t { fn from(val: SvgUnit) -> ffi::cairo_svg_unit_t { match val { SvgUnit::User => ffi::SVG_UNIT_USER, SvgUnit::Em => ffi::SVG_UNIT_EM, SvgUnit::Ex => ffi::SVG_UNIT_EX, SvgUnit::Px => ffi::SVG_UNIT_PX, SvgUnit::In => ffi::SVG_UNIT_IN, SvgUnit::Cm => ffi::SVG_UNIT_CM, SvgUnit::Mm => ffi::SVG_UNIT_MM, SvgUnit::Pt => ffi::SVG_UNIT_PT, SvgUnit::Pc => ffi::SVG_UNIT_PC, SvgUnit::Percent => ffi::SVG_UNIT_PERCENT, SvgUnit::__Unknown(value) => value, } } } #[doc(hidden)] #[cfg(all(feature = "svg", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "svg", feature = "v1_16"))))] impl From for SvgUnit { fn from(value: ffi::cairo_svg_unit_t) -> Self { match value { ffi::SVG_UNIT_USER => Self::User, ffi::SVG_UNIT_EM => Self::Em, ffi::SVG_UNIT_EX => Self::Ex, ffi::SVG_UNIT_PX => Self::Px, ffi::SVG_UNIT_IN => Self::In, ffi::SVG_UNIT_CM => Self::Cm, ffi::SVG_UNIT_MM => Self::Mm, ffi::SVG_UNIT_PT => Self::Pt, ffi::SVG_UNIT_PC => Self::Pc, ffi::SVG_UNIT_PERCENT => Self::Percent, value => Self::__Unknown(value), } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[non_exhaustive] #[doc(alias = "cairo_format_t")] pub enum Format { #[doc(alias = "FORMAT_INVALID")] Invalid, #[doc(alias = "FORMAT_A_RGB32")] ARgb32, #[doc(alias = "FORMAT_RGB24")] Rgb24, #[doc(alias = "FORMAT_A8")] A8, #[doc(alias = "FORMAT_A1")] A1, #[doc(alias = "FORMAT_RGB16_565")] Rgb16_565, #[doc(alias = "FORMAT_RGB30")] Rgb30, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_format_t { fn from(val: Format) -> ffi::cairo_format_t { match val { Format::Invalid => ffi::FORMAT_INVALID, Format::ARgb32 => ffi::FORMAT_A_RGB32, Format::Rgb24 => ffi::FORMAT_RGB24, Format::A8 => ffi::FORMAT_A8, Format::A1 => ffi::FORMAT_A1, Format::Rgb16_565 => ffi::FORMAT_RGB16_565, Format::Rgb30 => ffi::FORMAT_RGB30, Format::__Unknown(value) => value, } } } #[doc(hidden)] impl From for Format { fn from(value: ffi::cairo_format_t) -> Self { match value { ffi::FORMAT_INVALID => Self::Invalid, ffi::FORMAT_A_RGB32 => Self::ARgb32, ffi::FORMAT_RGB24 => Self::Rgb24, ffi::FORMAT_A8 => Self::A8, ffi::FORMAT_A1 => Self::A1, ffi::FORMAT_RGB16_565 => Self::Rgb16_565, ffi::FORMAT_RGB30 => Self::Rgb30, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(Format, ffi::gobject::cairo_gobject_format_get_type); impl Format { #[doc(alias = "cairo_format_stride_for_width")] pub fn stride_for_width(self, width: u32) -> Result { assert!(width <= i32::MAX as u32); let width = width as i32; let stride = unsafe { ffi::cairo_format_stride_for_width(self.into(), width) }; if stride == -1 { Err(Error::InvalidFormat) } else { Ok(stride) } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[non_exhaustive] #[doc(alias = "cairo_region_overlap_t")] pub enum RegionOverlap { #[doc(alias = "REGION_OVERLAP_IN")] In, #[doc(alias = "REGION_OVERLAP_OUT")] Out, #[doc(alias = "REGION_OVERLAP_PART")] Part, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_region_overlap_t { fn from(val: RegionOverlap) -> ffi::cairo_region_overlap_t { match val { RegionOverlap::In => ffi::REGION_OVERLAP_IN, RegionOverlap::Out => ffi::REGION_OVERLAP_OUT, RegionOverlap::Part => ffi::REGION_OVERLAP_PART, RegionOverlap::__Unknown(value) => value, } } } #[doc(hidden)] impl From for RegionOverlap { fn from(value: ffi::cairo_region_overlap_t) -> Self { match value { ffi::REGION_OVERLAP_IN => Self::In, ffi::REGION_OVERLAP_OUT => Self::Out, ffi::REGION_OVERLAP_PART => Self::Part, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!( RegionOverlap, ffi::gobject::cairo_gobject_region_overlap_get_type ); bitflags::bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct PdfOutline: i32 { #[doc(alias = "PDF_OUTLINE_FLAG_OPEN")] const OPEN = ffi::PDF_OUTLINE_FLAG_OPEN; #[doc(alias = "PDF_OUTLINE_FLAG_BOLD")] const BOLD = ffi::PDF_OUTLINE_FLAG_BOLD; #[doc(alias = "PDF_OUTLINE_FLAG_ITALIC")] const ITALIC = ffi::PDF_OUTLINE_FLAG_ITALIC; } } #[cfg(feature = "pdf")] #[cfg_attr(docsrs, doc(cfg(feature = "pdf")))] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[non_exhaustive] #[doc(alias = "cairo_pdf_metadata_t")] pub enum PdfMetadata { #[doc(alias = "PDF_METADATA_TITLE")] Title, #[doc(alias = "PDF_METADATA_AUTHOR")] Author, #[doc(alias = "PDF_METADATA_SUBJECT")] Subject, #[doc(alias = "PDF_METADATA_KEYWORDS")] Keywords, #[doc(alias = "PDF_METADATA_CREATOR")] Creator, #[doc(alias = "PDF_METADATA_CREATE_DATE")] CreateDate, #[doc(alias = "PDF_METADATA_MOD_DATE")] ModDate, #[doc(hidden)] __Unknown(i32), } #[cfg(all(feature = "pdf", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "pdf", feature = "v1_16"))))] #[doc(hidden)] impl From for ffi::cairo_pdf_metadata_t { fn from(val: PdfMetadata) -> ffi::cairo_pdf_metadata_t { match val { PdfMetadata::Title => ffi::PDF_METADATA_TITLE, PdfMetadata::Author => ffi::PDF_METADATA_AUTHOR, PdfMetadata::Subject => ffi::PDF_METADATA_SUBJECT, PdfMetadata::Keywords => ffi::PDF_METADATA_KEYWORDS, PdfMetadata::Creator => ffi::PDF_METADATA_CREATOR, PdfMetadata::CreateDate => ffi::PDF_METADATA_CREATE_DATE, PdfMetadata::ModDate => ffi::PDF_METADATA_MOD_DATE, PdfMetadata::__Unknown(value) => value, } } } #[cfg(all(feature = "pdf", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "pdf", feature = "v1_16"))))] #[doc(hidden)] impl From for PdfMetadata { fn from(value: ffi::cairo_pdf_metadata_t) -> Self { match value { ffi::PDF_METADATA_TITLE => Self::Title, ffi::PDF_METADATA_AUTHOR => Self::Author, ffi::PDF_METADATA_SUBJECT => Self::Subject, ffi::PDF_METADATA_KEYWORDS => Self::Keywords, ffi::PDF_METADATA_CREATOR => Self::Creator, ffi::PDF_METADATA_CREATE_DATE => Self::CreateDate, ffi::PDF_METADATA_MOD_DATE => Self::ModDate, value => Self::__Unknown(value), } } } #[cfg(feature = "pdf")] #[cfg_attr(docsrs, doc(cfg(feature = "pdf")))] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[non_exhaustive] #[doc(alias = "cairo_pdf_version_t")] pub enum PdfVersion { #[doc(alias = "PDF_VERSION__1_4")] _1_4, #[doc(alias = "PDF_VERSION__1_5")] _1_5, #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "PDF_VERSION__1_6")] _1_6, #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "PDF_VERSION__1_7")] _1_7, #[doc(hidden)] __Unknown(i32), } #[cfg(feature = "pdf")] #[cfg_attr(docsrs, doc(cfg(feature = "pdf")))] #[doc(hidden)] impl From for ffi::cairo_pdf_version_t { fn from(val: PdfVersion) -> ffi::cairo_pdf_version_t { match val { PdfVersion::_1_4 => ffi::PDF_VERSION__1_4, PdfVersion::_1_5 => ffi::PDF_VERSION__1_5, #[cfg(feature = "v1_18")] PdfVersion::_1_6 => ffi::PDF_VERSION__1_6, #[cfg(feature = "v1_18")] PdfVersion::_1_7 => ffi::PDF_VERSION__1_7, PdfVersion::__Unknown(value) => value, } } } #[cfg(feature = "pdf")] #[cfg_attr(docsrs, doc(cfg(feature = "pdf")))] #[doc(hidden)] impl From for PdfVersion { fn from(value: ffi::cairo_pdf_version_t) -> Self { match value { ffi::PDF_VERSION__1_4 => Self::_1_4, ffi::PDF_VERSION__1_5 => Self::_1_5, #[cfg(feature = "v1_18")] ffi::PDF_VERSION__1_6 => Self::_1_6, #[cfg(feature = "v1_18")] ffi::PDF_VERSION__1_7 => Self::_1_7, value => Self::__Unknown(value), } } } #[cfg(feature = "svg")] #[cfg_attr(docsrs, doc(cfg(feature = "svg")))] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[non_exhaustive] #[doc(alias = "cairo_svg_version_t")] pub enum SvgVersion { #[doc(alias = "SVG_VERSION__1_1")] _1_1, #[doc(alias = "SVG_VERSION__1_2")] _1_2, #[doc(hidden)] __Unknown(i32), } #[cfg(feature = "svg")] #[cfg_attr(docsrs, doc(cfg(feature = "svg")))] #[doc(hidden)] impl From for ffi::cairo_svg_version_t { fn from(val: SvgVersion) -> ffi::cairo_svg_version_t { match val { SvgVersion::_1_1 => ffi::SVG_VERSION__1_1, SvgVersion::_1_2 => ffi::SVG_VERSION__1_2, SvgVersion::__Unknown(value) => value, } } } #[cfg(feature = "svg")] #[cfg_attr(docsrs, doc(cfg(feature = "svg")))] #[doc(hidden)] impl From for SvgVersion { fn from(value: ffi::cairo_svg_version_t) -> Self { match value { ffi::SVG_VERSION__1_1 => Self::_1_1, ffi::SVG_VERSION__1_2 => Self::_1_2, value => Self::__Unknown(value), } } } #[cfg(feature = "ps")] #[cfg_attr(docsrs, doc(cfg(feature = "ps")))] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[non_exhaustive] #[doc(alias = "cairo_ps_level_t")] pub enum PsLevel { #[doc(alias = "PS_LEVEL__2")] _2, #[doc(alias = "PS_LEVEL__3")] _3, #[doc(hidden)] __Unknown(i32), } #[cfg(feature = "ps")] #[cfg_attr(docsrs, doc(cfg(feature = "ps")))] #[doc(hidden)] impl From for ffi::cairo_ps_level_t { fn from(val: PsLevel) -> ffi::cairo_ps_level_t { match val { PsLevel::_2 => ffi::PS_LEVEL__2, PsLevel::_3 => ffi::PS_LEVEL__3, PsLevel::__Unknown(value) => value, } } } #[cfg(feature = "ps")] #[cfg_attr(docsrs, doc(cfg(feature = "ps")))] #[doc(hidden)] impl From for PsLevel { fn from(value: ffi::cairo_ps_level_t) -> Self { match value { ffi::PS_LEVEL__2 => Self::_2, ffi::PS_LEVEL__3 => Self::_3, value => Self::__Unknown(value), } } } #[derive(Clone, PartialEq, Eq, PartialOrd, Copy, Debug)] #[non_exhaustive] #[doc(alias = "cairo_mesh_corner_t")] pub enum MeshCorner { #[doc(alias = "MESH_CORNER_MESH_CORNER0")] MeshCorner0, #[doc(alias = "MESH_CORNER_MESH_CORNER1")] MeshCorner1, #[doc(alias = "MESH_CORNER_MESH_CORNER2")] MeshCorner2, #[doc(alias = "MESH_CORNER_MESH_CORNER3")] MeshCorner3, #[doc(hidden)] __Unknown(u32), } #[doc(hidden)] impl From for ffi::cairo_mesh_corner_t { fn from(val: MeshCorner) -> ffi::cairo_mesh_corner_t { match val { MeshCorner::MeshCorner0 => ffi::MESH_CORNER_MESH_CORNER0, MeshCorner::MeshCorner1 => ffi::MESH_CORNER_MESH_CORNER1, MeshCorner::MeshCorner2 => ffi::MESH_CORNER_MESH_CORNER2, MeshCorner::MeshCorner3 => ffi::MESH_CORNER_MESH_CORNER3, MeshCorner::__Unknown(value) => value, } } } #[doc(hidden)] impl From for MeshCorner { fn from(value: ffi::cairo_mesh_corner_t) -> Self { match value { ffi::MESH_CORNER_MESH_CORNER0 => Self::MeshCorner0, ffi::MESH_CORNER_MESH_CORNER1 => Self::MeshCorner1, ffi::MESH_CORNER_MESH_CORNER2 => Self::MeshCorner2, ffi::MESH_CORNER_MESH_CORNER3 => Self::MeshCorner3, value => Self::__Unknown(value), } } } #[cfg(feature = "freetype")] #[cfg_attr(docsrs, doc(cfg(feature = "freetype")))] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_ft_synthesize_t")] pub enum FtSynthesize { #[doc(alias = "CAIRO_FT_SYNTHESIZE_BOLD")] Bold, #[doc(alias = "CAIRO_FT_SYNTHESIZE_OBLIQUE")] Oblique, #[doc(hidden)] __Unknown(u32), } #[cfg(feature = "freetype")] #[cfg_attr(docsrs, doc(cfg(feature = "freetype")))] #[doc(hidden)] impl From for ffi::cairo_ft_synthesize_t { fn from(val: FtSynthesize) -> ffi::cairo_ft_synthesize_t { match val { FtSynthesize::Bold => ffi::CAIRO_FT_SYNTHESIZE_BOLD, FtSynthesize::Oblique => ffi::CAIRO_FT_SYNTHESIZE_OBLIQUE, FtSynthesize::__Unknown(value) => value, } } } #[cfg(feature = "freetype")] #[cfg_attr(docsrs, doc(cfg(feature = "freetype")))] #[doc(hidden)] impl From for FtSynthesize { fn from(value: ffi::cairo_ft_synthesize_t) -> Self { match value { ffi::CAIRO_FT_SYNTHESIZE_BOLD => Self::Bold, ffi::CAIRO_FT_SYNTHESIZE_OBLIQUE => Self::Oblique, value => Self::__Unknown(value), } } } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_script_mode_t")] pub enum ScriptMode { #[doc(alias = "CAIRO_SCRIPT_MODE_ASCII")] Ascii, #[doc(alias = "CAIRO_SCRIPT_MODE_BINARY")] Binary, #[doc(hidden)] __Unknown(i32), } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[doc(hidden)] impl From for ffi::cairo_script_mode_t { fn from(val: ScriptMode) -> ffi::cairo_script_mode_t { match val { ScriptMode::Ascii => ffi::CAIRO_SCRIPT_MODE_ASCII, ScriptMode::Binary => ffi::CAIRO_SCRIPT_MODE_BINARY, ScriptMode::__Unknown(value) => value, } } } #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] #[doc(hidden)] impl From for ScriptMode { fn from(value: ffi::cairo_script_mode_t) -> Self { match value { ffi::CAIRO_SCRIPT_MODE_ASCII => Self::Ascii, ffi::CAIRO_SCRIPT_MODE_BINARY => Self::Binary, value => Self::__Unknown(value), } } } #[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Copy)] #[non_exhaustive] #[doc(alias = "cairo_device_type_t")] pub enum DeviceType { #[doc(alias = "CAIRO_DEVICE_TYPE_DRM")] Ascii, #[doc(alias = "CAIRO_DEVICE_TYPE_GL")] Binary, #[doc(alias = "CAIRO_DEVICE_TYPE_SCRIPT")] Script, #[doc(alias = "CAIRO_DEVICE_TYPE_XCB")] Xcb, #[doc(alias = "CAIRO_DEVICE_TYPE_XLIB")] Xlib, #[doc(alias = "CAIRO_DEVICE_TYPE_XML")] Xml, #[doc(alias = "CAIRO_DEVICE_TYPE_COGL")] Cogl, #[doc(alias = "CAIRO_DEVICE_TYPE_WIN32")] Win32, #[doc(alias = "CAIRO_DEVICE_TYPE_INVALID")] Invalid, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl From for ffi::cairo_device_type_t { fn from(val: DeviceType) -> ffi::cairo_device_type_t { match val { DeviceType::Ascii => ffi::CAIRO_DEVICE_TYPE_DRM, DeviceType::Binary => ffi::CAIRO_DEVICE_TYPE_GL, DeviceType::Script => ffi::CAIRO_DEVICE_TYPE_SCRIPT, DeviceType::Xcb => ffi::CAIRO_DEVICE_TYPE_XCB, DeviceType::Xlib => ffi::CAIRO_DEVICE_TYPE_XLIB, DeviceType::Xml => ffi::CAIRO_DEVICE_TYPE_XML, DeviceType::Cogl => ffi::CAIRO_DEVICE_TYPE_COGL, DeviceType::Win32 => ffi::CAIRO_DEVICE_TYPE_WIN32, DeviceType::Invalid => ffi::CAIRO_DEVICE_TYPE_INVALID, DeviceType::__Unknown(value) => value, } } } #[doc(hidden)] impl From for DeviceType { fn from(value: ffi::cairo_device_type_t) -> Self { match value { ffi::CAIRO_DEVICE_TYPE_DRM => Self::Ascii, ffi::CAIRO_DEVICE_TYPE_GL => Self::Binary, ffi::CAIRO_DEVICE_TYPE_SCRIPT => Self::Script, ffi::CAIRO_DEVICE_TYPE_XCB => Self::Xcb, ffi::CAIRO_DEVICE_TYPE_XLIB => Self::Xlib, ffi::CAIRO_DEVICE_TYPE_XML => Self::Xml, ffi::CAIRO_DEVICE_TYPE_COGL => Self::Cogl, ffi::CAIRO_DEVICE_TYPE_WIN32 => Self::Win32, ffi::CAIRO_DEVICE_TYPE_INVALID => Self::Invalid, value => Self::__Unknown(value), } } } #[cfg(feature = "use_glib")] gvalue_impl!(DeviceType, ffi::gobject::cairo_gobject_device_type_get_type); #[cfg(test)] mod tests { use super::*; #[test] #[should_panic] fn stride_panics_on_bad_value() { let _ = Format::Rgb24.stride_for_width(u32::MAX); } #[test] fn stride_errors_on_large_width() { assert!(Format::Rgb24.stride_for_width(i32::MAX as u32).is_err()); } #[test] fn stride_works() { assert_eq!(Format::Rgb24.stride_for_width(1).unwrap(), 4); } } cairo-rs-0.20.1/src/error.rs000064400000000000000000000345651046102023000137260ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use std::{fmt, fmt::Debug, io}; #[derive(Debug, Clone, PartialEq, Copy, Eq)] #[non_exhaustive] #[doc(alias = "cairo_status_t")] pub enum Error { #[doc(alias = "STATUS_NO_MEMORY")] NoMemory, #[doc(alias = "STATUS_INVALID_RESTORE")] InvalidRestore, #[doc(alias = "STATUS_INVALID_POP_GROUP")] InvalidPopGroup, #[doc(alias = "STATUS_NO_CURRENT_POINT")] NoCurrentPoint, #[doc(alias = "STATUS_INVALID_MATRIX")] InvalidMatrix, #[doc(alias = "STATUS_INVALID_STATUS")] InvalidStatus, #[doc(alias = "STATUS_NULL_POINTER")] NullPointer, #[doc(alias = "STATUS_INVALID_STRING")] InvalidString, #[doc(alias = "STATUS_INVALID_PATH_DATA")] InvalidPathData, #[doc(alias = "STATUS_READ_ERROR")] ReadError, #[doc(alias = "STATUS_WRITE_ERROR")] WriteError, #[doc(alias = "STATUS_SURFACE_FINISHED")] SurfaceFinished, #[doc(alias = "STATUS_SURFACE_TYPE_MISMATCH")] SurfaceTypeMismatch, #[doc(alias = "STATUS_PATTERN_TYPE_MISMATCH")] PatternTypeMismatch, #[doc(alias = "STATUS_INVALID_CONTENT")] InvalidContent, #[doc(alias = "STATUS_INVALID_FORMAT")] InvalidFormat, #[doc(alias = "STATUS_INVALID_VISUAL")] InvalidVisual, #[doc(alias = "STATUS_FILE_NOT_FOUND")] FileNotFound, #[doc(alias = "STATUS_INVALID_DASH")] InvalidDash, #[doc(alias = "STATUS_INVALID_DSC_COMMENT")] InvalidDscComment, #[doc(alias = "STATUS_INVALID_INDEX")] InvalidIndex, #[doc(alias = "STATUS_CLIP_NOT_REPRESENTABLE")] ClipNotRepresentable, #[doc(alias = "STATUS_TEMP_FILE_ERROR")] TempFileError, #[doc(alias = "STATUS_INVALID_STRIDE")] InvalidStride, #[doc(alias = "STATUS_FONT_TYPE_MISMATCH")] FontTypeMismatch, #[doc(alias = "STATUS_USER_FONT_IMMUTABLE")] UserFontImmutable, #[doc(alias = "STATUS_USER_FONT_ERROR")] UserFontError, #[doc(alias = "STATUS_NEGATIVE_COUNT")] NegativeCount, #[doc(alias = "STATUS_INVALID_CLUSTERS")] InvalidClusters, #[doc(alias = "STATUS_INVALID_SLANT")] InvalidSlant, #[doc(alias = "STATUS_INVALID_WEIGHT")] InvalidWeight, #[doc(alias = "STATUS_INVALID_SIZE")] InvalidSize, #[doc(alias = "STATUS_USER_FONT_NOT_IMPLEMENTED")] UserFontNotImplemented, #[doc(alias = "STATUS_DEVICE_TYPE_MISMATCH")] DeviceTypeMismatch, #[doc(alias = "STATUS_DEVICE_ERROR")] DeviceError, #[doc(alias = "STATUS_INVALID_MESH_CONSTRUCTION")] InvalidMeshConstruction, #[doc(alias = "STATUS_DEVICE_FINISHED")] DeviceFinished, #[doc(alias = "STATUS_J_BIG2_GLOBAL_MISSING")] JBig2GlobalMissing, #[doc(alias = "STATUS_PNG_ERROR")] PngError, #[doc(alias = "STATUS_FREETYPE_ERROR")] FreetypeError, #[doc(alias = "STATUS_WIN32_GDI_ERROR")] Win32GdiError, #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "STATUS_TAG_ERROR")] TagError, #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "STATUS_DWRITE_ERROR")] DwriteError, #[doc(alias = "STATUS_LAST_STATUS")] LastStatus, #[doc(hidden)] __Unknown(i32), } impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Error::NoMemory => fmt.write_str("No Memory"), Error::InvalidRestore => fmt.write_str("Invalid Restore"), Error::InvalidPopGroup => fmt.write_str("Invalid Pop Group"), Error::NoCurrentPoint => fmt.write_str("No Current Point"), Error::InvalidMatrix => fmt.write_str("Invalid Matrix"), Error::InvalidStatus => fmt.write_str("Invalid Status"), Error::NullPointer => fmt.write_str("Null Pointer"), Error::InvalidString => fmt.write_str("Invalid String"), Error::InvalidPathData => fmt.write_str("Invalid Path Data"), Error::ReadError => fmt.write_str("Cairo : Read Error"), Error::WriteError => fmt.write_str("Write Error"), Error::SurfaceFinished => fmt.write_str("Surface Finished"), Error::SurfaceTypeMismatch => fmt.write_str("Surface Type Mismatch"), Error::PatternTypeMismatch => fmt.write_str("Pattern Type Mismatch"), Error::InvalidContent => fmt.write_str("Invalid Content"), Error::InvalidFormat => fmt.write_str("Invalid Format"), Error::InvalidVisual => fmt.write_str("Invalid Visual"), Error::FileNotFound => fmt.write_str("File Not Found"), Error::InvalidDash => fmt.write_str("Invalid Dash"), Error::InvalidDscComment => fmt.write_str("Invalid Dash Comment"), Error::InvalidIndex => fmt.write_str("Invalid Index"), Error::ClipNotRepresentable => fmt.write_str("Clip Not Representable"), Error::TempFileError => fmt.write_str("Temp File Error"), Error::InvalidStride => fmt.write_str("Invalid Stride"), Error::FontTypeMismatch => fmt.write_str("Font Type Mismatch"), Error::UserFontImmutable => fmt.write_str("User Font Immutable"), Error::UserFontError => fmt.write_str("User Font Error"), Error::NegativeCount => fmt.write_str("Negative Count"), Error::InvalidClusters => fmt.write_str("Invalid Clusters"), Error::InvalidSlant => fmt.write_str("Invalid Slant"), Error::InvalidWeight => fmt.write_str("Invalid Weight"), Error::InvalidSize => fmt.write_str("Invalid Size"), Error::UserFontNotImplemented => fmt.write_str("User Font Not Implemented"), Error::DeviceTypeMismatch => fmt.write_str("Device Type Mismatch"), Error::DeviceError => fmt.write_str("Device Error"), Error::InvalidMeshConstruction => fmt.write_str("Invalid Mesh Construction"), Error::DeviceFinished => fmt.write_str("Device Finished"), Error::JBig2GlobalMissing => fmt.write_str("JBig2Global Missing"), Error::PngError => fmt.write_str("PNG Error"), Error::FreetypeError => fmt.write_str("Freetype Error"), Error::Win32GdiError => fmt.write_str("Win32Gdi Error"), #[cfg(feature = "v1_16")] Error::TagError => fmt.write_str("Tag error"), #[cfg(feature = "v1_18")] Error::DwriteError => fmt.write_str("Dwrite error"), Error::LastStatus => fmt.write_str("LastStatus"), Error::__Unknown(value) => write!(fmt, "Unknown {value}"), } } } #[doc(hidden)] impl From for ffi::cairo_status_t { fn from(err: Error) -> Self { match err { Error::NoMemory => ffi::STATUS_NO_MEMORY, Error::InvalidRestore => ffi::STATUS_INVALID_RESTORE, Error::InvalidPopGroup => ffi::STATUS_INVALID_POP_GROUP, Error::NoCurrentPoint => ffi::STATUS_NO_CURRENT_POINT, Error::InvalidMatrix => ffi::STATUS_INVALID_MATRIX, Error::InvalidStatus => ffi::STATUS_INVALID_STATUS, Error::NullPointer => ffi::STATUS_NULL_POINTER, Error::InvalidString => ffi::STATUS_INVALID_STRING, Error::InvalidPathData => ffi::STATUS_INVALID_PATH_DATA, Error::ReadError => ffi::STATUS_READ_ERROR, Error::WriteError => ffi::STATUS_WRITE_ERROR, Error::SurfaceFinished => ffi::STATUS_SURFACE_FINISHED, Error::SurfaceTypeMismatch => ffi::STATUS_SURFACE_TYPE_MISMATCH, Error::PatternTypeMismatch => ffi::STATUS_PATTERN_TYPE_MISMATCH, Error::InvalidContent => ffi::STATUS_INVALID_CONTENT, Error::InvalidFormat => ffi::STATUS_INVALID_FORMAT, Error::InvalidVisual => ffi::STATUS_INVALID_VISUAL, Error::FileNotFound => ffi::STATUS_FILE_NOT_FOUND, Error::InvalidDash => ffi::STATUS_INVALID_DASH, Error::InvalidDscComment => ffi::STATUS_INVALID_DSC_COMMENT, Error::InvalidIndex => ffi::STATUS_INVALID_INDEX, Error::ClipNotRepresentable => ffi::STATUS_CLIP_NOT_REPRESENTABLE, Error::TempFileError => ffi::STATUS_TEMP_FILE_ERROR, Error::InvalidStride => ffi::STATUS_INVALID_STRIDE, Error::FontTypeMismatch => ffi::STATUS_FONT_TYPE_MISMATCH, Error::UserFontImmutable => ffi::STATUS_USER_FONT_IMMUTABLE, Error::UserFontError => ffi::STATUS_USER_FONT_ERROR, Error::NegativeCount => ffi::STATUS_NEGATIVE_COUNT, Error::InvalidClusters => ffi::STATUS_INVALID_CLUSTERS, Error::InvalidSlant => ffi::STATUS_INVALID_SLANT, Error::InvalidWeight => ffi::STATUS_INVALID_WEIGHT, Error::InvalidSize => ffi::STATUS_INVALID_SIZE, Error::UserFontNotImplemented => ffi::STATUS_USER_FONT_NOT_IMPLEMENTED, Error::DeviceTypeMismatch => ffi::STATUS_DEVICE_TYPE_MISMATCH, Error::DeviceError => ffi::STATUS_DEVICE_ERROR, Error::InvalidMeshConstruction => ffi::STATUS_INVALID_MESH_CONSTRUCTION, Error::DeviceFinished => ffi::STATUS_DEVICE_FINISHED, Error::JBig2GlobalMissing => ffi::STATUS_J_BIG2_GLOBAL_MISSING, Error::PngError => ffi::STATUS_PNG_ERROR, Error::FreetypeError => ffi::STATUS_FREETYPE_ERROR, Error::Win32GdiError => ffi::STATUS_WIN32_GDI_ERROR, #[cfg(feature = "v1_16")] Error::TagError => ffi::STATUS_TAG_ERROR, #[cfg(feature = "v1_18")] Error::DwriteError => ffi::STATUS_DWRITE_ERROR, Error::LastStatus => ffi::STATUS_LAST_STATUS, Error::__Unknown(value) => value, } } } #[doc(hidden)] impl From for Error { fn from(value: ffi::cairo_status_t) -> Self { match value { ffi::STATUS_NO_MEMORY => Self::NoMemory, ffi::STATUS_INVALID_RESTORE => Self::InvalidRestore, ffi::STATUS_INVALID_POP_GROUP => Self::InvalidPopGroup, ffi::STATUS_NO_CURRENT_POINT => Self::NoCurrentPoint, ffi::STATUS_INVALID_MATRIX => Self::InvalidMatrix, ffi::STATUS_INVALID_STATUS => Self::InvalidStatus, ffi::STATUS_NULL_POINTER => Self::NullPointer, ffi::STATUS_INVALID_STRING => Self::InvalidString, ffi::STATUS_INVALID_PATH_DATA => Self::InvalidPathData, ffi::STATUS_READ_ERROR => Self::ReadError, ffi::STATUS_WRITE_ERROR => Self::WriteError, ffi::STATUS_SURFACE_FINISHED => Self::SurfaceFinished, ffi::STATUS_SURFACE_TYPE_MISMATCH => Self::SurfaceTypeMismatch, ffi::STATUS_PATTERN_TYPE_MISMATCH => Self::PatternTypeMismatch, ffi::STATUS_INVALID_CONTENT => Self::InvalidContent, ffi::STATUS_INVALID_FORMAT => Self::InvalidFormat, ffi::STATUS_INVALID_VISUAL => Self::InvalidVisual, ffi::STATUS_FILE_NOT_FOUND => Self::FileNotFound, ffi::STATUS_INVALID_DASH => Self::InvalidDash, ffi::STATUS_INVALID_DSC_COMMENT => Self::InvalidDscComment, ffi::STATUS_INVALID_INDEX => Self::InvalidIndex, ffi::STATUS_CLIP_NOT_REPRESENTABLE => Self::ClipNotRepresentable, ffi::STATUS_TEMP_FILE_ERROR => Self::TempFileError, ffi::STATUS_INVALID_STRIDE => Self::InvalidStride, ffi::STATUS_FONT_TYPE_MISMATCH => Self::FontTypeMismatch, ffi::STATUS_USER_FONT_IMMUTABLE => Self::UserFontImmutable, ffi::STATUS_USER_FONT_ERROR => Self::UserFontError, ffi::STATUS_NEGATIVE_COUNT => Self::NegativeCount, ffi::STATUS_INVALID_CLUSTERS => Self::InvalidClusters, ffi::STATUS_INVALID_SLANT => Self::InvalidSlant, ffi::STATUS_INVALID_WEIGHT => Self::InvalidWeight, ffi::STATUS_INVALID_SIZE => Self::InvalidSize, ffi::STATUS_USER_FONT_NOT_IMPLEMENTED => Self::UserFontNotImplemented, ffi::STATUS_DEVICE_TYPE_MISMATCH => Self::DeviceTypeMismatch, ffi::STATUS_DEVICE_ERROR => Self::DeviceError, ffi::STATUS_INVALID_MESH_CONSTRUCTION => Self::InvalidMeshConstruction, ffi::STATUS_DEVICE_FINISHED => Self::DeviceFinished, ffi::STATUS_J_BIG2_GLOBAL_MISSING => Self::JBig2GlobalMissing, ffi::STATUS_PNG_ERROR => Self::PngError, ffi::STATUS_FREETYPE_ERROR => Self::FreetypeError, ffi::STATUS_WIN32_GDI_ERROR => Self::Win32GdiError, #[cfg(feature = "v1_16")] ffi::STATUS_TAG_ERROR => Error::TagError, #[cfg(feature = "v1_18")] ffi::STATUS_DWRITE_ERROR => Error::DwriteError, ffi::STATUS_LAST_STATUS => Self::LastStatus, value => Self::__Unknown(value), } } } #[derive(Debug)] pub enum IoError { Cairo(Error), Io(io::Error), } impl std::error::Error for IoError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { IoError::Cairo(err) => Some(err), IoError::Io(err) => Some(err), } } } impl fmt::Display for IoError { fn fmt(&self, fmt: &mut fmt::Formatter) -> ::core::fmt::Result { match self { IoError::Cairo(err) => write!(fmt, "Cairo error: {err}"), IoError::Io(err) => write!(fmt, "IO error: {err}"), } } } impl std::convert::From for IoError { fn from(source: Error) -> Self { IoError::Cairo(source) } } impl std::convert::From for IoError { fn from(source: io::Error) -> Self { IoError::Io(source) } } #[derive(Debug)] pub enum BorrowError { Cairo(crate::Error), NonExclusive, } impl std::error::Error for BorrowError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { BorrowError::Cairo(err) => Some(err), BorrowError::NonExclusive => None, } } } impl fmt::Display for BorrowError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { BorrowError::Cairo(err) => write!(fmt, "Failed to borrow with Cairo error: {err}"), BorrowError::NonExclusive => fmt.write_str("Can't get exclusive access"), } } } impl std::convert::From for BorrowError { fn from(err: crate::Error) -> Self { BorrowError::Cairo(err) } } pub type Result = std::result::Result; cairo-rs-0.20.1/src/font/font_extents.rs000064400000000000000000000034551046102023000162550ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use std::fmt; #[derive(Clone, Copy)] #[repr(transparent)] #[doc(alias = "cairo_font_extents_t")] pub struct FontExtents(ffi::cairo_font_extents_t); impl FontExtents { pub fn ascent(&self) -> f64 { self.0.ascent } pub fn descent(&self) -> f64 { self.0.descent } pub fn height(&self) -> f64 { self.0.height } pub fn max_x_advance(&self) -> f64 { self.0.max_x_advance } pub fn max_y_advance(&self) -> f64 { self.0.max_y_advance } pub fn set_ascent(&mut self, ascent: f64) { self.0.ascent = ascent; } pub fn set_descent(&mut self, descent: f64) { self.0.descent = descent; } pub fn set_height(&mut self, height: f64) { self.0.height = height; } pub fn set_max_x_advance(&mut self, max_x_advance: f64) { self.0.max_x_advance = max_x_advance; } pub fn set_max_y_advance(&mut self, max_y_advance: f64) { self.0.max_y_advance = max_y_advance; } } impl fmt::Debug for FontExtents { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FontExtents") .field("ascent", &self.ascent()) .field("descent", &self.descent()) .field("height", &self.height()) .field("max_x_advance", &self.max_x_advance()) .field("max_y_advance", &self.max_y_advance()) .finish() } } #[doc(hidden)] impl From for ffi::cairo_font_extents_t { fn from(val: FontExtents) -> ffi::cairo_font_extents_t { val.0 } } #[doc(hidden)] impl From for FontExtents { fn from(value: ffi::cairo_font_extents_t) -> Self { Self(value) } } cairo-rs-0.20.1/src/font/font_face.rs000064400000000000000000000171161046102023000154600ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ffi::{CStr, CString}; #[cfg(not(feature = "use_glib"))] use std::ptr; #[cfg(feature = "freetype")] use std::rc::Rc; #[cfg(feature = "use_glib")] use glib::translate::*; #[cfg(feature = "freetype")] use crate::FtSynthesize; use crate::{ffi, utils::status_to_result, Error, FontSlant, FontType, FontWeight}; #[cfg(feature = "freetype")] static FT_FACE_KEY: crate::UserDataKey = crate::UserDataKey::new(); #[cfg(feature = "use_glib")] glib::wrapper! { #[derive(Debug)] #[doc(alias = "cairo_font_face_t")] pub struct FontFace(Shared); match fn { ref => |ptr| ffi::cairo_font_face_reference(ptr), unref => |ptr| ffi::cairo_font_face_destroy(ptr), type_ => || ffi::gobject::cairo_gobject_font_face_get_type(), } } #[cfg(not(feature = "use_glib"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "use_glib"))))] #[derive(Debug)] #[doc(alias = "cairo_font_face_t")] pub struct FontFace(ptr::NonNull); impl FontFace { #[doc(alias = "cairo_toy_font_face_create")] pub fn toy_create( family: &str, slant: FontSlant, weight: FontWeight, ) -> Result { let font_face: FontFace = unsafe { let family = CString::new(family).unwrap(); FontFace::from_raw_full(ffi::cairo_toy_font_face_create( family.as_ptr(), slant.into(), weight.into(), )) }; let status = unsafe { ffi::cairo_font_face_status(font_face.to_raw_none()) }; status_to_result(status)?; Ok(font_face) } // rustdoc-stripper-ignore-next /// Creates a new font face for the FreeType backend from an already opened FreeType face. #[cfg(feature = "freetype")] #[cfg_attr(docsrs, doc(cfg(feature = "freetype")))] #[doc(alias = "cairo_ft_font_face_create_for_ft_face")] pub fn create_from_ft(face: &freetype::face::Face) -> Result { // Increase reference count of `FT_Face`. let mut face = face.clone(); // SAFETY: The user data entry keeps `freetype::face::Face` alive // until the FontFace is dropped. let font_face = unsafe { FontFace::from_raw_full(ffi::cairo_ft_font_face_create_for_ft_face( face.raw_mut() as freetype::ffi::FT_Face as *mut _, 0, )) }; font_face.set_user_data(&FT_FACE_KEY, Rc::new(face))?; let status = unsafe { ffi::cairo_font_face_status(font_face.to_raw_none()) }; status_to_result(status)?; Ok(font_face) } // rustdoc-stripper-ignore-next /// Creates a new font face for the FreeType backend from an already opened FreeType face, /// additionally allowing you to pass flags to the underlying C API. #[cfg(feature = "freetype")] #[cfg_attr(docsrs, doc(cfg(feature = "freetype")))] #[doc(alias = "cairo_ft_font_face_create_for_ft_face")] pub fn create_from_ft_with_flags( face: &freetype::face::Face, load_flags: libc::c_int, ) -> Result { // Increase reference count of `FT_Face`. let mut face = face.clone(); // SAFETY: The user data entry keeps `freetype::face::Face` alive // until the FontFace is dropped. let font_face = unsafe { FontFace::from_raw_full(ffi::cairo_ft_font_face_create_for_ft_face( face.raw_mut() as freetype::ffi::FT_Face as *mut _, load_flags, )) }; font_face.set_user_data(&FT_FACE_KEY, Rc::new(face))?; let status = unsafe { ffi::cairo_font_face_status(font_face.to_raw_none()) }; status_to_result(status)?; Ok(font_face) } #[cfg(feature = "use_glib")] #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_font_face_t) -> FontFace { from_glib_full(ptr) } #[cfg(not(feature = "use_glib"))] #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_font_face_t) -> FontFace { debug_assert!(!ptr.is_null()); FontFace(ptr::NonNull::new_unchecked(ptr)) } #[cfg(feature = "use_glib")] #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_font_face_t) -> FontFace { from_glib_none(ptr) } #[cfg(not(feature = "use_glib"))] #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_font_face_t) -> FontFace { debug_assert!(!ptr.is_null()); FontFace(ptr::NonNull::new_unchecked(ptr)) } #[cfg(feature = "use_glib")] #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_font_face_t { self.to_glib_none().0 } #[cfg(not(feature = "use_glib"))] #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_font_face_t { self.0.as_ptr() } #[doc(alias = "cairo_toy_font_face_get_family")] pub fn toy_get_family(&self) -> Option { unsafe { to_optional_string(ffi::cairo_toy_font_face_get_family(self.to_raw_none())) } } #[doc(alias = "cairo_toy_font_face_get_slant")] pub fn toy_get_slant(&self) -> FontSlant { unsafe { FontSlant::from(ffi::cairo_toy_font_face_get_slant(self.to_raw_none())) } } #[doc(alias = "cairo_toy_font_face_get_weight")] pub fn toy_get_weight(&self) -> FontWeight { unsafe { FontWeight::from(ffi::cairo_toy_font_face_get_weight(self.to_raw_none())) } } #[doc(alias = "cairo_font_face_get_type")] #[doc(alias = "get_type")] pub fn type_(&self) -> FontType { unsafe { FontType::from(ffi::cairo_font_face_get_type(self.to_raw_none())) } } #[doc(alias = "cairo_font_face_get_reference_count")] #[doc(alias = "get_reference_count")] pub fn reference_count(&self) -> usize { unsafe { ffi::cairo_font_face_get_reference_count(self.to_raw_none()) as usize } } #[cfg(feature = "freetype")] #[doc(alias = "cairo_ft_font_face_get_synthesize")] #[doc(alias = "get_synthesize")] pub fn synthesize(&self) -> FtSynthesize { unsafe { FtSynthesize::from(ffi::cairo_ft_font_face_get_synthesize(self.to_raw_none())) } } #[cfg(feature = "freetype")] #[doc(alias = "cairo_ft_font_face_set_synthesize")] pub fn set_synthesize(&self, synth_flags: FtSynthesize) { unsafe { ffi::cairo_ft_font_face_set_synthesize(self.to_raw_none(), synth_flags.into()) } } #[cfg(feature = "freetype")] #[doc(alias = "cairo_ft_font_face_unset_synthesize")] pub fn unset_synthesize(&self, synth_flags: FtSynthesize) { unsafe { ffi::cairo_ft_font_face_unset_synthesize(self.to_raw_none(), synth_flags.into()) } } #[doc(alias = "cairo_font_face_status")] pub fn status(&self) -> Result<(), Error> { let status = unsafe { ffi::cairo_font_face_status(self.to_raw_none()) }; status_to_result(status) } user_data_methods! { ffi::cairo_font_face_get_user_data, ffi::cairo_font_face_set_user_data, } } #[cfg(not(feature = "use_glib"))] impl Drop for FontFace { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_font_face_destroy(self.to_raw_none()); } } } #[cfg(not(feature = "use_glib"))] impl Clone for FontFace { #[inline] fn clone(&self) -> FontFace { unsafe { FontFace::from_raw_none(self.to_raw_none()) } } } pub(crate) unsafe fn to_optional_string(str: *const libc::c_char) -> Option { if str.is_null() { None } else { Some(String::from_utf8_lossy(CStr::from_ptr(str).to_bytes()).into_owned()) } } cairo-rs-0.20.1/src/font/font_options.rs000064400000000000000000000155241046102023000162560ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(feature = "v1_16")] use std::ffi::CString; use std::hash; #[cfg(not(feature = "use_glib"))] use std::ptr; #[cfg(feature = "use_glib")] use glib::translate::*; #[cfg(feature = "v1_16")] use crate::font::font_face::to_optional_string; use crate::{ ffi, utils::status_to_result, Antialias, Error, HintMetrics, HintStyle, SubpixelOrder, }; #[cfg(feature = "use_glib")] glib::wrapper! { #[derive(Debug)] #[doc(alias = "cairo_font_options_t")] pub struct FontOptions(Boxed); match fn { copy => |ptr| { let ptr = ffi::cairo_font_options_copy(ptr); let status = ffi::cairo_font_options_status(ptr); status_to_result(status).expect("Failed to create a copy of FontOptions"); ptr }, free => |ptr| ffi::cairo_font_options_destroy(ptr), type_ => || ffi::gobject::cairo_gobject_font_options_get_type(), } } #[cfg(not(feature = "use_glib"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "use_glib"))))] #[derive(Debug)] #[doc(alias = "cairo_font_options_t")] pub struct FontOptions(ptr::NonNull); unsafe impl Send for FontOptions {} unsafe impl Sync for FontOptions {} impl FontOptions { #[doc(alias = "cairo_font_options_create")] pub fn new() -> Result { let font_options: FontOptions = unsafe { FontOptions::from_raw_full(ffi::cairo_font_options_create()) }; let status = unsafe { ffi::cairo_font_options_status(font_options.to_raw_none()) }; status_to_result(status)?; Ok(font_options) } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_font_options_t) -> Self { from_glib_full(ptr) } #[cfg(not(feature = "use_glib"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "use_glib"))))] #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_font_options_t) -> Self { debug_assert!(!ptr.is_null()); Self(ptr::NonNull::new_unchecked(ptr)) } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_font_options_t { mut_override(self.to_glib_none().0) } #[cfg(not(feature = "use_glib"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "use_glib"))))] #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_font_options_t { self.0.as_ptr() } #[doc(alias = "cairo_font_options_merge")] pub fn merge(&mut self, other: &FontOptions) { unsafe { ffi::cairo_font_options_merge(self.to_raw_none(), other.to_raw_none()) } } #[doc(alias = "cairo_font_options_set_antialias")] pub fn set_antialias(&mut self, antialias: Antialias) { unsafe { ffi::cairo_font_options_set_antialias(self.to_raw_none(), antialias.into()) } } #[doc(alias = "cairo_font_options_get_antialias")] #[doc(alias = "get_antialias")] pub fn antialias(&self) -> Antialias { unsafe { Antialias::from(ffi::cairo_font_options_get_antialias(self.to_raw_none())) } } #[doc(alias = "cairo_font_options_set_subpixel_order")] pub fn set_subpixel_order(&mut self, order: SubpixelOrder) { unsafe { ffi::cairo_font_options_set_subpixel_order(self.to_raw_none(), order.into()) } } #[doc(alias = "cairo_font_options_get_subpixel_order")] #[doc(alias = "get_subpixel_order")] pub fn subpixel_order(&self) -> SubpixelOrder { unsafe { SubpixelOrder::from(ffi::cairo_font_options_get_subpixel_order( self.to_raw_none(), )) } } #[doc(alias = "cairo_font_options_set_hint_style")] pub fn set_hint_style(&mut self, hint_style: HintStyle) { unsafe { ffi::cairo_font_options_set_hint_style(self.to_raw_none(), hint_style.into()) } } #[doc(alias = "cairo_font_options_get_hint_style")] #[doc(alias = "get_hint_style")] pub fn hint_style(&self) -> HintStyle { unsafe { HintStyle::from(ffi::cairo_font_options_get_hint_style(self.to_raw_none())) } } #[doc(alias = "cairo_font_options_set_hint_metrics")] pub fn set_hint_metrics(&mut self, hint_metrics: HintMetrics) { unsafe { ffi::cairo_font_options_set_hint_metrics(self.to_raw_none(), hint_metrics.into()) } } #[doc(alias = "cairo_font_options_get_hint_metrics")] #[doc(alias = "get_hint_metrics")] pub fn hint_metrics(&self) -> HintMetrics { unsafe { HintMetrics::from(ffi::cairo_font_options_get_hint_metrics(self.to_raw_none())) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "cairo_font_options_get_variations")] #[doc(alias = "get_variations")] pub fn variations(&self) -> Option { unsafe { to_optional_string(ffi::cairo_font_options_get_variations(self.to_raw_none())) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "cairo_font_options_set_variations")] pub fn set_variations(&self, variations: Option<&str>) { unsafe { match variations { Some(v) => { let v = CString::new(v).unwrap(); ffi::cairo_font_options_set_variations(self.to_raw_none(), v.as_ptr()) } None => { ffi::cairo_font_options_set_variations(self.to_raw_none(), std::ptr::null()) } } } } #[doc(alias = "cairo_font_options_status")] pub fn status(&self) -> Result<(), Error> { let status = unsafe { ffi::cairo_font_options_status(self.to_raw_none()) }; status_to_result(status) } } impl PartialEq for FontOptions { #[doc(alias = "cairo_font_options_equal")] fn eq(&self, other: &FontOptions) -> bool { unsafe { ffi::cairo_font_options_equal(self.to_raw_none(), other.to_raw_none()).as_bool() } } } impl Eq for FontOptions {} impl hash::Hash for FontOptions { #[doc(alias = "cairo_font_options_hash")] fn hash(&self, state: &mut H) where H: hash::Hasher, { unsafe { hash::Hash::hash(&ffi::cairo_font_options_hash(self.to_raw_none()), state) } } } #[cfg(not(feature = "use_glib"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "use_glib"))))] impl Drop for FontOptions { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_font_options_destroy(self.to_raw_none()); } } } #[cfg(not(feature = "use_glib"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "use_glib"))))] impl Clone for FontOptions { #[inline] fn clone(&self) -> FontOptions { unsafe { FontOptions::from_raw_full(ffi::cairo_font_options_copy(self.to_raw_none())) } } } cairo-rs-0.20.1/src/font/glyph.rs000064400000000000000000000020071046102023000146500ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use std::fmt; #[derive(Clone, Copy)] #[repr(transparent)] #[doc(alias = "cairo_glyph_t")] pub struct Glyph(ffi::cairo_glyph_t); impl Glyph { pub fn new(index: libc::c_ulong, x: f64, y: f64) -> Self { Self(ffi::cairo_glyph_t { index, x, y }) } pub fn index(&self) -> libc::c_ulong { self.0.index } pub fn x(&self) -> f64 { self.0.x } pub fn y(&self) -> f64 { self.0.y } pub fn set_index(&mut self, index: libc::c_ulong) { self.0.index = index; } pub fn set_x(&mut self, x: f64) { self.0.x = x; } pub fn set_y(&mut self, y: f64) { self.0.y = y; } } impl fmt::Debug for Glyph { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Glyph") .field("index", &self.index()) .field("x", &self.x()) .field("y", &self.y()) .finish() } } cairo-rs-0.20.1/src/font/mod.rs000064400000000000000000000026541046102023000143140ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. mod font_extents; mod font_face; mod font_options; mod glyph; mod scaled_font; mod text_cluster; mod text_extents; mod user_fonts; /* TODO Allocates an array of cairo_glyph_t's. This function is only useful in implementations of cairo_user_scaled_font_text_to_glyphs_func_t where the user needs to allocate an array of glyphs that cairo will free. For all other uses, user can use their own allocation method for glyphs. impl Glyph { //pub fn cairo_glyph_allocate(num_glyphs: c_int) -> *Glyph; //pub fn cairo_glyph_free(glyphs: *Glyph); } Allocates an array of cairo_glyph_t's. This function is only useful in implementations of cairo_user_scaled_font_text_to_glyphs_func_t where the user needs to allocate an array of glyphs that cairo will free. For all other uses, user can use their own allocation method for glyphs. impl TextCluster { //pub fn cairo_text_cluster_allocate(num_clusters: c_int) -> *TextCluster; //pub fn cairo_text_cluster_free(clusters: *TextCluster); } */ pub use self::{ font_extents::FontExtents, font_face::FontFace, font_options::FontOptions, glyph::Glyph, scaled_font::ScaledFont, text_cluster::TextCluster, text_extents::TextExtents, user_fonts::UserFontFace, }; pub use crate::enums::{ Antialias, FontSlant, FontType, FontWeight, HintMetrics, HintStyle, SubpixelOrder, TextClusterFlags, }; cairo-rs-0.20.1/src/font/scaled_font.rs000064400000000000000000000211001046102023000160010ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ffi::CString, mem::MaybeUninit, ptr}; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ ffi, utils::status_to_result, Error, FontExtents, FontFace, FontOptions, FontType, Glyph, Matrix, TextCluster, TextExtents, }; #[cfg(feature = "use_glib")] glib::wrapper! { #[derive(Debug)] #[doc(alias = "cairo_scaled_font_t")] pub struct ScaledFont(Shared); match fn { ref => |ptr| ffi::cairo_scaled_font_reference(ptr), unref => |ptr| ffi::cairo_scaled_font_destroy(ptr), type_ => || ffi::gobject::cairo_gobject_scaled_font_get_type(), } } #[cfg(not(feature = "use_glib"))] #[derive(Debug)] #[doc(alias = "cairo_scaled_font_t")] pub struct ScaledFont(ptr::NonNull); impl ScaledFont { #[doc(alias = "cairo_scaled_font_create")] pub fn new( font_face: &FontFace, font_matrix: &Matrix, ctm: &Matrix, options: &FontOptions, ) -> Result { let scaled_font: ScaledFont = unsafe { ScaledFont::from_raw_full(ffi::cairo_scaled_font_create( font_face.to_raw_none(), font_matrix.ptr(), ctm.ptr(), options.to_raw_none(), )) }; let status = unsafe { ffi::cairo_scaled_font_status(scaled_font.to_raw_none()) }; status_to_result(status)?; Ok(scaled_font) } #[cfg(feature = "use_glib")] #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_scaled_font_t { self.to_glib_none().0 } #[cfg(not(feature = "use_glib"))] #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_scaled_font_t { self.0.as_ptr() } #[cfg(not(feature = "use_glib"))] #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_scaled_font_t) -> ScaledFont { debug_assert!(!ptr.is_null()); ScaledFont(ptr::NonNull::new_unchecked(ptr)) } #[cfg(feature = "use_glib")] #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_scaled_font_t) -> ScaledFont { from_glib_full(ptr) } #[cfg(feature = "use_glib")] #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_scaled_font_t) -> ScaledFont { from_glib_none(ptr) } #[cfg(not(feature = "use_glib"))] #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_scaled_font_t) -> ScaledFont { debug_assert!(!ptr.is_null()); ffi::cairo_scaled_font_reference(ptr); ScaledFont(ptr::NonNull::new_unchecked(ptr)) } #[doc(alias = "cairo_scaled_font_get_type")] #[doc(alias = "get_type")] pub fn type_(&self) -> FontType { unsafe { FontType::from(ffi::cairo_scaled_font_get_type(self.to_raw_none())) } } #[doc(alias = "cairo_scaled_font_get_reference_count")] #[doc(alias = "get_reference_count")] pub fn reference_count(&self) -> usize { unsafe { ffi::cairo_scaled_font_get_reference_count(self.to_raw_none()) as usize } } #[doc(alias = "cairo_scaled_font_extents")] pub fn extents(&self) -> FontExtents { let mut extents = MaybeUninit::::uninit(); unsafe { ffi::cairo_scaled_font_extents(self.to_raw_none(), extents.as_mut_ptr() as *mut _); extents.assume_init() } } #[doc(alias = "cairo_scaled_font_text_extents")] pub fn text_extents(&self, text: &str) -> TextExtents { let mut extents = MaybeUninit::::uninit(); let text = CString::new(text).unwrap(); unsafe { ffi::cairo_scaled_font_text_extents( self.to_raw_none(), text.as_ptr(), extents.as_mut_ptr() as *mut _, ); extents.assume_init() } } #[doc(alias = "cairo_scaled_font_glyph_extents")] pub fn glyph_extents(&self, glyphs: &[Glyph]) -> TextExtents { let mut extents = MaybeUninit::::uninit(); unsafe { ffi::cairo_scaled_font_glyph_extents( self.to_raw_none(), glyphs.as_ptr() as *const _, glyphs.len() as _, extents.as_mut_ptr() as *mut _, ); extents.assume_init() } } #[doc(alias = "cairo_scaled_font_text_to_glyphs")] pub fn text_to_glyphs( &self, x: f64, y: f64, text: &str, ) -> Result<(Vec, Vec), Error> { // This large unsafe block is due to the FFI function returning two specially allocated // (cairo_{glyph,text_cluster}_allocate) pointers that need to be copied into Vec // types before they're of any use to Rust code. unsafe { let mut glyphs_ptr: *mut Glyph = ptr::null_mut(); let mut glyph_count = 0i32; let mut clusters_ptr: *mut TextCluster = ptr::null_mut(); let mut cluster_count = 0i32; let mut cluster_flags = 0i32; let text_length = text.len() as i32; let text = CString::new(text).unwrap(); let status = ffi::cairo_scaled_font_text_to_glyphs( self.to_raw_none(), x, y, text.as_ptr(), text_length, &mut glyphs_ptr as *mut *mut Glyph as *mut _, &mut glyph_count, &mut clusters_ptr as *mut *mut TextCluster as *mut _, &mut cluster_count, &mut cluster_flags, ); status_to_result(status)?; let glyph_count = glyph_count as usize; let glyphs: Vec = { let mut glyphs: Vec = Vec::with_capacity(glyph_count); ptr::copy(glyphs_ptr, glyphs.as_mut_ptr(), glyph_count); glyphs.set_len(glyph_count); glyphs }; let cluster_count = cluster_count as usize; let clusters: Vec = { let mut clusters = Vec::with_capacity(cluster_count); ptr::copy(clusters_ptr, clusters.as_mut_ptr(), cluster_count); clusters.set_len(cluster_count); clusters }; ffi::cairo_glyph_free(glyphs_ptr as _); ffi::cairo_text_cluster_free(clusters_ptr as _); Ok((glyphs, clusters)) } } #[doc(alias = "cairo_scaled_font_get_font_face")] #[doc(alias = "get_font_face")] pub fn font_face(&self) -> FontFace { unsafe { FontFace::from_raw_none(ffi::cairo_scaled_font_get_font_face(self.to_raw_none())) } } #[doc(alias = "cairo_scaled_font_get_font_options")] #[doc(alias = "get_font_options")] pub fn font_options(&self) -> Result { let options = FontOptions::new()?; unsafe { ffi::cairo_scaled_font_get_font_options(self.to_raw_none(), options.to_raw_none()) } Ok(options) } #[doc(alias = "cairo_scaled_font_get_font_matrix")] #[doc(alias = "get_font_matrix")] pub fn font_matrix(&self) -> Matrix { let mut matrix = Matrix::null(); unsafe { ffi::cairo_scaled_font_get_font_matrix(self.to_raw_none(), matrix.mut_ptr()) } matrix } #[doc(alias = "cairo_scaled_font_get_ctm")] #[doc(alias = "get_ctm")] pub fn ctm(&self) -> Matrix { let mut matrix = Matrix::null(); unsafe { ffi::cairo_scaled_font_get_ctm(self.to_raw_none(), matrix.mut_ptr()) } matrix } #[doc(alias = "cairo_scaled_font_get_scale_matrix")] #[doc(alias = "get_scale_matrix")] pub fn scale_matrix(&self) -> Matrix { let mut matrix = Matrix::null(); unsafe { ffi::cairo_scaled_font_get_scale_matrix(self.to_raw_none(), matrix.mut_ptr()) } matrix } #[doc(alias = "cairo_scaled_font_status")] pub fn status(&self) -> Result<(), Error> { let status = unsafe { ffi::cairo_scaled_font_status(self.to_raw_none()) }; status_to_result(status) } user_data_methods! { ffi::cairo_scaled_font_get_user_data, ffi::cairo_scaled_font_set_user_data, } } #[cfg(not(feature = "use_glib"))] impl Drop for ScaledFont { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_scaled_font_destroy(self.to_raw_none()); } } } #[cfg(not(feature = "use_glib"))] impl Clone for ScaledFont { #[inline] fn clone(&self) -> ScaledFont { unsafe { ScaledFont::from_raw_none(self.to_raw_none()) } } } cairo-rs-0.20.1/src/font/text_cluster.rs000064400000000000000000000020231046102023000162500ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use std::fmt; #[derive(Clone, Copy)] #[repr(transparent)] #[doc(alias = "cairo_text_cluster_t")] pub struct TextCluster(ffi::cairo_text_cluster_t); impl TextCluster { pub fn new(num_bytes: i32, num_glyphs: i32) -> Self { Self(ffi::cairo_text_cluster_t { num_bytes, num_glyphs, }) } pub fn num_bytes(&self) -> i32 { self.0.num_bytes } pub fn num_glyphs(&self) -> i32 { self.0.num_glyphs } pub fn set_num_bytes(&mut self, num_bytes: i32) { self.0.num_bytes = num_bytes; } pub fn set_num_glyphs(&mut self, num_glyphs: i32) { self.0.num_glyphs = num_glyphs; } } impl fmt::Debug for TextCluster { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TextCluster") .field("num_bytes", &self.num_bytes()) .field("num_glyphs", &self.num_glyphs()) .finish() } } cairo-rs-0.20.1/src/font/text_extents.rs000064400000000000000000000044671046102023000162770ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use std::fmt; #[derive(Clone, Copy)] #[repr(transparent)] #[doc(alias = "cairo_text_extents_t")] pub struct TextExtents(ffi::cairo_text_extents_t); impl TextExtents { pub fn new( x_bearing: f64, y_bearing: f64, width: f64, height: f64, x_advance: f64, y_advance: f64, ) -> Self { Self(ffi::cairo_text_extents_t { x_bearing, y_bearing, width, height, x_advance, y_advance, }) } pub fn x_bearing(&self) -> f64 { self.0.x_bearing } pub fn y_bearing(&self) -> f64 { self.0.y_bearing } pub fn width(&self) -> f64 { self.0.width } pub fn height(&self) -> f64 { self.0.height } pub fn x_advance(&self) -> f64 { self.0.x_advance } pub fn y_advance(&self) -> f64 { self.0.y_advance } pub fn set_x_bearing(&mut self, x_bearing: f64) { self.0.x_bearing = x_bearing; } pub fn set_y_bearing(&mut self, y_bearing: f64) { self.0.y_bearing = y_bearing; } pub fn set_width(&mut self, width: f64) { self.0.width = width; } pub fn set_height(&mut self, height: f64) { self.0.height = height; } pub fn set_x_advance(&mut self, x_advance: f64) { self.0.x_advance = x_advance; } pub fn set_y_advance(&mut self, y_advance: f64) { self.0.y_advance = y_advance; } } impl fmt::Debug for TextExtents { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TextExtents") .field("x_bearing", &self.x_bearing()) .field("y_bearing", &self.y_bearing()) .field("width", &self.width()) .field("height", &self.height()) .field("x_advance", &self.x_advance()) .field("y_advance", &self.y_advance()) .finish() } } #[doc(hidden)] impl From for ffi::cairo_text_extents_t { fn from(val: TextExtents) -> ffi::cairo_text_extents_t { val.0 } } #[doc(hidden)] impl From for TextExtents { fn from(value: ffi::cairo_text_extents_t) -> Self { Self(value) } } cairo-rs-0.20.1/src/font/user_fonts.rs000064400000000000000000000221451046102023000157210ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::sync::OnceLock; use super::{FontExtents, FontFace, ScaledFont, TextCluster, TextClusterFlags, TextExtents}; use crate::{ffi, utils::status_to_result, Context, Error, Glyph}; type BoxInitFunc = Box Result<(), Error> + Send + Sync>; type BoxRenderGlyphFunc = Box< dyn Fn(&ScaledFont, libc::c_ulong, &Context, &mut TextExtents) -> Result<(), Error> + Send + Sync, >; type BoxUnicodeToGlyphFunc = Box Result + Send + Sync>; type BoxTextToGlyphsFunc = Box< dyn Fn(&ScaledFont, &str) -> Result<(Vec, Vec, TextClusterFlags), Error> + Send + Sync, >; pub struct UserFontFace(FontFace); impl UserFontFace { #[doc(alias = "cairo_user_font_face_create")] pub fn create() -> Result { let font_face = unsafe { FontFace::from_raw_full(ffi::cairo_user_font_face_create()) }; let status = unsafe { ffi::cairo_font_face_status(font_face.to_raw_none()) }; status_to_result(status)?; Ok(Self(font_face)) } #[doc(alias = "cairo_user_font_face_set_init_func")] pub fn set_init_func(&self, func: F) where F: Fn(&ScaledFont, &Context, &mut FontExtents) -> Result<(), Error> + Send + Sync + 'static, { static INIT_FUNC: OnceLock = OnceLock::new(); if INIT_FUNC.set(Box::new(func)).is_err() { panic!("Init func can only be set once") } unsafe extern "C" fn init_trampoline( scaled_font: *mut ffi::cairo_scaled_font_t, cr: *mut ffi::cairo_t, extents: *mut ffi::cairo_font_extents_t, ) -> ffi::cairo_status_t { let font_extents = &mut *(extents as *mut FontExtents); let init_func = INIT_FUNC.get().unwrap(); if let Err(err) = init_func( &ScaledFont::from_raw_none(scaled_font), &Context::from_raw_none(cr), font_extents, ) { err.into() } else { ffi::STATUS_SUCCESS } } unsafe { ffi::cairo_user_font_face_set_init_func(self.to_raw_none(), Some(init_trampoline)); } } #[doc(alias = "cairo_user_font_face_set_render_glyph_func")] pub fn set_render_glyph_func(&self, func: F) where F: Fn(&ScaledFont, libc::c_ulong, &Context, &mut TextExtents) -> Result<(), Error> + Send + Sync + 'static, { static RENDER_GLYPH_FUNC: OnceLock = OnceLock::new(); if RENDER_GLYPH_FUNC.set(Box::new(func)).is_err() { panic!("RenderGlyph func can only be set once") } unsafe extern "C" fn render_glyph_trampoline( scaled_font: *mut ffi::cairo_scaled_font_t, glyph: libc::c_ulong, cr: *mut ffi::cairo_t, extents: *mut ffi::cairo_text_extents_t, ) -> ffi::cairo_status_t { let text_extents = &mut *(extents as *mut TextExtents); let render_glyph_func = RENDER_GLYPH_FUNC.get().unwrap(); if let Err(err) = render_glyph_func( &ScaledFont::from_raw_none(scaled_font), glyph, &Context::from_raw_none(cr), text_extents, ) { err.into() } else { ffi::STATUS_SUCCESS } } unsafe { ffi::cairo_user_font_face_set_render_glyph_func( self.to_raw_none(), Some(render_glyph_trampoline), ); } } #[doc(alias = "cairo_user_font_face_set_render_color_glyph_func")] pub fn set_render_color_glyph_func(&self, func: F) where F: Fn(&ScaledFont, libc::c_ulong, &Context, &mut TextExtents) -> Result<(), Error> + Send + Sync + 'static, { static RENDER_COLOR_GLYPH_FUNC: OnceLock = OnceLock::new(); if RENDER_COLOR_GLYPH_FUNC.set(Box::new(func)).is_err() { panic!("RenderColorGlyph func can only be set once") } unsafe extern "C" fn render_glyph_trampoline( scaled_font: *mut ffi::cairo_scaled_font_t, glyph: libc::c_ulong, cr: *mut ffi::cairo_t, extents: *mut ffi::cairo_text_extents_t, ) -> ffi::cairo_status_t { let text_extents = &mut *(extents as *mut TextExtents); let render_glyph_func = RENDER_COLOR_GLYPH_FUNC.get().unwrap(); if let Err(err) = render_glyph_func( &ScaledFont::from_raw_none(scaled_font), glyph, &Context::from_raw_none(cr), text_extents, ) { err.into() } else { ffi::STATUS_SUCCESS } } unsafe { ffi::cairo_user_font_face_set_render_glyph_func( self.to_raw_none(), Some(render_glyph_trampoline), ); } } #[doc(alias = "cairo_user_font_face_set_unicode_to_glyph_func")] pub fn set_unicode_to_glyph_func(&self, func: F) where F: Fn(&ScaledFont, libc::c_ulong) -> Result + Send + Sync + 'static, { static UNICODE_TO_GLYPH_FUNC: OnceLock = OnceLock::new(); if UNICODE_TO_GLYPH_FUNC.set(Box::new(func)).is_err() { panic!("UnicodeToGlyph func can only be set once") } unsafe extern "C" fn unicode_to_glyph_trampoline( scaled_font: *mut ffi::cairo_scaled_font_t, unicode: libc::c_ulong, glyph_index: *mut libc::c_ulong, ) -> ffi::cairo_status_t { let unicode_to_glyph_func = UNICODE_TO_GLYPH_FUNC.get().unwrap(); match unicode_to_glyph_func(&ScaledFont::from_raw_none(scaled_font), unicode) { Err(err) => err.into(), Ok(glyph) => { *glyph_index = glyph; ffi::STATUS_SUCCESS } } } unsafe { ffi::cairo_user_font_face_set_unicode_to_glyph_func( self.to_raw_none(), Some(unicode_to_glyph_trampoline), ); } } #[doc(alias = "cairo_user_font_face_set_text_to_glyphs_func")] pub fn set_text_to_glyphs_func(&self, func: F) where F: Fn(&ScaledFont, &str) -> Result<(Vec, Vec, TextClusterFlags), Error> + Send + Sync + 'static, { static TEXT_TO_GLYPHS_FUNC: OnceLock = OnceLock::new(); if TEXT_TO_GLYPHS_FUNC.set(Box::new(func)).is_err() { panic!("TextToGlyphs func can only be set once") } unsafe extern "C" fn text_to_glyphs_trampoline( scaled_font: *mut ffi::cairo_scaled_font_t, utf8: *const libc::c_char, utf8_len: libc::c_int, glyphs: *mut *mut ffi::cairo_glyph_t, num_glyphs: *mut libc::c_int, clusters: *mut *mut ffi::cairo_text_cluster_t, num_clusters: *mut libc::c_int, cluster_flags: *mut ffi::cairo_text_cluster_flags_t, ) -> ffi::cairo_status_t { let text_to_glyphs_func = TEXT_TO_GLYPHS_FUNC.get().unwrap(); let text = if utf8_len > 0 { let bytes = std::slice::from_raw_parts(utf8 as *const u8, utf8_len as usize); std::str::from_utf8_unchecked(bytes) } else { std::ffi::CStr::from_ptr(utf8).to_str().unwrap() }; match text_to_glyphs_func(&ScaledFont::from_raw_none(scaled_font), text) { Err(err) => err.into(), Ok((glyphs_, clusters_, flags)) => { *num_glyphs = glyphs_.len() as _; let c_glyphs = ffi::cairo_glyph_allocate(*num_glyphs); std::ptr::copy_nonoverlapping( glyphs_.as_ptr(), c_glyphs as *mut _, glyphs_.len(), ); *glyphs = c_glyphs; *num_clusters = clusters_.len() as _; let c_clusters = ffi::cairo_text_cluster_allocate(*num_clusters); std::ptr::copy_nonoverlapping( clusters_.as_ptr(), c_clusters as *mut _, clusters_.len(), ); *clusters = c_clusters; *cluster_flags = flags.into(); ffi::STATUS_SUCCESS } } } unsafe { ffi::cairo_user_font_face_set_text_to_glyphs_func( self.to_raw_none(), Some(text_to_glyphs_trampoline), ); } } } impl std::ops::Deref for UserFontFace { type Target = FontFace; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } cairo-rs-0.20.1/src/image_surface.rs000064400000000000000000000251431046102023000153570ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ ops::{Deref, DerefMut}, rc::Rc, slice, }; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, utils::status_to_result, BorrowError, Error, Format, Surface, SurfaceType}; declare_surface!(ImageSurface, SurfaceType::Image); impl ImageSurface { #[doc(alias = "cairo_image_surface_create")] pub fn create(format: Format, width: i32, height: i32) -> Result { unsafe { Self::from_raw_full(ffi::cairo_image_surface_create( format.into(), width, height, )) } } // rustdoc-stripper-ignore-next /// Creates an image surface for the provided pixel data. /// - The pointer `data` is the beginning of the underlying slice, /// and at least `width * stride` succeeding bytes should be allocated. /// - `data` must live longer than any reference to the returned surface. /// - You have to free `data` by yourself. #[doc(alias = "cairo_image_surface_create_for_data")] pub unsafe fn create_for_data_unsafe( data: *mut u8, format: Format, width: i32, height: i32, stride: i32, ) -> Result { ImageSurface::from_raw_full(ffi::cairo_image_surface_create_for_data( data, format.into(), width, height, stride, )) } #[doc(alias = "cairo_image_surface_create_for_data")] pub fn create_for_data + 'static>( data: D, format: Format, width: i32, height: i32, stride: i32, ) -> Result { let mut data: Box> = Box::new(data); let (ptr, len) = { let data: &mut [u8] = (*data).as_mut(); (data.as_mut_ptr(), data.len()) }; assert!(len >= (height * stride) as usize); let result = unsafe { ImageSurface::from_raw_full(ffi::cairo_image_surface_create_for_data( ptr, format.into(), width, height, stride, )) }; if let Ok(surface) = &result { static IMAGE_SURFACE_DATA: crate::UserDataKey>> = crate::UserDataKey::new(); surface.set_user_data(&IMAGE_SURFACE_DATA, Rc::new(data))?; } result } #[doc(alias = "cairo_image_surface_get_data")] #[doc(alias = "get_data")] pub fn data(&mut self) -> Result { unsafe { if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 { return Err(BorrowError::NonExclusive); } self.flush(); let status = ffi::cairo_surface_status(self.to_raw_none()); if let Some(err) = status_to_result(status).err() { return Err(BorrowError::from(err)); } if ffi::cairo_image_surface_get_data(self.to_raw_none()).is_null() || is_finished(self) { return Err(BorrowError::from(Error::SurfaceFinished)); } Ok(ImageSurfaceData::new(self)) } } pub fn take_data(self) -> Result { unsafe { if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 { return Err(BorrowError::NonExclusive); } self.flush(); let status = ffi::cairo_surface_status(self.to_raw_none()); if let Some(err) = status_to_result(status).err() { return Err(BorrowError::from(err)); } if ffi::cairo_image_surface_get_data(self.to_raw_none()).is_null() || is_finished(&self) { return Err(BorrowError::from(Error::SurfaceFinished)); } Ok(ImageSurfaceDataOwned { surface: self }) } } pub fn with_data(&self, f: F) -> Result<(), BorrowError> { self.flush(); unsafe { let status = ffi::cairo_surface_status(self.to_raw_none()); if let Some(err) = status_to_result(status).err() { return Err(BorrowError::from(err)); } let ptr = ffi::cairo_image_surface_get_data(self.to_raw_none()); if ptr.is_null() || is_finished(self) { return Err(BorrowError::from(Error::SurfaceFinished)); } let len = self.height() as usize * self.stride() as usize; let data = if len == 0 { &[] } else { slice::from_raw_parts(ptr, len) }; f(data); } Ok(()) } #[doc(alias = "cairo_image_surface_get_format")] #[doc(alias = "get_format")] pub fn format(&self) -> Format { unsafe { Format::from(ffi::cairo_image_surface_get_format(self.to_raw_none())) } } #[doc(alias = "cairo_image_surface_get_height")] #[doc(alias = "get_height")] pub fn height(&self) -> i32 { unsafe { ffi::cairo_image_surface_get_height(self.to_raw_none()) } } #[doc(alias = "cairo_image_surface_get_stride")] #[doc(alias = "get_stride")] pub fn stride(&self) -> i32 { unsafe { ffi::cairo_image_surface_get_stride(self.to_raw_none()) } } #[doc(alias = "cairo_image_surface_get_width")] #[doc(alias = "get_width")] pub fn width(&self) -> i32 { unsafe { ffi::cairo_image_surface_get_width(self.to_raw_none()) } } } pub struct ImageSurfaceDataOwned { surface: ImageSurface, } unsafe impl Send for ImageSurfaceDataOwned {} unsafe impl Sync for ImageSurfaceDataOwned {} impl ImageSurfaceDataOwned { #[inline] pub fn into_inner(self) -> ImageSurface { self.surface } } impl AsRef<[u8]> for ImageSurfaceDataOwned { #[inline] fn as_ref(&self) -> &[u8] { let len = (self.surface.stride() as usize) * (self.surface.height() as usize); unsafe { let ptr = ffi::cairo_image_surface_get_data(self.surface.to_raw_none()); if ptr.is_null() || len == 0 { return &[]; } slice::from_raw_parts(ptr, len) } } } impl AsMut<[u8]> for ImageSurfaceDataOwned { #[inline] fn as_mut(&mut self) -> &mut [u8] { let len = (self.surface.stride() as usize) * (self.surface.height() as usize); unsafe { let ptr = ffi::cairo_image_surface_get_data(self.surface.to_raw_none()); if ptr.is_null() || len == 0 { return &mut []; } slice::from_raw_parts_mut(ptr, len) } } } impl Deref for ImageSurfaceDataOwned { type Target = [u8]; #[inline] fn deref(&self) -> &Self::Target { self.as_ref() } } impl DerefMut for ImageSurfaceDataOwned { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut() } } #[derive(Debug)] pub struct ImageSurfaceData<'a> { surface: &'a mut ImageSurface, slice: &'a mut [u8], dirty: bool, } unsafe impl<'a> Send for ImageSurfaceData<'a> {} unsafe impl<'a> Sync for ImageSurfaceData<'a> {} impl<'a> ImageSurfaceData<'a> { fn new(surface: &'a mut ImageSurface) -> ImageSurfaceData<'a> { unsafe { let ptr = ffi::cairo_image_surface_get_data(surface.to_raw_none()); let len = (surface.stride() as usize) * (surface.height() as usize); ImageSurfaceData { surface, slice: if ptr.is_null() || len == 0 { &mut [] } else { slice::from_raw_parts_mut(ptr, len) }, dirty: false, } } } } impl<'a> Drop for ImageSurfaceData<'a> { #[inline] fn drop(&mut self) { if self.dirty { self.surface.mark_dirty() } } } impl<'a> Deref for ImageSurfaceData<'a> { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { self.slice } } impl<'a> DerefMut for ImageSurfaceData<'a> { #[inline] fn deref_mut(&mut self) -> &mut [u8] { self.dirty = true; self.slice } } // Workaround for cairo not having a direct way to check if the surface is finished. // See: https://gitlab.freedesktop.org/cairo/cairo/-/issues/406 fn is_finished(surface: &ImageSurface) -> bool { use super::Context; Context::new(surface).is_err() } #[cfg(test)] mod tests { use super::*; #[test] fn create_with_invalid_size_yields_error() { let result = ImageSurface::create(Format::ARgb32, 50000, 50000); assert!(result.is_err()); } #[test] fn create_for_data_with_invalid_stride_yields_error() { let result = ImageSurface::create_for_data(vec![0u8; 10], Format::ARgb32, 1, 2, 5); // unaligned stride assert!(result.is_err()); } #[test] fn create_with_valid_size() { let result = ImageSurface::create(Format::ARgb32, 10, 10); assert!(result.is_ok()); let result = ImageSurface::create_for_data(vec![0u8; 40 * 10], Format::ARgb32, 10, 10, 40); assert!(result.is_ok()); } #[test] fn no_crash_after_finish() { let mut surf = ImageSurface::create(Format::ARgb32, 1024, 1024).unwrap(); surf.finish(); assert!(surf.data().is_err()); } #[test] fn create_from_owned() { let result = ImageSurface::create(Format::ARgb32, 10, 10); assert!(result.is_ok()); let image_surface = result.unwrap(); let stride = image_surface.stride(); let data = image_surface.take_data().unwrap(); let second = ImageSurface::create_for_data(data, Format::ARgb32, 10, 10, stride); assert!(second.is_ok()) } #[cfg(feature = "use_glib")] #[test] fn surface_gvalues() { use glib::prelude::*; let surface = ImageSurface::create(Format::ARgb32, 10, 10).unwrap(); let value = surface.to_value(); assert_eq!(value.get::().unwrap().width(), 10); let _ = surface.to_value(); let surface = Some(surface); let value = surface.to_value(); assert_eq!( value .get::>() .unwrap() .map(|s| s.width()), Some(10) ); let _ = surface.as_ref().to_value(); assert_eq!( value .get::>() .unwrap() .map(|s| s.width()), Some(10) ); } } cairo-rs-0.20.1/src/lib.rs000064400000000000000000000261531046102023000133350ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #![cfg_attr(docsrs, feature(doc_cfg))] #![allow(clippy::missing_safety_doc)] #![doc = include_str!("../README.md")] pub use cairo_sys as ffi; #[cfg(feature = "freetype")] #[cfg_attr(docsrs, doc(cfg(feature = "freetype")))] pub use freetype; #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] pub use glib; // Helper macros for our GValue related trait impls #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] macro_rules! gvalue_impl_inner { ($name:ty, $ffi_name:ty, $get_type:expr) => { #[allow(unused_imports)] use glib::translate::*; impl glib::prelude::StaticType for $name { #[inline] fn static_type() -> glib::types::Type { unsafe { from_glib($get_type()) } } } impl glib::value::ValueType for $name { type Type = Self; } impl glib::value::ValueTypeOptional for $name {} }; } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] macro_rules! gvalue_impl { ($name:ty, $ffi_name:ty, $get_type:expr) => { gvalue_impl_inner!($name, $ffi_name, $get_type); unsafe impl<'a> glib::value::FromValue<'a> for $name { type Checker = glib::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { let ptr = glib::gobject_ffi::g_value_dup_boxed( glib::translate::ToGlibPtr::to_glib_none(value).0, ); debug_assert!(!ptr.is_null()); <$name as glib::translate::FromGlibPtrFull<*mut $ffi_name>>::from_glib_full( ptr as *mut $ffi_name, ) } } unsafe impl<'a> glib::value::FromValue<'a> for &'a $name { type Checker = glib::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { debug_assert_eq!( std::mem::size_of::(), std::mem::size_of::() ); let value = &*(value as *const glib::Value as *const glib::gobject_ffi::GValue); let ptr = &value.data[0].v_pointer as *const glib::ffi::gpointer as *const *const $ffi_name; debug_assert!(!(*ptr).is_null()); &*(ptr as *const $name) } } impl glib::value::ToValue for $name { fn to_value(&self) -> glib::Value { unsafe { let mut value = glib::Value::from_type_unchecked( <$name as glib::prelude::StaticType>::static_type(), ); glib::gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, self.to_glib_full() as *mut _, ); value } } fn value_type(&self) -> glib::Type { <$name as glib::prelude::StaticType>::static_type() } } impl From<$name> for glib::Value { fn from(v: $name) -> Self { unsafe { let mut value = glib::Value::from_type_unchecked( <$name as glib::prelude::StaticType>::static_type(), ); glib::gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, glib::translate::IntoGlibPtr::into_glib_ptr(v) as *mut _, ); value } } } impl glib::value::ToValueOptional for $name { fn to_value_optional(s: Option<&Self>) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, glib::translate::ToGlibPtr::to_glib_full(&s) as *mut _, ); } value } } }; } #[cfg(feature = "use_glib")] #[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))] macro_rules! gvalue_impl_inline { ($name:ty, $ffi_name:ty, $get_type:expr) => { gvalue_impl_inner!($name, $ffi_name, $get_type); unsafe impl<'a> glib::value::FromValue<'a> for $name { type Checker = glib::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { let ptr = glib::gobject_ffi::g_value_get_boxed( glib::translate::ToGlibPtr::to_glib_none(value).0, ); debug_assert!(!ptr.is_null()); <$name as glib::translate::FromGlibPtrNone<*mut $ffi_name>>::from_glib_none( ptr as *mut $ffi_name, ) } } unsafe impl<'a> glib::value::FromValue<'a> for &'a $name { type Checker = glib::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { let ptr = glib::gobject_ffi::g_value_get_boxed( glib::translate::ToGlibPtr::to_glib_none(value).0, ); debug_assert!(!ptr.is_null()); &*(ptr as *mut $name) } } impl glib::value::ToValue for $name { fn to_value(&self) -> glib::Value { unsafe { let ptr = glib::ffi::g_malloc0(std::mem::size_of::<$ffi_name>()) as *mut $ffi_name; ptr.write(self.0); let mut value = glib::Value::from_type_unchecked( <$name as glib::prelude::StaticType>::static_type(), ); glib::gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, ptr as *mut _, ); value } } fn value_type(&self) -> glib::Type { <$name as glib::prelude::StaticType>::static_type() } } impl glib::value::ToValueOptional for $name { fn to_value_optional(s: Option<&Self>) -> glib::Value { let ptr: *mut $ffi_name = match s { Some(s) => unsafe { let ptr = glib::ffi::g_malloc0(std::mem::size_of::<$ffi_name>()) as *mut $ffi_name; ptr.write(s.0); ptr }, None => std::ptr::null_mut(), }; let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, ptr as *mut _, ); } value } } }; } #[cfg(feature = "pdf")] #[cfg_attr(docsrs, doc(cfg(feature = "pdf")))] pub use pdf::PdfSurface; #[cfg(feature = "ps")] #[cfg_attr(docsrs, doc(cfg(feature = "ps")))] pub use ps::PsSurface; #[cfg(any(feature = "pdf", feature = "svg", feature = "ps"))] #[cfg_attr( docsrs, doc(cfg(any(feature = "pdf", feature = "svg", feature = "ps"))) )] pub use stream::StreamWithError; #[cfg(feature = "svg")] #[cfg_attr(docsrs, doc(cfg(feature = "svg")))] pub use svg::SvgSurface; #[cfg(feature = "xcb")] #[cfg_attr(docsrs, doc(cfg(feature = "xcb")))] pub use xcb::{ XCBConnection, XCBDrawable, XCBPixmap, XCBRenderPictFormInfo, XCBScreen, XCBSurface, XCBVisualType, }; pub use crate::{ context::{Context, RectangleList}, device::Device, enums::*, error::{BorrowError, Error, IoError, Result}, font::{ Antialias, FontExtents, FontFace, FontOptions, FontSlant, FontType, FontWeight, Glyph, HintMetrics, HintStyle, ScaledFont, SubpixelOrder, TextCluster, TextExtents, UserFontFace, }, image_surface::{ImageSurface, ImageSurfaceData, ImageSurfaceDataOwned}, matrices::Matrix, paths::{Path, PathSegment, PathSegments}, patterns::{ Gradient, LinearGradient, Mesh, Pattern, RadialGradient, SolidPattern, SurfacePattern, }, recording_surface::RecordingSurface, rectangle::Rectangle, rectangle_int::RectangleInt, region::Region, surface::{MappedImageSurface, Surface}, user_data::UserDataKey, }; #[macro_use] mod surface_macros; #[macro_use] mod user_data; mod constants; pub use crate::constants::*; mod utils; pub use crate::utils::{debug_reset_static_data, version_string, Version}; mod context; mod device; mod enums; mod error; mod font; mod image_surface; mod matrices; mod paths; mod patterns; mod recording_surface; mod rectangle; mod rectangle_int; mod region; mod surface; #[cfg(feature = "png")] mod surface_png; #[cfg(feature = "xcb")] mod xcb; #[cfg(any(feature = "pdf", feature = "svg", feature = "ps"))] #[macro_use] mod stream; #[cfg(feature = "pdf")] mod pdf; #[cfg(feature = "ps")] mod ps; #[cfg(feature = "svg")] mod svg; #[cfg(target_os = "macos")] mod quartz_surface; #[cfg(target_os = "macos")] pub use quartz_surface::QuartzSurface; #[cfg(all(windows, feature = "win32-surface"))] mod win32_surface; #[cfg(all(windows, feature = "win32-surface"))] #[cfg_attr(docsrs, doc(cfg(all(windows, feature = "win32-surface"))))] pub use win32_surface::Win32Surface; #[cfg(not(feature = "use_glib"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "use_glib"))))] mod borrowed { use std::mem; /// Wrapper around values representing borrowed C memory. /// /// This is returned by `from_glib_borrow()` and ensures that the wrapped value /// is never dropped when going out of scope. /// /// Borrowed values must never be passed by value or mutable reference to safe Rust code and must /// not leave the C scope in which they are valid. #[derive(Debug)] pub struct Borrowed(mem::ManuallyDrop); impl Borrowed { /// Creates a new borrowed value. #[inline] pub fn new(val: T) -> Self { Self(mem::ManuallyDrop::new(val)) } /// Extracts the contained value. /// /// The returned value must never be dropped and instead has to be passed to `mem::forget()` or /// be directly wrapped in `mem::ManuallyDrop` or another `Borrowed` wrapper. #[inline] pub unsafe fn into_inner(self) -> T { mem::ManuallyDrop::into_inner(self.0) } } impl AsRef for Borrowed { #[inline] fn as_ref(&self) -> &T { &*self.0 } } impl std::ops::Deref for Borrowed { type Target = T; #[inline] fn deref(&self) -> &T { &*self.0 } } } #[cfg(not(feature = "use_glib"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "use_glib"))))] pub use borrowed::Borrowed; #[cfg(feature = "use_glib")] pub(crate) use glib::translate::Borrowed; cairo-rs-0.20.1/src/matrices.rs000064400000000000000000000156131046102023000143750ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::fmt; #[cfg(feature = "use_glib")] use std::marker::PhantomData; use crate::{ffi, utils::status_to_result, Error}; #[repr(transparent)] #[derive(Clone, Copy, PartialEq)] #[doc(alias = "cairo_matrix_t")] pub struct Matrix(ffi::cairo_matrix_t); impl Default for Matrix { fn default() -> Self { Self::identity() } } impl Matrix { #[inline] pub(crate) fn ptr(&self) -> *const ffi::cairo_matrix_t { self as *const Matrix as _ } #[inline] pub(crate) fn mut_ptr(&mut self) -> *mut ffi::cairo_matrix_t { self as *mut Matrix as _ } #[inline] pub(crate) fn null() -> Self { Self(ffi::cairo_matrix_t { xx: 0.0, yx: 0.0, xy: 0.0, yy: 0.0, x0: 0.0, y0: 0.0, }) } #[inline] pub fn identity() -> Self { Self(ffi::cairo_matrix_t { xx: 1.0, yx: 0.0, xy: 0.0, yy: 1.0, x0: 0.0, y0: 0.0, }) } #[inline] pub fn new(xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64) -> Self { Self(ffi::cairo_matrix_t { xx, yx, xy, yy, x0, y0, }) } #[inline] pub fn xx(&self) -> f64 { self.0.xx } #[inline] pub fn set_xx(&mut self, xx: f64) { self.0.xx = xx; } #[inline] pub fn yx(&self) -> f64 { self.0.yx } #[inline] pub fn set_yx(&mut self, yx: f64) { self.0.yx = yx; } #[inline] pub fn xy(&self) -> f64 { self.0.xy } #[inline] pub fn set_xy(&mut self, xy: f64) { self.0.xy = xy; } #[inline] pub fn yy(&self) -> f64 { self.0.yy } #[inline] pub fn set_yy(&mut self, yy: f64) { self.0.yy = yy; } #[inline] pub fn x0(&self) -> f64 { self.0.x0 } #[inline] pub fn set_x0(&mut self, x0: f64) { self.0.x0 = x0; } #[inline] pub fn y0(&self) -> f64 { self.0.y0 } #[inline] pub fn set_y0(&mut self, y0: f64) { self.0.y0 = y0; } #[doc(alias = "cairo_matrix_multiply")] #[inline] pub fn multiply(left: &Matrix, right: &Matrix) -> Matrix { let mut matrix = Self::null(); unsafe { ffi::cairo_matrix_multiply(matrix.mut_ptr(), left.ptr(), right.ptr()); } matrix } #[doc(alias = "cairo_matrix_translate")] #[inline] pub fn translate(&mut self, tx: f64, ty: f64) { unsafe { ffi::cairo_matrix_translate(self.mut_ptr(), tx, ty) } } #[doc(alias = "cairo_matrix_scale")] #[inline] pub fn scale(&mut self, sx: f64, sy: f64) { unsafe { ffi::cairo_matrix_scale(self.mut_ptr(), sx, sy) } } #[doc(alias = "cairo_matrix_rotate")] #[inline] pub fn rotate(&mut self, angle: f64) { unsafe { ffi::cairo_matrix_rotate(self.mut_ptr(), angle) } } #[doc(alias = "cairo_matrix_invert")] #[inline] pub fn invert(&mut self) { let status = unsafe { ffi::cairo_matrix_invert(self.mut_ptr()) }; status_to_result(status).expect("Failed to invert the matrix") } #[doc(alias = "cairo_matrix_invert")] pub fn try_invert(&self) -> Result { let mut matrix = *self; let status = unsafe { ffi::cairo_matrix_invert(matrix.mut_ptr()) }; status_to_result(status)?; Ok(matrix) } #[doc(alias = "cairo_matrix_transform_distance")] #[inline] pub fn transform_distance(&self, _dx: f64, _dy: f64) -> (f64, f64) { let mut dx = _dx; let mut dy = _dy; unsafe { ffi::cairo_matrix_transform_distance(self.ptr(), &mut dx, &mut dy); } (dx, dy) } #[doc(alias = "cairo_matrix_transform_point")] #[inline] pub fn transform_point(&self, _x: f64, _y: f64) -> (f64, f64) { let mut x = _x; let mut y = _y; unsafe { ffi::cairo_matrix_transform_point(self.ptr(), &mut x, &mut y); } (x, y) } } impl fmt::Debug for Matrix { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Matrix") .field("xx", &self.xx()) .field("yx", &self.yx()) .field("xy", &self.xy()) .field("yy", &self.yy()) .field("x0", &self.x0()) .field("y0", &self.y0()) .finish() } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl Uninitialized for Matrix { #[inline] unsafe fn uninitialized() -> Self { std::mem::zeroed() } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const ffi::cairo_matrix_t> for Matrix { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::cairo_matrix_t, Self> { Stash( self as *const Matrix as *const ffi::cairo_matrix_t, PhantomData, ) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut ffi::cairo_matrix_t> for Matrix { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::cairo_matrix_t, Self> { StashMut(self as *mut Matrix as *mut ffi::cairo_matrix_t, PhantomData) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrNone<*const ffi::cairo_matrix_t> for Matrix { #[inline] unsafe fn from_glib_none(ptr: *const ffi::cairo_matrix_t) -> Self { *(ptr as *const Matrix) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrBorrow<*mut ffi::cairo_matrix_t> for Matrix { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_matrix_t) -> crate::Borrowed { crate::Borrowed::new(*(ptr as *mut Matrix)) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrNone<*mut ffi::cairo_matrix_t> for Matrix { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::cairo_matrix_t) -> Self { *(ptr as *mut Matrix) } } #[cfg(feature = "use_glib")] gvalue_impl_inline!( Matrix, ffi::cairo_matrix_t, ffi::gobject::cairo_gobject_matrix_get_type ); #[cfg(test)] mod tests { use super::*; #[test] fn invalid_matrix_does_not_invert() { let matrix = Matrix::null(); assert!(matrix.try_invert().is_err()); } #[test] #[should_panic] fn inverting_invalid_matrix_panics() { let mut matrix = Matrix::null(); matrix.invert(); } #[test] fn valid_matrix_try_invert() { let matrix = Matrix::identity(); assert_eq!(matrix.try_invert().unwrap(), Matrix::identity()); } #[test] fn valid_matrix_invert() { let mut matrix = Matrix::identity(); matrix.invert(); assert_eq!(matrix, Matrix::identity()); } } cairo-rs-0.20.1/src/paths.rs000064400000000000000000000130321046102023000136760ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{iter::FusedIterator, ptr}; use crate::{ffi, PathDataType}; #[derive(Debug)] #[doc(alias = "cairo_path_t")] pub struct Path(ptr::NonNull); impl Path { #[inline] pub fn as_ptr(&self) -> *mut ffi::cairo_path_t { self.0.as_ptr() } #[inline] pub unsafe fn from_raw_full(pointer: *mut ffi::cairo_path_t) -> Path { debug_assert!(!pointer.is_null()); Path(ptr::NonNull::new_unchecked(pointer)) } pub fn iter(&self) -> PathSegments { use std::slice; unsafe { let ptr: *mut ffi::cairo_path_t = self.as_ptr(); let length = (*ptr).num_data as usize; let data_ptr = (*ptr).data; let data_vec = if length != 0 && !data_ptr.is_null() { slice::from_raw_parts(data_ptr, length) } else { &[] }; PathSegments { data: data_vec, i: 0, num_data: length, } } } } impl Drop for Path { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_path_destroy(self.as_ptr()); } } } #[derive(Debug, Clone, Copy, PartialEq)] pub enum PathSegment { MoveTo((f64, f64)), LineTo((f64, f64)), CurveTo((f64, f64), (f64, f64), (f64, f64)), ClosePath, } pub struct PathSegments<'a> { data: &'a [ffi::cairo_path_data], i: usize, num_data: usize, } impl<'a> Iterator for PathSegments<'a> { type Item = PathSegment; fn next(&mut self) -> Option { if self.i >= self.num_data { return None; } unsafe { let res = match PathDataType::from(self.data[self.i].header.data_type) { PathDataType::MoveTo => PathSegment::MoveTo(to_tuple(&self.data[self.i + 1].point)), PathDataType::LineTo => PathSegment::LineTo(to_tuple(&self.data[self.i + 1].point)), PathDataType::CurveTo => PathSegment::CurveTo( to_tuple(&self.data[self.i + 1].point), to_tuple(&self.data[self.i + 2].point), to_tuple(&self.data[self.i + 3].point), ), PathDataType::ClosePath => PathSegment::ClosePath, PathDataType::__Unknown(x) => panic!("Unknown value: {x}"), }; self.i += self.data[self.i].header.length as usize; Some(res) } } } impl<'a> FusedIterator for PathSegments<'a> {} fn to_tuple(pair: &[f64; 2]) -> (f64, f64) { (pair[0], pair[1]) } #[cfg(test)] mod tests { use super::*; use crate::{context::*, enums::Format, image_surface::*}; fn make_cr() -> Context { let surface = ImageSurface::create(Format::Rgb24, 1, 1).unwrap(); Context::new(&surface).expect("Can't create a Cairo context") } fn assert_path_equals_segments(expected: &Path, actual: &[PathSegment]) { // First ensure the lengths are equal let expected_iter = expected.iter(); let actual_iter = actual.iter(); assert_eq!(expected_iter.count(), actual_iter.count()); // Then actually compare the contents let expected_iter = expected.iter(); let actual_iter = actual.iter(); let iter = expected_iter.zip(actual_iter); for (e, a) in iter { assert_eq!(e, *a); } } #[test] fn empty_path_doesnt_iter() { let cr = make_cr(); let path = cr.copy_path().expect("Invalid context"); assert!(path.iter().next().is_none()); } #[test] fn moveto() { let cr = make_cr(); cr.move_to(1.0, 2.0); let path = cr.copy_path().expect("Invalid path"); assert_path_equals_segments(&path, &[PathSegment::MoveTo((1.0, 2.0))]); } #[test] fn moveto_lineto_moveto() { let cr = make_cr(); cr.move_to(1.0, 2.0); cr.line_to(3.0, 4.0); cr.move_to(5.0, 6.0); let path = cr.copy_path().expect("Invalid path"); assert_path_equals_segments( &path, &[ PathSegment::MoveTo((1.0, 2.0)), PathSegment::LineTo((3.0, 4.0)), PathSegment::MoveTo((5.0, 6.0)), ], ); } #[test] fn moveto_closepath() { let cr = make_cr(); cr.move_to(1.0, 2.0); cr.close_path(); let path = cr.copy_path().expect("Invalid path"); // Note that Cairo represents a close_path as closepath+moveto, // so that the next subpath will have a starting point, // from the extra moveto. assert_path_equals_segments( &path, &[ PathSegment::MoveTo((1.0, 2.0)), PathSegment::ClosePath, PathSegment::MoveTo((1.0, 2.0)), ], ); } #[test] fn curveto_closed_subpath_lineto() { let cr = make_cr(); cr.move_to(1.0, 2.0); cr.curve_to(3.0, 4.0, 5.0, 6.0, 7.0, 8.0); cr.close_path(); cr.line_to(9.0, 10.0); let path = cr.copy_path().expect("Invalid path"); assert_path_equals_segments( &path, &[ PathSegment::MoveTo((1.0, 2.0)), PathSegment::CurveTo((3.0, 4.0), (5.0, 6.0), (7.0, 8.0)), PathSegment::ClosePath, PathSegment::MoveTo((1.0, 2.0)), PathSegment::LineTo((9.0, 10.0)), ], ); } } cairo-rs-0.20.1/src/patterns.rs000064400000000000000000000372211046102023000144250ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ops::Deref, ptr}; use libc::{c_double, c_int, c_uint}; use crate::{ ffi, utils::status_to_result, Error, Extend, Filter, Matrix, MeshCorner, Path, PatternType, Surface, }; // See https://cairographics.org/manual/bindings-patterns.html for more info #[derive(Debug)] pub struct Pattern { pointer: *mut ffi::cairo_pattern_t, } impl Pattern { user_data_methods! { ffi::cairo_pattern_get_user_data, ffi::cairo_pattern_set_user_data, } #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_pattern_t { self.pointer } #[inline] pub unsafe fn from_raw_none(pointer: *mut ffi::cairo_pattern_t) -> Pattern { ffi::cairo_pattern_reference(pointer); Self::from_raw_full(pointer) } #[inline] pub unsafe fn from_raw_full(pointer: *mut ffi::cairo_pattern_t) -> Pattern { Self { pointer } } #[doc(alias = "cairo_pattern_get_type")] #[doc(alias = "get_type")] pub fn type_(&self) -> PatternType { unsafe { ffi::cairo_pattern_get_type(self.pointer).into() } } #[doc(alias = "cairo_pattern_get_reference_count")] #[doc(alias = "get_reference_count")] pub fn reference_count(&self) -> isize { unsafe { ffi::cairo_pattern_get_reference_count(self.pointer) as isize } } #[doc(alias = "cairo_pattern_set_extend")] pub fn set_extend(&self, extend: Extend) { unsafe { ffi::cairo_pattern_set_extend(self.pointer, extend.into()) } } #[doc(alias = "cairo_pattern_get_extend")] #[doc(alias = "get_extend")] pub fn extend(&self) -> Extend { unsafe { Extend::from(ffi::cairo_pattern_get_extend(self.pointer)) } } #[doc(alias = "cairo_pattern_set_filter")] pub fn set_filter(&self, filter: Filter) { unsafe { ffi::cairo_pattern_set_filter(self.pointer, filter.into()) } } #[doc(alias = "cairo_pattern_get_filter")] #[doc(alias = "get_filter")] pub fn filter(&self) -> Filter { unsafe { Filter::from(ffi::cairo_pattern_get_filter(self.pointer)) } } #[doc(alias = "cairo_pattern_set_matrix")] pub fn set_matrix(&self, matrix: Matrix) { unsafe { ffi::cairo_pattern_set_matrix(self.pointer, matrix.ptr()) } } #[doc(alias = "cairo_pattern_get_matrix")] #[doc(alias = "get_matrix")] pub fn matrix(&self) -> Matrix { let mut matrix = Matrix::null(); unsafe { ffi::cairo_pattern_get_matrix(self.pointer, matrix.mut_ptr()); } matrix } #[doc(alias = "cairo_pattern_status")] pub fn status(&self) -> Result<(), Error> { let status = unsafe { ffi::cairo_pattern_status(self.pointer) }; status_to_result(status) } } impl Clone for Pattern { #[inline] fn clone(&self) -> Self { Self { pointer: unsafe { ffi::cairo_pattern_reference(self.pointer) }, } } } impl Drop for Pattern { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_pattern_destroy(self.pointer) } } } impl AsRef for Pattern { #[inline] fn as_ref(&self) -> &Pattern { self } } macro_rules! convert { ($source: ident => $dest: ident = $( $variant: ident )|+ $( ($intermediate: ident) )*) => { impl TryFrom<$source> for $dest { type Error = $source; fn try_from(pattern: $source) -> Result { if $( pattern.type_() == PatternType::$variant )||+ { $( let pattern = $intermediate(pattern); )* Ok($dest(pattern)) } else { Err(pattern) } } } }; } macro_rules! pattern_type( //Signals without arguments ($pattern_type:ident $( = $variant: ident)*) => ( #[derive(Debug, Clone)] pub struct $pattern_type(Pattern); impl Deref for $pattern_type { type Target = Pattern; #[inline] fn deref(&self) -> &Pattern { &self.0 } } impl AsRef for $pattern_type { #[inline] fn as_ref(&self) -> &Pattern { &self.0 } } $( convert!(Pattern => $pattern_type = $variant); )* ); ); pattern_type!(SolidPattern = Solid); impl SolidPattern { #[doc(alias = "cairo_pattern_create_rgb")] pub fn from_rgb(red: f64, green: f64, blue: f64) -> Self { unsafe { Self(Pattern::from_raw_full(ffi::cairo_pattern_create_rgb( red, green, blue, ))) } } #[doc(alias = "cairo_pattern_create_rgba")] pub fn from_rgba(red: f64, green: f64, blue: f64, alpha: f64) -> Self { unsafe { Self(Pattern::from_raw_full(ffi::cairo_pattern_create_rgba( red, green, blue, alpha, ))) } } #[doc(alias = "cairo_pattern_get_rgba")] #[doc(alias = "get_rgba")] pub fn rgba(&self) -> Result<(f64, f64, f64, f64), Error> { unsafe { let mut red = 0.0; let mut green = 0.0; let mut blue = 0.0; let mut alpha = 0.0; let status = ffi::cairo_pattern_get_rgba( self.pointer, &mut red, &mut green, &mut blue, &mut alpha, ); status_to_result(status)?; Ok((red, green, blue, alpha)) } } } pattern_type!(Gradient); convert!(Pattern => Gradient = LinearGradient | RadialGradient); impl Gradient { #[doc(alias = "cairo_pattern_add_color_stop_rgb")] pub fn add_color_stop_rgb(&self, offset: f64, red: f64, green: f64, blue: f64) { unsafe { ffi::cairo_pattern_add_color_stop_rgb(self.pointer, offset, red, green, blue) } } #[doc(alias = "cairo_pattern_add_color_stop_rgba")] pub fn add_color_stop_rgba(&self, offset: f64, red: f64, green: f64, blue: f64, alpha: f64) { unsafe { ffi::cairo_pattern_add_color_stop_rgba(self.pointer, offset, red, green, blue, alpha) } } #[doc(alias = "cairo_pattern_get_color_stop_count")] #[doc(alias = "get_color_stop_count")] pub fn color_stop_count(&self) -> Result { unsafe { let mut count = 0; let status = ffi::cairo_pattern_get_color_stop_count(self.pointer, &mut count); status_to_result(status)?; Ok(count as isize) } } #[doc(alias = "cairo_pattern_get_color_stop_rgba")] #[doc(alias = "get_color_stop_rgba")] pub fn color_stop_rgba(&self, index: isize) -> Result<(f64, f64, f64, f64, f64), Error> { unsafe { let mut offset = 0.0; let mut red = 0.0; let mut green = 0.0; let mut blue = 0.0; let mut alpha = 0.0; let status = ffi::cairo_pattern_get_color_stop_rgba( self.pointer, index as c_int, &mut offset, &mut red, &mut green, &mut blue, &mut alpha, ); status_to_result(status)?; Ok((offset, red, green, blue, alpha)) } } } macro_rules! gradient_type { ($gradient_type: ident) => { #[derive(Debug, Clone)] pub struct $gradient_type(Gradient); impl Deref for $gradient_type { type Target = Gradient; #[inline] fn deref(&self) -> &Gradient { &self.0 } } impl AsRef for $gradient_type { #[inline] fn as_ref(&self) -> &Gradient { &self.0 } } impl AsRef for $gradient_type { #[inline] fn as_ref(&self) -> &Pattern { &self.0 } } convert!(Pattern => $gradient_type = $gradient_type (Gradient)); convert!(Gradient => $gradient_type = $gradient_type); } } gradient_type!(LinearGradient); impl LinearGradient { #[doc(alias = "cairo_pattern_create_linear")] pub fn new(x0: f64, y0: f64, x1: f64, y1: f64) -> Self { unsafe { Self(Gradient(Pattern::from_raw_full( ffi::cairo_pattern_create_linear(x0, y0, x1, y1), ))) } } #[doc(alias = "cairo_pattern_get_linear_points")] #[doc(alias = "get_linear_points")] pub fn linear_points(&self) -> Result<(f64, f64, f64, f64), Error> { unsafe { let mut x0 = 0.0; let mut y0 = 0.0; let mut x1 = 0.0; let mut y1 = 0.0; let status = ffi::cairo_pattern_get_linear_points( self.pointer, &mut x0, &mut y0, &mut x1, &mut y1, ); status_to_result(status)?; Ok((x0, y0, x1, y1)) } } } gradient_type!(RadialGradient); impl RadialGradient { #[doc(alias = "cairo_pattern_create_radial")] pub fn new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64) -> Self { unsafe { Self(Gradient(Pattern::from_raw_full( ffi::cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1), ))) } } #[doc(alias = "cairo_pattern_get_radial_circles")] #[doc(alias = "get_radial_circles")] pub fn radial_circles(&self) -> Result<(f64, f64, f64, f64, f64, f64), Error> { unsafe { let mut x0 = 0.0; let mut y0 = 0.0; let mut r0 = 0.0; let mut x1 = 0.0; let mut y1 = 0.0; let mut r1 = 0.0; let status = ffi::cairo_pattern_get_radial_circles( self.pointer, &mut x0, &mut y0, &mut r0, &mut x1, &mut y1, &mut r1, ); status_to_result(status)?; Ok((x0, y0, r0, x1, y1, r1)) } } } pattern_type!(SurfacePattern = Surface); impl SurfacePattern { #[doc(alias = "cairo_pattern_create_for_surface")] pub fn create(surface: impl AsRef) -> Self { unsafe { Self(Pattern::from_raw_full( ffi::cairo_pattern_create_for_surface(surface.as_ref().to_raw_none()), )) } } #[doc(alias = "cairo_pattern_get_surface")] #[doc(alias = "get_surface")] pub fn surface(&self) -> Result { unsafe { let mut surface_ptr: *mut ffi::cairo_surface_t = ptr::null_mut(); let status = ffi::cairo_pattern_get_surface(self.pointer, &mut surface_ptr); status_to_result(status)?; Ok(Surface::from_raw_none(surface_ptr)) } } } pattern_type!(Mesh = Mesh); impl Mesh { #[doc(alias = "cairo_pattern_create_mesh")] pub fn new() -> Self { unsafe { Self(Pattern::from_raw_full(ffi::cairo_pattern_create_mesh())) } } #[doc(alias = "cairo_mesh_pattern_begin_patch")] pub fn begin_patch(&self) { unsafe { ffi::cairo_mesh_pattern_begin_patch(self.pointer) } } #[doc(alias = "cairo_mesh_pattern_end_patch")] pub fn end_patch(&self) { unsafe { ffi::cairo_mesh_pattern_end_patch(self.pointer) } } #[doc(alias = "cairo_mesh_pattern_move_to")] pub fn move_to(&self, x: f64, y: f64) { unsafe { ffi::cairo_mesh_pattern_move_to(self.pointer, x, y) } } #[doc(alias = "cairo_mesh_pattern_line_to")] pub fn line_to(&self, x: f64, y: f64) { unsafe { ffi::cairo_mesh_pattern_line_to(self.pointer, x, y) } } #[doc(alias = "cairo_mesh_pattern_curve_to")] pub fn curve_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) { unsafe { ffi::cairo_mesh_pattern_curve_to(self.pointer, x1, y1, x2, y2, x3, y3) } } #[doc(alias = "cairo_mesh_pattern_set_control_point")] pub fn set_control_point(&self, corner: MeshCorner, x: f64, y: f64) { unsafe { ffi::cairo_mesh_pattern_set_control_point(self.pointer, corner.into(), x, y) } } #[doc(alias = "cairo_mesh_pattern_get_control_point")] #[doc(alias = "get_control_point")] pub fn control_point(&self, patch_num: usize, corner: MeshCorner) -> Result<(f64, f64), Error> { let mut x: c_double = 0.0; let mut y: c_double = 0.0; let status = unsafe { ffi::cairo_mesh_pattern_get_control_point( self.pointer, patch_num as c_uint, corner.into(), &mut x, &mut y, ) }; status_to_result(status)?; Ok((x, y)) } #[doc(alias = "cairo_mesh_pattern_set_corner_color_rgb")] pub fn set_corner_color_rgb(&self, corner: MeshCorner, red: f64, green: f64, blue: f64) { unsafe { ffi::cairo_mesh_pattern_set_corner_color_rgb( self.pointer, corner.into(), red, green, blue, ) } } #[doc(alias = "cairo_mesh_pattern_set_corner_color_rgba")] pub fn set_corner_color_rgba( &self, corner: MeshCorner, red: f64, green: f64, blue: f64, alpha: f64, ) { unsafe { ffi::cairo_mesh_pattern_set_corner_color_rgba( self.pointer, corner.into(), red, green, blue, alpha, ) } } #[doc(alias = "cairo_mesh_pattern_get_corner_color_rgba")] #[doc(alias = "get_corner_color_rgba")] pub fn corner_color_rgba( &self, patch_num: usize, corner: MeshCorner, ) -> Result<(f64, f64, f64, f64), Error> { let mut red: c_double = 0.0; let mut green: c_double = 0.0; let mut blue: c_double = 0.0; let mut alpha: c_double = 0.0; let status = unsafe { ffi::cairo_mesh_pattern_get_corner_color_rgba( self.pointer, patch_num as c_uint, corner.into(), &mut red, &mut green, &mut blue, &mut alpha, ) }; status_to_result(status)?; Ok((red, green, blue, alpha)) } #[doc(alias = "cairo_mesh_pattern_get_patch_count")] #[doc(alias = "get_patch_count")] pub fn patch_count(&self) -> Result { let mut count: c_uint = 0; unsafe { let status = ffi::cairo_mesh_pattern_get_patch_count(self.pointer, &mut count); status_to_result(status)?; } Ok(count as usize) } #[doc(alias = "cairo_mesh_pattern_get_path")] #[doc(alias = "get_path")] pub fn path(&self, patch_num: usize) -> Result { let path: Path = unsafe { Path::from_raw_full(ffi::cairo_mesh_pattern_get_path( self.pointer, patch_num as c_uint, )) }; let status = unsafe { let ptr: *mut ffi::cairo_path_t = path.as_ptr(); (*ptr).status }; status_to_result(status)?; Ok(path) } } impl Default for Mesh { fn default() -> Self { Self::new() } } #[test] fn try_from() { let linear = LinearGradient::new(0., 0., 1., 1.); let gradient = Gradient::clone(&linear); let pattern = Pattern::clone(&linear); assert!(Gradient::try_from(pattern.clone()).is_ok()); assert!(LinearGradient::try_from(gradient).is_ok()); assert!(LinearGradient::try_from(pattern).is_ok()); } cairo-rs-0.20.1/src/pdf.rs000064400000000000000000000212031046102023000133270ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ ffi::{CStr, CString}, io, mem, ops::Deref, path::Path, ptr, }; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, Error, PdfVersion, Surface, SurfaceType}; #[cfg(all(feature = "pdf", feature = "v1_16"))] use crate::{PdfMetadata, PdfOutline}; impl PdfVersion { pub fn as_str(self) -> Option<&'static str> { unsafe { let res = ffi::cairo_pdf_version_to_string(self.into()); res.as_ref() .and_then(|cstr| CStr::from_ptr(cstr as _).to_str().ok()) } } } declare_surface!(PdfSurface, SurfaceType::Pdf); impl PdfSurface { #[doc(alias = "cairo_pdf_surface_create")] pub fn new>(width: f64, height: f64, path: P) -> Result { let path = path.as_ref().to_string_lossy().into_owned(); let path = CString::new(path).unwrap(); unsafe { Self::from_raw_full(ffi::cairo_pdf_surface_create(path.as_ptr(), width, height)) } } for_stream_constructors!(cairo_pdf_surface_create_for_stream); #[doc(alias = "cairo_pdf_get_versions")] #[doc(alias = "get_versions")] pub fn versions() -> impl Iterator { let vers_slice = unsafe { let mut vers_ptr = ptr::null_mut(); let mut num_vers = mem::MaybeUninit::uninit(); ffi::cairo_pdf_get_versions(&mut vers_ptr, num_vers.as_mut_ptr()); let num_vers = num_vers.assume_init(); if num_vers == 0 { &[] } else { std::slice::from_raw_parts(vers_ptr, num_vers as _) } }; vers_slice.iter().map(|v| PdfVersion::from(*v)) } #[doc(alias = "cairo_pdf_surface_restrict_to_version")] pub fn restrict(&self, version: PdfVersion) -> Result<(), Error> { unsafe { ffi::cairo_pdf_surface_restrict_to_version(self.0.to_raw_none(), version.into()); } self.status() } #[doc(alias = "cairo_pdf_surface_set_size")] pub fn set_size(&self, width: f64, height: f64) -> Result<(), Error> { unsafe { ffi::cairo_pdf_surface_set_size(self.0.to_raw_none(), width, height); } self.status() } #[cfg(all(feature = "pdf", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "pdf", feature = "v1_16"))))] #[doc(alias = "cairo_pdf_surface_set_metadata")] pub fn set_metadata(&self, metadata: PdfMetadata, value: &str) -> Result<(), Error> { let value = CString::new(value).unwrap(); unsafe { ffi::cairo_pdf_surface_set_metadata( self.0.to_raw_none(), metadata.into(), value.as_ptr(), ); } self.status() } #[cfg(all(feature = "pdf", feature = "v1_18"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "pdf", feature = "v1_18"))))] #[doc(alias = "cairo_pdf_surface_set_custom_metadata")] pub fn set_custom_metadata(&self, name: &str, value: &str) -> Result<(), Error> { let name = CString::new(name).unwrap(); let value = CString::new(value).unwrap(); unsafe { ffi::cairo_pdf_surface_set_custom_metadata( self.0.to_raw_none(), name.as_ptr(), value.as_ptr(), ); } self.status() } #[cfg(all(feature = "pdf", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "pdf", feature = "v1_16"))))] #[doc(alias = "cairo_pdf_surface_set_page_label")] pub fn set_page_label(&self, label: &str) -> Result<(), Error> { let label = CString::new(label).unwrap(); unsafe { ffi::cairo_pdf_surface_set_page_label(self.0.to_raw_none(), label.as_ptr()); } self.status() } #[cfg(all(feature = "pdf", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "pdf", feature = "v1_16"))))] #[doc(alias = "cairo_pdf_surface_set_thumbnail_size")] pub fn set_thumbnail_size(&self, width: i32, height: i32) -> Result<(), Error> { unsafe { ffi::cairo_pdf_surface_set_thumbnail_size( self.0.to_raw_none(), width as _, height as _, ); } self.status() } #[cfg(all(feature = "pdf", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "pdf", feature = "v1_16"))))] #[doc(alias = "cairo_pdf_surface_add_outline")] pub fn add_outline( &self, parent_id: i32, name: &str, link_attribs: &str, flags: PdfOutline, ) -> Result { let name = CString::new(name).unwrap(); let link_attribs = CString::new(link_attribs).unwrap(); let res = unsafe { ffi::cairo_pdf_surface_add_outline( self.0.to_raw_none(), parent_id, name.as_ptr(), link_attribs.as_ptr(), flags.bits() as _, ) as _ }; self.status()?; Ok(res) } } #[cfg(test)] mod test { use tempfile::tempfile; use super::*; use crate::context::*; fn draw(surface: &Surface) { let cr = Context::new(surface).expect("Can't create a Cairo context"); cr.set_line_width(25.0); cr.set_source_rgba(1.0, 0.0, 0.0, 0.5); cr.line_to(0., 0.); cr.line_to(100., 100.); cr.stroke().expect("Surface on an invalid state"); cr.set_source_rgba(0.0, 0.0, 1.0, 0.5); cr.line_to(0., 100.); cr.line_to(100., 0.); cr.stroke().expect("Surface on an invalid state"); } fn draw_in_buffer() -> Vec { let buffer: Vec = vec![]; let surface = PdfSurface::for_stream(100., 100., buffer).unwrap(); surface.restrict(PdfVersion::_1_5).unwrap(); draw(&surface); *surface.finish_output_stream().unwrap().downcast().unwrap() } #[test] fn versions() { assert!(PdfSurface::versions().any(|v| v == PdfVersion::_1_4)); } #[test] fn version_string() { let ver_str = PdfVersion::_1_4.as_str().unwrap(); assert_eq!(ver_str, "PDF 1.4"); } #[test] #[cfg(unix)] fn file() { let surface = PdfSurface::new(100., 100., "/dev/null").unwrap(); draw(&surface); surface.finish(); } #[test] fn writer() { let file = tempfile().expect("tempfile failed"); let surface = PdfSurface::for_stream(100., 100., file).unwrap(); draw(&surface); let stream = surface.finish_output_stream().unwrap(); let file = stream.downcast::().unwrap(); let buffer = draw_in_buffer(); let file_size = file.metadata().unwrap().len(); assert_eq!(file_size, buffer.len() as u64); } #[test] fn ref_writer() { let mut file = tempfile().expect("tempfile failed"); let surface = unsafe { PdfSurface::for_raw_stream(100., 100., &mut file).unwrap() }; draw(&surface); surface.finish_output_stream().unwrap(); drop(file); } #[test] fn buffer() { let buffer = draw_in_buffer(); let header = b"%PDF-1.5"; assert_eq!(&buffer[..header.len()], header); } #[test] fn custom_writer() { struct CustomWriter(usize); impl io::Write for CustomWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.0 += buf.len(); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } let custom_writer = CustomWriter(0); let surface = PdfSurface::for_stream(20., 20., custom_writer).unwrap(); surface.set_size(100., 100.).unwrap(); draw(&surface); let stream = surface.finish_output_stream().unwrap(); let custom_writer = stream.downcast::().unwrap(); let buffer = draw_in_buffer(); assert_eq!(custom_writer.0, buffer.len()); } fn with_panicky_stream() -> PdfSurface { struct PanicWriter; impl io::Write for PanicWriter { fn write(&mut self, _buf: &[u8]) -> io::Result { panic!("panic in writer"); } fn flush(&mut self) -> io::Result<()> { Ok(()) } } let surface = PdfSurface::for_stream(20., 20., PanicWriter).unwrap(); surface.finish(); surface } #[test] #[should_panic] fn finish_stream_propagates_panic() { let _ = with_panicky_stream().finish_output_stream(); } } cairo-rs-0.20.1/src/ps.rs000064400000000000000000000156511046102023000132120ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ ffi::{CStr, CString}, io, mem, ops::Deref, path::Path, ptr, }; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, Error, PsLevel, Surface, SurfaceType}; impl PsLevel { pub fn as_str(self) -> Option<&'static str> { unsafe { let res = ffi::cairo_ps_level_to_string(self.into()); res.as_ref() .and_then(|cstr| CStr::from_ptr(cstr as _).to_str().ok()) } } } declare_surface!(PsSurface, SurfaceType::Ps); impl PsSurface { #[doc(alias = "cairo_ps_surface_create")] pub fn new>(width: f64, height: f64, path: P) -> Result { let path = path.as_ref().to_string_lossy().into_owned(); let path = CString::new(path).unwrap(); unsafe { Self::from_raw_full(ffi::cairo_ps_surface_create(path.as_ptr(), width, height)) } } for_stream_constructors!(cairo_ps_surface_create_for_stream); #[doc(alias = "cairo_ps_get_levels")] #[doc(alias = "get_levels")] pub fn levels() -> impl Iterator { let lvls_slice = unsafe { let mut vers_ptr = ptr::null_mut(); let mut num_vers = mem::MaybeUninit::uninit(); ffi::cairo_ps_get_levels(&mut vers_ptr, num_vers.as_mut_ptr()); let num_vers = num_vers.assume_init(); if num_vers == 0 { &[] } else { std::slice::from_raw_parts(vers_ptr, num_vers as _) } }; lvls_slice.iter().map(|v| PsLevel::from(*v)) } #[doc(alias = "cairo_ps_surface_restrict_to_level")] pub fn restrict(&self, level: PsLevel) { unsafe { ffi::cairo_ps_surface_restrict_to_level(self.0.to_raw_none(), level.into()); } } #[doc(alias = "cairo_ps_surface_get_eps")] #[doc(alias = "get_eps")] pub fn is_eps(&self) -> bool { unsafe { ffi::cairo_ps_surface_get_eps(self.0.to_raw_none()).as_bool() } } #[doc(alias = "cairo_ps_surface_set_eps")] pub fn set_eps(&self, eps: bool) { unsafe { ffi::cairo_ps_surface_set_eps(self.0.to_raw_none(), eps.into()); } } #[doc(alias = "cairo_ps_surface_set_size")] pub fn set_size(&self, width: f64, height: f64) { unsafe { ffi::cairo_ps_surface_set_size(self.0.to_raw_none(), width, height); } } #[doc(alias = "cairo_ps_surface_dsc_begin_setup")] pub fn dsc_begin_setup(&self) { unsafe { ffi::cairo_ps_surface_dsc_begin_setup(self.0.to_raw_none()); } } #[doc(alias = "cairo_ps_surface_dsc_begin_page_setup")] pub fn begin_page_setup(&self) { unsafe { ffi::cairo_ps_surface_dsc_begin_page_setup(self.0.to_raw_none()); } } #[doc(alias = "cairo_ps_surface_dsc_comment")] pub fn dsc_comment(&self, comment: &str) { let comment = CString::new(comment).unwrap(); unsafe { ffi::cairo_ps_surface_dsc_comment(self.0.to_raw_none(), comment.as_ptr()); } } } #[cfg(test)] mod test { use tempfile::tempfile; use super::*; use crate::context::*; fn draw(surface: &Surface) { let cr = Context::new(surface).expect("Can't create a Cairo context"); // Note: Not using RGBA here as PS doesn't natively support // semi-transparency and Cairo would then embed a rasterized bitmap cr.set_line_width(25.0); cr.set_source_rgb(1.0, 0.0, 0.0); cr.line_to(0., 0.); cr.line_to(100., 100.); cr.stroke().expect("Surface on an invalid state"); cr.set_source_rgb(0.0, 0.0, 1.0); cr.line_to(0., 100.); cr.line_to(100., 0.); cr.stroke().expect("Surface on an invalid state"); } fn draw_in_buffer() -> Vec { let buffer: Vec = vec![]; let surface = PsSurface::for_stream(100., 100., buffer).unwrap(); draw(&surface); *surface.finish_output_stream().unwrap().downcast().unwrap() } #[test] fn levels() { assert!(PsSurface::levels().any(|v| v == PsLevel::_2)); } #[test] fn level_string() { let ver_str = PsLevel::_2.as_str().unwrap(); assert_eq!(ver_str, "PS Level 2"); } #[test] fn eps() { let buffer: Vec = vec![]; let surface = PsSurface::for_stream(100., 100., buffer).unwrap(); surface.set_eps(true); assert!(surface.is_eps()); } #[test] #[cfg(unix)] fn file() { let surface = PsSurface::new(100., 100., "/dev/null").unwrap(); draw(&surface); surface.finish(); } #[test] fn writer() { let file = tempfile().expect("tempfile failed"); let surface = PsSurface::for_stream(100., 100., file).unwrap(); draw(&surface); let stream = surface.finish_output_stream().unwrap(); let file = stream.downcast::().unwrap(); let buffer = draw_in_buffer(); let file_size = file.metadata().unwrap().len(); assert_eq!(file_size, buffer.len() as u64); } #[test] fn ref_writer() { let mut file = tempfile().expect("tempfile failed"); let surface = unsafe { PsSurface::for_raw_stream(100., 100., &mut file).unwrap() }; draw(&surface); surface.finish_output_stream().unwrap(); } #[test] fn buffer() { let buffer = draw_in_buffer(); let header = b"%!PS-Adobe"; assert_eq!(&buffer[..header.len()], header); } #[test] fn custom_writer() { struct CustomWriter(usize); impl io::Write for CustomWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.0 += buf.len(); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } let custom_writer = CustomWriter(0); let surface = PsSurface::for_stream(20., 20., custom_writer).unwrap(); surface.set_size(100., 100.); draw(&surface); let stream = surface.finish_output_stream().unwrap(); let custom_writer = stream.downcast::().unwrap(); let buffer = draw_in_buffer(); assert_eq!(custom_writer.0, buffer.len()); } fn with_panicky_stream() -> PsSurface { struct PanicWriter; impl io::Write for PanicWriter { fn write(&mut self, _buf: &[u8]) -> io::Result { panic!("panic in writer"); } fn flush(&mut self) -> io::Result<()> { Ok(()) } } let surface = PsSurface::for_stream(20., 20., PanicWriter).unwrap(); surface.finish(); surface } #[test] #[should_panic] fn finish_stream_propagates_panic() { let _ = with_panicky_stream().finish_output_stream(); } } cairo-rs-0.20.1/src/quartz_surface.rs000064400000000000000000000023701046102023000156200ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, ops::Deref}; use ffi::CGContextRef; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, Error, Format, Surface, SurfaceType}; declare_surface!(QuartzSurface, SurfaceType::Quartz); impl QuartzSurface { #[doc(alias = "cairo_quartz_surface_create")] pub fn create(format: Format, width: u32, height: u32) -> Result { unsafe { Self::from_raw_full(ffi::cairo_quartz_surface_create( format.into(), width, height, )) } } #[doc(alias = "cairo_quartz_surface_create_for_cg_context")] pub fn create_for_cg_context( cg_context: CGContextRef, width: u32, height: u32, ) -> Result { unsafe { Self::from_raw_full(ffi::cairo_quartz_surface_create_for_cg_context( cg_context, width, height, )) } } #[doc(alias = "cairo_quartz_surface_get_cg_context")] #[doc(alias = "get_cg_context")] pub fn cg_context(&self) -> CGContextRef { unsafe { ffi::cairo_quartz_surface_get_cg_context(self.to_raw_none()) } } } cairo-rs-0.20.1/src/recording_surface.rs000064400000000000000000000033431046102023000162470ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ops::Deref; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, Content, Error, Rectangle, Surface, SurfaceType}; declare_surface!(RecordingSurface, SurfaceType::Recording); impl RecordingSurface { #[doc(alias = "cairo_recording_surface_create")] pub fn create(content: Content, extends: Option) -> Result { unsafe { let extends_ptr = match extends { Some(ref c) => c.to_raw_none(), None => ::std::ptr::null(), }; Self::from_raw_full(ffi::cairo_recording_surface_create( content.into(), extends_ptr, )) } } #[doc(alias = "cairo_recording_surface_get_extents")] #[doc(alias = "get_extents")] pub fn extents(&self) -> Option { unsafe { let rectangle: Rectangle = ::std::mem::zeroed(); if ffi::cairo_recording_surface_get_extents(self.to_raw_none(), rectangle.to_raw_none()) .as_bool() { Some(rectangle) } else { None } } } #[doc(alias = "cairo_recording_surface_ink_extents")] pub fn ink_extents(&self) -> (f64, f64, f64, f64) { let mut x0 = 0.; let mut y0 = 0.; let mut width = 0.; let mut height = 0.; unsafe { ffi::cairo_recording_surface_ink_extents( self.to_raw_none(), &mut x0, &mut y0, &mut width, &mut height, ); } (x0, y0, width, height) } } cairo-rs-0.20.1/src/rectangle.rs000064400000000000000000000103771046102023000145340ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use std::fmt; #[cfg(feature = "use_glib")] use std::{marker::PhantomData, mem}; #[cfg(feature = "use_glib")] use glib::translate::*; #[derive(Clone, Copy, PartialEq)] #[repr(transparent)] #[doc(alias = "cairo_rectangle_t")] pub struct Rectangle(ffi::cairo_rectangle_t); impl Rectangle { #[inline] pub fn new(x: f64, y: f64, width: f64, height: f64) -> Self { Self(ffi::cairo_rectangle_t { x, y, width, height, }) } #[inline] pub fn x(&self) -> f64 { self.0.x } #[inline] pub fn set_x(&mut self, x: f64) { self.0.x = x; } #[inline] pub fn y(&self) -> f64 { self.0.y } #[inline] pub fn set_y(&mut self, y: f64) { self.0.y = y; } #[inline] pub fn width(&self) -> f64 { self.0.width } #[inline] pub fn set_width(&mut self, width: f64) { self.0.width = width; } #[inline] pub fn height(&self) -> f64 { self.0.height } #[inline] pub fn set_height(&mut self, height: f64) { self.0.height = height; } } impl fmt::Debug for Rectangle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Rectangle") .field("x", &self.x()) .field("y", &self.y()) .field("width", &self.width()) .field("height", &self.height()) .finish() } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl Uninitialized for Rectangle { #[inline] unsafe fn uninitialized() -> Self { mem::zeroed() } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const ffi::cairo_rectangle_t> for Rectangle { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::cairo_rectangle_t, Self> { Stash( self as *const Rectangle as *const ffi::cairo_rectangle_t, PhantomData, ) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut ffi::cairo_rectangle_t> for Rectangle { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::cairo_rectangle_t, Self> { StashMut( self as *mut Rectangle as *mut ffi::cairo_rectangle_t, PhantomData, ) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrNone<*const ffi::cairo_rectangle_t> for Rectangle { #[inline] unsafe fn from_glib_none(ptr: *const ffi::cairo_rectangle_t) -> Self { *(ptr as *const Rectangle) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrBorrow<*mut ffi::cairo_rectangle_t> for Rectangle { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_rectangle_t) -> crate::Borrowed { crate::Borrowed::new(*(ptr as *mut Rectangle)) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrNone<*mut ffi::cairo_rectangle_t> for Rectangle { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::cairo_rectangle_t) -> Self { *(ptr as *mut Rectangle) } } #[cfg(feature = "use_glib")] gvalue_impl_inline!( Rectangle, ffi::cairo_rectangle_t, ffi::gobject::cairo_gobject_rectangle_get_type ); impl Rectangle { #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_rectangle_t { &self.0 as *const ffi::cairo_rectangle_t as *mut ffi::cairo_rectangle_t } } #[cfg(test)] mod tests { use super::*; #[cfg(feature = "use_glib")] #[test] fn rectangle_gvalues() { use glib::prelude::*; let rect = Rectangle::new(1., 2., 3., 4.); let value = rect.to_value(); assert_eq!(value.get::().unwrap().width(), 3.); let _ = rect.to_value(); let rect = Some(rect); let value = rect.to_value(); assert_eq!( value.get::>().unwrap().map(|s| s.width()), Some(3.) ); let _ = rect.as_ref().to_value(); assert_eq!( value .get::>() .unwrap() .map(|s| s.width()), Some(3.) ); } } cairo-rs-0.20.1/src/rectangle_int.rs000064400000000000000000000072171046102023000154050ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use std::fmt; #[cfg(feature = "use_glib")] use std::{marker::PhantomData, mem}; #[cfg(feature = "use_glib")] use glib::translate::*; #[derive(Clone, Copy, PartialEq, Eq)] #[repr(transparent)] #[doc(alias = "cairo_rectangle_int_t")] pub struct RectangleInt(ffi::cairo_rectangle_int_t); impl RectangleInt { #[inline] pub fn new(x: i32, y: i32, width: i32, height: i32) -> Self { Self(ffi::cairo_rectangle_int_t { x, y, width, height, }) } #[inline] pub fn x(&self) -> i32 { self.0.x } #[inline] pub fn set_x(&mut self, x: i32) { self.0.x = x; } #[inline] pub fn y(&self) -> i32 { self.0.y } #[inline] pub fn set_y(&mut self, y: i32) { self.0.y = y; } #[inline] pub fn width(&self) -> i32 { self.0.width } #[inline] pub fn set_width(&mut self, width: i32) { self.0.width = width; } #[inline] pub fn height(&self) -> i32 { self.0.height } #[inline] pub fn set_height(&mut self, height: i32) { self.0.height = height; } } impl fmt::Debug for RectangleInt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RectangleInt") .field("x", &self.x()) .field("y", &self.y()) .field("width", &self.width()) .field("height", &self.height()) .finish() } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl Uninitialized for RectangleInt { #[inline] unsafe fn uninitialized() -> Self { mem::zeroed() } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const ffi::cairo_rectangle_int_t> for RectangleInt { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::cairo_rectangle_int_t, Self> { Stash( self as *const RectangleInt as *const ffi::cairo_rectangle_int_t, PhantomData, ) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut ffi::cairo_rectangle_int_t> for RectangleInt { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::cairo_rectangle_int_t, Self> { StashMut( self as *mut RectangleInt as *mut ffi::cairo_rectangle_int_t, PhantomData, ) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrNone<*const ffi::cairo_rectangle_int_t> for RectangleInt { #[inline] unsafe fn from_glib_none(ptr: *const ffi::cairo_rectangle_int_t) -> Self { *(ptr as *const RectangleInt) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrBorrow<*mut ffi::cairo_rectangle_int_t> for RectangleInt { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_rectangle_int_t) -> crate::Borrowed { crate::Borrowed::new(*(ptr as *mut RectangleInt)) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrNone<*mut ffi::cairo_rectangle_int_t> for RectangleInt { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::cairo_rectangle_int_t) -> Self { *(ptr as *mut RectangleInt) } } #[cfg(feature = "use_glib")] gvalue_impl_inline!( RectangleInt, ffi::cairo_rectangle_int_t, ffi::gobject::cairo_gobject_rectangle_int_get_type ); impl RectangleInt { #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_rectangle_int_t { &self.0 as *const ffi::cairo_rectangle_int_t as *mut ffi::cairo_rectangle_int_t } } cairo-rs-0.20.1/src/region.rs000064400000000000000000000210401046102023000140400ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(feature = "use_glib")] use std::marker::PhantomData; use std::ptr; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, utils::status_to_result, Error, RectangleInt, RegionOverlap}; #[derive(Debug)] #[repr(transparent)] #[doc(alias = "cairo_region_t")] pub struct Region(ptr::NonNull); #[cfg(feature = "use_glib")] impl IntoGlibPtr<*mut ffi::cairo_region_t> for Region { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::cairo_region_t { (&*std::mem::ManuallyDrop::new(self)).to_glib_none().0 } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut ffi::cairo_region_t> for &'a Region { type Storage = PhantomData<&'a Region>; #[inline] fn to_glib_none(&self) -> Stash<'a, *mut ffi::cairo_region_t, Self> { Stash(self.0.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *mut ffi::cairo_region_t { unsafe { ffi::cairo_region_reference(self.0.as_ptr()) } } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut ffi::cairo_region_t> for Region { type Storage = PhantomData<&'a mut Self>; // FIXME: This is unsafe: regions are reference counted, so we could get multiple mutable // references here #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::cairo_region_t, Self> { StashMut(self.0.as_ptr(), PhantomData) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrNone<*mut ffi::cairo_region_t> for Region { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::cairo_region_t) -> Region { Self::from_raw_none(ptr) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrBorrow<*mut ffi::cairo_region_t> for Region { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_region_t) -> crate::Borrowed { Self::from_raw_borrow(ptr) } } #[cfg(feature = "use_glib")] #[doc(hidden)] impl FromGlibPtrFull<*mut ffi::cairo_region_t> for Region { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::cairo_region_t) -> Region { Self::from_raw_full(ptr) } } #[cfg(feature = "use_glib")] gvalue_impl!( Region, ffi::cairo_region_t, ffi::gobject::cairo_gobject_region_get_type ); impl Clone for Region { #[inline] fn clone(&self) -> Region { unsafe { Self::from_raw_none(self.to_raw_none()) } } } impl Drop for Region { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_region_destroy(self.0.as_ptr()); } } } impl PartialEq for Region { #[doc(alias = "cairo_region_equal")] #[inline] fn eq(&self, other: &Region) -> bool { unsafe { ffi::cairo_region_equal(self.0.as_ptr(), other.0.as_ptr()).as_bool() } } } impl Eq for Region {} impl Region { #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_region_t) -> Region { debug_assert!(!ptr.is_null()); ffi::cairo_region_reference(ptr); Region(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_region_t) -> crate::Borrowed { debug_assert!(!ptr.is_null()); crate::Borrowed::new(Region(ptr::NonNull::new_unchecked(ptr))) } #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_region_t) -> Region { debug_assert!(!ptr.is_null()); Region(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_region_t { self.0.as_ptr() } #[doc(alias = "cairo_region_create")] pub fn create() -> Region { unsafe { Self::from_raw_full(ffi::cairo_region_create()) } } #[doc(alias = "cairo_region_create_rectangle")] pub fn create_rectangle(rectangle: &RectangleInt) -> Region { unsafe { Self::from_raw_full(ffi::cairo_region_create_rectangle(rectangle.to_raw_none())) } } #[doc(alias = "cairo_region_create_rectangles")] pub fn create_rectangles(rectangles: &[RectangleInt]) -> Region { unsafe { Self::from_raw_full(ffi::cairo_region_create_rectangles( rectangles.as_ptr() as *mut ffi::cairo_rectangle_int_t, rectangles.len() as i32, )) } } #[doc(alias = "cairo_region_copy")] #[must_use] pub fn copy(&self) -> Region { unsafe { Self::from_raw_full(ffi::cairo_region_copy(self.0.as_ptr())) } } #[doc(alias = "get_extents")] #[doc(alias = "cairo_region_get_extents")] pub fn extents(&self, rectangle: &RectangleInt) { unsafe { ffi::cairo_region_get_extents(self.0.as_ptr(), rectangle.to_raw_none()) } } #[doc(alias = "cairo_region_num_rectangles")] pub fn num_rectangles(&self) -> i32 { unsafe { ffi::cairo_region_num_rectangles(self.0.as_ptr()) } } #[doc(alias = "get_rectangle")] #[doc(alias = "cairo_region_get_rectangle")] pub fn rectangle(&self, nth: i32) -> RectangleInt { unsafe { let rectangle: RectangleInt = ::std::mem::zeroed(); ffi::cairo_region_get_rectangle(self.0.as_ptr(), nth, rectangle.to_raw_none()); rectangle } } #[doc(alias = "cairo_region_is_empty")] pub fn is_empty(&self) -> bool { unsafe { ffi::cairo_region_is_empty(self.0.as_ptr()).as_bool() } } #[doc(alias = "cairo_region_contains_point")] pub fn contains_point(&self, x: i32, y: i32) -> bool { unsafe { ffi::cairo_region_contains_point(self.0.as_ptr(), x, y).as_bool() } } #[doc(alias = "cairo_region_contains_rectangle")] pub fn contains_rectangle(&self, rectangle: &RectangleInt) -> RegionOverlap { unsafe { RegionOverlap::from(ffi::cairo_region_contains_rectangle( self.0.as_ptr(), rectangle.to_raw_none(), )) } } #[doc(alias = "cairo_region_translate")] pub fn translate(&self, dx: i32, dy: i32) { unsafe { ffi::cairo_region_translate(self.0.as_ptr(), dx, dy) } } #[doc(alias = "cairo_region_intersect")] pub fn intersect(&self, other: &Region) -> Result<(), Error> { unsafe { let status = ffi::cairo_region_intersect(self.0.as_ptr(), other.0.as_ptr()); status_to_result(status) } } #[doc(alias = "cairo_region_intersect_rectangle")] pub fn intersect_rectangle(&self, rectangle: &RectangleInt) -> Result<(), Error> { unsafe { let status = ffi::cairo_region_intersect_rectangle(self.0.as_ptr(), rectangle.to_raw_none()); status_to_result(status) } } #[doc(alias = "cairo_region_subtract")] pub fn subtract(&self, other: &Region) -> Result<(), Error> { unsafe { let status = ffi::cairo_region_subtract(self.0.as_ptr(), other.0.as_ptr()); status_to_result(status) } } #[doc(alias = "cairo_region_subtract_rectangle")] pub fn subtract_rectangle(&self, rectangle: &RectangleInt) -> Result<(), Error> { unsafe { let status = ffi::cairo_region_subtract_rectangle(self.0.as_ptr(), rectangle.to_raw_none()); status_to_result(status) } } #[doc(alias = "cairo_region_union")] pub fn union(&self, other: &Region) -> Result<(), Error> { unsafe { let status = ffi::cairo_region_union(self.0.as_ptr(), other.0.as_ptr()); status_to_result(status) } } #[doc(alias = "cairo_region_union_rectangle")] pub fn union_rectangle(&self, rectangle: &RectangleInt) -> Result<(), Error> { unsafe { let status = ffi::cairo_region_union_rectangle(self.0.as_ptr(), rectangle.to_raw_none()); status_to_result(status) } } #[doc(alias = "cairo_region_xor")] pub fn xor(&self, other: &Region) -> Result<(), Error> { unsafe { let status = ffi::cairo_region_xor(self.0.as_ptr(), other.0.as_ptr()); status_to_result(status) } } #[doc(alias = "cairo_region_xor_rectangle")] pub fn xor_rectangle(&self, rectangle: &RectangleInt) -> Result<(), Error> { unsafe { let status = ffi::cairo_region_xor_rectangle(self.0.as_ptr(), rectangle.to_raw_none()); status_to_result(status) } } #[doc(alias = "cairo_region_status")] pub fn status(&self) -> Result<(), Error> { let status = unsafe { ffi::cairo_region_status(self.0.as_ptr()) }; status_to_result(status) } } cairo-rs-0.20.1/src/stream.rs000064400000000000000000000225241046102023000140600ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ any::Any, cell::{Cell, RefCell}, io, panic::AssertUnwindSafe, ptr, rc::Rc, }; use crate::ffi; use libc::{c_double, c_uchar, c_uint, c_void}; use crate::{Error, Surface, UserDataKey}; macro_rules! for_stream_constructors { ($constructor_ffi: ident) => { /// Takes full ownership of the output stream, /// which is not allowed to borrow any lifetime shorter than `'static`. /// /// Because the underlying `cairo_surface_t` is reference-counted, /// a lifetime parameter in a Rust wrapper type would not be enough to track /// how long it can keep writing to the stream. pub fn for_stream( width: f64, height: f64, stream: W, ) -> Result { Ok(Self(Surface::_for_stream( ffi::$constructor_ffi, width, height, stream, )?)) } /// Allows writing to a borrowed stream. The lifetime of the borrow is not tracked. /// /// # Safety /// /// The value that `stream` points to must live at least until the underlying `cairo_surface_t` /// (which maybe be longer then the Rust `PdfSurface` wrapper, because of reference-counting), /// or until the output stream is removed from the surface with [`Surface::finish_output_stream`]. /// /// Since the former is hard to track for sure, the latter is strongly recommended. /// The concrete type behind the `Box` value returned by `finish_output_stream` /// is private, so you won’t be able to downcast it. /// But removing it anyway ensures that later writes do not go through a dangling pointer. pub unsafe fn for_raw_stream( width: f64, height: f64, stream: *mut W, ) -> Result { Ok(Self(Surface::_for_raw_stream( ffi::$constructor_ffi, width, height, stream, )?)) } }; } impl Surface { pub(crate) fn _for_stream( constructor: Constructor, width: f64, height: f64, stream: W, ) -> Result { let env_rc = Rc::new(CallbackEnvironment { mutable: RefCell::new(MutableCallbackEnvironment { stream: Some((Box::new(stream), None)), unwind_payload: None, }), saw_already_borrowed: Cell::new(false), }); let env: *const CallbackEnvironment = &*env_rc; unsafe { let ptr = constructor(Some(write_callback::), env as *mut c_void, width, height); let surface = Surface::from_raw_full(ptr)?; surface.set_user_data(&STREAM_CALLBACK_ENVIRONMENT, env_rc)?; Ok(surface) } } pub(crate) unsafe fn _for_raw_stream( constructor: Constructor, width: f64, height: f64, stream: *mut W, ) -> Result { Self::_for_stream( constructor, width, height, RawStream(ptr::NonNull::new(stream).expect("NULL stream passed")), ) } /// Finish the surface, then remove and return the output stream if any. /// /// This calls [`Surface::finish`], to make sure pending writes are done. /// /// This is relevant for surfaces created for example with [`crate::PdfSurface::for_stream`]. /// /// Use [`Box::downcast`] to recover the concrete stream type. /// /// # Panics /// /// This method panics if: /// /// * This method was already called for this surface, or /// * This surface was not created with an output stream in the first place, or /// * A previous write to this surface panicked, or /// * A previous write happened while another write was ongoing, or /// * A write is ongoing now. /// /// The latter two cases can only occur with a pathological output stream type /// that accesses the same surface again from `Write::write_all`. pub fn finish_output_stream(&self) -> Result, StreamWithError> { self.finish(); let env = self .user_data_ptr(&STREAM_CALLBACK_ENVIRONMENT) .expect("surface without an output stream"); // Safety: since `STREAM_CALLBACK_ENVIRONMENT` is private and we never // call `set_user_data` again or `remove_user_data` with it, // the contract of `get_user_data_ptr` says that the user data entry // lives as long as the underlying `cairo_surface_t` // which is at least as long as `self`. let env = unsafe { &*env.as_ptr() }; if env.saw_already_borrowed.get() { panic!("The output stream’s RefCell was already borrowed when cairo attempted a write") } let mut mutable = env.mutable.borrow_mut(); if let Some(payload) = mutable.unwind_payload.take() { std::panic::resume_unwind(payload) } let (stream, io_error) = mutable .stream .take() .expect("output stream was already taken"); if let Some(error) = io_error { Err(StreamWithError { stream, error }) } else { Ok(stream) } } } pub struct StreamWithError { pub stream: Box, pub error: io::Error, } impl std::fmt::Debug for StreamWithError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { self.error.fmt(f) } } impl std::fmt::Display for StreamWithError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { self.error.fmt(f) } } impl From for io::Error { fn from(e: StreamWithError) -> Self { e.error } } pub(crate) type Constructor = unsafe extern "C" fn( ffi::cairo_write_func_t, *mut c_void, c_double, c_double, ) -> *mut ffi::cairo_surface_t; static STREAM_CALLBACK_ENVIRONMENT: UserDataKey = UserDataKey::new(); struct CallbackEnvironment { mutable: RefCell, saw_already_borrowed: Cell, } struct MutableCallbackEnvironment { stream: Option<(Box, Option)>, unwind_payload: Option>, } // Safety: unwinding into C is undefined behavior (https://github.com/rust-lang/rust/issues/58794) // so code outside of the `catch_unwind` call must never panic. extern "C" fn write_callback( env: *mut c_void, data: *mut c_uchar, length: c_uint, ) -> ffi::cairo_status_t { // This is consistent with the type of `env` in `Surface::_for_stream`. let env: *const CallbackEnvironment = env as _; // Safety: the user data entry keeps `Rc` alive // until the surface is destroyed. // If this is called by cairo, the surface is still alive. let env: &CallbackEnvironment = unsafe { &*env }; if let Ok(mut mutable) = env.mutable.try_borrow_mut() { if let MutableCallbackEnvironment { stream: Some(( stream, // Don’t attempt another write, if a previous one errored or panicked: io_error @ None, )), unwind_payload: unwind_payload @ None, } = &mut *mutable { // Safety: `write_callback` was instantiated in `Surface::_for_stream` // with a W parameter consistent with the box that was unsized to `Box`. let stream = unsafe { AnyExt::downcast_mut_unchecked::(&mut **stream) }; // Safety: this is the callback contract from cairo’s API let data = unsafe { if data.is_null() || length == 0 { &[] } else { std::slice::from_raw_parts(data, length as usize) } }; // Because `::write_all` is a generic, // we must conservatively assume that it can panic. let result = std::panic::catch_unwind(AssertUnwindSafe(|| stream.write_all(data))); match result { Ok(Ok(())) => return ffi::STATUS_SUCCESS, Ok(Err(error)) => { *io_error = Some(error); } Err(payload) => { *unwind_payload = Some(payload); } } } } else { env.saw_already_borrowed.set(true) } Error::WriteError.into() } struct RawStream(ptr::NonNull); impl io::Write for RawStream { fn write(&mut self, buf: &[u8]) -> io::Result { unsafe { (*self.0.as_ptr()).write(buf) } } fn flush(&mut self) -> io::Result<()> { unsafe { (*self.0.as_ptr()).flush() } } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { unsafe { (*self.0.as_ptr()).write_all(buf) } } } trait AnyExt { /// Any::downcast_mut, but YOLO unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { let ptr = self as *mut Self as *mut T; &mut *ptr } } impl AnyExt for dyn Any {} cairo-rs-0.20.1/src/surface.rs000064400000000000000000000313041046102023000142110ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(feature = "use_glib")] use std::marker::PhantomData; use std::{ffi::CString, ops::Deref, ptr, slice}; #[cfg(feature = "use_glib")] use glib::translate::*; use libc::{c_ulong, c_void}; use crate::{ ffi, utils::status_to_result, Content, Device, Error, Format, ImageSurface, Rectangle, RectangleInt, SurfaceType, }; #[derive(Debug)] #[doc(alias = "cairo_surface_t")] #[repr(transparent)] pub struct Surface(ptr::NonNull); impl Surface { #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_surface_t) -> Surface { debug_assert!(!ptr.is_null()); ffi::cairo_surface_reference(ptr); Surface(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_surface_t) -> crate::Borrowed { debug_assert!(!ptr.is_null()); crate::Borrowed::new(Surface(ptr::NonNull::new_unchecked(ptr))) } #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Result { debug_assert!(!ptr.is_null()); let status = ffi::cairo_surface_status(ptr); status_to_result(status)?; Ok(Surface(ptr::NonNull::new_unchecked(ptr))) } #[inline] pub fn to_raw_none(&self) -> *mut ffi::cairo_surface_t { self.0.as_ptr() } #[doc(alias = "cairo_surface_create_similar")] pub fn create_similar( &self, content: Content, width: i32, height: i32, ) -> Result { unsafe { Self::from_raw_full(ffi::cairo_surface_create_similar( self.0.as_ptr(), content.into(), width, height, )) } } #[doc(alias = "cairo_surface_create_for_rectangle")] pub fn create_for_rectangle(&self, bounds: Rectangle) -> Result { unsafe { Self::from_raw_full(ffi::cairo_surface_create_for_rectangle( self.0.as_ptr(), bounds.x(), bounds.y(), bounds.width(), bounds.height(), )) } } #[doc(alias = "cairo_surface_get_mime_data")] #[doc(alias = "get_mime_data")] pub fn mime_data(&self, mime_type: &str) -> Option> { let data_ptr: *mut u8 = ptr::null_mut(); let mut length: c_ulong = 0; unsafe { let mime_type = CString::new(mime_type).unwrap(); ffi::cairo_surface_get_mime_data( self.to_raw_none(), mime_type.as_ptr(), &data_ptr, &mut length, ); if !data_ptr.is_null() && length != 0 { Some(slice::from_raw_parts(data_ptr as *const u8, length as usize).to_vec()) } else { None } } } #[doc(alias = "cairo_surface_get_mime_data")] #[doc(alias = "get_mime_data_raw")] pub unsafe fn mime_data_raw(&self, mime_type: &str) -> Option<&[u8]> { let data_ptr: *mut u8 = ptr::null_mut(); let mut length: c_ulong = 0; let mime_type = CString::new(mime_type).unwrap(); ffi::cairo_surface_get_mime_data( self.to_raw_none(), mime_type.as_ptr(), &data_ptr, &mut length, ); if !data_ptr.is_null() && length != 0 { Some(slice::from_raw_parts( data_ptr as *const u8, length as usize, )) } else { None } } #[doc(alias = "cairo_surface_set_mime_data")] pub fn set_mime_data + 'static>( &self, mime_type: &str, slice: T, ) -> Result<(), Error> { let b = Box::new(slice); let (size, data) = { let slice = (*b).as_ref(); (slice.len(), slice.as_ptr()) }; let user_data = Box::into_raw(b); unsafe extern "C" fn unbox(data: *mut c_void) { let data: Box = Box::from_raw(data as *mut T); drop(data); } let status = unsafe { let mime_type = CString::new(mime_type).unwrap(); ffi::cairo_surface_set_mime_data( self.to_raw_none(), mime_type.as_ptr(), data, size as c_ulong, Some(unbox::), user_data as *mut _, ) }; status_to_result(status) } #[doc(alias = "cairo_surface_supports_mime_type")] pub fn supports_mime_type(&self, mime_type: &str) -> bool { unsafe { let mime_type = CString::new(mime_type).unwrap(); ffi::cairo_surface_supports_mime_type(self.0.as_ptr(), mime_type.as_ptr()).as_bool() } } #[doc(alias = "cairo_surface_get_device")] #[doc(alias = "get_device")] pub fn device(&self) -> Option { unsafe { let device = ffi::cairo_surface_get_device(self.to_raw_none()); if device.is_null() { None } else { Some(Device::from_raw_none(device)) } } } #[doc(alias = "cairo_surface_get_content")] pub fn content(&self) -> Content { unsafe { ffi::cairo_surface_get_content(self.to_raw_none()) }.into() } #[doc(alias = "cairo_surface_set_device_offset")] pub fn set_device_offset(&self, x_offset: f64, y_offset: f64) { unsafe { ffi::cairo_surface_set_device_offset(self.to_raw_none(), x_offset, y_offset) } } #[doc(alias = "cairo_surface_get_device_offset")] #[doc(alias = "get_device_offset")] pub fn device_offset(&self) -> (f64, f64) { let mut x_offset = 0.0f64; let mut y_offset = 0.0f64; unsafe { ffi::cairo_surface_get_device_offset(self.to_raw_none(), &mut x_offset, &mut y_offset); } (x_offset, y_offset) } #[doc(alias = "cairo_surface_set_device_scale")] pub fn set_device_scale(&self, x_scale: f64, y_scale: f64) { unsafe { ffi::cairo_surface_set_device_scale(self.to_raw_none(), x_scale, y_scale) } } #[doc(alias = "cairo_surface_get_device_scale")] #[doc(alias = "get_device_scale")] pub fn device_scale(&self) -> (f64, f64) { let mut x_scale = 0.0f64; let mut y_scale = 0.0f64; unsafe { ffi::cairo_surface_get_device_scale(self.to_raw_none(), &mut x_scale, &mut y_scale); } (x_scale, y_scale) } #[doc(alias = "cairo_surface_set_fallback_resolution")] pub fn set_fallback_resolution(&self, x_pixels_per_inch: f64, y_pixels_per_inch: f64) { unsafe { ffi::cairo_surface_set_fallback_resolution( self.to_raw_none(), x_pixels_per_inch, y_pixels_per_inch, ) } } #[doc(alias = "cairo_surface_get_fallback_resolution")] #[doc(alias = "get_fallback_resolution")] pub fn fallback_resolution(&self) -> (f64, f64) { let mut x_pixels_per_inch = 0.0f64; let mut y_pixels_per_inch = 0.0f64; unsafe { ffi::cairo_surface_get_fallback_resolution( self.to_raw_none(), &mut x_pixels_per_inch, &mut y_pixels_per_inch, ); } (x_pixels_per_inch, y_pixels_per_inch) } #[doc(alias = "cairo_surface_create_similar_image")] pub fn create_similar_image( &self, format: Format, width: i32, height: i32, ) -> Result { unsafe { ImageSurface::from_raw_full(ffi::cairo_surface_create_similar_image( self.to_raw_none(), format.into(), width, height, )) } } #[doc(alias = "cairo_surface_map_to_image")] pub fn map_to_image(&self, extents: Option) -> Result { unsafe { ImageSurface::from_raw_none(match extents { Some(ref e) => ffi::cairo_surface_map_to_image(self.to_raw_none(), e.to_raw_none()), None => ffi::cairo_surface_map_to_image(self.to_raw_none(), std::ptr::null()), }) .map(|s| MappedImageSurface { original_surface: self.clone(), image_surface: s, }) } } #[doc(alias = "cairo_surface_mark_dirty")] pub fn mark_dirty(&self) { unsafe { ffi::cairo_surface_mark_dirty(self.to_raw_none()) } } #[doc(alias = "cairo_surface_mark_dirty_rectangle")] pub fn mark_dirty_rectangle(&self, x: i32, y: i32, width: i32, height: i32) { unsafe { ffi::cairo_surface_mark_dirty_rectangle(self.to_raw_none(), x, y, width, height) } } #[doc(alias = "cairo_surface_status")] #[inline] pub fn status(&self) -> Result<(), Error> { let status = unsafe { ffi::cairo_surface_status(self.to_raw_none()) }; status_to_result(status) } user_data_methods! { ffi::cairo_surface_get_user_data, ffi::cairo_surface_set_user_data, } } #[cfg(feature = "use_glib")] impl IntoGlibPtr<*mut ffi::cairo_surface_t> for Surface { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::cairo_surface_t { std::mem::ManuallyDrop::new(self).to_glib_none().0 } } #[cfg(feature = "use_glib")] impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for Surface { type Storage = PhantomData<&'a Surface>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> { Stash(self.to_raw_none(), PhantomData) } #[inline] fn to_glib_full(&self) -> *mut ffi::cairo_surface_t { unsafe { ffi::cairo_surface_reference(self.to_raw_none()) } } } #[cfg(feature = "use_glib")] impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for Surface { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> Surface { Self::from_raw_none(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for Surface { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> crate::Borrowed { Self::from_raw_borrow(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface { Self::from_raw_full(ptr).unwrap() } } #[cfg(feature = "use_glib")] gvalue_impl!( Surface, ffi::cairo_surface_t, ffi::gobject::cairo_gobject_surface_get_type ); impl Clone for Surface { #[inline] fn clone(&self) -> Surface { unsafe { Self::from_raw_none(self.0.as_ptr()) } } } impl Drop for Surface { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_surface_destroy(self.0.as_ptr()); } } } impl AsRef for Surface { #[inline] fn as_ref(&self) -> &Surface { self } } impl Surface { #[doc(alias = "cairo_surface_flush")] pub fn flush(&self) { unsafe { ffi::cairo_surface_flush(self.0.as_ptr()); } } #[doc(alias = "cairo_surface_finish")] pub fn finish(&self) { unsafe { ffi::cairo_surface_finish(self.0.as_ptr()); } } #[doc(alias = "cairo_surface_get_type")] #[doc(alias = "get_type")] pub fn type_(&self) -> SurfaceType { unsafe { SurfaceType::from(ffi::cairo_surface_get_type(self.0.as_ptr())) } } } #[derive(Debug)] pub struct MappedImageSurface { original_surface: Surface, image_surface: ImageSurface, } impl Deref for MappedImageSurface { type Target = ImageSurface; #[inline] fn deref(&self) -> &ImageSurface { &self.image_surface } } impl AsRef for MappedImageSurface { #[inline] fn as_ref(&self) -> &ImageSurface { &self.image_surface } } impl Drop for MappedImageSurface { #[inline] fn drop(&mut self) { unsafe { ffi::cairo_surface_unmap_image( self.original_surface.to_raw_none(), self.image_surface.to_raw_none(), ); } } } #[cfg(test)] mod tests { use crate::{constants::MIME_TYPE_PNG, Format, ImageSurface}; #[test] fn mime_data() { let surface = ImageSurface::create(Format::ARgb32, 500, 500).unwrap(); let data = surface.mime_data(MIME_TYPE_PNG); /* Initially the data for any mime type has to be none */ assert!(data.is_none()); assert!(surface.set_mime_data(MIME_TYPE_PNG, [1u8, 10u8]).is_ok()); let data = surface.mime_data(MIME_TYPE_PNG).unwrap(); assert_eq!(data, &[1u8, 10u8]); } } cairo-rs-0.20.1/src/surface_macros.rs000064400000000000000000000102411046102023000155520ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // e.g. declare_surface(ImageSurface, SurfaceType::Image) macro_rules! declare_surface { ($surf_name:ident, $surf_type:expr) => { #[derive(Debug)] #[repr(transparent)] pub struct $surf_name(Surface); impl TryFrom for $surf_name { type Error = Surface; #[inline] fn try_from(surface: Surface) -> Result<$surf_name, Surface> { if surface.type_() == $surf_type { Ok($surf_name(surface)) } else { Err(surface) } } } impl $surf_name { #[inline] pub unsafe fn from_raw_full( ptr: *mut crate::ffi::cairo_surface_t, ) -> Result<$surf_name, crate::error::Error> { let surface = Surface::from_raw_full(ptr)?; Self::try_from(surface).map_err(|_| crate::error::Error::SurfaceTypeMismatch) } #[inline] pub unsafe fn from_raw_none( ptr: *mut crate::ffi::cairo_surface_t, ) -> Result<$surf_name, crate::error::Error> { let surface = Surface::from_raw_none(ptr); Self::try_from(surface).map_err(|_| crate::error::Error::SurfaceTypeMismatch) } } #[cfg(feature = "use_glib")] impl IntoGlibPtr<*mut crate::ffi::cairo_surface_t> for $surf_name { #[inline] unsafe fn into_glib_ptr(self) -> *mut crate::ffi::cairo_surface_t { std::mem::ManuallyDrop::new(self).to_glib_none().0 } } #[cfg(feature = "use_glib")] impl<'a> ToGlibPtr<'a, *mut crate::ffi::cairo_surface_t> for $surf_name { type Storage = std::marker::PhantomData<&'a Surface>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut crate::ffi::cairo_surface_t, Self> { let stash = self.0.to_glib_none(); Stash(stash.0, stash.1) } #[inline] fn to_glib_full(&self) -> *mut crate::ffi::cairo_surface_t { unsafe { crate::ffi::cairo_surface_reference(self.to_glib_none().0) } } } #[cfg(feature = "use_glib")] impl FromGlibPtrNone<*mut crate::ffi::cairo_surface_t> for $surf_name { #[inline] unsafe fn from_glib_none(ptr: *mut crate::ffi::cairo_surface_t) -> $surf_name { Self::try_from(from_glib_none::<_, Surface>(ptr)).unwrap() } } #[cfg(feature = "use_glib")] impl FromGlibPtrBorrow<*mut crate::ffi::cairo_surface_t> for $surf_name { #[inline] unsafe fn from_glib_borrow( ptr: *mut crate::ffi::cairo_surface_t, ) -> crate::Borrowed<$surf_name> { let surface = from_glib_borrow::<_, Surface>(ptr); let surface = Self::try_from(surface.into_inner()) .map_err(std::mem::forget) .unwrap(); crate::Borrowed::new(surface) } } #[cfg(feature = "use_glib")] impl FromGlibPtrFull<*mut crate::ffi::cairo_surface_t> for $surf_name { #[inline] unsafe fn from_glib_full(ptr: *mut crate::ffi::cairo_surface_t) -> $surf_name { Self::from_raw_full(ptr).unwrap() } } #[cfg(feature = "use_glib")] gvalue_impl!( $surf_name, crate::ffi::cairo_surface_t, crate::ffi::gobject::cairo_gobject_surface_get_type ); impl Deref for $surf_name { type Target = Surface; #[inline] fn deref(&self) -> &Surface { &self.0 } } impl AsRef for $surf_name { #[inline] fn as_ref(&self) -> &Surface { &self.0 } } impl Clone for $surf_name { #[inline] fn clone(&self) -> $surf_name { $surf_name(self.0.clone()) } } }; } cairo-rs-0.20.1/src/surface_png.rs000064400000000000000000000160371046102023000150630ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ any::Any, io::{self, Read, Write}, panic::AssertUnwindSafe, slice, }; use crate::ffi; use libc::{c_uint, c_void}; use crate::{utils::status_to_result, Error, ImageSurface, IoError, Surface}; struct ReadEnv<'a, R: 'a + Read> { reader: &'a mut R, io_error: Option, unwind_payload: Option>, } unsafe extern "C" fn read_func( closure: *mut c_void, data: *mut u8, len: c_uint, ) -> crate::ffi::cairo_status_t { let read_env: &mut ReadEnv = &mut *(closure as *mut ReadEnv); // Don’t attempt another read, if a previous one errored or panicked: if read_env.io_error.is_some() || read_env.unwind_payload.is_some() { return Error::ReadError.into(); } let buffer = if data.is_null() || len == 0 { &mut [] } else { slice::from_raw_parts_mut(data, len as usize) }; let result = std::panic::catch_unwind(AssertUnwindSafe(|| read_env.reader.read_exact(buffer))); match result { Ok(Ok(())) => ffi::STATUS_SUCCESS, Ok(Err(error)) => { read_env.io_error = Some(error); Error::ReadError.into() } Err(payload) => { read_env.unwind_payload = Some(payload); Error::ReadError.into() } } } struct WriteEnv<'a, W: 'a + Write> { writer: &'a mut W, io_error: Option, unwind_payload: Option>, } unsafe extern "C" fn write_func( closure: *mut c_void, data: *mut u8, len: c_uint, ) -> crate::ffi::cairo_status_t { let write_env: &mut WriteEnv = &mut *(closure as *mut WriteEnv); // Don’t attempt another write, if a previous one errored or panicked: if write_env.io_error.is_some() || write_env.unwind_payload.is_some() { return Error::WriteError.into(); } let buffer = if data.is_null() || len == 0 { &[] } else { slice::from_raw_parts(data, len as usize) }; let result = std::panic::catch_unwind(AssertUnwindSafe(|| write_env.writer.write_all(buffer))); match result { Ok(Ok(())) => ffi::STATUS_SUCCESS, Ok(Err(error)) => { write_env.io_error = Some(error); Error::WriteError.into() } Err(payload) => { write_env.unwind_payload = Some(payload); Error::WriteError.into() } } } impl ImageSurface { #[doc(alias = "cairo_image_surface_create_from_png_stream")] pub fn create_from_png(stream: &mut R) -> Result { let mut env = ReadEnv { reader: stream, io_error: None, unwind_payload: None, }; unsafe { let raw_surface = ffi::cairo_image_surface_create_from_png_stream( Some(read_func::), &mut env as *mut ReadEnv as *mut c_void, ); let surface = ImageSurface::from_raw_full(raw_surface)?; if let Some(payload) = env.unwind_payload { std::panic::resume_unwind(payload) } match env.io_error { None => Ok(surface), Some(err) => Err(IoError::Io(err)), } } } } impl Surface { // rustdoc-stripper-ignore-next /// This function writes the surface as a PNG image to the given stream. /// /// If the underlying surface does not support being written as a PNG, this will return /// [`Error::SurfaceTypeMismatch`] #[doc(alias = "cairo_surface_write_to_png_stream")] #[doc(alias = "cairo_surface_write_to_png")] pub fn write_to_png(&self, stream: &mut W) -> Result<(), IoError> { let mut env = WriteEnv { writer: stream, io_error: None, unwind_payload: None, }; let status = unsafe { ffi::cairo_surface_write_to_png_stream( self.to_raw_none(), Some(write_func::), &mut env as *mut WriteEnv as *mut c_void, ) }; if let Some(payload) = env.unwind_payload { std::panic::resume_unwind(payload) } match env.io_error { None => match status_to_result(status) { Err(err) => Err(IoError::Cairo(err)), Ok(_) => Ok(()), }, Some(err) => Err(IoError::Io(err)), } } } #[cfg(test)] mod tests { use std::io::ErrorKind; use super::*; use crate::enums::Format; struct IoErrorReader; // A reader that always returns an error impl Read for IoErrorReader { fn read(&mut self, _: &mut [u8]) -> Result { Err(io::Error::new(ErrorKind::Other, "yikes!")) } } #[test] fn valid_png_reads_correctly() { // A 1x1 PNG, RGB, no alpha, with a single pixel with (42, 42, 42) values let png_data: Vec = vec![ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xde, 0x00, 0x00, 0x00, 0x0c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xd0, 0xd2, 0xd2, 0x02, 0x00, 0x01, 0x00, 0x00, 0x7f, 0x09, 0xa9, 0x5a, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, ]; let r = ImageSurface::create_from_png(&mut &png_data[..]); assert!(r.is_ok()); let mut surface = r.unwrap(); assert_eq!(surface.width(), 1); assert_eq!(surface.height(), 1); assert_eq!(surface.format(), Format::Rgb24); let data = surface.data().unwrap(); assert!(data.len() >= 3); let slice = &data[0..3]; assert_eq!(slice[0], 42); assert_eq!(slice[1], 42); assert_eq!(slice[2], 42); } #[cfg(not(target_os = "macos"))] #[test] fn invalid_png_yields_error() { let png_data: Vec = vec![ // v--- this byte is modified 0x89, 0x40, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xde, 0x00, 0x00, 0x00, 0x0c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xd0, 0xd2, 0xd2, 0x02, 0x00, 0x01, 0x00, 0x00, 0x7f, 0x09, 0xa9, 0x5a, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, ]; match ImageSurface::create_from_png(&mut &png_data[..]) { Err(IoError::Cairo(_)) => (), _ => unreachable!(), } } #[cfg(not(target_os = "macos"))] #[test] fn io_error_yields_cairo_read_error() { let mut r = IoErrorReader; match ImageSurface::create_from_png(&mut r) { Err(IoError::Cairo(Error::ReadError)) => (), _ => unreachable!(), } } } cairo-rs-0.20.1/src/svg.rs000064400000000000000000000173421046102023000133660ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(not(windows))] use std::os::unix::prelude::*; use std::{ ffi::{CStr, CString}, io, mem, ops::Deref, path::Path, ptr, }; #[cfg(feature = "use_glib")] use glib::translate::*; #[cfg(all(feature = "svg", feature = "v1_16"))] use crate::SvgUnit; use crate::{ffi, Error, Surface, SurfaceType, SvgVersion}; impl SvgVersion { pub fn as_str(self) -> Option<&'static str> { unsafe { let res = ffi::cairo_svg_version_to_string(self.into()); res.as_ref() .and_then(|cstr| CStr::from_ptr(cstr as _).to_str().ok()) } } } declare_surface!(SvgSurface, SurfaceType::Svg); impl SvgSurface { #[doc(alias = "cairo_svg_surface_create")] pub fn new>( width: f64, height: f64, path: Option

, ) -> Result { #[cfg(not(windows))] let path = path.map(|p| { CString::new(p.as_ref().as_os_str().as_bytes()).expect("Invalid path with NULL bytes") }); #[cfg(windows)] let path = path.map(|p| { let path_str = p .as_ref() .to_str() .expect("Path can't be represented as UTF-8") .to_owned(); if path_str.starts_with("\\\\?\\") { CString::new(path_str[4..].as_bytes()) } else { CString::new(path_str.as_bytes()) } .expect("Invalid path with NUL bytes") }); unsafe { Ok(Self(Surface::from_raw_full( ffi::cairo_svg_surface_create( path.as_ref().map(|p| p.as_ptr()).unwrap_or(ptr::null()), width, height, ), )?)) } } for_stream_constructors!(cairo_svg_surface_create_for_stream); #[doc(alias = "cairo_svg_get_versions")] #[doc(alias = "get_versions")] pub fn versions() -> impl Iterator { let vers_slice = unsafe { let mut vers_ptr = ptr::null_mut(); let mut num_vers = mem::MaybeUninit::uninit(); ffi::cairo_svg_get_versions(&mut vers_ptr, num_vers.as_mut_ptr()); let num_vers = num_vers.assume_init(); if num_vers == 0 { &[] } else { std::slice::from_raw_parts(vers_ptr, num_vers as _) } }; vers_slice.iter().map(|v| SvgVersion::from(*v)) } #[doc(alias = "cairo_svg_surface_restrict_to_version")] pub fn restrict(&self, version: SvgVersion) { unsafe { ffi::cairo_svg_surface_restrict_to_version(self.0.to_raw_none(), version.into()); } } #[cfg(all(feature = "svg", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "svg", feature = "v1_16"))))] #[doc(alias = "cairo_svg_surface_set_document_unit")] pub fn set_document_unit(&mut self, unit: SvgUnit) { unsafe { ffi::cairo_svg_surface_set_document_unit(self.0.to_raw_none(), unit.into()); } } #[cfg(all(feature = "svg", feature = "v1_16"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "svg", feature = "v1_16"))))] #[doc(alias = "cairo_svg_surface_get_document_unit")] #[doc(alias = "get_document_unit")] pub fn document_unit(&self) -> SvgUnit { unsafe { SvgUnit::from(ffi::cairo_svg_surface_get_document_unit( self.0.to_raw_none(), )) } } } #[cfg(test)] mod test { use tempfile::{tempfile, NamedTempFile}; use super::*; use crate::context::*; fn draw(surface: &Surface) { let cr = Context::new(surface).expect("Can't create a Cairo context"); cr.set_line_width(25.0); cr.set_source_rgba(1.0, 0.0, 0.0, 0.5); cr.line_to(0., 0.); cr.line_to(100., 100.); cr.stroke().expect("Surface on an invalid state"); cr.set_source_rgba(0.0, 0.0, 1.0, 0.5); cr.line_to(0., 100.); cr.line_to(100., 0.); cr.stroke().expect("Surface on an invalid state"); } fn draw_in_buffer() -> Vec { let buffer: Vec = vec![]; let surface = SvgSurface::for_stream(100., 100., buffer).unwrap(); draw(&surface); *surface.finish_output_stream().unwrap().downcast().unwrap() } #[track_caller] fn assert_len_close_enough(len_a: usize, len_b: usize) { // It seems cairo randomizes some element IDs which might make one svg slightly // larger than the other. Here we make sure the difference is within ~10%. let len_diff = usize::abs_diff(len_a, len_b); assert!(len_diff < len_b / 10); } #[test] fn versions() { assert!(SvgSurface::versions().any(|v| v == SvgVersion::_1_1)); } #[test] fn version_string() { let ver_str = SvgVersion::_1_1.as_str().unwrap(); assert_eq!(ver_str, "SVG 1.1"); } #[test] fn without_file() { let surface = SvgSurface::new(100., 100., None::<&Path>).unwrap(); draw(&surface); surface.finish(); } #[test] fn file() { let file = NamedTempFile::new().expect("tempfile failed"); let surface = SvgSurface::new(100., 100., Some(&file.path())).unwrap(); draw(&surface); surface.finish(); } #[test] fn writer() { let file = tempfile().expect("tempfile failed"); let surface = SvgSurface::for_stream(100., 100., file).unwrap(); draw(&surface); let stream = surface.finish_output_stream().unwrap(); let file = stream.downcast::().unwrap(); let buffer = draw_in_buffer(); let file_size = file.metadata().unwrap().len(); assert_len_close_enough(file_size as usize, buffer.len()); } #[test] fn ref_writer() { let mut file = tempfile().expect("tempfile failed"); let surface = unsafe { SvgSurface::for_raw_stream(100., 100., &mut file).unwrap() }; draw(&surface); surface.finish_output_stream().unwrap(); } #[test] fn buffer() { let buffer = draw_in_buffer(); let header = b" io::Result { self.1.write_all(buf)?; self.0 += buf.len(); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } let file = tempfile().expect("tempfile failed"); let custom_writer = CustomWriter(0, file); let surface = SvgSurface::for_stream(100., 100., custom_writer).unwrap(); draw(&surface); let stream = surface.finish_output_stream().unwrap(); let custom_writer = stream.downcast::().unwrap(); let buffer = draw_in_buffer(); assert_len_close_enough(custom_writer.0, buffer.len()); } fn with_panicky_stream() -> SvgSurface { struct PanicWriter; impl io::Write for PanicWriter { fn write(&mut self, _buf: &[u8]) -> io::Result { panic!("panic in writer"); } fn flush(&mut self) -> io::Result<()> { Ok(()) } } let surface = SvgSurface::for_stream(20., 20., PanicWriter).unwrap(); surface.finish(); surface } #[test] #[should_panic] fn finish_stream_propagates_panic() { let _ = with_panicky_stream().finish_output_stream(); } } cairo-rs-0.20.1/src/user_data.rs000064400000000000000000000141261046102023000145330ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::marker::PhantomData; use crate::ffi; pub struct UserDataKey { pub(crate) ffi: ffi::cairo_user_data_key_t, marker: PhantomData<*const T>, } unsafe impl Sync for UserDataKey {} impl UserDataKey { pub const fn new() -> Self { Self { ffi: ffi::cairo_user_data_key_t { unused: 0 }, marker: PhantomData, } } } impl Default for UserDataKey { fn default() -> Self { Self::new() } } // In a safe API for user data we can’t make `get_user_data` // transfer full ownership of the value to the caller (e.g. by returning `Box`) // because `self` still has a pointer to that value // and `get_user_data` could be called again with the same key. // // We also can’t return a `&T` reference that borrows from `self` // because the value could be removed with `remove_user_data` or replaced with `set_user_data` // while the borrow still needs to be valid. // (Borrowing with `&mut self` would not help as `Self` can be itself reference-counted.) // // Therefore, the value must be reference-counted. // // We use `Rc` over `Arc` because the types implementing these methods are `!Send` and `!Sync`. // See macro_rules! user_data_methods { ($ffi_get_user_data: path, $ffi_set_user_data: path,) => { /// Attach user data to `self` for the given `key`. pub fn set_user_data( &self, key: &'static crate::UserDataKey, value: std::rc::Rc, ) -> Result<(), crate::Error> { unsafe extern "C" fn destructor(ptr: *mut libc::c_void) { let ptr: *const T = ptr as _; drop(std::rc::Rc::from_raw(ptr)) } // Safety: // // The destructor’s cast and `from_raw` are symmetric // with the `into_raw` and cast below. // They both transfer ownership of one strong reference: // neither of them touches the reference count. let ptr: *const T = std::rc::Rc::into_raw(value); let ptr = ptr as *mut T as *mut libc::c_void; let status = crate::utils::status_to_result(unsafe { $ffi_set_user_data(self.to_raw_none(), &key.ffi, ptr, Some(destructor::)) }); if status.is_err() { // Safety: // // On errors the user data is leaked by cairo and needs to be freed here. unsafe { destructor::(ptr); } } status } /// Return the user data previously attached to `self` with the given `key`, if any. pub fn user_data( &self, key: &'static crate::UserDataKey, ) -> Option> { let ptr = self.user_data_ptr(key)?.as_ptr(); // Safety: // // `Rc::from_raw` would normally take ownership of a strong reference for this pointer. // But `self` still has a copy of that pointer and `get_user_data` can be called again // with the same key. // We use `ManuallyDrop` to avoid running the destructor of that first `Rc`, // and return a cloned one (which increments the reference count). unsafe { let rc = std::mem::ManuallyDrop::new(std::rc::Rc::from_raw(ptr)); Some(std::rc::Rc::clone(&rc)) } } /// Return the user data previously attached to `self` with the given `key`, if any, /// without incrementing the reference count. /// /// The pointer is valid when it is returned from this method, /// until the cairo object that `self` represents is destroyed /// or `remove_user_data` or `set_user_data` is called with the same key. pub fn user_data_ptr( &self, key: &'static crate::UserDataKey, ) -> Option> { // Safety: // // If `ffi_get_user_data` returns a non-null pointer, // there was a previous call to `ffi_set_user_data` with a key with the same address. // Either: // // * This was a call to a Rust `Self::set_user_data` method. // Because that method takes a `&'static` reference, // the key used then must live at that address until the end of the process. // Because `UserDataKey` has a non-zero size regardless of `T`, // no other `UserDataKey` value can have the same address. // Therefore, the `T` type was the same then at it is now and `cast` is type-safe. // // * Or, it is technically possible that the `set` call was to the C function directly, // with a `cairo_user_data_key_t` in heap-allocated memory that was then freed, // then `Box::new(UserDataKey::new()).leak()` was used to create a `&'static` // that happens to have the same address because the allocator for `Box` // reused that memory region. // Since this involves a C (or FFI) call *and* is so far out of “typical” use // of the user data functionality, we consider this a misuse of an unsafe API. unsafe { let ptr = $ffi_get_user_data(self.to_raw_none(), &key.ffi); Some(std::ptr::NonNull::new(ptr)?.cast()) } } /// Unattached from `self` the user data associated with `key`, if any. /// If there is no other `Rc` strong reference, the data is destroyed. pub fn remove_user_data( &self, key: &'static crate::UserDataKey, ) -> Result<(), crate::Error> { let status = unsafe { $ffi_set_user_data(self.to_raw_none(), &key.ffi, std::ptr::null_mut(), None) }; crate::utils::status_to_result(status) } }; } cairo-rs-0.20.1/src/utils.rs000064400000000000000000000042011046102023000137150ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ffi::CStr, fmt}; use crate::{ffi, Error}; // rustdoc-stripper-ignore-next /// Resets all static data within cairo to its original state (i.e. identical to the state at program /// invocation). For example, all caches within cairo will be flushed empty. /// /// # Safety /// It is only safe to call this function when there are no active cairo objects remaining (all /// cairo objects have been dropped). /// /// This function is thread safe. #[doc(alias = "cairo_debug_reset_static_data")] pub unsafe fn debug_reset_static_data() { ffi::cairo_debug_reset_static_data() } pub fn status_to_result(status: ffi::cairo_status_t) -> Result<(), Error> { match status { ffi::STATUS_SUCCESS => Ok(()), err => Err(err.into()), } } #[doc(alias = "cairo_version_string")] #[doc(alias = "get_version_string")] pub fn version_string() -> &'static str { unsafe { let ptr = ffi::cairo_version_string(); CStr::from_ptr(ptr) .to_str() .expect("invalid version string") } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub struct Version { major: u8, minor: u8, micro: u8, } impl Version { #[doc(alias = "cairo_version")] #[doc(alias = "get_version")] pub fn new() -> Version { let version = unsafe { ffi::cairo_version() }; Version { major: (version / 10_000 % 100) as _, minor: (version / 100 % 100) as _, micro: (version % 100) as _, } } pub fn major(self) -> u8 { self.major } pub fn minor(self) -> u8 { self.minor } pub fn micro(self) -> u8 { self.micro } } impl Default for Version { fn default() -> Self { Self::new() } } impl fmt::Display for Version { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}.{}.{}", self.major, self.minor, self.micro) } } #[cfg(test)] mod tests { use super::*; #[test] fn check_versions() { assert_eq!(version_string(), Version::new().to_string()); } } cairo-rs-0.20.1/src/win32_surface.rs000064400000000000000000000035361046102023000152410ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ops::Deref; pub use ffi::windows; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, Error, Format, Surface, SurfaceType}; declare_surface!(Win32Surface, SurfaceType::Win32); impl Win32Surface { #[doc(alias = "cairo_win32_surface_create")] pub fn create(hdc: windows::HDC) -> Result { unsafe { Self::from_raw_full(ffi::cairo_win32_surface_create(hdc)) } } #[doc(alias = "cairo_win32_surface_create_with_format")] pub fn create_with_format(hdc: windows::HDC, format: Format) -> Result { unsafe { Self::from_raw_full(ffi::cairo_win32_surface_create_with_format( hdc, format.into(), )) } } #[doc(alias = "cairo_win32_surface_create_with_dib")] pub fn create_with_dib(format: Format, width: i32, height: i32) -> Result { unsafe { Self::from_raw_full(ffi::cairo_win32_surface_create_with_dib( format.into(), width, height, )) } } #[doc(alias = "cairo_win32_surface_create_with_ddb")] pub fn create_with_ddb( hdc: windows::HDC, format: Format, width: i32, height: i32, ) -> Result { unsafe { Self::from_raw_full(ffi::cairo_win32_surface_create_with_ddb( hdc, format.into(), width, height, )) } } #[doc(alias = "cairo_win32_printing_surface_create")] pub fn printing_surface_create(hdc: windows::HDC) -> Result { unsafe { Self::from_raw_full(ffi::cairo_win32_printing_surface_create(hdc)) } } } cairo-rs-0.20.1/src/xcb.rs000064400000000000000000000277241046102023000133500ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(feature = "use_glib")] use std::marker::PhantomData; use std::{ops::Deref, ptr}; #[cfg(feature = "use_glib")] use glib::translate::*; use crate::{ffi, Error, Surface, SurfaceType}; #[derive(Debug)] pub struct XCBDrawable(pub u32); impl XCBDrawable { #[inline] fn to_raw_none(&self) -> u32 { self.0 } } #[derive(Debug)] pub struct XCBPixmap(pub u32); impl XCBPixmap { #[inline] fn to_raw_none(&self) -> u32 { self.0 } } #[derive(Debug)] #[doc(alias = "xcb_connection_t")] pub struct XCBConnection(pub ptr::NonNull); impl XCBConnection { #[inline] pub fn to_raw_none(&self) -> *mut ffi::xcb_connection_t { self.0.as_ptr() } #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::xcb_connection_t) -> XCBConnection { debug_assert!(!ptr.is_null()); XCBConnection(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub unsafe fn from_raw_borrow(ptr: *mut ffi::xcb_connection_t) -> Borrowed { debug_assert!(!ptr.is_null()); Borrowed::new(XCBConnection(ptr::NonNull::new_unchecked(ptr))) } #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::xcb_connection_t) -> XCBConnection { debug_assert!(!ptr.is_null()); XCBConnection(ptr::NonNull::new_unchecked(ptr)) } } #[cfg(feature = "use_glib")] impl<'a> ToGlibPtr<'a, *mut ffi::xcb_connection_t> for &'a XCBConnection { type Storage = PhantomData<&'a XCBConnection>; #[inline] fn to_glib_none(&self) -> Stash<'a, *mut ffi::xcb_connection_t, &'a XCBConnection> { Stash(self.to_raw_none(), PhantomData) } } #[cfg(feature = "use_glib")] impl FromGlibPtrNone<*mut ffi::xcb_connection_t> for XCBConnection { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::xcb_connection_t) -> XCBConnection { Self::from_raw_none(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrBorrow<*mut ffi::xcb_connection_t> for XCBConnection { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::xcb_connection_t) -> Borrowed { Self::from_raw_borrow(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrFull<*mut ffi::xcb_connection_t> for XCBConnection { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::xcb_connection_t) -> XCBConnection { Self::from_raw_full(ptr) } } impl Clone for XCBConnection { #[inline] fn clone(&self) -> XCBConnection { unsafe { Self::from_raw_none(self.to_raw_none()) } } } #[derive(Debug)] #[doc(alias = "xcb_render_pictforminfo_t")] pub struct XCBRenderPictFormInfo(pub ptr::NonNull); impl XCBRenderPictFormInfo { #[inline] pub fn to_raw_none(&self) -> *mut ffi::xcb_render_pictforminfo_t { self.0.as_ptr() } #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::xcb_render_pictforminfo_t) -> XCBRenderPictFormInfo { debug_assert!(!ptr.is_null()); XCBRenderPictFormInfo(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub unsafe fn from_raw_borrow( ptr: *mut ffi::xcb_render_pictforminfo_t, ) -> Borrowed { debug_assert!(!ptr.is_null()); Borrowed::new(XCBRenderPictFormInfo(ptr::NonNull::new_unchecked(ptr))) } #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::xcb_render_pictforminfo_t) -> XCBRenderPictFormInfo { debug_assert!(!ptr.is_null()); XCBRenderPictFormInfo(ptr::NonNull::new_unchecked(ptr)) } } #[cfg(feature = "use_glib")] impl<'a> ToGlibPtr<'a, *mut ffi::xcb_render_pictforminfo_t> for &'a XCBRenderPictFormInfo { type Storage = PhantomData<&'a XCBRenderPictFormInfo>; #[inline] fn to_glib_none( &self, ) -> Stash<'a, *mut ffi::xcb_render_pictforminfo_t, &'a XCBRenderPictFormInfo> { Stash(self.to_raw_none(), PhantomData) } } #[cfg(feature = "use_glib")] impl FromGlibPtrNone<*mut ffi::xcb_render_pictforminfo_t> for XCBRenderPictFormInfo { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::xcb_render_pictforminfo_t) -> XCBRenderPictFormInfo { Self::from_raw_none(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrBorrow<*mut ffi::xcb_render_pictforminfo_t> for XCBRenderPictFormInfo { #[inline] unsafe fn from_glib_borrow( ptr: *mut ffi::xcb_render_pictforminfo_t, ) -> Borrowed { Self::from_raw_borrow(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrFull<*mut ffi::xcb_render_pictforminfo_t> for XCBRenderPictFormInfo { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::xcb_render_pictforminfo_t) -> XCBRenderPictFormInfo { Self::from_raw_full(ptr) } } impl Clone for XCBRenderPictFormInfo { #[inline] fn clone(&self) -> XCBRenderPictFormInfo { unsafe { Self::from_raw_none(self.to_raw_none()) } } } #[derive(Debug)] #[doc(alias = "xcb_screen_t")] pub struct XCBScreen(pub ptr::NonNull); impl XCBScreen { #[inline] pub fn to_raw_none(&self) -> *mut ffi::xcb_screen_t { self.0.as_ptr() } #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::xcb_screen_t) -> XCBScreen { debug_assert!(!ptr.is_null()); XCBScreen(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub unsafe fn from_raw_borrow(ptr: *mut ffi::xcb_screen_t) -> Borrowed { debug_assert!(!ptr.is_null()); Borrowed::new(XCBScreen(ptr::NonNull::new_unchecked(ptr))) } #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::xcb_screen_t) -> XCBScreen { debug_assert!(!ptr.is_null()); XCBScreen(ptr::NonNull::new_unchecked(ptr)) } } #[cfg(feature = "use_glib")] impl<'a> ToGlibPtr<'a, *mut ffi::xcb_screen_t> for &'a XCBScreen { type Storage = PhantomData<&'a XCBScreen>; #[inline] fn to_glib_none(&self) -> Stash<'a, *mut ffi::xcb_screen_t, &'a XCBScreen> { Stash(self.to_raw_none(), PhantomData) } } #[cfg(feature = "use_glib")] impl FromGlibPtrNone<*mut ffi::xcb_screen_t> for XCBScreen { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::xcb_screen_t) -> XCBScreen { Self::from_raw_none(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrBorrow<*mut ffi::xcb_screen_t> for XCBScreen { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::xcb_screen_t) -> Borrowed { Self::from_raw_borrow(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrFull<*mut ffi::xcb_screen_t> for XCBScreen { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::xcb_screen_t) -> XCBScreen { Self::from_raw_full(ptr) } } impl Clone for XCBScreen { #[inline] fn clone(&self) -> XCBScreen { unsafe { Self::from_raw_none(self.to_raw_none()) } } } declare_surface!(XCBSurface, SurfaceType::Xcb); impl XCBSurface { #[doc(alias = "cairo_xcb_surface_create")] pub fn create( connection: &XCBConnection, drawable: &XCBDrawable, visual: &XCBVisualType, width: i32, height: i32, ) -> Result { unsafe { Self::from_raw_full(ffi::cairo_xcb_surface_create( connection.to_raw_none(), drawable.to_raw_none(), visual.to_raw_none(), width, height, )) } } #[doc(alias = "cairo_xcb_surface_create_for_bitmap")] pub fn create_for_bitmap( connection: &XCBConnection, screen: &XCBScreen, bitmap: &XCBPixmap, width: i32, height: i32, ) -> Result { unsafe { Ok(Self(Surface::from_raw_full( ffi::cairo_xcb_surface_create_for_bitmap( connection.to_raw_none(), screen.to_raw_none(), bitmap.to_raw_none(), width, height, ), )?)) } } #[doc(alias = "cairo_xcb_surface_create_with_xrender_format")] pub fn create_with_xrender_format( connection: &XCBConnection, screen: &XCBScreen, bitmap: &XCBPixmap, format: &XCBRenderPictFormInfo, width: i32, height: i32, ) -> Result { unsafe { Ok(Self(Surface::from_raw_full( ffi::cairo_xcb_surface_create_with_xrender_format( connection.to_raw_none(), screen.to_raw_none(), bitmap.to_raw_none(), format.to_raw_none(), width, height, ), )?)) } } #[doc(alias = "cairo_xcb_surface_set_size")] pub fn set_size(&self, width: i32, height: i32) -> Result<(), Error> { unsafe { ffi::cairo_xcb_surface_set_size(self.to_raw_none(), width, height) } self.status() } #[doc(alias = "cairo_xcb_surface_set_drawable")] pub fn set_drawable( &self, drawable: &XCBDrawable, width: i32, height: i32, ) -> Result<(), Error> { unsafe { ffi::cairo_xcb_surface_set_drawable( self.to_raw_none(), drawable.to_raw_none(), width, height, ) } self.status() } } #[derive(Debug)] #[doc(alias = "xcb_visualtype_t")] pub struct XCBVisualType(pub ptr::NonNull); impl XCBVisualType { #[inline] pub fn to_raw_none(&self) -> *mut ffi::xcb_visualtype_t { self.0.as_ptr() } #[inline] pub unsafe fn from_raw_none(ptr: *mut ffi::xcb_visualtype_t) -> XCBVisualType { debug_assert!(!ptr.is_null()); XCBVisualType(ptr::NonNull::new_unchecked(ptr)) } #[inline] pub unsafe fn from_raw_borrow(ptr: *mut ffi::xcb_visualtype_t) -> Borrowed { debug_assert!(!ptr.is_null()); Borrowed::new(XCBVisualType(ptr::NonNull::new_unchecked(ptr))) } #[inline] pub unsafe fn from_raw_full(ptr: *mut ffi::xcb_visualtype_t) -> XCBVisualType { debug_assert!(!ptr.is_null()); XCBVisualType(ptr::NonNull::new_unchecked(ptr)) } } #[cfg(feature = "use_glib")] impl<'a> ToGlibPtr<'a, *mut ffi::xcb_visualtype_t> for &'a XCBVisualType { type Storage = PhantomData<&'a XCBVisualType>; #[inline] fn to_glib_none(&self) -> Stash<'a, *mut ffi::xcb_visualtype_t, &'a XCBVisualType> { Stash(self.to_raw_none(), PhantomData) } } #[cfg(feature = "use_glib")] impl FromGlibPtrNone<*mut ffi::xcb_visualtype_t> for XCBVisualType { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::xcb_visualtype_t) -> XCBVisualType { Self::from_raw_none(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrBorrow<*mut ffi::xcb_visualtype_t> for XCBVisualType { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::xcb_visualtype_t) -> Borrowed { Self::from_raw_borrow(ptr) } } #[cfg(feature = "use_glib")] impl FromGlibPtrFull<*mut ffi::xcb_visualtype_t> for XCBVisualType { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::xcb_visualtype_t) -> XCBVisualType { Self::from_raw_full(ptr) } } impl Clone for XCBVisualType { #[inline] fn clone(&self) -> XCBVisualType { unsafe { Self::from_raw_none(self.to_raw_none()) } } } impl crate::device::Device { #[doc(alias = "cairo_xcb_device_get_connection")] #[doc(alias = "get_connection")] pub fn connection(&self) -> XCBConnection { unsafe { XCBConnection::from_raw_full(ffi::cairo_xcb_device_get_connection(self.to_raw_none())) } } #[doc(alias = "cairo_xcb_device_debug_cap_xshm_version")] pub fn debug_cap_xshm_version(&self, major_version: i32, minor_version: i32) { unsafe { ffi::cairo_xcb_device_debug_cap_xshm_version( self.to_raw_none(), major_version, minor_version, ) } } }