azul_webrender_api/
color.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* 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, PartialOrd, Ord, Serialize)]
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,
        }
    }
}