Skip to content

Commit f2c78af

Browse files
zhongwuzwfacebook-github-bot
authored andcommitted
Reland: [iOS] [Fabric] Fixes crash of dynamic color when light/dark mode changed (#49265)
Summary: Reland #48496 . ## Changelog: [IOS] [FIXED] - Fabric: Fixes crash of dynamic color when light/dark mode changed Pull Request resolved: #49265 Test Plan: RNTester -> PlatformColor example -> changed the dark/light mode in the system settings -> go back to App and pop and push the PlatformColor example, it would crash: Reviewed By: javache Differential Revision: D69309825 Pulled By: cipolleschi fbshipit-source-id: 7a533a73ef343b071000388b653b2d1d0c54ae88
1 parent b1735bc commit f2c78af

5 files changed

Lines changed: 130 additions & 21 deletions

File tree

packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ struct Color {
2424
Color(int32_t color);
2525
Color(const DynamicColor& dynamicColor);
2626
Color(const ColorComponents& components);
27-
Color(std::shared_ptr<void> uiColor);
27+
Color() : uiColor_(nullptr){};
2828
int32_t getColor() const;
29+
int32_t getUIColorHash() const;
30+
31+
static Color createSemanticColor(std::vector<std::string>& semanticItems);
32+
2933
std::shared_ptr<void> getUIColor() const {
3034
return uiColor_;
3135
}
@@ -48,7 +52,9 @@ struct Color {
4852
}
4953

5054
private:
55+
Color(std::shared_ptr<void> uiColor);
5156
std::shared_ptr<void> uiColor_;
57+
int32_t uiColorHashValue_;
5258
};
5359

5460
namespace HostPlatformColor {
@@ -59,7 +65,7 @@ namespace HostPlatformColor {
5965
#define NO_DESTROY
6066
#endif
6167

62-
NO_DESTROY static const facebook::react::Color UndefinedColor = Color(nullptr);
68+
NO_DESTROY static const facebook::react::Color UndefinedColor = Color();
6369
} // namespace HostPlatformColor
6470

6571
inline Color
@@ -103,8 +109,6 @@ inline float blueFromHostPlatformColor(Color color) {
103109
template <>
104110
struct std::hash<facebook::react::Color> {
105111
size_t operator()(const facebook::react::Color& color) const {
106-
auto seed = size_t{0};
107-
facebook::react::hash_combine(seed, color.getColor());
108-
return seed;
112+
return color.getUIColorHash();
109113
}
110114
};

packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm

Lines changed: 112 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
#import <Foundation/Foundation.h>
1111
#import <UIKit/UIKit.h>
12+
#import <objc/runtime.h>
13+
#import <react/renderer/graphics/RCTPlatformColorUtils.h>
1214
#import <react/utils/ManagedObjectWrapper.h>
1315
#import <string>
1416

@@ -19,13 +21,30 @@
1921
namespace facebook::react {
2022

2123
namespace {
24+
25+
bool UIColorIsP3ColorSpace(const std::shared_ptr<void> &uiColor)
26+
{
27+
UIColor *color = unwrapManagedObject(uiColor);
28+
CGColorSpaceRef colorSpace = CGColorGetColorSpace(color.CGColor);
29+
30+
if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelRGB) {
31+
CFStringRef name = CGColorSpaceGetName(colorSpace);
32+
if (name != NULL && CFEqual(name, kCGColorSpaceDisplayP3)) {
33+
return true;
34+
}
35+
}
36+
return false;
37+
}
38+
2239
UIColor *_Nullable UIColorFromInt32(int32_t intColor)
2340
{
2441
CGFloat a = CGFloat((intColor >> 24) & 0xFF) / 255.0;
2542
CGFloat r = CGFloat((intColor >> 16) & 0xFF) / 255.0;
2643
CGFloat g = CGFloat((intColor >> 8) & 0xFF) / 255.0;
2744
CGFloat b = CGFloat(intColor & 0xFF) / 255.0;
28-
return [UIColor colorWithRed:r green:g blue:b alpha:a];
45+
46+
UIColor *color = [UIColor colorWithRed:r green:g blue:b alpha:a];
47+
return color;
2948
}
3049

3150
UIColor *_Nullable UIColorFromDynamicColor(const facebook::react::DynamicColor &dynamicColor)
@@ -64,64 +83,132 @@
6483
return nil;
6584
}
6685

67-
int32_t ColorFromUIColor(UIColor *color)
86+
int32_t ColorFromColorComponents(const facebook::react::ColorComponents &components)
6887
{
6988
float ratio = 255;
89+
auto color = ((int32_t)round((float)components.alpha * ratio) & 0xff) << 24 |
90+
((int)round((float)components.red * ratio) & 0xff) << 16 |
91+
((int)round((float)components.green * ratio) & 0xff) << 8 | ((int)round((float)components.blue * ratio) & 0xff);
92+
return color;
93+
}
94+
95+
int32_t ColorFromUIColor(UIColor *color)
96+
{
7097
CGFloat rgba[4];
7198
[color getRed:&rgba[0] green:&rgba[1] blue:&rgba[2] alpha:&rgba[3]];
72-
return ((int32_t)round((float)rgba[3] * ratio) & 0xff) << 24 | ((int)round((float)rgba[0] * ratio) & 0xff) << 16 |
73-
((int)round((float)rgba[1] * ratio) & 0xff) << 8 | ((int)round((float)rgba[2] * ratio) & 0xff);
99+
return ColorFromColorComponents({(float)rgba[0], (float)rgba[1], (float)rgba[2], (float)rgba[3]});
74100
}
75101

76-
int32_t ColorFromUIColor(const std::shared_ptr<void> &uiColor)
102+
int32_t ColorFromUIColorForSpecificTraitCollection(
103+
const std::shared_ptr<void> &uiColor,
104+
UITraitCollection *traitCollection)
77105
{
78106
UIColor *color = (UIColor *)unwrapManagedObject(uiColor);
79107
if (color) {
80-
UITraitCollection *currentTraitCollection = [UITraitCollection currentTraitCollection];
81-
color = [color resolvedColorWithTraitCollection:currentTraitCollection];
108+
color = [color resolvedColorWithTraitCollection:traitCollection];
82109
return ColorFromUIColor(color);
83110
}
84111

85112
return 0;
86113
}
87114

115+
int32_t ColorFromUIColor(const std::shared_ptr<void> &uiColor)
116+
{
117+
return ColorFromUIColorForSpecificTraitCollection(uiColor, [UITraitCollection currentTraitCollection]);
118+
}
119+
88120
UIColor *_Nullable UIColorFromComponentsColor(const facebook::react::ColorComponents &components)
89121
{
122+
UIColor *uiColor = nil;
90123
if (components.colorSpace == ColorSpace::DisplayP3) {
91-
return [UIColor colorWithDisplayP3Red:components.red
92-
green:components.green
93-
blue:components.blue
94-
alpha:components.alpha];
124+
uiColor = [UIColor colorWithDisplayP3Red:components.red
125+
green:components.green
126+
blue:components.blue
127+
alpha:components.alpha];
128+
} else {
129+
uiColor = [UIColor colorWithRed:components.red green:components.green blue:components.blue alpha:components.alpha];
130+
}
131+
132+
return uiColor;
133+
}
134+
135+
int32_t hashFromUIColor(const std::shared_ptr<void> &uiColor)
136+
{
137+
if (uiColor == nullptr) {
138+
return 0;
95139
}
96-
return [UIColor colorWithRed:components.red green:components.green blue:components.blue alpha:components.alpha];
140+
141+
static UITraitCollection *darkModeTraitCollection =
142+
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark];
143+
auto darkColor = ColorFromUIColorForSpecificTraitCollection(uiColor, darkModeTraitCollection);
144+
145+
static UITraitCollection *lightModeTraitCollection =
146+
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight];
147+
auto lightColor = ColorFromUIColorForSpecificTraitCollection(uiColor, lightModeTraitCollection);
148+
149+
static UITraitCollection *darkModeAccessibilityContrastTraitCollection =
150+
[UITraitCollection traitCollectionWithTraitsFromCollections:@[
151+
darkModeTraitCollection,
152+
[UITraitCollection traitCollectionWithAccessibilityContrast:UIAccessibilityContrastHigh]
153+
]];
154+
auto darkAccessibilityContrastColor =
155+
ColorFromUIColorForSpecificTraitCollection(uiColor, darkModeAccessibilityContrastTraitCollection);
156+
157+
static UITraitCollection *lightModeAccessibilityContrastTraitCollection =
158+
[UITraitCollection traitCollectionWithTraitsFromCollections:@[
159+
lightModeTraitCollection,
160+
[UITraitCollection traitCollectionWithAccessibilityContrast:UIAccessibilityContrastHigh]
161+
]];
162+
auto lightAccessibilityContrastColor =
163+
ColorFromUIColorForSpecificTraitCollection(uiColor, lightModeAccessibilityContrastTraitCollection);
164+
return facebook::react::hash_combine(
165+
darkColor,
166+
lightColor,
167+
darkAccessibilityContrastColor,
168+
lightAccessibilityContrastColor,
169+
UIColorIsP3ColorSpace(uiColor));
97170
}
171+
98172
} // anonymous namespace
99173

