diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /gfx/wr/webrender_api/src/color.rs | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/wr/webrender_api/src/color.rs')
-rw-r--r-- | gfx/wr/webrender_api/src/color.rs | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/gfx/wr/webrender_api/src/color.rs b/gfx/wr/webrender_api/src/color.rs new file mode 100644 index 0000000000..4b0a43a10d --- /dev/null +++ b/gfx/wr/webrender_api/src/color.rs @@ -0,0 +1,161 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use peek_poke::PeekPoke; +use std::cmp; +use std::hash::{Hash, Hasher}; + +/// Represents pre-multiplied RGBA colors with floating point numbers. +/// +/// All components must be between 0.0 and 1.0. +/// An alpha value of 1.0 is opaque while 0.0 is fully transparent. +/// +/// In premultiplied colors transitions to transparent always look "nice" +/// therefore they are used in CSS gradients. +#[repr(C)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)] +pub struct PremultipliedColorF { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +#[allow(missing_docs)] +impl PremultipliedColorF { + pub const BLACK: PremultipliedColorF = PremultipliedColorF { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }; + pub const TRANSPARENT: PremultipliedColorF = PremultipliedColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }; + pub const WHITE: PremultipliedColorF = PremultipliedColorF { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }; + + pub fn to_array(&self) -> [f32; 4] { + [self.r, self.g, self.b, self.a] + } +} + +/// Represents RGBA screen colors with floating point numbers. +/// +/// All components must be between 0.0 and 1.0. +/// An alpha value of 1.0 is opaque while 0.0 is fully transparent. +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] +pub struct ColorF { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +#[allow(missing_docs)] +impl ColorF { + pub const BLACK: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }; + pub const TRANSPARENT: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }; + pub const WHITE: ColorF = ColorF { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }; + + /// Constructs a new `ColorF` from its components. + pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self { + ColorF { r, g, b, a } + } + + /// Multiply the RGB channels (but not alpha) with a given factor. + pub fn scale_rgb(&self, scale: f32) -> Self { + ColorF { + r: self.r * scale, + g: self.g * scale, + b: self.b * scale, + a: self.a, + } + } + + // Scale the alpha by a given factor. + pub fn scale_alpha(&self, scale: f32) -> Self { + ColorF { + r: self.r, + g: self.g, + b: self.b, + a: self.a * scale, + } + } + + pub fn to_array(&self) -> [f32; 4] { + [self.r, self.g, self.b, self.a] + } + + /// Multiply the RGB components with the alpha channel. + pub fn premultiplied(&self) -> PremultipliedColorF { + let c = self.scale_rgb(self.a); + PremultipliedColorF { r: c.r, g: c.g, b: c.b, a: c.a } + } +} + +// Floats don't impl Hash/Eq/Ord... +impl Eq for PremultipliedColorF {} +impl Ord for PremultipliedColorF { + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.partial_cmp(other).unwrap_or(cmp::Ordering::Equal) + } +} + +#[cfg_attr(feature = "cargo-clippy", allow(clippy::derive_hash_xor_eq))] +impl Hash for PremultipliedColorF { + fn hash<H: Hasher>(&self, state: &mut H) { + // Note: this is inconsistent with the Eq impl for -0.0 (don't care). + self.r.to_bits().hash(state); + self.g.to_bits().hash(state); + self.b.to_bits().hash(state); + self.a.to_bits().hash(state); + } +} + +/// Represents RGBA screen colors with one byte per channel. +/// +/// If the alpha value `a` is 255 the color is opaque. +#[repr(C)] +#[derive(Clone, Copy, Hash, Eq, Debug, Deserialize, MallocSizeOf, PartialEq)] +#[derive(PartialOrd, Ord, Serialize, PeekPoke, Default)] +pub struct ColorU { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, +} + +impl ColorU { + /// Constructs a new additive `ColorU` from its components. + pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self { + ColorU { r, g, b, a } + } +} + +fn round_to_int(x: f32) -> u8 { + debug_assert!((0.0 <= x) && (x <= 1.0), "{} should be between 0 and 1", x); + let f = (255.0 * x) + 0.5; + let val = f.floor(); + debug_assert!(val <= 255.0); + val as u8 +} + +// TODO: We shouldn't really convert back to `ColorU` ever, +// since it's lossy. One of the blockers is that all of our debug colors +// are specified in `ColorF`. Changing it to `ColorU` would be nice. +impl From<ColorF> for ColorU { + fn from(color: ColorF) -> Self { + ColorU { + r: round_to_int(color.r), + g: round_to_int(color.g), + b: round_to_int(color.b), + a: round_to_int(color.a), + } + } +} + +impl From<ColorU> for ColorF { + fn from(color: ColorU) -> Self { + ColorF { + r: color.r as f32 / 255.0, + g: color.g as f32 / 255.0, + b: color.b as f32 / 255.0, + a: color.a as f32 / 255.0, + } + } +} |