skia_safe/core/
surface_props.rs

1use std::fmt;
2
3use skia_bindings::{self as sb, SkPixelGeometry, SkSurfaceProps};
4
5use crate::{prelude::*, scalar};
6
7// TODO: use the enum rewriter and strip underscores?
8#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
9#[repr(i32)]
10pub enum PixelGeometry {
11    #[default]
12    Unknown = SkPixelGeometry::kUnknown_SkPixelGeometry as _,
13    RGBH = SkPixelGeometry::kRGB_H_SkPixelGeometry as _,
14    BGRH = SkPixelGeometry::kBGR_H_SkPixelGeometry as _,
15    RGBV = SkPixelGeometry::kRGB_V_SkPixelGeometry as _,
16    BGRV = SkPixelGeometry::kBGR_V_SkPixelGeometry as _,
17}
18
19native_transmutable!(SkPixelGeometry, PixelGeometry);
20
21impl PixelGeometry {
22    pub fn is_rgb(self) -> bool {
23        self == PixelGeometry::RGBH || self == PixelGeometry::RGBV
24    }
25
26    pub fn is_bgr(self) -> bool {
27        self == PixelGeometry::BGRH || self == PixelGeometry::BGRV
28    }
29
30    pub fn is_h(self) -> bool {
31        self == PixelGeometry::RGBH || self == PixelGeometry::BGRH
32    }
33
34    pub fn is_v(self) -> bool {
35        self == PixelGeometry::RGBV || self == PixelGeometry::BGRV
36    }
37}
38
39bitflags! {
40    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
41    pub struct SurfacePropsFlags: u32 {
42        #[allow(clippy::unnecessary_cast)]
43        const DEFAULT = sb::SkSurfaceProps_Flags_kDefault_Flag as u32;
44        #[allow(clippy::unnecessary_cast)]
45        const USE_DEVICE_INDEPENDENT_FONTS =
46            sb::SkSurfaceProps_Flags_kUseDeviceIndependentFonts_Flag as u32;
47        #[allow(clippy::unnecessary_cast)]
48        const DYNAMIC_MSAA =
49            sb::SkSurfaceProps_Flags_kDynamicMSAA_Flag as u32;
50        #[allow(clippy::unnecessary_cast)]
51        const ALWAYS_DITHER =
52            sb::SkSurfaceProps_Flags_kAlwaysDither_Flag as u32;
53        #[allow(clippy::unnecessary_cast)]
54        const PRESERVES_TRANSPARENT_DRAWS =
55            sb::SkSurfaceProps_Flags_kPreservesTransparentDraws_Flag as u32;
56    }
57}
58
59impl Default for SurfacePropsFlags {
60    fn default() -> Self {
61        SurfacePropsFlags::empty()
62    }
63}
64
65#[derive(Copy, Clone)]
66#[repr(transparent)]
67pub struct SurfaceProps(SkSurfaceProps);
68
69native_transmutable!(SkSurfaceProps, SurfaceProps);
70
71impl PartialEq for SurfaceProps {
72    fn eq(&self, other: &Self) -> bool {
73        unsafe { sb::C_SkSurfaceProps_Equals(self.native(), other.native()) }
74    }
75}
76
77impl Eq for SurfaceProps {}
78
79impl Default for SurfaceProps {
80    fn default() -> Self {
81        SurfaceProps::new(Default::default(), Default::default())
82    }
83}
84
85impl fmt::Debug for SurfaceProps {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        f.debug_struct("SurfaceProps")
88            .field("flags", &self.flags())
89            .field("pixel_geometry", &self.pixel_geometry())
90            .field("text_contrast", &self.text_contrast())
91            .field("text_gamma", &self.text_gamma())
92            .finish()
93    }
94}
95
96impl SurfaceProps {
97    pub fn new(flags: SurfacePropsFlags, pixel_geometry: PixelGeometry) -> SurfaceProps {
98        Self::from_native_c(unsafe {
99            SkSurfaceProps::new1(flags.bits(), pixel_geometry.into_native())
100        })
101    }
102
103    pub fn new_with_text_properties(
104        flags: SurfacePropsFlags,
105        pixel_geometry: PixelGeometry,
106        text_contrast: scalar,
107        text_gamma: scalar,
108    ) -> SurfaceProps {
109        Self::from_native_c(unsafe {
110            SkSurfaceProps::new2(
111                flags.bits(),
112                pixel_geometry.into_native(),
113                text_contrast,
114                text_gamma,
115            )
116        })
117    }
118
119    pub fn flags(self) -> SurfacePropsFlags {
120        SurfacePropsFlags::from_bits_truncate(self.native().fFlags)
121    }
122
123    #[must_use]
124    pub fn clone_with_pixel_geometry(&self, new_pixel_geometry: PixelGeometry) -> Self {
125        Self::new_with_text_properties(
126            self.flags(),
127            new_pixel_geometry,
128            self.text_contrast(),
129            self.text_gamma(),
130        )
131    }
132
133    pub const MAX_CONTRAST_INCLUSIVE: scalar = 1.;
134    pub const MIN_CONTRAST_INCLUSIVE: scalar = 0.;
135    pub const MAX_GAMMA_EXCLUSIVE: scalar = 4.;
136    pub const MIN_GAMMA_INCLUSIVE: scalar = 0.;
137
138    pub fn pixel_geometry(self) -> PixelGeometry {
139        PixelGeometry::from_native_c(self.native().fPixelGeometry)
140    }
141
142    pub fn text_contrast(self) -> scalar {
143        self.native().fTextContrast
144    }
145
146    pub fn text_gamma(self) -> scalar {
147        self.native().fTextGamma
148    }
149
150    pub fn is_use_device_independent_fonts(self) -> bool {
151        self.flags()
152            .contains(SurfacePropsFlags::USE_DEVICE_INDEPENDENT_FONTS)
153    }
154
155    pub fn is_always_dither(self) -> bool {
156        self.flags().contains(SurfacePropsFlags::ALWAYS_DITHER)
157    }
158
159    pub fn preserves_transparent_draws(self) -> bool {
160        self.flags()
161            .contains(SurfacePropsFlags::PRESERVES_TRANSPARENT_DRAWS)
162    }
163}
164
165#[test]
166fn create() {
167    let props = SurfaceProps::new(
168        SurfacePropsFlags::USE_DEVICE_INDEPENDENT_FONTS,
169        PixelGeometry::RGBH,
170    );
171    assert_eq!(
172        SurfacePropsFlags::USE_DEVICE_INDEPENDENT_FONTS,
173        props.flags()
174    );
175    assert_eq!(PixelGeometry::RGBH, props.pixel_geometry());
176    assert!(props.is_use_device_independent_fonts());
177}