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