Skip to main content

ferroui_base/rendering/composition/
enums.rs

1use super::transport::{BatchValue, BatchValueReader};
2use crate::media::imaging::BitmapInterpolationMode;
3use bitflags::bitflags;
4
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
6#[repr(i32)]
7pub enum CompositionBlendMode {
8    /// No regions are enabled.
9    #[default]
10    Clear,
11    /// Only the source will be present.
12    Src,
13    /// Only the destination will be present.
14    Dst,
15    /// Source is placed over the destination.
16    SrcOver,
17    /// Destination is placed over the source.
18    DstOver,
19    /// The source that overlaps the destination, replaces the destination.
20    SrcIn,
21    /// Destination which overlaps the source, replaces the source.
22    DstIn,
23    /// Source is placed, where it falls outside of the destination.
24    SrcOut,
25    /// Destination is placed, where it falls outside of the source.
26    DstOut,
27    /// Source which overlaps the destination, replaces the destination.
28    SrcATop,
29    /// Destination which overlaps the source replaces the source.
30    DstATop,
31    /// The non-overlapping regions of source and destination are combined.
32    Xor,
33    /// Display the sum of the source image and destination image.
34    Plus,
35    /// Multiplies all components (= alpha and color).
36    Modulate,
37    /// Multiplies the complements of the backdrop and source color values,
38    /// then complements the result.
39    Screen,
40    /// Multiplies or screens the colors, depending on the backdrop color
41    /// value.
42    Overlay,
43    /// Selects the darker of the backdrop and source colors.
44    Darken,
45    /// Selects the lighter of the backdrop and source colors.
46    Lighten,
47    /// Brightens the backdrop color to reflect the source color.
48    ColorDodge,
49    /// Darkens the backdrop color to reflect the source color.
50    ColorBurn,
51    /// Multiplies or screens the colors, depending on the source color
52    /// value.
53    HardLight,
54    /// Darkens or lightens the colors, depending on the source color value.
55    SoftLight,
56    /// Subtracts the darker of the two constituent colors from the lighter
57    /// color.
58    Difference,
59    /// Produces an effect similar to that of the Difference mode but lower
60    /// in contrast.
61    Exclusion,
62    /// The source color is multiplied by the destination color and replaces
63    /// the destination.
64    Multiply,
65    /// Creates a color with the hue of the source color and the saturation
66    /// and luminosity of the backdrop color.
67    Hue,
68    /// Creates a color with the saturation of the source color and the hue
69    /// and luminosity of the backdrop color.
70    Saturation,
71    /// Creates a color with the hue and saturation of the source color and
72    /// the luminosity of the backdrop color.
73    Color,
74    /// Creates a color with the luminosity of the source color and the hue
75    /// and saturation of the backdrop color.
76    Luminosity,
77}
78
79#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
80#[repr(i32)]
81pub enum CompositionGradientExtendMode {
82    #[default]
83    Clamp,
84    Wrap,
85    Mirror,
86}
87
88bitflags! {
89    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
90    pub struct CompositionTileMode: i32 {
91        const NONE = 0;
92        const TILE_X = 1;
93        const TILE_Y = 2;
94        const FLIP_X = 4;
95        const FLIP_Y = 8;
96        const TILE = Self::TILE_X.bits() | Self::TILE_Y.bits();
97        const FLIP = Self::FLIP_X.bits() | Self::FLIP_Y.bits();
98    }
99}
100
101/// How the content of a composition surface brush fills the area of the
102/// brush (WinUI `CompositionStretch`).
103#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
104#[repr(i32)]
105pub enum CompositionStretch {
106    /// The content keeps its natural size.
107    #[default]
108    None = 0,
109    /// The content is scaled to the area, without keeping its aspect ratio.
110    Fill = 1,
111    /// The content is scaled to fit inside the area, keeping its aspect ratio.
112    Uniform = 2,
113    /// The content is scaled to cover the area, keeping its aspect ratio; the
114    /// part outside the area is clipped.
115    UniformToFill = 3,
116}
117
118/// How a bitmap is resampled when a composition surface brush scales it
119/// (WinUI `CompositionBitmapInterpolationMode`).
120#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
121#[repr(i32)]
122pub enum CompositionBitmapInterpolationMode {
123    /// The nearest pixel.
124    NearestNeighbor = 0,
125    /// Linear interpolation (the WinUI default).
126    #[default]
127    Linear = 1,
128    MagLinearMinLinearMipLinear = 2,
129    MagLinearMinLinearMipNearest = 3,
130    MagLinearMinNearestMipLinear = 4,
131    MagLinearMinNearestMipNearest = 5,
132    MagNearestMinLinearMipLinear = 6,
133    MagNearestMinLinearMipNearest = 7,
134    MagNearestMinNearestMipLinear = 8,
135    MagNearestMinNearestMipNearest = 9,
136}
137
138impl CompositionBitmapInterpolationMode {
139    const ALL: [CompositionBitmapInterpolationMode; 10] = [
140        Self::NearestNeighbor,
141        Self::Linear,
142        Self::MagLinearMinLinearMipLinear,
143        Self::MagLinearMinLinearMipNearest,
144        Self::MagLinearMinNearestMipLinear,
145        Self::MagLinearMinNearestMipNearest,
146        Self::MagNearestMinLinearMipLinear,
147        Self::MagNearestMinLinearMipNearest,
148        Self::MagNearestMinNearestMipLinear,
149        Self::MagNearestMinNearestMipNearest,
150    ];
151
152    /// The interpolation mode of the drawing context that comes closest.
153    ///
154    /// Deviation (winui-composition.md): the drawing contexts have one
155    /// quality setting, not separate minification, magnification and mip
156    /// filters. Nearest magnification maps to no interpolation, a linear
157    /// filter with linear mip filtering to the medium quality (mipmaps),
158    /// every other linear filter to the low quality (bilinear).
159    pub fn to_bitmap_interpolation_mode(self) -> BitmapInterpolationMode {
160        match self {
161            Self::NearestNeighbor
162            | Self::MagNearestMinLinearMipLinear
163            | Self::MagNearestMinLinearMipNearest
164            | Self::MagNearestMinNearestMipLinear
165            | Self::MagNearestMinNearestMipNearest => BitmapInterpolationMode::None,
166            Self::MagLinearMinLinearMipLinear => BitmapInterpolationMode::MediumQuality,
167            Self::Linear
168            | Self::MagLinearMinLinearMipNearest
169            | Self::MagLinearMinNearestMipLinear
170            | Self::MagLinearMinNearestMipNearest => BitmapInterpolationMode::LowQuality,
171        }
172    }
173}
174
175/// What a drop shadow is cast from (WinUI
176/// `CompositionDropShadowSourcePolicy`).
177#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
178#[repr(i32)]
179pub enum CompositionDropShadowSourcePolicy {
180    /// The shadow uses the mask, or the shape of the visual when there is
181    /// none.
182    #[default]
183    Default = 0,
184    /// The shadow uses the alpha of the content of the visual.
185    InheritFromVisualContent = 1,
186}
187
188impl BatchValue for CompositionBitmapInterpolationMode {
189    fn write_to(&self, out: &mut Vec<u8>) {
190        (*self as i32).write_to(out);
191    }
192
193    fn read_from(input: &mut BatchValueReader<'_>) -> Self {
194        let value = i32::read_from(input);
195        match Self::ALL.iter().find(|mode| **mode as i32 == value) {
196            Some(mode) => *mode,
197            None => panic!("the batch value stream holds {value}, which is not a CompositionBitmapInterpolationMode"),
198        }
199    }
200}
201
202impl BatchValue for CompositionDropShadowSourcePolicy {
203    fn write_to(&self, out: &mut Vec<u8>) {
204        (*self as i32).write_to(out);
205    }
206
207    fn read_from(input: &mut BatchValueReader<'_>) -> Self {
208        match i32::read_from(input) {
209            0 => Self::Default,
210            1 => Self::InheritFromVisualContent,
211            value => panic!("the batch value stream holds {value}, which is not a CompositionDropShadowSourcePolicy"),
212        }
213    }
214}
215
216#[cfg(test)]
217mod tests {
218    use super::*;
219
220    #[test]
221    fn values_match_the_reference() {
222        assert_eq!(CompositionBlendMode::Clear as i32, 0);
223        assert_eq!(CompositionBlendMode::SrcOver as i32, 3);
224        assert_eq!(CompositionBlendMode::Luminosity as i32, 28);
225        assert_eq!(CompositionGradientExtendMode::Mirror as i32, 2);
226        assert_eq!(CompositionTileMode::TILE.bits(), 3);
227        assert_eq!(CompositionTileMode::FLIP.bits(), 12);
228        assert_eq!(CompositionStretch::Fill as i32, 1);
229    }
230
231    #[test]
232    fn winui_values() {
233        assert_eq!(CompositionStretch::Uniform as i32, 2);
234        assert_eq!(CompositionStretch::UniformToFill as i32, 3);
235        assert_eq!(CompositionBitmapInterpolationMode::default(), CompositionBitmapInterpolationMode::Linear);
236        assert_eq!(CompositionBitmapInterpolationMode::MagNearestMinNearestMipNearest as i32, 9);
237        assert_eq!(CompositionDropShadowSourcePolicy::InheritFromVisualContent as i32, 1);
238    }
239
240    #[test]
241    fn enums_cross_a_batch() {
242        use crate::rendering::composition::transport::{BatchValue, BatchValueReader};
243
244        let mut out = Vec::new();
245        CompositionBitmapInterpolationMode::MagLinearMinNearestMipLinear.write_to(&mut out);
246        CompositionDropShadowSourcePolicy::InheritFromVisualContent.write_to(&mut out);
247        CompositionStretch::UniformToFill.write_to(&mut out);
248        let mut offset = 0;
249        let mut input = BatchValueReader::new(&out, &mut offset);
250        assert_eq!(
251            CompositionBitmapInterpolationMode::MagLinearMinNearestMipLinear,
252            CompositionBitmapInterpolationMode::read_from(&mut input)
253        );
254        assert_eq!(
255            CompositionDropShadowSourcePolicy::InheritFromVisualContent,
256            CompositionDropShadowSourcePolicy::read_from(&mut input)
257        );
258        assert_eq!(CompositionStretch::UniformToFill, CompositionStretch::read_from(&mut input));
259    }
260}