1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use std::convert::TryFrom;

use mupdf_sys::*;
use num_enum::TryFromPrimitive;

use crate::{context, Error};

#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
#[repr(u32)]
pub enum LineCap {
    Butt = 0,
    Round = 1,
    Square = 2,
    Triangle = 3,
}

impl Default for LineCap {
    fn default() -> Self {
        Self::Butt
    }
}

#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
#[repr(u32)]
pub enum LineJoin {
    Miter = 0,
    Round = 1,
    Bevel = 2,
    MiterXps = 3,
}

impl Default for LineJoin {
    fn default() -> Self {
        Self::Miter
    }
}

#[derive(Debug)]
pub struct StrokeState {
    pub(crate) inner: *mut fz_stroke_state,
}

impl StrokeState {
    pub fn new(
        start_cap: LineCap,
        dash_cap: LineCap,
        end_cap: LineCap,
        line_join: LineJoin,
        line_width: f32,
        miter_limit: f32,
        dash_phase: f32,
        dash: &[f32],
    ) -> Result<Self, Error> {
        let dash_len = dash.len() as i32;
        let inner = unsafe {
            ffi_try!(mupdf_new_stroke_state(
                context(),
                start_cap as fz_linecap,
                dash_cap as fz_linecap,
                end_cap as fz_linecap,
                line_join as fz_linejoin,
                line_width,
                miter_limit,
                dash_phase,
                dash.as_ptr(),
                dash_len
            ))
        };
        Ok(Self { inner })
    }

    pub fn try_clone(&self) -> Result<Self, Error> {
        let start_cap = self.start_cap();
        let dash_cap = self.dash_cap();
        let end_cap = self.end_cap();
        let line_join = self.line_join();
        let line_width = self.line_width();
        let miter_limit = self.miter_limit();
        let dash_phase = self.dash_phase();
        let dashes = self.dashes();
        Self::new(
            start_cap,
            dash_cap,
            end_cap,
            line_join,
            line_width,
            miter_limit,
            dash_phase,
            &dashes,
        )
    }

    pub fn start_cap(&self) -> LineCap {
        LineCap::try_from(unsafe { (*self.inner).start_cap as u32 }).unwrap()
    }

    pub fn dash_cap(&self) -> LineCap {
        LineCap::try_from(unsafe { (*self.inner).dash_cap as u32 }).unwrap()
    }

    pub fn end_cap(&self) -> LineCap {
        LineCap::try_from(unsafe { (*self.inner).end_cap as u32 }).unwrap()
    }

    pub fn line_join(&self) -> LineJoin {
        LineJoin::try_from(unsafe { (*self.inner).linejoin as u32 }).unwrap()
    }

    pub fn line_width(&self) -> f32 {
        unsafe { (*self.inner).linewidth }
    }

    pub fn miter_limit(&self) -> f32 {
        unsafe { (*self.inner).miterlimit }
    }

    pub fn dash_phase(&self) -> f32 {
        unsafe { (*self.inner).dash_phase }
    }

    pub fn dashes(&self) -> Vec<f32> {
        unsafe {
            let dash_len = (*self.inner).dash_len as usize;
            let mut dash_list = Vec::with_capacity(dash_len);
            dash_list.extend_from_slice(&(*self.inner).dash_list[0..dash_len]);
            dash_list
        }
    }
}

impl Drop for StrokeState {
    fn drop(&mut self) {
        if !self.inner.is_null() {
            unsafe {
                fz_drop_stroke_state(context(), self.inner);
            }
        }
    }
}

impl Clone for StrokeState {
    fn clone(&self) -> StrokeState {
        self.try_clone().unwrap()
    }
}

impl Default for StrokeState {
    fn default() -> Self {
        let inner = unsafe { mupdf_default_stroke_state(context()) };
        Self { inner }
    }
}

#[cfg(test)]
mod test {
    use super::StrokeState;

    #[test]
    fn test_default_stroke_state() {
        let _stroke = StrokeState::default();
    }
}