#![no_std]
#![warn(clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::match_wildcard_for_single_variants)]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
mod accessor;
mod animation;
mod canvas;
mod color;
mod error;
mod gradient;
mod lottie;
mod paint;
mod path;
mod picture;
mod saver;
mod scene;
mod shape;
mod text;
pub use accessor::{Accessor, BorrowedAccessor};
pub use animation::Animation;
pub use canvas::{
Canvas, EngineOption, GlCanvas, GlTarget, SwCanvas, WgCanvas, WgTarget, WgTargetType,
};
pub use error::{Error, Result};
pub use gradient::{
BorrowedGradient, BorrowedLinearGradient, BorrowedRadialGradient, ColorStop, FillSpread,
LinearGradient, RadialGradient,
};
pub use lottie::{LottieAnimation, Marker};
pub use paint::{BlendMethod, BorrowedPaint, MaskMethod, Matrix, Paint, PaintType, Point};
pub use path::{Path, PathCommand, Segment, Segments};
pub use picture::{FilterMethod, MimeType, Picture};
pub use saver::Saver;
pub use color::{ColorSpace, Rgb, Rgba};
pub use scene::{BlurBorder, BlurDirection, DropShadow, GaussianBlur, Scene, Tint, Tritone};
pub use shape::{Circle, FillRule, PaintOrder, Rect, Shape, StrokeCap, StrokeJoin};
pub use text::{GlyphMetrics, Text, TextMetrics, TextWrap};
use thorvg_sys as sys;
#[cfg(all(test, not(feature = "threads")))]
mod tests_no_threads {
use super::Thorvg;
#[test]
fn init_no_arg_signature() {
let _engine = Thorvg::init().expect("init() should succeed");
let (major, _minor, _micro, version_str) =
Thorvg::version().expect("Failed to get version");
assert!(major >= 1);
assert!(!version_str.is_empty());
}
}
pub struct Thorvg {
_not_send_sync: core::marker::PhantomData<*const ()>,
}
impl Thorvg {
#[cfg(feature = "threads")]
pub fn init(threads: u32) -> Result<Self> {
let result = unsafe { sys::tvg_engine_init(threads) };
Error::from_raw(result)?;
Ok(Self {
_not_send_sync: core::marker::PhantomData,
})
}
#[cfg(not(feature = "threads"))]
pub fn init() -> Result<Self> {
let result = unsafe { sys::tvg_engine_init(0) };
Error::from_raw(result)?;
Ok(Self {
_not_send_sync: core::marker::PhantomData,
})
}
pub fn version() -> Result<(u32, u32, u32, alloc::string::String)> {
let mut major: u32 = 0;
let mut minor: u32 = 0;
let mut micro: u32 = 0;
let mut version: *const core::ffi::c_char = core::ptr::null();
let result = unsafe {
sys::tvg_engine_version(
&raw mut major,
&raw mut minor,
&raw mut micro,
&raw mut version,
)
};
Error::from_raw(result)?;
let version_str = if version.is_null() {
alloc::string::String::new()
} else {
unsafe { core::ffi::CStr::from_ptr(version) }
.to_string_lossy()
.into_owned()
};
Ok((major, minor, micro, version_str))
}
pub fn shape(&self) -> Result<Shape<'_>> {
Shape::new()
}
pub fn scene(&self) -> Result<Scene<'_>> {
Scene::new()
}
pub fn picture(&self) -> Result<Picture<'_>> {
Picture::new()
}
pub fn text(&self) -> Result<Text<'_>> {
Text::new()
}
pub fn linear_gradient(&self) -> Result<LinearGradient<'_>> {
LinearGradient::new()
}
pub fn radial_gradient(&self) -> Result<RadialGradient<'_>> {
RadialGradient::new()
}
pub fn sw_canvas(&self, option: EngineOption) -> Result<SwCanvas<'_>> {
SwCanvas::new(option)
}
pub fn gl_canvas(&self, option: EngineOption) -> Result<GlCanvas<'_>> {
GlCanvas::new(option)
}
pub fn wg_canvas(&self, option: EngineOption) -> Result<WgCanvas<'_>> {
WgCanvas::new(option)
}
pub fn animation(&self) -> Result<Animation<'_>> {
Animation::new()
}
pub fn lottie_animation(&self) -> Result<LottieAnimation<'_>> {
LottieAnimation::new()
}
pub fn saver(&self) -> Result<Saver<'_>> {
Saver::new()
}
pub fn load_font_from_str(&self, path: &str) -> Result<()> {
let c_path = alloc::ffi::CString::new(path)?;
Error::from_raw(unsafe { sys::tvg_font_load(c_path.as_ptr()) })
}
#[cfg(feature = "std")]
pub fn load_font<P: AsRef<std::path::Path>>(&self, path: P) -> Result<()> {
self.load_font_from_str(&path.as_ref().to_string_lossy())
}
pub fn unload_font_from_str(&self, path: &str) -> Result<()> {
let c_path = alloc::ffi::CString::new(path)?;
Error::from_raw(unsafe { sys::tvg_font_unload(c_path.as_ptr()) })
}
#[cfg(feature = "std")]
pub fn unload_font<P: AsRef<std::path::Path>>(&self, path: P) -> Result<()> {
self.unload_font_from_str(&path.as_ref().to_string_lossy())
}
pub fn load_font_data(&self, name: &str, data: &[u8], mimetype: Option<&str>) -> Result<()> {
load_font_data_inner(name, data, mimetype, true)
}
pub fn load_font_data_static(
&self,
name: &str,
data: &'static [u8],
mimetype: Option<&str>,
) -> Result<()> {
load_font_data_inner(name, data, mimetype, false)
}
pub fn accessor(&self) -> Result<Accessor<'_>> {
Accessor::new()
}
}
impl Drop for Thorvg {
fn drop(&mut self) {
unsafe {
sys::tvg_engine_term();
}
}
}
#[allow(clippy::cast_possible_truncation)]
fn load_font_data_inner(name: &str, data: &[u8], mimetype: Option<&str>, copy: bool) -> Result<()> {
let c_name = alloc::ffi::CString::new(name)?;
let c_mime = mimetype.map(alloc::ffi::CString::new).transpose()?;
let mime_ptr = c_mime.as_ref().map_or(core::ptr::null(), |c| c.as_ptr());
Error::from_raw(unsafe {
sys::tvg_font_load_data(
c_name.as_ptr(),
data.as_ptr().cast::<core::ffi::c_char>(),
data.len() as u32,
mime_ptr,
copy,
)
})
}