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