100174
Color::Color(int32_t color)
101175
{
102176
uiColor_ = wrapManagedObject(UIColorFromInt32(color));
177+
uiColorHashValue_ = facebook::react::hash_combine(color, 0);
103178
}
104179

105180
Color::Color(const DynamicColor &dynamicColor)
106181
{
107182
uiColor_ = wrapManagedObject(UIColorFromDynamicColor(dynamicColor));
183+
uiColorHashValue_ = facebook::react::hash_combine(
184+
dynamicColor.darkColor,
185+
dynamicColor.lightColor,
186+
dynamicColor.highContrastDarkColor,
187+
dynamicColor.highContrastLightColor,
188+
0);
108189
}
109190

110191
Color::Color(const ColorComponents &components)
111192
{
112193
uiColor_ = wrapManagedObject(UIColorFromComponentsColor(components));
194+
uiColorHashValue_ = facebook::react::hash_combine(
195+
ColorFromColorComponents(components), components.colorSpace == ColorSpace::DisplayP3);
113196
}
114197

115198
Color::Color(std::shared_ptr<void> uiColor)
116199
{
200+
UIColor *color = ((UIColor *)unwrapManagedObject(uiColor));
201+
if (color) {
202+
auto colorHash = hashFromUIColor(uiColor);
203+
uiColorHashValue_ = colorHash;
204+
}
117205
uiColor_ = std::move(uiColor);
118206
}
119207

