peniko/
style.rs

1// Copyright 2022 the Peniko Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4use kurbo::Stroke;
5
6/// Describes the rule that determines the interior portion of a shape.
7///
8/// This is only relevant for self-intersecting paths (e.g. a hourglass shape).
9/// For non-self-intersecting paths, both rules produce the same result.
10#[derive(Copy, Clone, PartialEq, Eq, Debug)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[repr(u8)]
13pub enum Fill {
14    /// Non-zero fill rule.
15    ///
16    /// All regions where the winding number of the path is not zero will be filled.
17    /// This is generally more correct, but can be more expensive to implement in renderers.
18    /// This matches the default behavior of the web canvas, and is the default value.
19    NonZero = 0,
20    /// Even-odd fill rule.
21    ///
22    /// All regions where the winding number of the path is odd will be willed.
23    /// The most common use case for this rule is as an optimisation when the
24    /// paths are known to not be self-intersecting. There may also be cases where
25    /// this rendering is desired. <!-- TODO: Are there? -->
26    /// This can be implemented more efficiently than even-odd, as the winding
27    /// number state can be stored in only one bit (and so the winding numbers for
28    /// several pixels can be packed extremely efficiently).
29    EvenOdd = 1,
30    // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the bytemuck impl.
31}
32
33/// Describes draw style-- either a [fill](Fill) or [stroke](Stroke).
34///
35/// See also [`StyleRef`] which can be used to avoid allocations.
36#[derive(Clone, Debug, PartialEq)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38pub enum Style {
39    /// Filled draw operation.
40    Fill(Fill),
41    /// Stroked draw operation.
42    Stroke(Stroke),
43}
44
45impl Default for Fill {
46    fn default() -> Self {
47        Self::NonZero
48    }
49}
50
51impl From<Fill> for Style {
52    fn from(fill: Fill) -> Self {
53        Self::Fill(fill)
54    }
55}
56
57impl From<Stroke> for Style {
58    fn from(stroke: Stroke) -> Self {
59        Self::Stroke(stroke)
60    }
61}
62
63/// Reference to a [draw style](Style).
64///
65/// This is useful for methods that would like to accept draw styles by reference. Defining
66/// the type as `impl<Into<DrawRef>>` allows accepting types like `&Stroke` or `Fill`
67/// directly without cloning or allocating.
68#[expect(
69    variant_size_differences,
70    reason = "We don't expect this enum to be operated on in bulk."
71)]
72#[derive(Debug, Copy, Clone)]
73pub enum StyleRef<'a> {
74    /// Filled draw operation.
75    Fill(Fill),
76    /// Stroked draw operation.
77    Stroke(&'a Stroke),
78}
79
80impl StyleRef<'_> {
81    /// Converts the reference to an owned draw.
82    #[must_use]
83    pub fn to_owned(&self) -> Style {
84        match self {
85            Self::Fill(fill) => Style::Fill(*fill),
86            Self::Stroke(stroke) => Style::Stroke((*stroke).clone()),
87        }
88    }
89}
90
91impl From<Fill> for StyleRef<'_> {
92    fn from(fill: Fill) -> Self {
93        Self::Fill(fill)
94    }
95}
96
97impl<'a> From<&'a Stroke> for StyleRef<'a> {
98    fn from(stroke: &'a Stroke) -> Self {
99        Self::Stroke(stroke)
100    }
101}
102
103impl<'a> From<&'a Style> for StyleRef<'a> {
104    fn from(draw: &'a Style) -> Self {
105        match draw {
106            Style::Fill(fill) => Self::Fill(*fill),
107            Style::Stroke(stroke) => Self::Stroke(stroke),
108        }
109    }
110}