Skip to content

Commit 350dd93

Browse files
committed
Move SVG color to a separate SVGBrush struct
1 parent e0595d8 commit 350dd93

File tree

7 files changed

+229
-121
lines changed

7 files changed

+229
-121
lines changed

packages/react-native-reanimated/Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <reanimated/CSS/common/transforms/TransformMatrix2D.h>
1414
#include <reanimated/CSS/common/values/complex/CSSBoxShadow.h>
1515

16+
#include <reanimated/CSS/svg/values/SVGBrush.h>
1617
#include <reanimated/CSS/svg/values/SVGLength.h>
1718
#include <reanimated/CSS/svg/values/SVGStrokeDashArray.h>
1819

@@ -31,8 +32,8 @@ namespace reanimated::css {
3132
namespace {
3233

3334
// Private implementation details
34-
const auto BLACK = CSSColor(0, 0, 0, 255);
35-
const auto TRANSPARENT = CSSColor::Transparent;
35+
const std::array<uint8_t, 4> BLACK = {0, 0, 0, 255};
36+
const std::array<uint8_t, 4> TRANSPARENT = {0, 0, 0, 0};
3637

3738
InterpolatorFactoriesRecord mergeInterpolators(
3839
const std::vector<InterpolatorFactoriesRecord> &maps) {
@@ -275,17 +276,17 @@ const InterpolatorFactoriesRecord IMAGE_INTERPOLATORS = mergeInterpolators(
275276
// =================
276277

277278
const InterpolatorFactoriesRecord SVG_COLOR_INTERPOLATORS = {
278-
{"color", value<CSSColor>(BLACK)},
279+
{"color", value<SVGBrush>(BLACK)},
279280
};
280281

281282
const InterpolatorFactoriesRecord SVG_FILL_INTERPOLATORS = {
282-
{"fill", value<CSSColor>(BLACK)},
283+
{"fill", value<SVGBrush>(BLACK)},
283284
{"fillOpacity", value<CSSDouble>(1)},
284285
{"fillRule", value<CSSInteger>(0)},
285286
};
286287

287288
const InterpolatorFactoriesRecord SVG_STROKE_INTERPOLATORS = {
288-
{"stroke", value<CSSColor>(BLACK)},
289+
{"stroke", value<SVGBrush>(BLACK)},
289290
{"strokeWidth", value<SVGLength>(1)},
290291
{"strokeOpacity", value<CSSDouble>(1)},
291292
{"strokeDasharray",
Lines changed: 68 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
#include <reanimated/CSS/common/values/CSSColor.h>
2+
#include <reanimated/CSS/svg/values/SVGBrush.h>
3+
4+
#include <utility>
25

36
namespace 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

5888
CSSColor::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

6995
CSSColor::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

80102
bool 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

86107
bool 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

91112
folly::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

99120
std::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

155131
std::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

packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSColor.h

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,40 @@
77

88
namespace reanimated::css {
99

10-
enum class ColorType {
11-
Rgba,
12-
Transparent,
13-
CurrentColor, // for SVG
10+
// Base class with common color value functionality
11+
12+
template <typename T>
13+
concept ColorTypeEnum = std::is_enum_v<T> && requires {
14+
T::Rgba;
15+
T::Transparent;
1416
};
1517

16-
struct CSSColor : public CSSSimpleValue<CSSColor> {
18+
template <ColorTypeEnum TColorType, typename TDerived>
19+
struct CSSColorBase : public CSSSimpleValue<TDerived> {
1720
ColorChannels channels;
18-
ColorType colorType;
21+
TColorType colorType;
22+
23+
CSSColorBase();
24+
explicit CSSColorBase(TColorType colorType);
25+
explicit CSSColorBase(int64_t numberValue);
1926

20-
static const CSSColor Transparent;
27+
explicit CSSColorBase(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
28+
explicit CSSColorBase(ColorChannels colorChannels);
2129

22-
CSSColor();
23-
explicit CSSColor(ColorType colorType);
24-
explicit CSSColor(int64_t numberValue);
25-
explicit CSSColor(const std::string &colorString);
30+
TDerived interpolate(double progress, const TDerived &to) const override;
2631

27-
explicit CSSColor(uint8_t r, uint8_t g, uint8_t b);
28-
explicit CSSColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
29-
explicit CSSColor(const ColorChannels &colorChannels);
32+
bool operator==(const TDerived &other) const;
33+
};
34+
35+
// Enum class for color type
36+
37+
enum class CSSColorType {
38+
Rgba,
39+
Transparent,
40+
};
41+
42+
struct CSSColor : public CSSColorBase<CSSColorType, CSSColor> {
43+
using CSSColorBase<CSSColorType, CSSColor>::CSSColorBase;
3044

3145
explicit CSSColor(jsi::Runtime &rt, const jsi::Value &jsiValue);
3246
explicit CSSColor(const folly::dynamic &value);
@@ -36,20 +50,10 @@ struct CSSColor : public CSSSimpleValue<CSSColor> {
3650

3751
folly::dynamic toDynamic() const override;
3852
std::string toString() const override;
39-
CSSColor interpolate(double progress, const CSSColor &to) const override;
40-
41-
static uint8_t interpolateChannel(uint8_t from, uint8_t to, double progress);
42-
43-
bool operator==(const CSSColor &other) const;
4453

4554
#ifndef NDEBUG
4655
friend std::ostream &operator<<(std::ostream &os, const CSSColor &colorValue);
4756
#endif // NDEBUG
48-
49-
private:
50-
static bool isValidColorString(const std::string &colorString);
5157
};
5258

53-
inline const CSSColor CSSColor::Transparent(ColorType::Transparent);
54-
5559
} // namespace reanimated::css

packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <reanimated/CSS/common/values/CSSNumber.h>
88
#include <reanimated/CSS/common/values/CSSValueVariant.h>
99
#include <reanimated/CSS/common/values/complex/CSSBoxShadow.h>
10+
#include <reanimated/CSS/svg/values/SVGBrush.h>
1011
#include <reanimated/CSS/svg/values/SVGLength.h>
1112
#include <reanimated/CSS/svg/values/SVGStrokeDashArray.h>
1213

@@ -179,5 +180,6 @@ template class CSSValueVariant<CSSDiscreteArray<CSSKeyword>>;
179180
template class CSSValueVariant<SVGLength>;
180181
template class CSSValueVariant<SVGLength, CSSKeyword>;
181182
template class CSSValueVariant<SVGStrokeDashArray, CSSKeyword>;
183+
template class CSSValueVariant<SVGBrush>;
182184

183185
} // namespace reanimated::css

packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/SimpleValueInterpolator.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <reanimated/CSS/common/values/CSSLength.h>
1212
#include <reanimated/CSS/common/values/CSSNumber.h>
1313
#include <reanimated/CSS/common/values/complex/CSSBoxShadow.h>
14+
#include <reanimated/CSS/svg/values/SVGBrush.h>
1415
#include <reanimated/CSS/svg/values/SVGLength.h>
1516
#include <reanimated/CSS/svg/values/SVGStrokeDashArray.h>
1617

@@ -66,5 +67,6 @@ template class SimpleValueInterpolator<CSSDiscreteArray<CSSKeyword>>;
6667
template class SimpleValueInterpolator<SVGLength>;
6768
template class SimpleValueInterpolator<SVGLength, CSSKeyword>;
6869
template class SimpleValueInterpolator<SVGStrokeDashArray, CSSKeyword>;
70+
template class SimpleValueInterpolator<SVGBrush>;
6971

7072
} // namespace reanimated::css

0 commit comments

Comments
 (0)