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: " 
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