1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use peek_poke::PeekPoke;
6 use std::cmp;
7 use std::hash::{Hash, Hasher};
8 
9 /// Represents pre-multiplied RGBA colors with floating point numbers.
10 ///
11 /// All components must be between 0.0 and 1.0.
12 /// An alpha value of 1.0 is opaque while 0.0 is fully transparent.
13 ///
14 /// In premultiplied colors transitions to transparent always look "nice"
15 /// therefore they are used in CSS gradients.
16 #[repr(C)]
17 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
18 pub struct PremultipliedColorF {
19     pub r: f32,
20     pub g: f32,
21     pub b: f32,
22     pub a: f32,
23 }
24 
25 #[allow(missing_docs)]
26 impl PremultipliedColorF {
27     pub const BLACK: PremultipliedColorF = PremultipliedColorF { r: 0.0, g: 0.0, b: 0.0, a: 1.0 };
28     pub const TRANSPARENT: PremultipliedColorF = PremultipliedColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 };
29     pub const WHITE: PremultipliedColorF = PremultipliedColorF { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
30 
to_array(&self) -> [f32; 4]31     pub fn to_array(&self) -> [f32; 4] {
32         [self.r, self.g, self.b, self.a]
33     }
34 }
35 
36 /// Represents RGBA screen colors with floating point numbers.
37 ///
38 /// All components must be between 0.0 and 1.0.
39 /// An alpha value of 1.0 is opaque while 0.0 is fully transparent.
40 #[repr(C)]
41 #[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
42 pub struct ColorF {
43     pub r: f32,
44     pub g: f32,
45     pub b: f32,
46     pub a: f32,
47 }
48 
49 #[allow(missing_docs)]
50 impl ColorF {
51     pub const BLACK: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 1.0 };
52     pub const TRANSPARENT: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 };
53     pub const WHITE: ColorF = ColorF { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
54 
55     /// Constructs a new `ColorF` from its components.
new(r: f32, g: f32, b: f32, a: f32) -> Self56     pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
57         ColorF { r, g, b, a }
58     }
59 
60     /// Multiply the RGB channels (but not alpha) with a given factor.
scale_rgb(&self, scale: f32) -> Self61     pub fn scale_rgb(&self, scale: f32) -> Self {
62         ColorF {
63             r: self.r * scale,
64             g: self.g * scale,
65             b: self.b * scale,
66             a: self.a,
67         }
68     }
69 
70     // Scale the alpha by a given factor.
scale_alpha(&self, scale: f32) -> Self71     pub fn scale_alpha(&self, scale: f32) -> Self {
72         ColorF {
73             r: self.r,
74             g: self.g,
75             b: self.b,
76             a: self.a * scale,
77         }
78     }
79 
to_array(&self) -> [f32; 4]80     pub fn to_array(&self) -> [f32; 4] {
81         [self.r, self.g, self.b, self.a]
82     }
83 
84     /// Multiply the RGB components with the alpha channel.
premultiplied(&self) -> PremultipliedColorF85     pub fn premultiplied(&self) -> PremultipliedColorF {
86         let c = self.scale_rgb(self.a);
87         PremultipliedColorF { r: c.r, g: c.g, b: c.b, a: c.a }
88     }
89 }
90 
91 // Floats don't impl Hash/Eq/Ord...
92 impl Eq for PremultipliedColorF {}
93 impl Ord for PremultipliedColorF {
cmp(&self, other: &Self) -> cmp::Ordering94     fn cmp(&self, other: &Self) -> cmp::Ordering {
95         self.partial_cmp(other).unwrap_or(cmp::Ordering::Equal)
96     }
97 }
98 
99 #[cfg_attr(feature = "cargo-clippy", allow(clippy::derive_hash_xor_eq))]
100 impl Hash for PremultipliedColorF {
hash<H: Hasher>(&self, state: &mut H)101     fn hash<H: Hasher>(&self, state: &mut H) {
102         // Note: this is inconsistent with the Eq impl for -0.0 (don't care).
103         self.r.to_bits().hash(state);
104         self.g.to_bits().hash(state);
105         self.b.to_bits().hash(state);
106         self.a.to_bits().hash(state);
107     }
108 }
109 
110 /// Represents RGBA screen colors with one byte per channel.
111 ///
112 /// If the alpha value `a` is 255 the color is opaque.
113 #[repr(C)]
114 #[derive(Clone, Copy, Hash, Eq, Debug, Deserialize, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
115 pub struct ColorU {
116     pub r: u8,
117     pub g: u8,
118     pub b: u8,
119     pub a: u8,
120 }
121 
122 impl ColorU {
123     /// Constructs a new additive `ColorU` from its components.
new(r: u8, g: u8, b: u8, a: u8) -> Self124     pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
125         ColorU { r, g, b, a }
126     }
127 }
128 
round_to_int(x: f32) -> u8129 fn round_to_int(x: f32) -> u8 {
130     debug_assert!((0.0 <= x) && (x <= 1.0), "{} should be between 0 and 1", x);
131     let f = (255.0 * x) + 0.5;
132     let val = f.floor();
133     debug_assert!(val <= 255.0);
134     val as u8
135 }
136 
137 // TODO: We shouldn't really convert back to `ColorU` ever,
138 // since it's lossy. One of the blockers is that all of our debug colors
139 // are specified in `ColorF`. Changing it to `ColorU` would be nice.
140 impl From<ColorF> for ColorU {
from(color: ColorF) -> Self141     fn from(color: ColorF) -> Self {
142         ColorU {
143             r: round_to_int(color.r),
144             g: round_to_int(color.g),
145             b: round_to_int(color.b),
146             a: round_to_int(color.a),
147         }
148     }
149 }
150 
151 impl From<ColorU> for ColorF {
from(color: ColorU) -> Self152     fn from(color: ColorU) -> Self {
153         ColorF {
154             r: color.r as f32 / 255.0,
155             g: color.g as f32 / 255.0,
156             b: color.b as f32 / 255.0,
157             a: color.a as f32 / 255.0,
158         }
159     }
160 }
161