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
ToSvgFillColorKey() const238 std::string Color::ToSvgFillColorKey() const
239 {
240 std::ostringstream oss;
241 oss << ColorToString() << "_cs" << static_cast<int32_t>(colorSpace_);
242 return oss.str();
243 }
244
FromARGB(uint8_t alpha,uint8_t red,uint8_t green,uint8_t blue)245 Color Color::FromARGB(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue)
246 {
247 ColorParam colorValue {
248 #if BIG_ENDIANNESS
249 .argb = { .alpha = alpha, .red = red, .green = green, .blue = blue }
250 #else
251 .argb = { .blue = blue, .green = green, .red = red, .alpha = alpha }
252 #endif
253 };
254 return Color(colorValue);
255 }
256
FromRGBO(uint8_t red,uint8_t green,uint8_t blue,double opacity)257 Color Color::FromRGBO(uint8_t red, uint8_t green, uint8_t blue, double opacity)
258 {
259 return FromARGB(static_cast<uint8_t>(round(opacity * 0xff)) & 0xff, red, green, blue);
260 }
261
FromRGB(uint8_t red,uint8_t green,uint8_t blue)262 Color Color::FromRGB(uint8_t red, uint8_t green, uint8_t blue)
263 {
264 return FromARGB(0xff, red, green, blue);
265 }
266
BlendColor(const Color & overlayColor) const267 Color Color::BlendColor(const Color& overlayColor) const
268 {
269 if (GetValue() == Color::TRANSPARENT.GetValue()) {
270 return overlayColor;
271 }
272 if (GetAlpha() < static_cast<uint8_t>(MAX_ALPHA)) {
273 return BlendColorWithAlpha(overlayColor);
274 }
275 auto alphaRate = static_cast<float>(overlayColor.GetAlpha()) / MAX_ALPHA;
276 auto newRed = static_cast<uint8_t>(GetRed() * (1.0f - alphaRate) + overlayColor.GetRed() * alphaRate);
277 auto newGreen = static_cast<uint8_t>(GetGreen() * (1.0f - alphaRate) + overlayColor.GetGreen() * alphaRate);
278 auto newBlue = static_cast<uint8_t>(GetBlue() * (1.0f - alphaRate) + overlayColor.GetBlue() * alphaRate);
279 auto newColor = Color::FromRGB(newRed, newGreen, newBlue);
280 newColor.SetColorSpace(GetColorSpace());
281 return newColor;
282 }
283
CalculateBlend(float alphaLeft,float alphaRight,float valueLeft,float valueRight) const284 float Color::CalculateBlend(float alphaLeft, float alphaRight, float valueLeft, float valueRight) const
285 {
286 return (valueLeft * alphaLeft * (1.0 - alphaRight) + valueRight * alphaRight) /
287 (alphaLeft + alphaRight - alphaLeft * alphaRight);
288 }
289
BlendColorWithAlpha(const Color & overlayColor) const290 Color Color::BlendColorWithAlpha(const Color& overlayColor) const
291 {
292 float alphaA = GetAlpha() / 255.0;
293 float alphaB = overlayColor.GetAlpha() / 255.0;
294 float blendAlpha = alphaA + alphaB - alphaA * alphaB;
295 float blendRed = CalculateBlend(alphaA, alphaB, GetRed() / 255.0, overlayColor.GetRed() / 255.0);
296 float blendGreen = CalculateBlend(alphaA, alphaB, GetGreen() / 255.0, overlayColor.GetGreen() / 255.0);
297 float blendBlue = CalculateBlend(alphaA, alphaB, GetBlue() / 255.0, overlayColor.GetBlue() / 255.0);
298
299 return Color::FromARGB(blendAlpha * 255, blendRed * 255, blendGreen * 255, blendBlue * 255);
300 }
301
LineColorTransition(const Color & startColor,const Color & endColor,double percent)302 const Color Color::LineColorTransition(const Color& startColor, const Color& endColor, double percent)
303 {
304 uint8_t red = 0;
305 uint8_t green = 0;
306 uint8_t blue = 0;
307 uint8_t alpha = 0;
308
309 red = static_cast<uint8_t>((endColor.GetRed()- startColor.GetRed()) * percent) + startColor.GetRed();
310 green = static_cast<uint8_t>((endColor.GetGreen() - startColor.GetGreen()) * percent) + startColor.GetGreen();
311 blue = static_cast<uint8_t>((endColor.GetBlue() - startColor.GetBlue()) * percent) + startColor.GetBlue();
312 alpha = static_cast<uint8_t>((endColor.GetAlpha() - startColor.GetAlpha()) * percent) + startColor.GetAlpha();
313
314 return Color::FromARGB(alpha, red, green, blue);
315 }
316
BlendOpacity(double opacityRatio) const317 Color Color::BlendOpacity(double opacityRatio) const
318 {
319 int32_t alpha = static_cast<int32_t>(GetAlpha() * opacityRatio);
320 alpha = std::clamp(alpha, 0, UINT8_MAX);
321 return Color::FromARGB(alpha, GetRed(), GetGreen(), GetBlue());
322 }
323
ChangeOpacity(double opacity) const324 Color Color::ChangeOpacity(double opacity) const
325 {
326 return Color::FromRGBO(GetRed(), GetGreen(), GetBlue(), opacity);
327 }
328
ChangeAlpha(uint8_t alpha) const329 Color Color::ChangeAlpha(uint8_t alpha) const
330 {
331 return Color::FromARGB(alpha, GetRed(), GetGreen(), GetBlue());
332 }
333
operator +(const Color & color) const334 Color Color::operator+(const Color& color) const
335 {
336 // convert first color from ARGB to linear
337 double firstLinearRed = 0.0;
338 double firstLinearGreen = 0.0;
339 double firstLinearBlue = 0.0;
340 ConvertGammaToLinear(*this, firstLinearRed, firstLinearGreen, firstLinearBlue);
341
342 // convert second color from ARGB to linear
343 double secondLinearRed = 0.0;
344 double secondLinearGreen = 0.0;
345 double secondLinearBlue = 0.0;
346 ConvertGammaToLinear(color, secondLinearRed, secondLinearGreen, secondLinearBlue);
347
348 // get linear result and convert to gamma
349 return ConvertLinearToGamma(GetAlpha() + color.GetAlpha(), firstLinearRed + secondLinearRed,
350 firstLinearGreen + secondLinearGreen, firstLinearBlue + secondLinearBlue);
351 }
352
operator -(const Color & color) const353 Color Color::operator-(const Color& color) const
354 {
355 // convert first color from ARGB to linear
356 double firstLinearRed = 0.0;
357 double firstLinearGreen = 0.0;
358 double firstLinearBlue = 0.0;
359 ConvertGammaToLinear(*this, firstLinearRed, firstLinearGreen, firstLinearBlue);
360
361 // convert second color from ARGB to linear
362 double secondLinearRed = 0.0;
363 double secondLinearGreen = 0.0;
364 double secondLinearBlue = 0.0;
365 ConvertGammaToLinear(color, secondLinearRed, secondLinearGreen, secondLinearBlue);
366
367 // get linear result and convert to gamma
368 return ConvertLinearToGamma(GetAlpha() - color.GetAlpha(), firstLinearRed - secondLinearRed,
369 firstLinearGreen - secondLinearGreen, firstLinearBlue - secondLinearBlue);
370 }
371
operator *(double value) const372 Color Color::operator*(double value) const
373 {
374 // convert color from ARGB to linear
375 double linearRed = 0.0;
376 double linearGreen = 0.0;
377 double linearBlue = 0.0;
378 ConvertGammaToLinear(*this, linearRed, linearGreen, linearBlue);
379
380 // get linear result and convert to gamma
381 return ConvertLinearToGamma(GetAlpha() * value, linearRed * value, linearGreen * value, linearBlue * value);
382 }
383
operator /(double value) const384 Color Color::operator/(double value) const
385 {
386 if (NearZero(value)) {
387 return *this;
388 }
389 // convert color from ARGB to linear
390 double linearRed = 0.0;
391 double linearGreen = 0.0;
392 double LinearBlue = 0.0;
393 ConvertGammaToLinear(*this, linearRed, linearGreen, LinearBlue);
394
395 // get linear result and convert to gamma
396 return ConvertLinearToGamma(GetAlpha() / value, linearRed / value, linearGreen / value, LinearBlue / value);
397 }
398
ConvertGammaToLinear(uint8_t value)399 double Color::ConvertGammaToLinear(uint8_t value)
400 {
401 return std::pow(value, GAMMA_FACTOR);
402 }
403
ConvertLinearToGamma(double value)404 uint8_t Color::ConvertLinearToGamma(double value)
405 {
406 return std::clamp(static_cast<int32_t>(round(std::pow(value, 1.0 / GAMMA_FACTOR))), 0, UINT8_MAX);
407 }
408
ConvertGammaToLinear(const Color & gammaColor,double & linearRed,double & linearGreen,double & linearBlue)409 void Color::ConvertGammaToLinear(const Color& gammaColor, double& linearRed, double& linearGreen, double& linearBlue)
410 {
411 linearRed = ConvertGammaToLinear(gammaColor.GetRed());
412 linearGreen = ConvertGammaToLinear(gammaColor.GetGreen());
413 linearBlue = ConvertGammaToLinear(gammaColor.GetBlue());
414 }
415
ConvertLinearToGamma(double alpha,double linearRed,double linearGreen,double linearBlue)416 Color Color::ConvertLinearToGamma(double alpha, double linearRed, double linearGreen, double linearBlue)
417 {
418 uint8_t gammaRed = ConvertLinearToGamma(linearRed);
419 uint8_t gammaGreen = ConvertLinearToGamma(linearGreen);
420 uint8_t gammaBlue = ConvertLinearToGamma(linearBlue);
421 uint8_t gammaAlpha = std::clamp(static_cast<int32_t>(round(alpha)), 0, UINT8_MAX);
422
423 return FromARGB(gammaAlpha, gammaRed, gammaGreen, gammaBlue);
424 }
425
IsHexNumber(std::string & colorStr)426 bool Color::IsHexNumber(std::string& colorStr)
427 {
428 for (size_t i = 1; i < colorStr.size(); i++) {
429 if (colorStr[i] >= '0' && colorStr[i] <= '9') {
430 continue;
431 }
432 if (colorStr[i] >= 'A' && colorStr[i] <= 'F') {
433 continue;
434 }
435 if (colorStr[i] >= 'a' && colorStr[i] <= 'f') {
436 continue;
437 }
438 return false;
439 }
440 return true;
441 }
442
FastCheckColorType(const std::string & colorStr,const std::string & expectPrefix,const std::vector<size_t> & expectLengths)443 bool Color::FastCheckColorType(const std::string& colorStr, const std::string& expectPrefix,
444 const std::vector<size_t>& expectLengths)
445 {
446 if (colorStr.rfind(expectPrefix, 0) != 0) {
447 return false;
448 }
449 if (expectLengths.size() == 0) {
450 return true;
451 }
452 for (size_t expectLength : expectLengths) {
453 if (expectLength == colorStr.size()) {
454 return true;
455 }
456 }
457 return false;
458 }
459
MatchColorWithMagic(std::string & colorStr,uint32_t maskAlpha,Color & color)460 bool Color::MatchColorWithMagic(std::string& colorStr, uint32_t maskAlpha, Color& color)
461 {
462 // Regex match for #909090 or #90909090
463 if (!FastCheckColorType(colorStr, "#", EXPECT_MAGIC_COLOR_LENGTHS)) {
464 return false;
465 }
466 if (!IsHexNumber(colorStr)) {
467 return false;
468 }
469 colorStr.erase(0, 1);
470 unsigned long int value = HandleIncorrectColor(colorStr);
471 if (colorStr.length() < COLOR_STRING_SIZE_STANDARD) {
472 // no alpha specified, set alpha to 0xff
473 value |= maskAlpha;
474 }
475 color = Color(value);
476 return true;
477 }
478
MatchColorWithMagicMini(std::string & colorStr,uint32_t maskAlpha,Color & color)479 bool Color::MatchColorWithMagicMini(std::string& colorStr, uint32_t maskAlpha, Color& color)
480 {
481 if (!FastCheckColorType(colorStr, "#", EXPECT_MAGIC_MINI_COLOR_LENGTHS)) {
482 return false;
483 }
484 if (!IsHexNumber(colorStr)) {
485 return false;
486 }
487 colorStr.erase(0, 1);
488 std::string newColorStr;
489 // translate #rgb or #rgba to #rrggbb or #rrggbbaa
490 for (auto& c : colorStr) {
491 newColorStr += c;
492 newColorStr += c;
493 }
494 unsigned long int value = HandleIncorrectColor(newColorStr);
495
496 if (newColorStr.length() < COLOR_STRING_SIZE_STANDARD) {
497 // no alpha specified, set alpha to 0xff
498 value |= maskAlpha;
499 }
500 color = Color(value);
501 return true;
502 }
503
MatchColorHexString(const std::string & colorStr)504 bool Color::MatchColorHexString(const std::string& colorStr)
505 {
506 if (colorStr.empty()) {
507 return false;
508 }
509 std::smatch matches;
510 if (std::regex_match(colorStr, matches, COLOR_WITH_MAGIC) ||
511 std::regex_match(colorStr, matches, COLOR_WITH_RGBA) ||
512 std::regex_match(colorStr, matches, COLOR_WITH_RGB) ||
513 std::regex_match(colorStr, matches, COLOR_WITH_MAGIC_MINI)) {
514 return true;
515 }
516 return false;
517 }
518
MatchColorWithRGB(const std::string & colorStr,Color & color)519 bool Color::MatchColorWithRGB(const std::string& colorStr, Color& color)
520 {
521 if (!FastCheckColorType(colorStr, "rgb(", {})) {
522 return false;
523 }
524 std::smatch matches;
525 if (std::regex_match(colorStr, matches, COLOR_WITH_RGB)) {
526 if (matches.size() == RGB_SUB_MATCH_SIZE) {
527 auto redInt = StringUtils::StringToInt(matches[1]);
528 auto greenInt = StringUtils::StringToInt(matches[2]);
529 auto blueInt = StringUtils::StringToInt(matches[3]);
530 if (!IsRGBValid(redInt) || !IsRGBValid(greenInt) || !IsRGBValid(blueInt)) {
531 return false;
532 }
533
534 auto red = static_cast<uint8_t>(redInt);
535 auto green = static_cast<uint8_t>(greenInt);
536 auto blue = static_cast<uint8_t>(blueInt);
537 color = FromRGB(red, green, blue);
538 return true;
539 }
540 }
541 return false;
542 }
543
MatchColorWithRGBA(const std::string & colorStr,Color & color)544 bool Color::MatchColorWithRGBA(const std::string& colorStr, Color& color)
545 {
546 if (!FastCheckColorType(colorStr, "rgba(", {})) {
547 return false;
548 }
549 std::smatch matches;
550 if (std::regex_match(colorStr, matches, COLOR_WITH_RGBA)) {
551 if (matches.size() == RGBA_SUB_MATCH_SIZE) {
552 auto redInt = StringUtils::StringToInt(matches[1]);
553 auto greenInt = StringUtils::StringToInt(matches[2]);
554 auto blueInt = StringUtils::StringToInt(matches[3]);
555 auto opacityDouble = StringUtils::StringToDouble(matches[4]);
556 if (!IsRGBValid(redInt) || !IsRGBValid(greenInt) || !IsRGBValid(blueInt) ||
557 !IsOpacityValid(opacityDouble)) {
558 return false;
559 }
560
561 auto red = static_cast<uint8_t>(redInt);
562 auto green = static_cast<uint8_t>(greenInt);
563 auto blue = static_cast<uint8_t>(blueInt);
564 auto opacity = static_cast<double>(opacityDouble);
565
566 color = FromRGBO(red, green, blue, opacity);
567 return true;
568 }
569 }
570
571 return false;
572 }
573
MatchColorSpecialString(const std::string & colorStr,Color & color)574 bool Color::MatchColorSpecialString(const std::string& colorStr, Color& color)
575 {
576 static const LinearMapNode<Color> colorTable[] = {
577 { "black", Color(0xff000000) },
578 { "blue", Color(0xff0000ff) },
579 { "gray", Color(0xffc0c0c0) },
580 { "green", Color(0xff00ff00) },
581 { "red", Color(0xffff0000) },
582 { "transparent", Color(0x00000000) },
583 { "white", Color(0xffffffff) },
584 };
585
586 int64_t colorIndex = BinarySearchFindIndex(colorTable, ArraySize(colorTable), colorStr.c_str());
587 if (colorIndex != -1) {
588 color = colorTable[colorIndex].value;
589 return true;
590 }
591
592 return false;
593 }
594
ParseUintColorString(const std::string & colorStr,Color & color,const Color & defaultColor)595 bool Color::ParseUintColorString(const std::string& colorStr, Color& color, const Color& defaultColor)
596 {
597 auto uint32Color = StringUtils::StringToUintCheck(colorStr, defaultColor.GetValue());
598 if (uint32Color > 0) {
599 if ((uint32Color >> COLOR_ALPHA_OFFSET) == 0) {
600 color = Color(uint32Color).ChangeAlpha(MAX_ALPHA);
601 } else {
602 color = Color(uint32Color);
603 }
604 return true;
605 }
606
607 return false;
608 }
609
ParseUintColorString(const std::string & colorStr,Color & color)610 bool Color::ParseUintColorString(const std::string& colorStr, Color& color)
611 {
612 auto uint32Color = StringUtils::StringToUint(colorStr);
613 if (uint32Color > 0) {
614 if ((uint32Color >> COLOR_ALPHA_OFFSET) == 0) {
615 color = Color(uint32Color).ChangeAlpha(MAX_ALPHA);
616 } else {
617 color = Color(uint32Color);
618 }
619 return true;
620 }
621
622 return false;
623 }
624
IsRGBValid(int value)625 bool Color::IsRGBValid(int value)
626 {
627 return value >= MIN_RGB_VALUE && value <= MAX_RGB_VALUE;
628 }
629
IsOpacityValid(double value)630 bool Color::IsOpacityValid(double value)
631 {
632 return value >= MIN_RGBA_OPACITY && value <= MAX_RGBA_OPACITY;
633 }
634
UpdateColorByResourceId()635 void Color::UpdateColorByResourceId()
636 {
637 #ifndef ACE_UNITTEST
638 CHECK_NULL_VOID(resourceId_ != 0);
639 auto resourceAdapter = ResourceManager::GetInstance().GetResourceAdapter(Container::CurrentIdSafely());
640 CHECK_NULL_VOID(resourceAdapter);
641 auto newColor = resourceAdapter->GetColor(resourceId_);
642 SetValue(newColor.GetValue());
643 #endif
644 }
645
646 } // namespace OHOS::Ace
647