tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

color.rs (4885B)


      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 
     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.
     56    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.
     61    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.
     71    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 
     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.
     85    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 {
     94    fn cmp(&self, other: &Self) -> cmp::Ordering {
     95        self.partial_cmp(other).unwrap_or(cmp::Ordering::Equal)
     96    }
     97 }
     98 
     99 #[allow(clippy::derived_hash_with_manual_eq)]
    100 impl Hash for PremultipliedColorF {
    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)]
    115 #[derive(PartialOrd, Ord, Serialize, PeekPoke, Default)]
    116 pub struct ColorU {
    117    pub r: u8,
    118    pub g: u8,
    119    pub b: u8,
    120    pub a: u8,
    121 }
    122 
    123 impl ColorU {
    124    /// Constructs a new additive `ColorU` from its components.
    125    pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
    126        ColorU { r, g, b, a }
    127    }
    128 }
    129 
    130 fn round_to_int(x: f32) -> u8 {
    131    debug_assert!((0.0 <= x) && (x <= 1.0), "{} should be between 0 and 1", x);
    132    let f = (255.0 * x) + 0.5;
    133    let val = f.floor();
    134    debug_assert!(val <= 255.0);
    135    val as u8
    136 }
    137 
    138 // TODO: We shouldn't really convert back to `ColorU` ever,
    139 // since it's lossy. One of the blockers is that all of our debug colors
    140 // are specified in `ColorF`. Changing it to `ColorU` would be nice.
    141 impl From<ColorF> for ColorU {
    142    fn from(color: ColorF) -> Self {
    143        ColorU {
    144            r: round_to_int(color.r),
    145            g: round_to_int(color.g),
    146            b: round_to_int(color.b),
    147            a: round_to_int(color.a),
    148        }
    149    }
    150 }
    151 
    152 impl From<ColorU> for ColorF {
    153    fn from(color: ColorU) -> Self {
    154        ColorF {
    155            r: color.r as f32 / 255.0,
    156            g: color.g as f32 / 255.0,
    157            b: color.b as f32 / 255.0,
    158            a: color.a as f32 / 255.0,
    159        }
    160    }
    161 }