1use std::{
2 borrow::Cow,
3 fmt,
4 ops::{Deref, DerefMut},
5};
6
7use crate::json::ToJson;
8use pathfinder_color::{ColorF, ColorU};
9use serde::{
10 de::{self, Unexpected},
11 Deserialize, Deserializer,
12};
13use serde_json::json;
14
15#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
16#[repr(transparent)]
17pub struct Color(ColorU);
18
19impl Color {
20 pub fn transparent_black() -> Self {
21 Self(ColorU::transparent_black())
22 }
23
24 pub fn black() -> Self {
25 Self(ColorU::black())
26 }
27
28 pub fn white() -> Self {
29 Self(ColorU::white())
30 }
31
32 pub fn red() -> Self {
33 Self(ColorU::from_u32(0xff0000ff))
34 }
35
36 pub fn green() -> Self {
37 Self(ColorU::from_u32(0x00ff00ff))
38 }
39
40 pub fn blue() -> Self {
41 Self(ColorU::from_u32(0x0000ffff))
42 }
43
44 pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
45 Self(ColorU::new(r, g, b, a))
46 }
47
48 pub fn from_u32(rgba: u32) -> Self {
49 Self(ColorU::from_u32(rgba))
50 }
51
52 pub fn blend(source: Color, dest: Color) -> Color {
53 // Skip blending if we don't need it.
54 if source.a == 255 {
55 return source;
56 } else if source.a == 0 {
57 return dest;
58 }
59
60 let source = source.0.to_f32();
61 let dest = dest.0.to_f32();
62
63 let a = source.a() + (dest.a() * (1. - source.a()));
64 let r = ((source.r() * source.a()) + (dest.r() * dest.a() * (1. - source.a()))) / a;
65 let g = ((source.g() * source.a()) + (dest.g() * dest.a() * (1. - source.a()))) / a;
66 let b = ((source.b() * source.a()) + (dest.b() * dest.a() * (1. - source.a()))) / a;
67
68 Self(ColorF::new(r, g, b, a).to_u8())
69 }
70
71 pub fn fade_out(&mut self, fade: f32) {
72 let fade = fade.clamp(0., 1.);
73 self.0.a = (self.0.a as f32 * (1. - fade)) as u8;
74 }
75}
76
77impl<'de> Deserialize<'de> for Color {
78 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
79 where
80 D: Deserializer<'de>,
81 {
82 let literal: Cow<str> = Deserialize::deserialize(deserializer)?;
83 if let Some(digits) = literal.strip_prefix('#') {
84 if let Ok(value) = u32::from_str_radix(digits, 16) {
85 if digits.len() == 6 {
86 return Ok(Color::from_u32((value << 8) | 0xFF));
87 } else if digits.len() == 8 {
88 return Ok(Color::from_u32(value));
89 }
90 }
91 }
92 Err(de::Error::invalid_value(
93 Unexpected::Str(literal.as_ref()),
94 &"#RRGGBB[AA]",
95 ))
96 }
97}
98
99impl ToJson for Color {
100 fn to_json(&self) -> serde_json::Value {
101 json!(format!(
102 "0x{:x}{:x}{:x}{:x}",
103 self.0.r, self.0.g, self.0.b, self.0.a
104 ))
105 }
106}
107
108impl Deref for Color {
109 type Target = ColorU;
110 fn deref(&self) -> &Self::Target {
111 &self.0
112 }
113}
114
115impl DerefMut for Color {
116 fn deref_mut(&mut self) -> &mut Self::Target {
117 &mut self.0
118 }
119}
120
121impl fmt::Debug for Color {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 self.0.fmt(f)
124 }
125}