use crate::error::{Error, Result};
use crate::paint::Paint;
use thorvg_sys as ffi;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ColorSpace {
ABGR8888,
ARGB8888,
ABGR8888S,
ARGB8888S,
}
impl ColorSpace {
pub(crate) fn to_raw(self) -> ffi::Tvg_Colorspace {
match self {
ColorSpace::ABGR8888 => ffi::Tvg_Colorspace::TVG_COLORSPACE_ABGR8888,
ColorSpace::ARGB8888 => ffi::Tvg_Colorspace::TVG_COLORSPACE_ARGB8888,
ColorSpace::ABGR8888S => ffi::Tvg_Colorspace::TVG_COLORSPACE_ABGR8888S,
ColorSpace::ARGB8888S => ffi::Tvg_Colorspace::TVG_COLORSPACE_ARGB8888S,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum EngineOption {
None,
#[default]
Default,
SmartRender,
}
impl EngineOption {
pub(crate) fn to_raw(self) -> ffi::Tvg_Engine_Option {
match self {
EngineOption::None => ffi::Tvg_Engine_Option::TVG_ENGINE_OPTION_NONE,
EngineOption::Default => ffi::Tvg_Engine_Option::TVG_ENGINE_OPTION_DEFAULT,
EngineOption::SmartRender => ffi::Tvg_Engine_Option::TVG_ENGINE_OPTION_SMART_RENDER,
}
}
}
pub struct SwCanvas<'eng> {
raw: ffi::Tvg_Canvas,
_engine: core::marker::PhantomData<&'eng ()>,
}
unsafe impl Send for SwCanvas<'_> {}
impl SwCanvas<'_> {
pub(crate) fn new(option: EngineOption) -> Result<Self> {
let raw = unsafe { ffi::tvg_swcanvas_create(option.to_raw()) };
if raw.is_null() {
return Err(Error::Unknown);
}
Ok(Self {
raw,
_engine: core::marker::PhantomData,
})
}
pub unsafe fn set_target(
&mut self,
buffer: &mut [u32],
stride: u32,
width: u32,
height: u32,
colorspace: ColorSpace,
) -> Result<()> {
assert!(
buffer.len() >= (stride * height) as usize,
"buffer too small: need {} elements, got {}",
stride * height,
buffer.len()
);
let result = unsafe {
ffi::tvg_swcanvas_set_target(
self.raw,
buffer.as_mut_ptr(),
stride,
width,
height,
colorspace.to_raw(),
)
};
Error::from_raw(result)
}
pub fn push<P: Paint>(&mut self, paint: P) -> Result<()> {
let raw_paint = paint.into_raw();
let result = unsafe { ffi::tvg_canvas_add(self.raw, raw_paint) };
Error::from_raw(result)
}
pub fn insert<P: Paint, Q: Paint>(&mut self, target: P, at: &Q) -> Result<()> {
let result = unsafe { ffi::tvg_canvas_insert(self.raw, target.into_raw(), at.raw()) };
Error::from_raw(result)
}
pub fn remove<P: Paint>(&mut self, paint: &P) -> Result<()> {
let result = unsafe { ffi::tvg_canvas_remove(self.raw, paint.raw()) };
Error::from_raw(result)
}
pub fn clear(&mut self) -> Result<()> {
let result = unsafe { ffi::tvg_canvas_remove(self.raw, core::ptr::null_mut()) };
Error::from_raw(result)
}
pub fn update(&mut self) -> Result<()> {
let result = unsafe { ffi::tvg_canvas_update(self.raw) };
Error::from_raw(result)
}
pub fn draw(&mut self, clear: bool) -> Result<()> {
let result = unsafe { ffi::tvg_canvas_draw(self.raw, clear) };
Error::from_raw(result)
}
pub fn sync(&mut self) -> Result<()> {
let result = unsafe { ffi::tvg_canvas_sync(self.raw) };
Error::from_raw(result)
}
pub fn set_viewport(&mut self, x: i32, y: i32, w: i32, h: i32) -> Result<()> {
let result = unsafe { ffi::tvg_canvas_set_viewport(self.raw, x, y, w, h) };
Error::from_raw(result)
}
pub fn render(&mut self) -> Result<()> {
self.update()?;
self.draw(true)?;
self.sync()
}
}
impl Drop for SwCanvas<'_> {
fn drop(&mut self) {
unsafe {
ffi::tvg_canvas_destroy(self.raw);
}
}
}
macro_rules! impl_canvas_ops {
($ty:ident) => {
impl $ty<'_> {
pub fn push<P: Paint>(&mut self, paint: P) -> Result<()> {
let raw_paint = paint.into_raw();
Error::from_raw(unsafe { ffi::tvg_canvas_add(self.raw, raw_paint) })
}
pub fn insert<P: Paint, Q: Paint>(&mut self, target: P, at: &Q) -> Result<()> {
Error::from_raw(unsafe {
ffi::tvg_canvas_insert(self.raw, target.into_raw(), at.raw())
})
}
pub fn remove<P: Paint>(&mut self, paint: &P) -> Result<()> {
Error::from_raw(unsafe { ffi::tvg_canvas_remove(self.raw, paint.raw()) })
}
pub fn clear(&mut self) -> Result<()> {
Error::from_raw(unsafe { ffi::tvg_canvas_remove(self.raw, core::ptr::null_mut()) })
}
pub fn update(&mut self) -> Result<()> {
Error::from_raw(unsafe { ffi::tvg_canvas_update(self.raw) })
}
pub fn draw(&mut self, clear: bool) -> Result<()> {
Error::from_raw(unsafe { ffi::tvg_canvas_draw(self.raw, clear) })
}
pub fn sync(&mut self) -> Result<()> {
Error::from_raw(unsafe { ffi::tvg_canvas_sync(self.raw) })
}
pub fn set_viewport(&mut self, x: i32, y: i32, w: i32, h: i32) -> Result<()> {
Error::from_raw(unsafe { ffi::tvg_canvas_set_viewport(self.raw, x, y, w, h) })
}
pub fn render(&mut self) -> Result<()> {
self.update()?;
self.draw(true)?;
self.sync()
}
}
impl Drop for $ty<'_> {
fn drop(&mut self) {
unsafe {
ffi::tvg_canvas_destroy(self.raw);
}
}
}
};
}
pub struct GlCanvas<'eng> {
raw: ffi::Tvg_Canvas,
_engine: core::marker::PhantomData<&'eng ()>,
}
unsafe impl Send for GlCanvas<'_> {}
impl GlCanvas<'_> {
pub(crate) fn new(option: EngineOption) -> Result<Self> {
let raw = unsafe { ffi::tvg_glcanvas_create(option.to_raw()) };
if raw.is_null() {
return Err(Error::Unknown);
}
Ok(Self {
raw,
_engine: core::marker::PhantomData,
})
}
#[allow(clippy::too_many_arguments)]
pub unsafe fn set_target(
&mut self,
display: *mut core::ffi::c_void,
surface: *mut core::ffi::c_void,
context: *mut core::ffi::c_void,
id: i32,
w: u32,
h: u32,
colorspace: ColorSpace,
) -> Result<()> {
Error::from_raw(unsafe {
ffi::tvg_glcanvas_set_target(
self.raw,
display,
surface,
context,
id,
w,
h,
colorspace.to_raw(),
)
})
}
}
impl_canvas_ops!(GlCanvas);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum WgTargetType {
Surface = 0,
Texture = 1,
}
pub struct WgCanvas<'eng> {
raw: ffi::Tvg_Canvas,
_engine: core::marker::PhantomData<&'eng ()>,
}
unsafe impl Send for WgCanvas<'_> {}
impl WgCanvas<'_> {
pub(crate) fn new(option: EngineOption) -> Result<Self> {
let raw = unsafe { ffi::tvg_wgcanvas_create(option.to_raw()) };
if raw.is_null() {
return Err(Error::Unknown);
}
Ok(Self {
raw,
_engine: core::marker::PhantomData,
})
}
#[allow(clippy::too_many_arguments)]
pub unsafe fn set_target(
&mut self,
device: *mut core::ffi::c_void,
instance: *mut core::ffi::c_void,
target: *mut core::ffi::c_void,
w: u32,
h: u32,
colorspace: ColorSpace,
target_type: WgTargetType,
) -> Result<()> {
Error::from_raw(unsafe {
ffi::tvg_wgcanvas_set_target(
self.raw,
device,
instance,
target,
w,
h,
colorspace.to_raw(),
target_type as i32,
)
})
}
}
impl_canvas_ops!(WgCanvas);
impl core::fmt::Debug for SwCanvas<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SwCanvas").finish_non_exhaustive()
}
}
impl core::fmt::Debug for GlCanvas<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("GlCanvas").finish_non_exhaustive()
}
}
impl core::fmt::Debug for WgCanvas<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("WgCanvas").finish_non_exhaustive()
}
}