120208
bool Color::operator==(const Color &other) const
121209
{
122210
return (!uiColor_ && !other.uiColor_) ||
123-
(uiColor_ && other.uiColor_ &&
124-
[unwrapManagedObject(getUIColor()) isEqual:unwrapManagedObject(other.getUIColor())]);
211+
(uiColor_ && other.uiColor_ && (uiColorHashValue_ == other.uiColorHashValue_));
125212
}
126213

127214
bool Color::operator!=(const Color &other) const
@@ -142,6 +229,17 @@ int32_t ColorFromUIColor(const std::shared_ptr<void> &uiColor)
142229
return static_cast<float>(rgba[channelId]);
143230
}
144231

232+
int32_t Color::getUIColorHash() const
233+
{
234+
return uiColorHashValue_;
235+
}
236+
237+
Color Color::createSemanticColor(std::vector<std::string> &semanticItems)
238+
{
239+
auto semanticColor = RCTPlatformColorFromSemanticItems(semanticItems);
240+
return Color(wrapManagedObject(semanticColor));
241+
}
242+
145243
} // namespace facebook::react
146244

147245
NS_ASSUME_NONNULL_END

packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/PlatformColorParser.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ SharedColor parsePlatformColor(const ContextContainer &contextContainer, int32_t
5656
auto items = (std::unordered_map<std::string, RawValue>)value;
5757
if (items.find("semantic") != items.end() && items.at("semantic").hasType<std::vector<std::string>>()) {
5858
auto semanticItems = (std::vector<std::string>)items.at("semantic");
59-
return {wrapManagedObject(RCTPlatformColorFromSemanticItems(semanticItems))};
59+
return SharedColor(Color::createSemanticColor(semanticItems));
6060
} else if (
6161
items.find("dynamic") != items.end() &&
6262
items.at("dynamic").hasType<std::unordered_map<std::string, RawValue>>()) {

packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/RCTPlatformColorUtils.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@
88
#pragma once
99

1010
#import <UIKit/UIKit.h>
11-
#import <react/renderer/graphics/HostPlatformColor.h>
1211
#import <vector>
1312

13+
namespace facebook {
14+
namespace react {
15+
struct ColorComponents;
16+
struct Color;
17+
} // namespace react
18+
} // namespace facebook
19+
1420
facebook::react::ColorComponents RCTPlatformColorComponentsFromSemanticItems(
1521
std::vector<std::string>& semanticItems);
1622
UIColor* RCTPlatformColorFromSemanticItems(

packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/RCTPlatformColorUtils.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#import <Foundation/Foundation.h>
1111
#import <UIKit/UIKit.h>
12+
#import <react/renderer/graphics/HostPlatformColor.h>
1213
#import <react/utils/ManagedObjectWrapper.h>
1314

1415
#include <string>

0 commit comments

Comments
 (0)