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
use crate::*;

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u32)]
pub enum CapStyle {
    Flat = D2D1_CAP_STYLE_FLAT.0,
    Square = D2D1_CAP_STYLE_SQUARE.0,
    Round = D2D1_CAP_STYLE_ROUND.0,
    Triangle = D2D1_CAP_STYLE_TRIANGLE.0,
}

#[derive(Clone, Copy, Debug)]
pub enum LineJoin {
    Miter,
    Bevel,
    Round,
    MiterOrBevel(f32),
}

#[derive(Clone, Copy, Debug)]
pub enum DashStyle<'a> {
    Solid,
    Dash,
    Dot,
    DashDot,
    DashDotDot,
    Custom(&'a [f32]),
}

#[derive(Debug)]
pub struct Dash<'a> {
    pub cap: CapStyle,
    pub style: DashStyle<'a>,
    pub offset: f32,
}

impl<'a> Default for Dash<'a> {
    #[inline]
    fn default() -> Self {
        Self {
            cap: CapStyle::Flat,
            style: DashStyle::Solid,
            offset: 0.0,
        }
    }
}

#[derive(Debug)]
pub struct StrokeStyleProperties<'a> {
    pub start_cap: CapStyle,
    pub end_cap: CapStyle,
    pub line_join: LineJoin,
    pub dash: Option<Dash<'a>>,
}

impl<'a> Default for StrokeStyleProperties<'a> {
    #[inline]
    fn default() -> Self {
        Self {
            start_cap: CapStyle::Flat,
            end_cap: CapStyle::Flat,
            line_join: LineJoin::Miter,
            dash: None,
        }
    }
}

#[derive(Clone, PartialEq, Eq)]
pub struct StrokeStyle(pub(crate) ID2D1StrokeStyle);

impl StrokeStyle {
    pub(crate) fn new(
        factory: &ID2D1Factory1,
        props: &StrokeStyleProperties,
    ) -> windows::core::Result<Self> {
        let (dash_cap, dash_style, dash_offset, dashes, dashes_len) = match props.dash.as_ref() {
            Some(dash) => {
                let cap = D2D1_CAP_STYLE(dash.cap as _);
                let (style, dashes, dashes_len) = match dash.style {
                    DashStyle::Solid => (D2D1_DASH_STYLE_SOLID, std::ptr::null(), 0),
                    DashStyle::Dash => (D2D1_DASH_STYLE_DASH, std::ptr::null(), 0),
                    DashStyle::Dot => (D2D1_DASH_STYLE_DOT, std::ptr::null(), 0),
                    DashStyle::DashDot => (D2D1_DASH_STYLE_DASH_DOT, std::ptr::null(), 0),
                    DashStyle::DashDotDot => (D2D1_DASH_STYLE_DASH_DOT_DOT, std::ptr::null(), 0),
                    DashStyle::Custom(dashes) => {
                        (D2D1_DASH_STYLE_CUSTOM, dashes.as_ptr(), dashes.len())
                    }
                };
                (cap, style, dash.offset, dashes, dashes_len)
            }
            None => (
                D2D1_CAP_STYLE_FLAT,
                D2D1_DASH_STYLE_SOLID,
                0.0,
                std::ptr::null(),
                0,
            ),
        };
        let (line_join, miter_limit) = match props.line_join {
            LineJoin::Miter => (D2D1_LINE_JOIN_MITER, 1.0),
            LineJoin::Bevel => (D2D1_LINE_JOIN_BEVEL, 1.0),
            LineJoin::Round => (D2D1_LINE_JOIN_ROUND, 1.0),
            LineJoin::MiterOrBevel(miter_limit) => (D2D1_LINE_JOIN_MITER_OR_BEVEL, miter_limit),
        };
        let props = D2D1_STROKE_STYLE_PROPERTIES {
            startCap: D2D1_CAP_STYLE(props.start_cap as _),
            endCap: D2D1_CAP_STYLE(props.end_cap as _),
            dashCap: dash_cap,
            lineJoin: line_join,
            miterLimit: miter_limit,
            dashStyle: dash_style,
            dashOffset: dash_offset,
        };
        let stroke_style = unsafe { factory.CreateStrokeStyle(&props, dashes, dashes_len as _)? };
        Ok(StrokeStyle(stroke_style))
    }
}

unsafe impl Send for StrokeStyle {}
unsafe impl Sync for StrokeStyle {}