11#include < reanimated/CSS/common/values/CSSColor.h>
2+ #include < reanimated/CSS/svg/values/SVGBrush.h>
3+
4+ #include < utility>
25
36namespace reanimated ::css {
47
5- CSSColor::CSSColor ()
6- : channels{0 , 0 , 0 , 0 }, colorType(ColorType::Transparent) {}
8+ // CSSColorBase template implementations
9+
10+ template <ColorTypeEnum TColorType, typename TDerived>
11+ CSSColorBase<TColorType, TDerived>::CSSColorBase()
12+ : channels{0 , 0 , 0 , 0 }, colorType(TColorType::Transparent) {}
713
8- CSSColor::CSSColor (ColorType colorType)
14+ template <ColorTypeEnum TColorType, typename TDerived>
15+ CSSColorBase<TColorType, TDerived>::CSSColorBase(TColorType colorType)
916 : channels{0 , 0 , 0 , 0 }, colorType(colorType) {}
1017
11- CSSColor::CSSColor (int64_t numberValue)
12- : channels{0 , 0 , 0 , 0 }, colorType(ColorType::Rgba) {
18+ template <ColorTypeEnum TColorType, typename TDerived>
19+ CSSColorBase<TColorType, TDerived>::CSSColorBase(int64_t numberValue)
20+ : channels{0 , 0 , 0 , 0 }, colorType(TColorType::Rgba) {
1321 uint32_t color;
1422 // On Android, colors are represented as signed 32-bit integers. In JS, we use
1523 // a bitwise operation (normalizedColor = normalizedColor | 0x0) to ensure the
@@ -26,130 +34,98 @@ CSSColor::CSSColor(int64_t numberValue)
2634 channels[1 ] = (color >> 8 ) & 0xFF ; // Green
2735 channels[2 ] = color & 0xFF ; // Blue
2836 channels[3 ] = (color >> 24 ) & 0xFF ; // Alpha
29- colorType = ColorType::Rgba;
30- }
31-
32- CSSColor::CSSColor (const std::string &colorString)
33- : channels{0 , 0 , 0 , 0 }, colorType(ColorType::Transparent) {
34- if (colorString == " transparent" ) {
35- colorType = ColorType::Transparent;
36- } else if (colorString == " currentColor" ) {
37- colorType = ColorType::CurrentColor;
38- } else {
39- throw std::invalid_argument (
40- " [Reanimated] CSSColor: Invalid string value: " + colorString);
41- }
37+ colorType = TColorType::Rgba;
4238}
4339
44- CSSColor::CSSColor (const uint8_t r, const uint8_t g, const uint8_t b)
45- : channels{r, g, b, 255 }, colorType(ColorType::Rgba) {}
46-
47- CSSColor::CSSColor (
40+ template <ColorTypeEnum TColorType, typename TDerived>
41+ CSSColorBase<TColorType, TDerived>::CSSColorBase(
4842 const uint8_t r,
4943 const uint8_t g,
5044 const uint8_t b,
5145 const uint8_t a)
52- : channels{r, g, b, a}, colorType(ColorType::Rgba) {}
46+ : channels{r, g, b, a}, colorType(TColorType::Rgba) {}
47+
48+ template <ColorTypeEnum TColorType, typename TDerived>
49+ CSSColorBase<TColorType, TDerived>::CSSColorBase(ColorChannels colorChannels)
50+ : channels{std::move (colorChannels)}, colorType(TColorType::Rgba) {}
51+
52+ template <ColorTypeEnum TColorType, typename TDerived>
53+ TDerived CSSColorBase<TColorType, TDerived>::interpolate(
54+ double progress,
55+ const TDerived &to) const {
56+ ColorChannels fromChannels = channels;
57+ ColorChannels toChannels = to.channels ;
58+
59+ if (colorType == TColorType::Transparent) {
60+ fromChannels = {toChannels[0 ], toChannels[1 ], toChannels[2 ], 0 };
61+ } else if (to.colorType == TColorType::Transparent) {
62+ toChannels = {fromChannels[0 ], fromChannels[1 ], fromChannels[2 ], 0 };
63+ }
64+
65+ ColorChannels resultChannels;
66+ for (size_t i = 0 ; i < 4 ; ++i) {
67+ const auto &from = fromChannels[i];
68+ const auto &to = toChannels[i];
69+ // Cast one of operands to double to avoid unsigned int subtraction overflow
70+ // (when from > to)
71+ const double interpolated =
72+ (static_cast <double >(to) - from) * progress + from;
73+ resultChannels[i] =
74+ static_cast <uint8_t >(std::round (std::clamp (interpolated, 0.0 , 255.0 )));
75+ }
76+
77+ return TDerived (std::move (resultChannels));
78+ }
79+
80+ template <ColorTypeEnum TColorType, typename TDerived>
81+ bool CSSColorBase<TColorType, TDerived>::operator ==(
82+ const TDerived &other) const {
83+ return colorType == other.colorType && channels == other.channels ;
84+ }
5385
54- CSSColor::CSSColor (const ColorChannels &colorChannels)
55- : channels{colorChannels[0 ], colorChannels[1 ], colorChannels[2 ], colorChannels[3 ]},
56- colorType (ColorType::Rgba) {}
86+ // CSSColor implementations
5787
5888CSSColor::CSSColor (jsi::Runtime &rt, const jsi::Value &jsiValue)
59- : channels{ 0 , 0 , 0 , 0 }, colorType(ColorType ::Transparent) {
89+ : CSSColorBase<CSSColorType, CSSColor>(CSSColorType ::Transparent) {
6090 if (jsiValue.isNumber ()) {
6191 *this = CSSColor (jsiValue.getNumber ());
62- } else if (jsiValue.isString ()) {
63- *this = CSSColor (jsiValue.getString (rt).utf8 (rt));
64- } else {
65- *this = Transparent;
6692 }
6793}
6894
6995CSSColor::CSSColor (const folly::dynamic &value)
70- : channels{ 0 , 0 , 0 , 0 }, colorType(ColorType ::Transparent) {
96+ : CSSColorBase<CSSColorType, CSSColor>(CSSColorType ::Transparent) {
7197 if (value.isNumber ()) {
7298 *this = CSSColor (value.asInt ());
73- } else if (value.isString ()) {
74- *this = CSSColor (value.getString ());
75- } else {
76- *this = Transparent;
7799 }
78100}
79101
80102bool CSSColor::canConstruct (jsi::Runtime &rt, const jsi::Value &jsiValue) {
81103 return jsiValue.isNumber () || jsiValue.isUndefined () ||
82- (jsiValue.isString () &&
83- isValidColorString (jsiValue.getString (rt).utf8 (rt)));
104+ (jsiValue.isString () && jsiValue.getString (rt).utf8 (rt) == " transparent" );
84105}
85106
86107bool CSSColor::canConstruct (const folly::dynamic &value) {
87108 return value.isNumber () || value.empty () ||
88- (value.isString () && isValidColorString ( value.getString ()) );
109+ (value.isString () && value.getString () == " transparent " );
89110}
90111
91112folly::dynamic CSSColor::toDynamic () const {
92- if (colorType == ColorType::Transparent) {
93- return 0x00000000 ;
113+ if (colorType == CSSColorType::Rgba) {
114+ return (channels[3 ] << 24 ) | (channels[0 ] << 16 ) | (channels[1 ] << 8 ) |
115+ channels[2 ];
94116 }
95- return (channels[3 ] << 24 ) | (channels[0 ] << 16 ) | (channels[1 ] << 8 ) |
96- channels[2 ];
117+ return 0 ;
97118}
98119
99120std::string CSSColor::toString () const {
100- if (colorType == ColorType ::Rgba) {
121+ if (colorType == CSSColorType ::Rgba) {
101122 return " rgba(" + std::to_string (channels[0 ]) + " ," +
102123 std::to_string (channels[1 ]) + " ," + std::to_string (channels[2 ]) + " ," +
103124 std::to_string (channels[3 ]) + " )" ;
104125 }
105- if (colorType == ColorType::CurrentColor) {
106- return " currentColor" ;
107- }
108126 return " transparent" ;
109127}
110128
111- CSSColor CSSColor::interpolate (const double progress, const CSSColor &to)
112- const {
113- if ((to.colorType == ColorType::Transparent &&
114- colorType == ColorType::Transparent) ||
115- colorType == ColorType::CurrentColor ||
116- to.colorType == ColorType::CurrentColor) {
117- return progress < 0.5 ? *this : to;
118- }
119-
120- ColorChannels fromChannels = channels;
121- ColorChannels toChannels = to.channels ;
122- if (colorType == ColorType::Transparent) {
123- fromChannels = {toChannels[0 ], toChannels[1 ], toChannels[2 ], 0 };
124- } else if (to.colorType == ColorType::Transparent) {
125- toChannels = {fromChannels[0 ], fromChannels[1 ], fromChannels[2 ], 0 };
126- }
127-
128- ColorChannels resultChannels;
129- for (size_t i = 0 ; i < 4 ; ++i) {
130- resultChannels[i] =
131- interpolateChannel (fromChannels[i], toChannels[i], progress);
132- }
133-
134- return CSSColor (resultChannels);
135- }
136-
137- uint8_t CSSColor::interpolateChannel (
138- const uint8_t from,
139- const uint8_t to,
140- const double progress) {
141- // Cast one of operands to double to avoid unsigned int subtraction overflow
142- // (when from > to)
143- double interpolated = (static_cast <double >(to) - from) * progress + from;
144- return static_cast <uint8_t >(std::round (std::clamp (interpolated, 0.0 , 255.0 )));
145- }
146-
147- bool CSSColor::operator ==(const CSSColor &other) const {
148- return colorType == other.colorType && channels[0 ] == other.channels [0 ] &&
149- channels[1 ] == other.channels [1 ] && channels[2 ] == other.channels [2 ] &&
150- channels[3 ] == other.channels [3 ];
151- }
152-
153129#ifndef NDEBUG
154130
155131std::ostream &operator <<(std::ostream &os, const CSSColor &colorValue) {
@@ -159,8 +135,8 @@ std::ostream &operator<<(std::ostream &os, const CSSColor &colorValue) {
159135
160136#endif // NDEBUG
161137
162- bool CSSColor::isValidColorString ( const std::string &colorString) {
163- return colorString == " transparent " || colorString == " currentColor " ;
164- }
138+ // Explicit template instantiation
139+ template struct CSSColorBase <CSSColorType, CSSColor> ;
140+ template struct CSSColorBase <SVGBrushType, SVGBrush>;
165141
166142} // namespace reanimated::css
0 commit comments