1 | use crate::prelude::*; |
2 | use skia_bindings::{self as sb, SkColor, SkColor4f, SkHSVToColor, SkPMColor, SkRGBToHSV, U8CPU}; |
3 | use 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)] |
15 | pub struct Color(SkColor); |
16 | |
17 | native_transmutable!(SkColor, Color, color_layout); |
18 | |
19 | impl From<u32> for Color { |
20 | fn from(argb: u32) -> Self { |
21 | Color::new(argb) |
22 | } |
23 | } |
24 | |
25 | impl 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 | |
35 | impl 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 | |
43 | impl 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 | |
51 | impl 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 | |
59 | impl 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 | |
67 | impl 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)] |
126 | pub struct RGB { |
127 | pub r: u8, |
128 | pub g: u8, |
129 | pub b: u8, |
130 | } |
131 | |
132 | impl 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 | |
138 | impl 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)] |
158 | pub struct HSV { |
159 | pub h: f32, |
160 | pub s: f32, |
161 | pub v: f32, |
162 | } |
163 | |
164 | impl 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 | |
170 | impl 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 | |
178 | pub type PMColor = SkPMColor; |
179 | |
180 | pub fn pre_multiply_argb(a: U8CPU, r: U8CPU, g: U8CPU, b: U8CPU) -> PMColor { |
181 | unsafe { sb::SkPreMultiplyARGB(a, r, g, b) } |
182 | } |
183 | |
184 | pub fn pre_multiply_color(c: impl Into<Color>) -> PMColor { |
185 | unsafe { sb::SkPreMultiplyColor(c.into().into_native()) } |
186 | } |
187 | |
188 | pub use sb::SkColorChannel as ColorChannel; |
189 | |
190 | #[test ] |
191 | fn color_channel_naming() { |
192 | let _ = ColorChannel::R; |
193 | } |
194 | |
195 | bitflags! { |
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)] |
214 | pub struct Color4f { |
215 | pub r: f32, |
216 | pub g: f32, |
217 | pub b: f32, |
218 | pub a: f32, |
219 | } |
220 | |
221 | native_transmutable!(SkColor4f, Color4f, color4f_layout); |
222 | |
223 | impl AsRef<Self> for Color4f { |
224 | fn as_ref(&self) -> &Self { |
225 | self |
226 | } |
227 | } |
228 | |
229 | impl 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 | |
240 | impl Mul for Color4f { |
241 | type Output = Self; |
242 | fn mul(self, scale: Self) -> Self { |
243 | self.mul(&scale) |
244 | } |
245 | } |
246 | |
247 | impl 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 | |
259 | impl Index<usize> for Color4f { |
260 | type Output = f32; |
261 | fn index(&self, index: usize) -> &f32 { |
262 | &self.as_array()[index] |
263 | } |
264 | } |
265 | |
266 | impl IndexMut<usize> for Color4f { |
267 | fn index_mut(&mut self, index: usize) -> &mut f32 { |
268 | &mut self.as_array_mut()[index] |
269 | } |
270 | } |
271 | |
272 | impl 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 | |
288 | impl From<u32> for Color4f { |
289 | fn from(color: u32) -> Self { |
290 | Color::from(color).into() |
291 | } |
292 | } |
293 | |
294 | impl From<RGB> for Color4f { |
295 | fn from(rgb: RGB) -> Self { |
296 | Color::from(rgb).into() |
297 | } |
298 | } |
299 | |
300 | impl 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 | |
363 | pub 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)] |
381 | mod 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 | |