1use crate::prelude::*;
2use skia_bindings::{self as sb, SkColor, SkColor4f, SkHSVToColor, SkPMColor, SkRGBToHSV, U8CPU};
3use std::ops::{BitAnd, BitOr, Index, IndexMut, Mul};
4
5// TODO: What should we do with SkAlpha?
6// It does not seem to be used, but if we want to export it, we'd
7// like to define Alpha::TRANSPARENT and Alpha::OPAQUE.
8// pub type Alpha = u8;
9
10// Note: SkColor _is_ a u32, and therefore its components are
11// endian dependent, so we can't expose it as (transmuted) individual
12// argb fields.
13#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
14#[repr(transparent)]
15pub struct Color(SkColor);
16
17native_transmutable!(SkColor, Color, color_layout);
18
19impl From<u32> for Color {
20 fn from(argb: u32) -> Self {
21 Color::new(argb)
22 }
23}
24
25impl From<RGB> for Color {
26 fn from(rgb: RGB) -> Self {
27 Color::from_rgb(rgb.r, rgb.g, rgb.b)
28 }
29}
30
31//
32// Bitwise operators.
33//
34
35impl BitOr for Color {
36 type Output = Self;
37
38 fn bitor(self, rhs: Self) -> Self::Output {
39 Color::from_native_c(self.native() | rhs.native())
40 }
41}
42
43impl BitAnd for Color {
44 type Output = Self;
45
46 fn bitand(self, rhs: Self) -> Self::Output {
47 Color::from_native_c(self.native() & rhs.native())
48 }
49}
50
51impl BitOr<u32> for Color {
52 type Output = Self;
53
54 fn bitor(self, rhs: u32) -> Self::Output {
55 self | Color::from_native_c(nt:rhs)
56 }
57}
58
59impl BitAnd<u32> for Color {
60 type Output = Self;
61
62 fn bitand(self, rhs: u32) -> Self::Output {
63 self & (Color::from_native_c(nt:rhs))
64 }
65}
66
67impl Color {
68 pub const fn new(argb: u32) -> Self {
69 Self(argb)
70 }
71
72 // Don't use the u8cpu type in the arguments here, because we trust the Rust compiler to
73 // optimize the storage type.
74 pub const fn from_argb(a: u8, r: u8, g: u8, b: u8) -> Color {
75 Self(((a as U8CPU) << 24) | ((r as U8CPU) << 16) | ((g as U8CPU) << 8) | (b as U8CPU))
76 }
77
78 pub const fn from_rgb(r: u8, g: u8, b: u8) -> Color {
79 Self::from_argb(0xff, r, g, b)
80 }
81
82 pub fn a(self) -> u8 {
83 (self.into_native() >> 24) as _
84 }
85
86 pub fn r(self) -> u8 {
87 (self.into_native() >> 16) as _
88 }
89
90 pub fn g(self) -> u8 {
91 (self.into_native() >> 8) as _
92 }
93
94 pub fn b(self) -> u8 {
95 self.into_native() as _
96 }
97
98 #[must_use]
99 pub fn with_a(self, a: u8) -> Self {
100 Self::from_argb(a, self.r(), self.g(), self.b())
101 }
102
103 pub const TRANSPARENT: Self = Self(sb::SK_ColorTRANSPARENT);
104 pub const BLACK: Self = Self(sb::SK_ColorBLACK);
105 pub const DARK_GRAY: Self = Self(sb::SK_ColorDKGRAY);
106 pub const GRAY: Self = Self(sb::SK_ColorGRAY);
107 pub const LIGHT_GRAY: Self = Self(sb::SK_ColorLTGRAY);
108 pub const WHITE: Self = Self(sb::SK_ColorWHITE);
109 pub const RED: Self = Self(sb::SK_ColorRED);
110 pub const GREEN: Self = Self(sb::SK_ColorGREEN);
111 pub const BLUE: Self = Self(sb::SK_ColorBLUE);
112 pub const YELLOW: Self = Self(sb::SK_ColorYELLOW);
113 pub const CYAN: Self = Self(sb::SK_ColorCYAN);
114 pub const MAGENTA: Self = Self(sb::SK_ColorMAGENTA);
115
116 pub fn to_rgb(self) -> RGB {
117 (self.r(), self.g(), self.b()).into()
118 }
119
120 pub fn to_hsv(self) -> HSV {
121 self.to_rgb().to_hsv()
122 }
123}
124
125#[derive(Copy, Clone, PartialEq, Eq, Debug)]
126pub struct RGB {
127 pub r: u8,
128 pub g: u8,
129 pub b: u8,
130}
131
132impl From<(u8, u8, u8)> for RGB {
133 fn from((r: u8, g: u8, b: u8): (u8, u8, u8)) -> Self {
134 Self { r, g, b }
135 }
136}
137
138impl RGB {
139 pub fn to_hsv(self) -> HSV {
140 let mut hsv: [f32; 3] = Default::default();
141 unsafe {
142 SkRGBToHSV(
143 self.r.into(),
144 self.g.into(),
145 self.b.into(),
146 hsv:hsv.as_mut_ptr(),
147 );
148 }
149 HSV {
150 h: hsv[0],
151 s: hsv[1],
152 v: hsv[2],
153 }
154 }
155}
156
157#[derive(Copy, Clone, PartialEq, Debug)]
158pub struct HSV {
159 pub h: f32,
160 pub s: f32,
161 pub v: f32,
162}
163
164impl From<(f32, f32, f32)> for HSV {
165 fn from((h: f32, s: f32, v: f32): (f32, f32, f32)) -> Self {
166 Self { h, s, v }
167 }
168}
169
170impl HSV {
171 pub fn to_color(self, alpha: u8) -> Color {
172 Color::from_native_c(nt:unsafe {
173 SkHSVToColor(alpha:alpha.into(), [self.h, self.s, self.v].as_ptr())
174 })
175 }
176}
177
178pub type PMColor = SkPMColor;
179
180pub fn pre_multiply_argb(a: U8CPU, r: U8CPU, g: U8CPU, b: U8CPU) -> PMColor {
181 unsafe { sb::SkPreMultiplyARGB(a, r, g, b) }
182}
183
184pub fn pre_multiply_color(c: impl Into<Color>) -> PMColor {
185 unsafe { sb::SkPreMultiplyColor(c.into().into_native()) }
186}
187
188pub use sb::SkColorChannel as ColorChannel;
189
190#[test]
191fn color_channel_naming() {
192 let _ = ColorChannel::R;
193}
194
195bitflags! {
196 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
197 pub struct ColorChannelFlag: u32 {
198 const RED = sb::SkColorChannelFlag::kRed_SkColorChannelFlag as _;
199 const GREEN = sb::SkColorChannelFlag::kGreen_SkColorChannelFlag as _;
200 const BLUE = sb::SkColorChannelFlag::kBlue_SkColorChannelFlag as _;
201 const ALPHA = sb::SkColorChannelFlag::kAlpha_SkColorChannelFlag as _;
202 const GRAY = sb::SkColorChannelFlag::kGray_SkColorChannelFlag as _;
203 const GRAY_ALPHA = Self::GRAY.bits() | Self::ALPHA.bits();
204 const RG = Self::RED.bits() | Self::GREEN.bits();
205 const RGB = Self::RG.bits() | Self::BLUE.bits();
206 const RGBA = Self::RGB.bits() | Self::ALPHA.bits();
207 }
208}
209
210// TODO: SkRGBA4f
211
212#[derive(Copy, Clone, PartialEq, Debug)]
213#[repr(C)]
214pub struct Color4f {
215 pub r: f32,
216 pub g: f32,
217 pub b: f32,
218 pub a: f32,
219}
220
221native_transmutable!(SkColor4f, Color4f, color4f_layout);
222
223impl AsRef<Self> for Color4f {
224 fn as_ref(&self) -> &Self {
225 self
226 }
227}
228
229impl Mul<f32> for Color4f {
230 type Output = Self;
231 fn mul(self, scale: f32) -> Self {
232 let r: f32 = self.r * scale;
233 let g: f32 = self.g * scale;
234 let b: f32 = self.b * scale;
235 let a: f32 = self.a * scale;
236 Self { r, g, b, a }
237 }
238}
239
240impl Mul for Color4f {
241 type Output = Self;
242 fn mul(self, scale: Self) -> Self {
243 self.mul(&scale)
244 }
245}
246
247impl Mul<&Self> for Color4f {
248 type Output = Self;
249 fn mul(self, scale: &Self) -> Self {
250 Self {
251 r: self.r * scale.r,
252 g: self.g * scale.g,
253 b: self.b * scale.b,
254 a: self.a * scale.a,
255 }
256 }
257}
258
259impl Index<usize> for Color4f {
260 type Output = f32;
261 fn index(&self, index: usize) -> &f32 {
262 &self.as_array()[index]
263 }
264}
265
266impl IndexMut<usize> for Color4f {
267 fn index_mut(&mut self, index: usize) -> &mut f32 {
268 &mut self.as_array_mut()[index]
269 }
270}
271
272impl From<Color> for Color4f {
273 fn from(color: Color) -> Self {
274 fn c(c: u8) -> f32 {
275 (f32::from(c)) * (1.0 / 255.0)
276 }
277 let r: f32 = c(color.r());
278 let g: f32 = c(color.g());
279 let b: f32 = c(color.b());
280 let a: f32 = c(color.a());
281 Self { r, g, b, a }
282 }
283}
284
285// Add all Color::From implementations to Color4f, so that
286// function signatures can promote Into<Color> to Into<Color4f>.
287
288impl From<u32> for Color4f {
289 fn from(color: u32) -> Self {
290 Color::from(color).into()
291 }
292}
293
294impl From<RGB> for Color4f {
295 fn from(rgb: RGB) -> Self {
296 Color::from(rgb).into()
297 }
298}
299
300impl Color4f {
301 pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Color4f {
302 Self { r, g, b, a }
303 }
304
305 // corresponding Skia function: vec()
306 pub fn as_array(&self) -> &[f32; 4] {
307 unsafe { transmute_ref(self) }
308 }
309
310 // corresponding Skia function: vec()
311 pub fn as_array_mut(&mut self) -> &mut [f32; 4] {
312 unsafe { transmute_ref_mut(self) }
313 }
314
315 #[allow(clippy::float_cmp)]
316 pub fn is_opaque(&self) -> bool {
317 self.a == 1.0
318 }
319
320 // TODO: This is the copied implementation, it would probably be better
321 // to call the Skia function.
322 pub fn fits_in_bytes(&self) -> bool {
323 debug_assert!(self.a >= 0.0 && self.a <= 1.0);
324 self.r >= 0.0
325 && self.r <= 1.0
326 && self.g >= 0.0
327 && self.g <= 1.0
328 && self.b >= 0.0
329 && self.b <= 1.0
330 }
331
332 pub fn to_color(self) -> Color {
333 fn c(f: f32) -> u8 {
334 (f.clamp(0.0, 1.0) * 255.0) as u8
335 }
336 let a = c(self.a);
337 let r = c(self.r);
338 let g = c(self.g);
339 let b = c(self.b);
340 Color::from_argb(a, r, g, b)
341 }
342
343 // TODO: FromPMColor
344 // TODO: premul()
345 // TODO: unpremul()
346
347 #[must_use]
348 pub fn to_bytes(self) -> u32 {
349 unsafe { sb::C_SkColor4f_toBytes_RGBA(self.native()) }
350 }
351
352 #[must_use]
353 pub fn from_bytes_rgba(color: u32) -> Self {
354 Self::from_native_c(unsafe { sb::C_SkColor4f_FromBytes_RGBA(color) })
355 }
356
357 #[must_use]
358 pub fn to_opaque(self) -> Self {
359 Self { a: 1.0, ..self }
360 }
361}
362
363pub mod colors {
364 use crate::Color4f;
365
366 pub const TRANSPARENT: Color4f = Color4f::new(r:0.0, g:0.0, b:0.0, a:0.0);
367 pub const BLACK: Color4f = Color4f::new(r:0.0, g:0.0, b:0.0, a:1.0);
368 pub const DARK_GREY: Color4f = Color4f::new(r:0.25, g:0.25, b:0.25, a:1.0);
369 pub const GREY: Color4f = Color4f::new(r:0.5, g:0.5, b:0.5, a:1.0);
370 pub const LIGHT_GREY: Color4f = Color4f::new(r:0.75, g:0.75, b:0.75, a:1.0);
371 pub const WHITE: Color4f = Color4f::new(r:1.0, g:1.0, b:1.0, a:1.0);
372 pub const RED: Color4f = Color4f::new(r:1.0, g:0.0, b:0.0, a:1.0);
373 pub const GREEN: Color4f = Color4f::new(r:0.0, g:1.0, b:0.0, a:1.0);
374 pub const BLUE: Color4f = Color4f::new(r:0.0, g:0.0, b:1.0, a:1.0);
375 pub const YELLOW: Color4f = Color4f::new(r:1.0, g:1.0, b:0.0, a:1.0);
376 pub const CYAN: Color4f = Color4f::new(r:0.0, g:1.0, b:1.0, a:1.0);
377 pub const MAGENTA: Color4f = Color4f::new(r:1.0, g:0.0, b:1.0, a:1.0);
378}
379
380#[cfg(test)]
381mod tests {
382 use super::{colors, Color, Color4f};
383
384 #[test]
385 #[allow(clippy::float_cmp)]
386 pub fn color4f_array_access() {
387 let mut color = Color4f {
388 r: 0.1,
389 g: 0.2,
390 b: 0.3,
391 a: 0.4,
392 };
393 color[1] = 0.5;
394 assert_eq!(0.5, color.g);
395 }
396
397 #[test]
398 pub fn color_color4f_conversion() {
399 let c = Color::from_argb(1, 2, 3, 4);
400 let cf = Color4f::from(c);
401 let c2 = cf.to_color();
402 assert_eq!(c, c2);
403 }
404
405 #[test]
406 pub fn color4f_value_can_be_passed_as_ref() {
407 fn passed_as_ref(_c: impl AsRef<Color4f>) {}
408 passed_as_ref(colors::BLACK);
409 }
410}
411