1 #ifndef face_hh_INCLUDED
2 #define face_hh_INCLUDED
3
4 #include "color.hh"
5 #include "flags.hh"
6
7 namespace Kakoune
8 {
9
10 enum class Attribute : int
11 {
12 Normal = 0,
13 Underline = 1 << 1,
14 CurlyUnderline = 1 << 2,
15 Reverse = 1 << 3,
16 Blink = 1 << 4,
17 Bold = 1 << 5,
18 Dim = 1 << 6,
19 Italic = 1 << 7,
20 Strikethrough = 1 << 8,
21 FinalFg = 1 << 9,
22 FinalBg = 1 << 10,
23 FinalAttr = 1 << 11,
24 Final = FinalFg | FinalBg | FinalAttr
25 };
26
with_bit_ops(Meta::Type<Attribute>)27 constexpr bool with_bit_ops(Meta::Type<Attribute>) { return true; }
28
29 struct Face
30 {
31 Color fg = Color::Default;
32 Color bg = Color::Default;
33 Attribute attributes = Attribute::Normal;
34 Color underline = Color::Default;
35
operator ==(const Face & lhs,const Face & rhs)36 friend constexpr bool operator==(const Face& lhs, const Face& rhs)
37 {
38 return lhs.fg == rhs.fg and
39 lhs.bg == rhs.bg and
40 lhs.underline == rhs.underline and
41 lhs.attributes == rhs.attributes;
42 }
43
operator !=(const Face & lhs,const Face & rhs)44 friend constexpr bool operator!=(const Face& lhs, const Face& rhs)
45 {
46 return not (lhs == rhs);
47 }
48
hash_value(const Face & val)49 friend constexpr size_t hash_value(const Face& val)
50 {
51 return hash_values(val.fg, val.bg, val.underline, val.attributes);
52 }
53 };
54
merge_faces(const Face & base,const Face & face)55 inline Face merge_faces(const Face& base, const Face& face)
56 {
57 auto alpha_blend = [](Color base, Color color) {
58 auto blend = [&](unsigned char Color::*field) {
59 int blended = (base.*field * (255 - color.a) + color.*field * color.a) / 255;
60 return static_cast<unsigned char>(blended <= 255 ? blended : 255);
61 };
62 int alpha = color.a + base.a * (255 - color.a) / 255;
63 return Color{blend(&Color::r), blend(&Color::g), blend(&Color::b),
64 static_cast<unsigned char>(alpha <= 255 ? alpha : 255)};
65 };
66
67 auto choose = [&](Color Face::*color, Attribute final_attr) {
68 if (face.attributes & final_attr)
69 return face.*color;
70 if (base.attributes & final_attr)
71 return base.*color;
72 if (face.*color == Color::Default)
73 return base.*color;
74 if ((base.*color).isRGB() and (face.*color).isRGB() and (face.*color).a != 255)
75 return alpha_blend(base.*color, face.*color);
76 return face.*color;
77 };
78
79 return Face{ choose(&Face::fg, Attribute::FinalFg),
80 choose(&Face::bg, Attribute::FinalBg),
81 face.attributes & Attribute::FinalAttr ? face.attributes :
82 base.attributes & Attribute::FinalAttr ? base.attributes :
83 face.attributes | base.attributes,
84 choose(&Face::underline, Attribute{0}) };
85 }
86
87 }
88
89 #endif // face_hh_INCLUDED
90