• 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 
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