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