1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components/common/properties/color.h"
17
18 #include <cstdlib>
19 #include <regex>
20
21 #include "base/utils/utils.h"
22 #include "core/common/container.h"
23 #include "core/common/resource/resource_manager.h"
24
25 namespace OHOS::Ace {
26 namespace {
27
28 constexpr uint32_t COLOR_ALPHA_OFFSET = 24;
29 constexpr uint32_t COLOR_STRING_SIZE_STANDARD = 8;
30 constexpr uint32_t COLOR_STRING_BASE = 16;
31 constexpr uint32_t RGB_SUB_MATCH_SIZE = 4;
32 constexpr uint32_t RGBA_SUB_MATCH_SIZE = 5;
33
34 const std::regex COLOR_WITH_MAGIC("#[0-9A-Fa-f]{6,8}");
35 const std::regex COLOR_WITH_MAGIC_MINI("#[0-9A-Fa-f]{3,4}");
36 const std::regex COLOR_WITH_RGB(R"(rgb\(([0-9]{1,3})\,([0-9]{1,3})\,([0-9]{1,3})\))", std::regex::icase);
37 const std::regex COLOR_WITH_RGBA(R"(rgba\(([0-9]{1,3})\,([0-9]{1,3})\,([0-9]{1,3})\,(\d+\.?\d*)\))", std::regex::icase);
38 constexpr double GAMMA_FACTOR = 2.2;
39 constexpr float MAX_ALPHA = 255.0f;
40 constexpr char HEX[] = "0123456789ABCDEF";
41 constexpr uint8_t BIT_LENGTH_INT32 = 8;
42 constexpr uint8_t MIN_RGB_VALUE = 0;
43 constexpr uint8_t MAX_RGB_VALUE = 255;
44 constexpr double MIN_RGBA_OPACITY = 0.0;
45 constexpr double MAX_RGBA_OPACITY = 1.0;
46 const std::vector<size_t> EXPECT_MAGIC_COLOR_LENGTHS = {7, 9};
47 const std::vector<size_t> EXPECT_MAGIC_MINI_COLOR_LENGTHS = {4, 5};
48 } // namespace
49
50 const Color Color::TRANSPARENT = Color(0x00000000);
51 const Color Color::WHITE = Color(0xffffffff);
52 const Color Color::BLACK = Color(0xff000000);
53 const Color Color::RED = Color(0xffff0000);
54 const Color Color::GREEN = Color(0xff00ff00);
55 const Color Color::BLUE = Color(0xff0000ff);
56 const Color Color::GRAY = Color(0xffc0c0c0);
57 const Color Color::FOREGROUND = Color(0x00000001); // foreground color and foreground color strategy identification
58
59 const LinearColor LinearColor::TRANSPARENT = LinearColor(0x00000000);
60 const LinearColor LinearColor::WHITE = LinearColor(0xffffffff);
61 const LinearColor LinearColor::BLACK = LinearColor(0xff000000);
62 const LinearColor LinearColor::RED = LinearColor(0xffff0000);
63 const LinearColor LinearColor::GREEN = LinearColor(0xff00ff00);
64 const LinearColor LinearColor::BLUE = LinearColor(0xff0000ff);
65 const LinearColor LinearColor::GRAY = LinearColor(0xffc0c0c0);
66
HandleIncorrectColor(const std::string & newColorStr)67 unsigned long int HandleIncorrectColor(const std::string& newColorStr)
68 {
69 errno = 0;
70 char* end = nullptr;
71 unsigned long int value = strtoul(newColorStr.c_str(), &end, COLOR_STRING_BASE);
72 if (errno == ERANGE) {
73 LOGE("%{public}s is out of range.", newColorStr.c_str());
74 }
75 if (value == 0 && end == newColorStr.c_str()) {
76 LOGW("input %{public}s can not be converted to number, use default color:0x00000000.", newColorStr.c_str());
77 }
78 return value;
79 }
80
FromString(std::string colorStr,uint32_t maskAlpha,Color defaultColor)81 Color Color::FromString(std::string colorStr, uint32_t maskAlpha, Color defaultColor)
82 {
83 if (colorStr.empty()) {
84 // empty string, return transparent
85 return Color::TRANSPARENT;
86 }
87
88 // Remove all " ".
89 colorStr.erase(std::remove(colorStr.begin(), colorStr.end(), ' '), colorStr.end());
90
91 std::smatch matches;
92 // Regex match for #909090 or #90909090.
93 if (std::regex_match(colorStr, matches, COLOR_WITH_MAGIC)) {
94 colorStr.erase(0, 1);
95 unsigned long int value = HandleIncorrectColor(colorStr);
96 if (colorStr.length() < COLOR_STRING_SIZE_STANDARD) {
97 // no alpha specified, set alpha to 0xff
98 value |= maskAlpha;
99 }
100 return Color(value);
101 }
102 // Regex match for #rgb or #rgba.
103 if (std::regex_match(colorStr, matches, COLOR_WITH_MAGIC_MINI)) {
104 colorStr.erase(0, 1);
105 std::string newColorStr;
106 // translate #rgb or #rgba to #rrggbb or #rrggbbaa
107 for (auto& c : colorStr) {
108 newColorStr += c;
109 newColorStr += c;
110 }
111 unsigned long int value = HandleIncorrectColor(newColorStr);
112 if (newColorStr.length() < COLOR_STRING_SIZE_STANDARD) {
113 // no alpha specified, set alpha to 0xff
114 value |= maskAlpha;
115 }
116 return Color(value);
117 }
118 // Regex match for rgb(90,254,180).
119 if (std::regex_match(colorStr, matches, COLOR_WITH_RGB)) {
120 if (matches.size() == RGB_SUB_MATCH_SIZE) {
121 auto red = static_cast<uint8_t>(StringUtils::StringToInt(matches[1])); // red value.
122 auto green = static_cast<uint8_t>(StringUtils::StringToInt(matches[2])); // green value.
123 auto blue = static_cast<uint8_t>(StringUtils::StringToInt(matches[3])); // blue value.
124 return FromRGB(red, green, blue);
125 }
126 }
127 // Regex match for rgba(90,254,180,0.5).
128 if (std::regex_match(colorStr, matches, COLOR_WITH_RGBA)) {
129 if (matches.size() == RGBA_SUB_MATCH_SIZE) {
130 auto red = static_cast<uint8_t>(StringUtils::StringToInt(matches[1]));
131 auto green = static_cast<uint8_t>(StringUtils::StringToInt(matches[2]));
132 auto blue = static_cast<uint8_t>(StringUtils::StringToInt(matches[3]));
133 auto opacity = StringUtils::StringToDouble(matches[4]);
134 return FromRGBO(red, green, blue, opacity);
135 }
136 }
137 // match for special string
138 static const LinearMapNode<Color> colorTable[] = {
139 { "black", Color(0xff000000) },
140 { "blue", Color(0xff0000ff) },
141 { "gray", Color(0xffc0c0c0) },
142 { "green", Color(0xff00ff00) },
143 { "red", Color(0xffff0000) },
144 { "white", Color(0xffffffff) },
145 };
146 int64_t colorIndex = BinarySearchFindIndex(colorTable, ArraySize(colorTable), colorStr.c_str());
147 if (colorIndex != -1) {
148 return colorTable[colorIndex].value;
149 }
150
151 // parse uint32_t color string.
152 auto uint32Color = StringUtils::StringToUint(colorStr);
153 if (uint32Color > 0) {
154 Color value;
155 if ((uint32Color >> COLOR_ALPHA_OFFSET) == 0) {
156 value = Color(uint32Color).ChangeAlpha(MAX_ALPHA);
157 } else {
158 value = Color(uint32Color);
159 }
160 return value;
161 }
162
163 // Default color.
164 return defaultColor;
165 }
166
ParseColorString(const std::string & colorStr,Color & color,const Color & defaultColor,uint32_t maskAlpha)167 bool Color::ParseColorString(const std::string& colorStr, Color& color, const Color& defaultColor, uint32_t maskAlpha)
168 {
169 if (colorStr.empty()) {
170 return false;
171 }
172
173 // Remove all " ".
174 std::string tmpColorStr = colorStr;
175 tmpColorStr.erase(std::remove(tmpColorStr.begin(), tmpColorStr.end(), ' '), tmpColorStr.end());
176
177 return (MatchColorWithMagic(tmpColorStr, maskAlpha, color) ||
178 MatchColorWithMagicMini(tmpColorStr, maskAlpha, color) ||
179 MatchColorWithRGB(tmpColorStr, color) ||
180 MatchColorWithRGBA(tmpColorStr, color) ||
181 MatchColorSpecialString(tmpColorStr, color) ||
182 ParseUintColorString(tmpColorStr, color, defaultColor));
183 }
184
ParseColorString(std::string colorStr,Color & color,uint32_t maskAlpha)185 bool Color::ParseColorString(std::string colorStr, Color& color, uint32_t maskAlpha)
186 {
187 if (colorStr.empty()) {
188 return false;
189 }
190
191 // Remove all " ".
192 colorStr.erase(std::remove(colorStr.begin(), colorStr.end(), ' '), colorStr.end());
193
194 return (MatchColorWithMagic(colorStr, maskAlpha, color) || MatchColorWithMagicMini(colorStr, maskAlpha, color) ||
195 MatchColorWithRGB(colorStr, color) || MatchColorWithRGBA(colorStr, color) ||
196 MatchColorSpecialString(colorStr, color) || ParseUintColorString(colorStr, color));
197 }
198
ColorToString() const199 std::string Color::ColorToString() const
200 {
201 std::string colorStr;
202 int count = 0;
203 uint32_t value = GetValue();
204 while (count++ < BIT_LENGTH_INT32) {
205 colorStr = HEX[(value & 0xf)] + colorStr;
206 value >>= 4;
207 }
208 colorStr = "#" + colorStr;
209 return colorStr;
210 }
211
212 // for example str = #FFFFFFFF
ColorFromString(const std::string & str)213 Color Color::ColorFromString(const std::string& str)
214 {
215 static const int32_t colorStrLen = 9;
216 static const int32_t offset = 4;
217
218 if (str.length() != colorStrLen || str.find('#') != 0) {
219 LOGE("UITree |ERROR| invalid %{public}s", str.c_str());
220 return Color::BLACK;
221 }
222
223 std::string colorStr = str.substr(1, colorStrLen - 1);
224 uint32_t value = 0;
225 for (const auto& it : colorStr) {
226 value <<= offset;
227 value += it < 'A' ? it - '0' : it - '7';
228 }
229
230 return Color(value);
231 }
232
ToString() const233 std::string Color::ToString() const
234 {
235 return ColorToString();
236 }
237
FromARGB(uint8_t alpha,uint8_t red,uint8_t green,uint8_t blue)238 Color Color::FromARGB(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue)
239 {
240 ColorParam colorValue {
241 #if BIG_ENDIANNESS
242 .argb = { .alpha = alpha, .red = red, .green = green, .blue = blue }
243 #else
244 .argb = { .blue = blue, .green = green, .red = red, .alpha = alpha }
245 #endif
246 };
247 return Color(colorValue);
248 }
249
FromRGBO(uint8_t red,uint8_t green,uint8_t blue,double opacity)250 Color Color::FromRGBO(uint8_t red, uint8_t green, uint8_t blue, double opacity)
251 {
252 return FromARGB(static_cast<uint8_t>(round(opacity * 0xff)) & 0xff, red, green, blue);
253 }
254
FromRGB(uint8_t red,uint8_t green,uint8_t blue)255 Color Color::FromRGB(uint8_t red, uint8_t green, uint8_t blue)
256 {
257 return FromARGB(0xff, red, green, blue);
258 }
259
BlendColor(const Color & overlayColor) const260 Color Color::BlendColor(const Color& overlayColor) const
261 {
262 if (GetValue() == Color::TRANSPARENT.GetValue()) {
263 return overlayColor;
264 }
265 if (GetAlpha() < static_cast<uint8_t>(MAX_ALPHA)) {
266 return BlendColorWithAlpha(overlayColor);
267 }
268 auto alphaRate = static_cast<float>(overlayColor.GetAlpha()) / MAX_ALPHA;
269 auto newRed = static_cast<uint8_t>(GetRed() * (1.0f - alphaRate) + overlayColor.GetRed() * alphaRate);
270 auto newGreen = static_cast<uint8_t>(GetGreen() * (1.0f - alphaRate) + overlayColor.GetGreen() * alphaRate);
271 auto newBlue = static_cast<uint8_t>(GetBlue() * (1.0f - alphaRate) + overlayColor.GetBlue() * alphaRate);
272 return Color::FromRGB(newRed, newGreen, newBlue);
273 }
274
CalculateBlend(float alphaLeft,float alphaRight,float valueLeft,float valueRight) const275 float Color::CalculateBlend(float alphaLeft, float alphaRight, float valueLeft, float valueRight) const
276 {
277 return (valueLeft * alphaLeft * (1.0 - alphaRight) + valueRight * alphaRight) /
278 (alphaLeft + alphaRight - alphaLeft * alphaRight);
279 }
280
BlendColorWithAlpha(const Color & overlayColor) const281 Color Color::BlendColorWithAlpha(const Color& overlayColor) const
282 {
283 float alphaA = GetAlpha() / 255.0;
284 float alphaB = overlayColor.GetAlpha() / 255.0;
285 float blendAlpha = alphaA + alphaB - alphaA * alphaB;
286 float blendRed = CalculateBlend(alphaA, alphaB, GetRed() / 255.0, overlayColor.GetRed() / 255.0);
287 float blendGreen = CalculateBlend(alphaA, alphaB, GetGreen() / 255.0, overlayColor.GetGreen() / 255.0);
288 float blendBlue = CalculateBlend(alphaA, alphaB, GetBlue() / 255.0, overlayColor.GetBlue() / 255.0);
289
290 return Color::FromARGB(blendAlpha * 255, blendRed * 255, blendGreen * 255, blendBlue * 255);
291 }
292
LineColorTransition(const Color & startColor,const Color & endColor,double percent)293 const Color Color::LineColorTransition(const Color& startColor, const Color& endColor, double percent)
294 {
295 uint8_t red = 0;
296 uint8_t green = 0;
297 uint8_t blue = 0;
298 uint8_t alpha = 0;
299
300 red = static_cast<uint8_t>((endColor.GetRed()- startColor.GetRed()) * percent) + startColor.GetRed();
301 green = static_cast<uint8_t>((endColor.GetGreen() - startColor.GetGreen()) * percent) + startColor.GetGreen();
302 blue = static_cast<uint8_t>((endColor.GetBlue() - startColor.GetBlue()) * percent) + startColor.GetBlue();
303 alpha = static_cast<uint8_t>((endColor.GetAlpha() - startColor.GetAlpha()) * percent) + startColor.GetAlpha();
304
305 return Color::FromARGB(alpha, red, green, blue);
306 }
307
BlendOpacity(double opacityRatio) const308 Color Color::BlendOpacity(double opacityRatio) const
309 {
310 int32_t alpha = static_cast<int32_t>(GetAlpha() * opacityRatio);
311 alpha = std::clamp(alpha, 0, UINT8_MAX);
312 return Color::FromARGB(alpha, GetRed(), GetGreen(), GetBlue());
313 }
314
ChangeOpacity(double opacity) const315 Color Color::ChangeOpacity(double opacity) const
316 {
317 return Color::FromRGBO(GetRed(), GetGreen(), GetBlue(), opacity);
318 }
319
ChangeAlpha(uint8_t alpha) const320 Color Color::ChangeAlpha(uint8_t alpha) const
321 {
322 return Color::FromARGB(alpha, GetRed(), GetGreen(), GetBlue());
323 }
324
operator +(const Color & color) const325 Color Color::operator+(const Color& color) const
326 {
327 // convert first color from ARGB to linear
328 double firstLinearRed = 0.0;
329 double firstLinearGreen = 0.0;
330 double firstLinearBlue = 0.0;
331 ConvertGammaToLinear(*this, firstLinearRed, firstLinearGreen, firstLinearBlue);
332
333 // convert second color from ARGB to linear
334 double secondLinearRed = 0.0;
335 double secondLinearGreen = 0.0;
336 double secondLinearBlue = 0.0;
337 ConvertGammaToLinear(color, secondLinearRed, secondLinearGreen, secondLinearBlue);
338
339 // get linear result and convert to gamma
340 return ConvertLinearToGamma(GetAlpha() + color.GetAlpha(), firstLinearRed + secondLinearRed,
341 firstLinearGreen + secondLinearGreen, firstLinearBlue + secondLinearBlue);
342 }
343
operator -(const Color & color) const344 Color Color::operator-(const Color& color) const
345 {
346 // convert first color from ARGB to linear
347 double firstLinearRed = 0.0;
348 double firstLinearGreen = 0.0;
349 double firstLinearBlue = 0.0;
350 ConvertGammaToLinear(*this, firstLinearRed, firstLinearGreen, firstLinearBlue);
351
352 // convert second color from ARGB to linear
353 double secondLinearRed = 0.0;
354 double secondLinearGreen = 0.0;
355 double secondLinearBlue = 0.0;
356 ConvertGammaToLinear(color, secondLinearRed, secondLinearGreen, secondLinearBlue);
357
358 // get linear result and convert to gamma
359 return ConvertLinearToGamma(GetAlpha() - color.GetAlpha(), firstLinearRed - secondLinearRed,
360 firstLinearGreen - secondLinearGreen, firstLinearBlue - secondLinearBlue);
361 }
362
operator *(double value) const363 Color Color::operator*(double value) const
364 {
365 // convert color from ARGB to linear
366 double linearRed = 0.0;
367 double linearGreen = 0.0;
368 double linearBlue = 0.0;
369 ConvertGammaToLinear(*this, linearRed, linearGreen, linearBlue);
370
371 // get linear result and convert to gamma
372 return ConvertLinearToGamma(GetAlpha() * value, linearRed * value, linearGreen * value, linearBlue * value);
373 }
374
operator /(double value) const375 Color Color::operator/(double value) const
376 {
377 if (NearZero(value)) {
378 return *this;
379 }
380 // convert color from ARGB to linear
381 double linearRed = 0.0;
382 double linearGreen = 0.0;
383 double LinearBlue = 0.0;
384 ConvertGammaToLinear(*this, linearRed, linearGreen, LinearBlue);
385
386 // get linear result and convert to gamma
387 return ConvertLinearToGamma(GetAlpha() / value, linearRed / value, linearGreen / value, LinearBlue / value);
388 }
389
ConvertGammaToLinear(uint8_t value)390 double Color::ConvertGammaToLinear(uint8_t value)
391 {
392 return std::pow(value, GAMMA_FACTOR);
393 }
394
ConvertLinearToGamma(double value)395 uint8_t Color::ConvertLinearToGamma(double value)
396 {
397 return std::clamp(static_cast<int32_t>(round(std::pow(value, 1.0 / GAMMA_FACTOR))), 0, UINT8_MAX);
398 }
399
ConvertGammaToLinear(const Color & gammaColor,double & linearRed,double & linearGreen,double & linearBlue)400 void Color::ConvertGammaToLinear(const Color& gammaColor, double& linearRed, double& linearGreen, double& linearBlue)
401 {
402 linearRed = ConvertGammaToLinear(gammaColor.GetRed());
403 linearGreen = ConvertGammaToLinear(gammaColor.GetGreen());
404 linearBlue = ConvertGammaToLinear(gammaColor.GetBlue());
405 }
406
ConvertLinearToGamma(double alpha,double linearRed,double linearGreen,double linearBlue)407 Color Color::ConvertLinearToGamma(double alpha, double linearRed, double linearGreen, double linearBlue)
408 {
409 uint8_t gammaRed = ConvertLinearToGamma(linearRed);
410 uint8_t gammaGreen = ConvertLinearToGamma(linearGreen);
411 uint8_t gammaBlue = ConvertLinearToGamma(linearBlue);
412 uint8_t gammaAlpha = std::clamp(static_cast<int32_t>(round(alpha)), 0, UINT8_MAX);
413
414 return FromARGB(gammaAlpha, gammaRed, gammaGreen, gammaBlue);
415 }
416
IsHexNumber(std::string & colorStr)417 bool Color::IsHexNumber(std::string& colorStr)
418 {
419 for (size_t i = 1; i < colorStr.size(); i++) {
420 if (colorStr[i] >= '0' && colorStr[i] <= '9') {
421 continue;
422 }
423 if (colorStr[i] >= 'A' && colorStr[i] <= 'F') {
424 continue;
425 }
426 if (colorStr[i] >= 'a' && colorStr[i] <= 'f') {
427 continue;
428 }
429 return false;
430 }
431 return true;
432 }
433
FastCheckColorType(const std::string & colorStr,const std::string & expectPrefix,const std::vector<size_t> & expectLengths)434 bool Color::FastCheckColorType(const std::string& colorStr, const std::string& expectPrefix,
435 const std::vector<size_t>& expectLengths)
436 {
437 if (colorStr.rfind(expectPrefix, 0) != 0) {
438 return false;
439 }
440 if (expectLengths.size() == 0) {
441 return true;
442 }
443 for (size_t expectLength : expectLengths) {
444 if (expectLength == colorStr.size()) {
445 return true;
446 }
447 }
448 return false;
449 }
450
MatchColorWithMagic(std::string & colorStr,uint32_t maskAlpha,Color & color)451 bool Color::MatchColorWithMagic(std::string& colorStr, uint32_t maskAlpha, Color& color)
452 {
453 // Regex match for #909090 or #90909090
454 if (!FastCheckColorType(colorStr, "#", EXPECT_MAGIC_COLOR_LENGTHS)) {
455 return false;
456 }
457 if (!IsHexNumber(colorStr)) {
458 return false;
459 }
460 colorStr.erase(0, 1);
461 unsigned long int value = HandleIncorrectColor(colorStr);
462 if (colorStr.length() < COLOR_STRING_SIZE_STANDARD) {
463 // no alpha specified, set alpha to 0xff
464 value |= maskAlpha;
465 }
466 color = Color(value);
467 return true;
468 }
469
MatchColorWithMagicMini(std::string & colorStr,uint32_t maskAlpha,Color & color)470 bool Color::MatchColorWithMagicMini(std::string& colorStr, uint32_t maskAlpha, Color& color)
471 {
472 if (!FastCheckColorType(colorStr, "#", EXPECT_MAGIC_MINI_COLOR_LENGTHS)) {
473 return false;
474 }
475 if (!IsHexNumber(colorStr)) {
476 return false;
477 }
478 colorStr.erase(0, 1);
479 std::string newColorStr;
480 // translate #rgb or #rgba to #rrggbb or #rrggbbaa
481 for (auto& c : colorStr) {
482 newColorStr += c;
483 newColorStr += c;
484 }
485 unsigned long int value = HandleIncorrectColor(newColorStr);
486
487 if (newColorStr.length() < COLOR_STRING_SIZE_STANDARD) {
488 // no alpha specified, set alpha to 0xff
489 value |= maskAlpha;
490 }
491 color = Color(value);
492 return true;
493 }
494
MatchColorHexString(const std::string & colorStr)495 bool Color::MatchColorHexString(const std::string& colorStr)
496 {
497 if (colorStr.empty()) {
498 return false;
499 }
500 std::smatch matches;
501 if (std::regex_match(colorStr, matches, COLOR_WITH_MAGIC) ||
502 std::regex_match(colorStr, matches, COLOR_WITH_RGBA) ||
503 std::regex_match(colorStr, matches, COLOR_WITH_RGB) ||
504 std::regex_match(colorStr, matches, COLOR_WITH_MAGIC_MINI)) {
505 return true;
506 }
507 return false;
508 }
509
MatchColorWithRGB(const std::string & colorStr,Color & color)510 bool Color::MatchColorWithRGB(const std::string& colorStr, Color& color)
511 {
512 if (!FastCheckColorType(colorStr, "rgb(", {})) {
513 return false;
514 }
515 std::smatch matches;
516 if (std::regex_match(colorStr, matches, COLOR_WITH_RGB)) {
517 if (matches.size() == RGB_SUB_MATCH_SIZE) {
518 auto redInt = StringUtils::StringToInt(matches[1]);
519 auto greenInt = StringUtils::StringToInt(matches[2]);
520 auto blueInt = StringUtils::StringToInt(matches[3]);
521 if (!IsRGBValid(redInt) || !IsRGBValid(greenInt) || !IsRGBValid(blueInt)) {
522 return false;
523 }
524
525 auto red = static_cast<uint8_t>(redInt);
526 auto green = static_cast<uint8_t>(greenInt);
527 auto blue = static_cast<uint8_t>(blueInt);
528 color = FromRGB(red, green, blue);
529 return true;
530 }
531 }
532 return false;
533 }
534
MatchColorWithRGBA(const std::string & colorStr,Color & color)535 bool Color::MatchColorWithRGBA(const std::string& colorStr, Color& color)
536 {
537 if (!FastCheckColorType(colorStr, "rgba(", {})) {
538 return false;
539 }
540 std::smatch matches;
541 if (std::regex_match(colorStr, matches, COLOR_WITH_RGBA)) {
542 if (matches.size() == RGBA_SUB_MATCH_SIZE) {
543 auto redInt = StringUtils::StringToInt(matches[1]);
544 auto greenInt = StringUtils::StringToInt(matches[2]);
545 auto blueInt = StringUtils::StringToInt(matches[3]);
546 auto opacityDouble = StringUtils::StringToDouble(matches[4]);
547 if (!IsRGBValid(redInt) || !IsRGBValid(greenInt) || !IsRGBValid(blueInt) ||
548 !IsOpacityValid(opacityDouble)) {
549 return false;
550 }
551
552 auto red = static_cast<uint8_t>(redInt);
553 auto green = static_cast<uint8_t>(greenInt);
554 auto blue = static_cast<uint8_t>(blueInt);
555 auto opacity = static_cast<double>(opacityDouble);
556
557 color = FromRGBO(red, green, blue, opacity);
558 return true;
559 }
560 }
561
562 return false;
563 }
564
MatchColorSpecialString(const std::string & colorStr,Color & color)565 bool Color::MatchColorSpecialString(const std::string& colorStr, Color& color)
566 {
567 static const LinearMapNode<Color> colorTable[] = {
568 { "black", Color(0xff000000) },
569 { "blue", Color(0xff0000ff) },
570 { "gray", Color(0xffc0c0c0) },
571 { "green", Color(0xff00ff00) },
572 { "red", Color(0xffff0000) },
573 { "transparent", Color(0x00000000) },
574 { "white", Color(0xffffffff) },
575 };
576
577 int64_t colorIndex = BinarySearchFindIndex(colorTable, ArraySize(colorTable), colorStr.c_str());
578 if (colorIndex != -1) {
579 color = colorTable[colorIndex].value;
580 return true;
581 }
582
583 return false;
584 }
585
ParseUintColorString(const std::string & colorStr,Color & color,const Color & defaultColor)586 bool Color::ParseUintColorString(const std::string& colorStr, Color& color, const Color& defaultColor)
587 {
588 auto uint32Color = StringUtils::StringToUintCheck(colorStr, defaultColor.GetValue());
589 if (uint32Color > 0) {
590 if ((uint32Color >> COLOR_ALPHA_OFFSET) == 0) {
591 color = Color(uint32Color).ChangeAlpha(MAX_ALPHA);
592 } else {
593 color = Color(uint32Color);
594 }
595 return true;
596 }
597
598 return false;
599 }
600
ParseUintColorString(const std::string & colorStr,Color & color)601 bool Color::ParseUintColorString(const std::string& colorStr, Color& color)
602 {
603 auto uint32Color = StringUtils::StringToUint(colorStr);
604 if (uint32Color > 0) {
605 if ((uint32Color >> COLOR_ALPHA_OFFSET) == 0) {
606 color = Color(uint32Color).ChangeAlpha(MAX_ALPHA);
607 } else {
608 color = Color(uint32Color);
609 }
610 return true;
611 }
612
613 return false;
614 }
615
IsRGBValid(int value)616 bool Color::IsRGBValid(int value)
617 {
618 return value >= MIN_RGB_VALUE && value <= MAX_RGB_VALUE;
619 }
620
IsOpacityValid(double value)621 bool Color::IsOpacityValid(double value)
622 {
623 return value >= MIN_RGBA_OPACITY && value <= MAX_RGBA_OPACITY;
624 }
625
UpdateColorByResourceId()626 void Color::UpdateColorByResourceId()
627 {
628 #ifndef ACE_UNITTEST
629 CHECK_NULL_VOID(resourceId_ != 0);
630 auto resourceAdapter = ResourceManager::GetInstance().GetResourceAdapter(Container::CurrentIdSafely());
631 CHECK_NULL_VOID(resourceAdapter);
632 auto newColor = resourceAdapter->GetColor(resourceId_);
633 SetValue(newColor.GetValue());
634 #endif
635 }
636
637 } // namespace OHOS::Ace
638