• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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