1use bytemuck::{Pod, Zeroable};
5use peniko::{
6 BlendMode,
7 color::{AlphaColor, ColorSpace, DynamicColor, OpaqueColor, PremulColor, Srgb},
8};
9
10use super::Monoid;
11
12#[derive(Copy, Clone, PartialEq, Eq, Pod, Zeroable)]
14#[repr(C)]
15pub struct DrawTag(pub u32);
16
17impl DrawTag {
18 pub const NOP: Self = Self(0);
20
21 pub const COLOR: Self = Self(0x44);
23
24 pub const LINEAR_GRADIENT: Self = Self(0x114);
26
27 pub const RADIAL_GRADIENT: Self = Self(0x29c);
29
30 pub const SWEEP_GRADIENT: Self = Self(0x254);
32
33 pub const IMAGE: Self = Self(0x28C); pub const BLUR_RECT: Self = Self(0x2d4); pub const BEGIN_CLIP: Self = Self(0x49);
41
42 pub const END_CLIP: Self = Self(0x21);
44}
45
46impl DrawTag {
47 pub const fn info_size(self) -> u32 {
49 (self.0 >> 6) & 0xf
50 }
51}
52
53pub const DRAW_INFO_FLAGS_FILL_RULE_BIT: u32 = 1;
59
60#[derive(Copy, Clone, Pod, Zeroable, Debug, Default)]
62#[repr(C)]
63pub struct DrawBbox {
64 pub bbox: [f32; 4],
65}
66
67#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
69#[repr(C)]
70pub struct DrawColor {
71 pub rgba: u32,
74}
75
76impl<CS: ColorSpace> From<AlphaColor<CS>> for DrawColor {
77 fn from(color: AlphaColor<CS>) -> Self {
78 Self {
79 rgba: color.convert::<Srgb>().premultiply().to_rgba8().to_u32(),
80 }
81 }
82}
83
84impl From<DynamicColor> for DrawColor {
85 fn from(color: DynamicColor) -> Self {
86 Self {
87 rgba: color
88 .to_alpha_color::<Srgb>()
89 .premultiply()
90 .to_rgba8()
91 .to_u32(),
92 }
93 }
94}
95
96impl<CS: ColorSpace> From<OpaqueColor<CS>> for DrawColor {
97 fn from(color: OpaqueColor<CS>) -> Self {
98 Self {
99 rgba: color
100 .convert::<Srgb>()
101 .with_alpha(1.)
102 .premultiply()
103 .to_rgba8()
104 .to_u32(),
105 }
106 }
107}
108
109impl<CS: ColorSpace> From<PremulColor<CS>> for DrawColor {
110 fn from(color: PremulColor<CS>) -> Self {
111 Self {
112 rgba: color.convert::<Srgb>().to_rgba8().to_u32(),
113 }
114 }
115}
116
117#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
119#[repr(C)]
120pub struct DrawLinearGradient {
121 pub index: u32,
123 pub p0: [f32; 2],
125 pub p1: [f32; 2],
127}
128
129#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
131#[repr(C)]
132pub struct DrawRadialGradient {
133 pub index: u32,
135 pub p0: [f32; 2],
137 pub p1: [f32; 2],
139 pub r0: f32,
141 pub r1: f32,
143}
144
145#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
147#[repr(C)]
148pub struct DrawSweepGradient {
149 pub index: u32,
151 pub p0: [f32; 2],
153 pub t0: f32,
155 pub t1: f32,
157}
158
159#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
161#[repr(C)]
162pub struct DrawImage {
163 pub xy: u32,
165 pub width_height: u32,
167 pub sample_alpha: u32,
170}
171
172#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
174#[repr(C)]
175pub struct DrawBlurRoundedRect {
176 pub color: DrawColor,
178 pub width: f32,
180 pub height: f32,
182 pub radius: f32,
184 pub std_dev: f32,
186}
187
188#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
190#[repr(C)]
191pub struct DrawBeginClip {
192 pub blend_mode: u32,
194 pub alpha: f32,
196}
197
198impl DrawBeginClip {
199 pub const LUMINANCE_MASK_BLEND_MODE: u32 = 0x10000;
205 pub const CLIP_BLEND_MODE: u32 = 0x8003;
212
213 pub fn new(blend_mode: BlendMode, alpha: f32) -> Self {
215 Self {
216 blend_mode: ((blend_mode.mix as u32) << 8) | blend_mode.compose as u32,
217 alpha,
218 }
219 }
220
221 pub fn luminance_mask(alpha: f32) -> Self {
223 Self {
224 blend_mode: Self::LUMINANCE_MASK_BLEND_MODE,
225 alpha,
226 }
227 }
228
229 pub fn clip() -> Self {
231 Self {
232 blend_mode: Self::CLIP_BLEND_MODE,
233 alpha: 1.0,
234 }
235 }
236}
237
238#[derive(Copy, Clone, PartialEq, Eq, Pod, Zeroable, Default, Debug)]
240#[repr(C)]
241pub struct DrawMonoid {
242 pub path_ix: u32,
244 pub clip_ix: u32,
246 pub scene_offset: u32,
248 pub info_offset: u32,
250}
251
252impl Monoid for DrawMonoid {
253 type SourceValue = DrawTag;
254
255 fn new(tag: DrawTag) -> Self {
256 Self {
257 path_ix: (tag != DrawTag::NOP) as u32,
258 clip_ix: tag.0 & 1,
259 scene_offset: (tag.0 >> 2) & 0x7,
260 info_offset: (tag.0 >> 6) & 0xf,
261 }
262 }
263
264 fn combine(&self, other: &Self) -> Self {
265 Self {
266 path_ix: self.path_ix + other.path_ix,
267 clip_ix: self.clip_ix + other.clip_ix,
268 scene_offset: self.scene_offset + other.scene_offset,
269 info_offset: self.info_offset + other.info_offset,
270 }
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use peniko::Color;
277
278 use super::DrawColor;
279
280 #[test]
281 fn draw_color_endianness() {
282 let c = Color::from_rgba8(0x00, 0xca, 0xfe, 0xff);
286 assert_eq!(
287 bytemuck::bytes_of(&DrawColor::from(c)),
288 [0x00, 0xca, 0xfe, 0xff]
289 );
290 }
291
292 #[test]
293 fn draw_color_premultiplied() {
294 let c = Color::from_rgba8(0x00, 0xca, 0xfe, 0x00);
296 assert_eq!(DrawColor::from(c).rgba, 0);
297 }
298}