Fcitx
color.cpp
1 /*
2  * SPDX-FileCopyrightText: 2015-2015 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 
8 #include "color.h"
9 #include <algorithm>
10 #include <climits>
11 #include <cmath>
12 #include <cstdint>
13 #include <cstdio>
14 #include <ostream>
15 #include <string>
16 #include "charutils.h"
17 
18 namespace fcitx {
19 static unsigned short roundColor(unsigned short c) {
20  return c <= 255 ? c : 255;
21 }
22 
23 static float roundColorF(float f) { return std::clamp(f, 0.0F, 1.0F); }
24 
25 static unsigned short extendColor(unsigned short c) {
26  c = roundColor(c);
27  return c << 8 | c;
28 }
29 
30 static inline char to_hex_char(int v) {
31  return (char)(((v) >= 0 && (v) < 10) ? (v + '0') : (v - 10 + 'a'));
32 }
33 
34 static inline unsigned short to_hex_digit(char hi, char lo) {
35  hi = charutils::tolower(hi);
36  lo = charutils::tolower(lo);
37  int dhi = 0;
38  int dlo = 0;
39  if (hi >= '0' && hi <= '9') {
40  dhi = hi - '0';
41  } else {
42  dhi = hi - 'a' + 10;
43  }
44  if (lo >= '0' && lo <= '9') {
45  dlo = lo - '0';
46  } else {
47  dlo = lo - 'a' + 10;
48  }
49 
50  return (dhi * 16) + dlo;
51 }
52 
53 Color::Color(unsigned short r, unsigned short g, unsigned short b,
54  unsigned short alpha)
55  : red_(extendColor(r)), green_(extendColor(g)), blue_(extendColor(b)),
56  alpha_(extendColor(alpha)) {}
57 
58 Color::Color() : red_(0), green_(0), blue_(0), alpha_(USHRT_MAX) {}
59 
60 bool Color::operator==(const Color &other) const {
61  return red_ == other.red_ && green_ == other.green_ &&
62  blue_ == other.blue_ && alpha_ == other.alpha_;
63 }
64 
65 void Color::setFromString(const char *str) {
66  size_t idx = 0;
67 
68  // skip space
69  while (str[idx] && charutils::isspace(str[idx])) {
70  idx++;
71  }
72 
73  if (str[idx] == '#') {
74  // count the digit length
75  size_t len = 0;
76  const char *digits = &str[idx + 1];
77  while (digits[len] &&
78  (charutils::isdigit(digits[len]) ||
79  ('A' <= digits[len] && digits[len] <= 'F') |
80  ('a' <= digits[len] && digits[len] <= 'f'))) {
81  len++;
82  }
83  if (len != 8 && len != 6) {
84  throw ColorParseException();
85  }
86 
87  uint16_t r;
88  uint16_t g;
89  uint16_t b;
90  uint16_t a;
91  r = to_hex_digit(digits[0], digits[1]);
92  digits += 2;
93  g = to_hex_digit(digits[0], digits[1]);
94  digits += 2;
95  b = to_hex_digit(digits[0], digits[1]);
96  if (len == 8) {
97  digits += 2;
98  a = to_hex_digit(digits[0], digits[1]);
99  } else {
100  a = 255;
101  }
102 
103  red_ = extendColor(r);
104  green_ = extendColor(g);
105  blue_ = extendColor(b);
106  alpha_ = extendColor(a);
107  } else {
108  uint16_t r;
109  uint16_t g;
110  uint16_t b;
111  if (sscanf(str, "%hu %hu %hu", &r, &g, &b) != 3) {
112  throw ColorParseException();
113  }
114 
115  red_ = extendColor(r);
116  green_ = extendColor(g);
117  blue_ = extendColor(b);
118  alpha_ = extendColor(255);
119  }
120 }
121 
122 std::string Color::toString() const {
123  std::string result;
124  result.push_back('#');
125  unsigned short v[] = {
126  static_cast<unsigned short>(red_ >> 8U),
127  static_cast<unsigned short>(green_ >> 8U),
128  static_cast<unsigned short>(blue_ >> 8U),
129  static_cast<unsigned short>(alpha_ >> 8U),
130  };
131 
132  for (auto value : v) {
133  auto hi = value / 16;
134  auto lo = value % 16;
135  result.push_back(to_hex_char(hi));
136  result.push_back(to_hex_char(lo));
137  }
138  if (result.ends_with("ff")) {
139  result.erase(result.size() - 2, 2);
140  }
141 
142  return result;
143 }
144 
145 unsigned short Color::red() const { return red_ >> 8; }
146 unsigned short Color::green() const { return green_ >> 8; }
147 unsigned short Color::blue() const { return blue_ >> 8; }
148 unsigned short Color::alpha() const { return alpha_ >> 8; }
149 
150 float Color::redF() const { return red_ / float(USHRT_MAX); }
151 float Color::greenF() const { return green_ / float(USHRT_MAX); }
152 float Color::blueF() const { return blue_ / float(USHRT_MAX); }
153 float Color::alphaF() const { return alpha_ / float(USHRT_MAX); }
154 
155 void Color::setRed(unsigned short red) { red_ = extendColor(red); }
156 void Color::setGreen(unsigned short green) { green_ = extendColor(green); }
157 void Color::setBlue(unsigned short blue) { blue_ = extendColor(blue); }
158 void Color::setAlpha(unsigned short alpha) { alpha_ = extendColor(alpha); }
159 
160 void Color::setRedF(float red) {
161  red_ = std::round(roundColorF(red) * USHRT_MAX);
162 }
163 void Color::setGreenF(float green) {
164  green_ = std::round(roundColorF(green) * USHRT_MAX);
165 }
166 void Color::setBlueF(float blue) {
167  blue_ = std::round(roundColorF(blue) * USHRT_MAX);
168 }
169 void Color::setAlphaF(float alpha) {
170  alpha_ = std::round(roundColorF(alpha) * USHRT_MAX);
171 }
172 
173 std::ostream &operator<<(std::ostream &os, const Color &c) {
174  os << "Color(" << c.toString() << ")";
175  return os;
176 }
177 } // namespace fcitx
std::string toString() const
Get color string in the format of "#rrggbbaa".
Definition: color.cpp:122
Definition: action.cpp:17
Color class for handling color.
Definition: color.h:28
Simple color class that represent a 64bit color.
Local independent API to detect character type.