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 yellow() -> Self {
45 Self(ColorU::from_u32(0xffff00ff))
46 }
47
48 pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
49 Self(ColorU::new(r, g, b, a))
50 }
51
52 pub fn from_u32(rgba: u32) -> Self {
53 Self(ColorU::from_u32(rgba))
54 }
55
56 pub fn blend(source: Color, dest: Color) -> Color {
57 // Skip blending if we don't need it.
58 if source.a == 255 {
59 return source;
60 } else if source.a == 0 {
61 return dest;
62 }
63
64 let source = source.0.to_f32();
65 let dest = dest.0.to_f32();
66
67 let a = source.a() + (dest.a() * (1. - source.a()));
68 let r = ((source.r() * source.a()) + (dest.r() * dest.a() * (1. - source.a()))) / a;
69 let g = ((source.g() * source.a()) + (dest.g() * dest.a() * (1. - source.a()))) / a;
70 let b = ((source.b() * source.a()) + (dest.b() * dest.a() * (1. - source.a()))) / a;
71
72 Self(ColorF::new(r, g, b, a).to_u8())
73 }
74
75 pub fn fade_out(&mut self, fade: f32) {
76 let fade = fade.clamp(0., 1.);
77 self.0.a = (self.0.a as f32 * (1. - fade)) as u8;
78 }
79}
80
81impl<'de> Deserialize<'de> for Color {
82 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
83 where
84 D: Deserializer<'de>,
85 {
86 let literal: Cow<str> = Deserialize::deserialize(deserializer)?;
87 if let Some(digits) = literal.strip_prefix('#') {
88 if let Ok(value) = u32::from_str_radix(digits, 16) {
89 if digits.len() == 6 {
90 return Ok(Color::from_u32((value << 8) | 0xFF));
91 } else if digits.len() == 8 {
92 return Ok(Color::from_u32(value));
93 }
94 }
95 }
96 Err(de::Error::invalid_value(
97 Unexpected::Str(literal.as_ref()),
98 &"#RRGGBB[AA]",
99 ))
100 }
101}
102
103impl ToJson for Color {
104 fn to_json(&self) -> serde_json::Value {
105 json!(format!(
106 "0x{:x}{:x}{:x}{:x}",
107 self.0.r, self.0.g, self.0.b, self.0.a
108 ))
109 }
110}
111
112impl Deref for Color {
113 type Target = ColorU;
114 fn deref(&self) -> &Self::Target {
115 &self.0
116 }
117}
118
119impl DerefMut for Color {
120 fn deref_mut(&mut self) -> &mut Self::Target {
121 &mut self.0
122 }
123}
124
125impl fmt::Debug for Color {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 self.0.fmt(f)
128 }
129}