mupdf/
stroke_state.rs

1use std::convert::TryFrom;
2
3use mupdf_sys::*;
4
5use crate::{context, from_enum, Error};
6
7from_enum! { fz_linecap => fz_linecap,
8    #[derive(Debug, Default, Clone, Copy, PartialEq)]
9    pub enum LineCap {
10        #[default]
11        Butt = FZ_LINECAP_BUTT,
12        Round = FZ_LINECAP_ROUND,
13        Square = FZ_LINECAP_SQUARE,
14        Triangle = FZ_LINECAP_TRIANGLE,
15    }
16}
17
18from_enum! { fz_linejoin => fz_linejoin,
19    #[derive(Debug, Default, Clone, Copy, PartialEq)]
20    pub enum LineJoin {
21        #[default]
22        Miter = FZ_LINEJOIN_MITER,
23        Round = FZ_LINEJOIN_ROUND,
24        Bevel = FZ_LINEJOIN_BEVEL,
25        MiterXps = FZ_LINEJOIN_MITER_XPS,
26    }
27}
28
29#[derive(Debug)]
30pub struct StrokeState {
31    pub(crate) inner: *mut fz_stroke_state,
32}
33
34impl StrokeState {
35    #[allow(clippy::too_many_arguments)]
36    pub fn new(
37        start_cap: LineCap,
38        dash_cap: LineCap,
39        end_cap: LineCap,
40        line_join: LineJoin,
41        line_width: f32,
42        miter_limit: f32,
43        dash_phase: f32,
44        dash: &[f32],
45    ) -> Result<Self, Error> {
46        let dash_len = dash.len() as i32;
47        unsafe {
48            ffi_try!(mupdf_new_stroke_state(
49                context(),
50                start_cap.into(),
51                dash_cap.into(),
52                end_cap.into(),
53                line_join.into(),
54                line_width,
55                miter_limit,
56                dash_phase,
57                dash.as_ptr(),
58                dash_len
59            ))
60        }
61        .map(|inner| Self { inner })
62    }
63
64    pub fn try_clone(&self) -> Result<Self, Error> {
65        let start_cap = self.start_cap();
66        let dash_cap = self.dash_cap();
67        let end_cap = self.end_cap();
68        let line_join = self.line_join();
69        let line_width = self.line_width();
70        let miter_limit = self.miter_limit();
71        let dash_phase = self.dash_phase();
72        let dashes = self.dashes();
73        Self::new(
74            start_cap,
75            dash_cap,
76            end_cap,
77            line_join,
78            line_width,
79            miter_limit,
80            dash_phase,
81            &dashes,
82        )
83    }
84
85    pub fn start_cap(&self) -> LineCap {
86        LineCap::try_from(unsafe { (*self.inner).start_cap }).unwrap()
87    }
88
89    pub fn dash_cap(&self) -> LineCap {
90        LineCap::try_from(unsafe { (*self.inner).dash_cap }).unwrap()
91    }
92
93    pub fn end_cap(&self) -> LineCap {
94        LineCap::try_from(unsafe { (*self.inner).end_cap }).unwrap()
95    }
96
97    pub fn line_join(&self) -> LineJoin {
98        LineJoin::try_from(unsafe { (*self.inner).linejoin }).unwrap()
99    }
100
101    pub fn line_width(&self) -> f32 {
102        unsafe { (*self.inner).linewidth }
103    }
104
105    pub fn miter_limit(&self) -> f32 {
106        unsafe { (*self.inner).miterlimit }
107    }
108
109    pub fn dash_phase(&self) -> f32 {
110        unsafe { (*self.inner).dash_phase }
111    }
112
113    pub fn dashes(&self) -> Vec<f32> {
114        unsafe {
115            let dash_len = (*self.inner).dash_len as usize;
116            let dash_ptr = (*self.inner).dash_list.as_ptr();
117            let mut dash_list = Vec::with_capacity(dash_len);
118            dash_list.extend_from_slice(std::slice::from_raw_parts(dash_ptr, dash_len));
119            dash_list
120        }
121    }
122}
123
124impl Drop for StrokeState {
125    fn drop(&mut self) {
126        if !self.inner.is_null() {
127            unsafe {
128                fz_drop_stroke_state(context(), self.inner);
129            }
130        }
131    }
132}
133
134impl Clone for StrokeState {
135    fn clone(&self) -> StrokeState {
136        self.try_clone().unwrap()
137    }
138}
139
140impl Default for StrokeState {
141    fn default() -> Self {
142        let inner = unsafe { mupdf_default_stroke_state(context()) };
143        Self { inner }
144    }
145}
146
147#[cfg(test)]
148mod test {
149    use super::StrokeState;
150
151    #[test]
152    fn test_default_stroke_state() {
153        let _stroke = StrokeState::default();
154    }
155}