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. an hourglass shape).
9/// For non-self-intersecting paths, both rules produce the same result.
10#[derive(Copy, Clone, Default, 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 #[default]
20 NonZero = 0,
21 /// Even-odd fill rule.
22 ///
23 /// All regions where the winding number of the path is odd will be filled.
24 /// The most common use case for this rule is as an optimisation when the
25 /// paths are known not to be self-intersecting. It is also useful for
26 /// creating intentional holes in self-intersecting shapes (e.g. star or
27 /// donut-like paths) or to match the SVG/Canvas even-odd fill rule.
28 /// This can be implemented more efficiently than non-zero, as the winding
29 /// number state can be stored in only one bit (and so the winding numbers for
30 /// several pixels can be packed extremely efficiently).
31 EvenOdd = 1,
32 // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl.
33}
34
35/// Describes draw style-- either a [fill](Fill) or [stroke](Stroke).
36///
37/// See also [`StyleRef`] which can be used to avoid allocations.
38#[derive(Clone, Debug, PartialEq)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40pub enum Style {
41 /// Filled draw operation.
42 Fill(Fill),
43 /// Stroked draw operation.
44 Stroke(Stroke),
45}
46
47impl From<Fill> for Style {
48 fn from(fill: Fill) -> Self {
49 Self::Fill(fill)
50 }
51}
52
53impl From<Stroke> for Style {
54 fn from(stroke: Stroke) -> Self {
55 Self::Stroke(stroke)
56 }
57}
58
59/// Reference to a [draw style](Style).
60///
61/// This is useful for methods that would like to accept draw styles by reference. Defining
62/// the type as `impl Into<StyleRef>` allows accepting types like `&Stroke` or `Fill`
63/// directly without cloning or allocating.
64#[derive(Debug, Copy, Clone)]
65pub enum StyleRef<'a> {
66 /// Filled draw operation.
67 Fill(Fill),
68 /// Stroked draw operation.
69 Stroke(&'a Stroke),
70}
71
72impl StyleRef<'_> {
73 /// Converts the reference to an owned draw.
74 #[must_use]
75 pub fn to_owned(&self) -> Style {
76 match self {
77 Self::Fill(fill) => Style::Fill(*fill),
78 Self::Stroke(stroke) => Style::Stroke((*stroke).clone()),
79 }
80 }
81}
82
83impl From<Fill> for StyleRef<'_> {
84 fn from(fill: Fill) -> Self {
85 Self::Fill(fill)
86 }
87}
88
89impl<'a> From<&'a Stroke> for StyleRef<'a> {
90 fn from(stroke: &'a Stroke) -> Self {
91 Self::Stroke(stroke)
92 }
93}
94
95impl<'a> From<&'a Style> for StyleRef<'a> {
96 fn from(draw: &'a Style) -> Self {
97 match draw {
98 Style::Fill(fill) => Self::Fill(*fill),
99 Style::Stroke(stroke) => Self::Stroke(stroke),
100 }
101 }
102}