use core::ptr::NonNull;
use std::ffi::{CString, c_void};
use crate::ffi::{
noesis_svg_image_destroy, noesis_svg_image_get_size, noesis_svg_image_parse,
noesis_svg_image_shape_count, noesis_svg_image_shape_fill_type, noesis_svg_path_add_ellipse,
noesis_svg_path_add_rect, noesis_svg_path_calculate_bounds, noesis_svg_path_close,
noesis_svg_path_command_count, noesis_svg_path_create, noesis_svg_path_destroy,
noesis_svg_path_fill_contains, noesis_svg_path_line_to, noesis_svg_path_move_to,
noesis_svg_path_parse, noesis_svg_path_stroke_contains,
};
pub use crate::geometry::FillRule;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum StrokeJoin {
Miter = 0,
Bevel = 1,
Round = 2,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum StrokeCap {
Butt = 0,
Square = 1,
Round = 2,
Triangle = 3,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Pen {
pub width: f32,
pub join: StrokeJoin,
pub start_cap: StrokeCap,
pub end_cap: StrokeCap,
pub miter_limit: f32,
}
impl Default for Pen {
fn default() -> Self {
Self {
width: 1.0,
join: StrokeJoin::Bevel,
start_cap: StrokeCap::Butt,
end_cap: StrokeCap::Butt,
miter_limit: 1.0,
}
}
}
pub struct SvgPath {
ptr: NonNull<c_void>,
}
unsafe impl Send for SvgPath {}
impl SvgPath {
#[must_use]
pub fn parse(path_data: &str) -> Option<Self> {
let c = CString::new(path_data).ok()?;
let ptr = unsafe { noesis_svg_path_parse(c.as_ptr()) };
NonNull::new(ptr).map(|ptr| Self { ptr })
}
#[must_use]
pub fn new() -> Self {
let ptr = unsafe { noesis_svg_path_create() };
Self {
ptr: NonNull::new(ptr).expect("noesis_svg_path_create returned null"),
}
}
#[must_use]
pub fn command_count(&self) -> u32 {
unsafe { noesis_svg_path_command_count(self.ptr.as_ptr()) }
}
pub fn move_to(&mut self, x: f32, y: f32) {
unsafe { noesis_svg_path_move_to(self.ptr.as_ptr(), x, y) };
}
pub fn line_to(&mut self, x: f32, y: f32) {
unsafe { noesis_svg_path_line_to(self.ptr.as_ptr(), x, y) };
}
pub fn close(&mut self) {
unsafe { noesis_svg_path_close(self.ptr.as_ptr()) };
}
pub fn add_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
unsafe { noesis_svg_path_add_rect(self.ptr.as_ptr(), x, y, width, height) };
}
pub fn add_ellipse(&mut self, x: f32, y: f32, rx: f32, ry: f32) {
unsafe { noesis_svg_path_add_ellipse(self.ptr.as_ptr(), x, y, rx, ry) };
}
#[must_use]
pub fn bounds(&self) -> [f32; 4] {
let mut out = [0.0f32; 4];
unsafe { noesis_svg_path_calculate_bounds(self.ptr.as_ptr(), out.as_mut_ptr()) };
out
}
#[must_use]
pub fn fill_contains(&self, x: f32, y: f32, rule: FillRule) -> bool {
unsafe { noesis_svg_path_fill_contains(self.ptr.as_ptr(), x, y, rule as i32) }
}
#[must_use]
pub fn stroke_contains(&self, x: f32, y: f32, pen: Pen) -> bool {
unsafe {
noesis_svg_path_stroke_contains(
self.ptr.as_ptr(),
x,
y,
pen.width,
pen.join as i32,
pen.start_cap as i32,
pen.end_cap as i32,
pen.miter_limit,
)
}
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl Default for SvgPath {
fn default() -> Self {
Self::new()
}
}
impl Drop for SvgPath {
fn drop(&mut self) {
unsafe { noesis_svg_path_destroy(self.ptr.as_ptr()) };
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum SvgBrushType {
None = 0,
Solid = 1,
Linear = 2,
Radial = 3,
}
impl SvgBrushType {
fn from_raw(v: i32) -> Option<Self> {
match v {
0 => Some(Self::None),
1 => Some(Self::Solid),
2 => Some(Self::Linear),
3 => Some(Self::Radial),
_ => None,
}
}
}
pub struct SvgImage {
ptr: NonNull<c_void>,
}
unsafe impl Send for SvgImage {}
impl SvgImage {
#[must_use]
pub fn parse(document: &str) -> Option<Self> {
let c = CString::new(document).ok()?;
let ptr = unsafe { noesis_svg_image_parse(c.as_ptr()) };
NonNull::new(ptr).map(|ptr| Self { ptr })
}
#[must_use]
pub fn size(&self) -> (f32, f32) {
let mut w = 0.0f32;
let mut h = 0.0f32;
unsafe { noesis_svg_image_get_size(self.ptr.as_ptr(), &mut w, &mut h) };
(w, h)
}
#[must_use]
pub fn shape_count(&self) -> u32 {
unsafe { noesis_svg_image_shape_count(self.ptr.as_ptr()) }
}
#[must_use]
pub fn shape_fill_type(&self, index: u32) -> Option<SvgBrushType> {
let v = unsafe { noesis_svg_image_shape_fill_type(self.ptr.as_ptr(), index) };
SvgBrushType::from_raw(v)
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl Drop for SvgImage {
fn drop(&mut self) {
unsafe { noesis_svg_image_destroy(self.ptr.as_ptr()) };
}
}