mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Reland: [iOS] [Fabric] Fixes crash of dynamic color when light/dark mode changed (#49265)
Summary: Reland https://github.com/facebook/react-native/issues/48496 . ## Changelog: [IOS] [FIXED] - Fabric: Fixes crash of dynamic color when light/dark mode changed Pull Request resolved: https://github.com/facebook/react-native/pull/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
This commit is contained in:
committed by
Facebook GitHub Bot
parent
b1735bc593
commit
f2c78af56a
+9
-5
@@ -24,8 +24,12 @@ struct Color {
|
||||
Color(int32_t color);
|
||||
Color(const DynamicColor& dynamicColor);
|
||||
Color(const ColorComponents& components);
|
||||
Color(std::shared_ptr<void> uiColor);
|
||||
Color() : uiColor_(nullptr){};
|
||||
int32_t getColor() const;
|
||||
int32_t getUIColorHash() const;
|
||||
|
||||
static Color createSemanticColor(std::vector<std::string>& semanticItems);
|
||||
|
||||
std::shared_ptr<void> getUIColor() const {
|
||||
return uiColor_;
|
||||
}
|
||||
@@ -48,7 +52,9 @@ struct Color {
|
||||
}
|
||||
|
||||
private:
|
||||
Color(std::shared_ptr<void> uiColor);
|
||||
std::shared_ptr<void> uiColor_;
|
||||
int32_t uiColorHashValue_;
|
||||
};
|
||||
|
||||
namespace HostPlatformColor {
|
||||
@@ -59,7 +65,7 @@ namespace HostPlatformColor {
|
||||
#define NO_DESTROY
|
||||
#endif
|
||||
|
||||
NO_DESTROY static const facebook::react::Color UndefinedColor = Color(nullptr);
|
||||
NO_DESTROY static const facebook::react::Color UndefinedColor = Color();
|
||||
} // namespace HostPlatformColor
|
||||
|
||||
inline Color
|
||||
@@ -103,8 +109,6 @@ inline float blueFromHostPlatformColor(Color color) {
|
||||
template <>
|
||||
struct std::hash<facebook::react::Color> {
|
||||
size_t operator()(const facebook::react::Color& color) const {
|
||||
auto seed = size_t{0};
|
||||
facebook::react::hash_combine(seed, color.getColor());
|
||||
return seed;
|
||||
return color.getUIColorHash();
|
||||
}
|
||||
};
|
||||
|
||||
+114
-16
@@ -9,6 +9,8 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <react/renderer/graphics/RCTPlatformColorUtils.h>
|
||||
#import <react/utils/ManagedObjectWrapper.h>
|
||||
#import <string>
|
||||
|
||||
@@ -19,13 +21,30 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
namespace facebook::react {
|
||||
|
||||
namespace {
|
||||
|
||||
bool UIColorIsP3ColorSpace(const std::shared_ptr<void> &uiColor)
|
||||
{
|
||||
UIColor *color = unwrapManagedObject(uiColor);
|
||||
CGColorSpaceRef colorSpace = CGColorGetColorSpace(color.CGColor);
|
||||
|
||||
if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelRGB) {
|
||||
CFStringRef name = CGColorSpaceGetName(colorSpace);
|
||||
if (name != NULL && CFEqual(name, kCGColorSpaceDisplayP3)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UIColor *_Nullable UIColorFromInt32(int32_t intColor)
|
||||
{
|
||||
CGFloat a = CGFloat((intColor >> 24) & 0xFF) / 255.0;
|
||||
CGFloat r = CGFloat((intColor >> 16) & 0xFF) / 255.0;
|
||||
CGFloat g = CGFloat((intColor >> 8) & 0xFF) / 255.0;
|
||||
CGFloat b = CGFloat(intColor & 0xFF) / 255.0;
|
||||
return [UIColor colorWithRed:r green:g blue:b alpha:a];
|
||||
|
||||
UIColor *color = [UIColor colorWithRed:r green:g blue:b alpha:a];
|
||||
return color;
|
||||
}
|
||||
|
||||
UIColor *_Nullable UIColorFromDynamicColor(const facebook::react::DynamicColor &dynamicColor)
|
||||
@@ -64,64 +83,132 @@ UIColor *_Nullable UIColorFromDynamicColor(const facebook::react::DynamicColor &
|
||||
return nil;
|
||||
}
|
||||
|
||||
int32_t ColorFromUIColor(UIColor *color)
|
||||
int32_t ColorFromColorComponents(const facebook::react::ColorComponents &components)
|
||||
{
|
||||
float ratio = 255;
|
||||
CGFloat rgba[4];
|
||||
[color getRed:&rgba[0] green:&rgba[1] blue:&rgba[2] alpha:&rgba[3]];
|
||||
return ((int32_t)round((float)rgba[3] * ratio) & 0xff) << 24 | ((int)round((float)rgba[0] * ratio) & 0xff) << 16 |
|
||||
((int)round((float)rgba[1] * ratio) & 0xff) << 8 | ((int)round((float)rgba[2] * ratio) & 0xff);
|
||||
auto color = ((int32_t)round((float)components.alpha * ratio) & 0xff) << 24 |
|
||||
((int)round((float)components.red * ratio) & 0xff) << 16 |
|
||||
((int)round((float)components.green * ratio) & 0xff) << 8 | ((int)round((float)components.blue * ratio) & 0xff);
|
||||
return color;
|
||||
}
|
||||
|
||||
int32_t ColorFromUIColor(const std::shared_ptr<void> &uiColor)
|
||||
int32_t ColorFromUIColor(UIColor *color)
|
||||
{
|
||||
CGFloat rgba[4];
|
||||
[color getRed:&rgba[0] green:&rgba[1] blue:&rgba[2] alpha:&rgba[3]];
|
||||
return ColorFromColorComponents({(float)rgba[0], (float)rgba[1], (float)rgba[2], (float)rgba[3]});
|
||||
}
|
||||
|
||||
int32_t ColorFromUIColorForSpecificTraitCollection(
|
||||
const std::shared_ptr<void> &uiColor,
|
||||
UITraitCollection *traitCollection)
|
||||
{
|
||||
UIColor *color = (UIColor *)unwrapManagedObject(uiColor);
|
||||
if (color) {
|
||||
UITraitCollection *currentTraitCollection = [UITraitCollection currentTraitCollection];
|
||||
color = [color resolvedColorWithTraitCollection:currentTraitCollection];
|
||||
color = [color resolvedColorWithTraitCollection:traitCollection];
|
||||
return ColorFromUIColor(color);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t ColorFromUIColor(const std::shared_ptr<void> &uiColor)
|
||||
{
|
||||
return ColorFromUIColorForSpecificTraitCollection(uiColor, [UITraitCollection currentTraitCollection]);
|
||||
}
|
||||
|
||||
UIColor *_Nullable UIColorFromComponentsColor(const facebook::react::ColorComponents &components)
|
||||
{
|
||||
UIColor *uiColor = nil;
|
||||
if (components.colorSpace == ColorSpace::DisplayP3) {
|
||||
return [UIColor colorWithDisplayP3Red:components.red
|
||||
green:components.green
|
||||
blue:components.blue
|
||||
alpha:components.alpha];
|
||||
uiColor = [UIColor colorWithDisplayP3Red:components.red
|
||||
green:components.green
|
||||
blue:components.blue
|
||||
alpha:components.alpha];
|
||||
} else {
|
||||
uiColor = [UIColor colorWithRed:components.red green:components.green blue:components.blue alpha:components.alpha];
|
||||
}
|
||||
return [UIColor colorWithRed:components.red green:components.green blue:components.blue alpha:components.alpha];
|
||||
|
||||
return uiColor;
|
||||
}
|
||||
|
||||
int32_t hashFromUIColor(const std::shared_ptr<void> &uiColor)
|
||||
{
|
||||
if (uiColor == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UITraitCollection *darkModeTraitCollection =
|
||||
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark];
|
||||
auto darkColor = ColorFromUIColorForSpecificTraitCollection(uiColor, darkModeTraitCollection);
|
||||
|
||||
static UITraitCollection *lightModeTraitCollection =
|
||||
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight];
|
||||
auto lightColor = ColorFromUIColorForSpecificTraitCollection(uiColor, lightModeTraitCollection);
|
||||
|
||||
static UITraitCollection *darkModeAccessibilityContrastTraitCollection =
|
||||
[UITraitCollection traitCollectionWithTraitsFromCollections:@[
|
||||
darkModeTraitCollection,
|
||||
[UITraitCollection traitCollectionWithAccessibilityContrast:UIAccessibilityContrastHigh]
|
||||
]];
|
||||
auto darkAccessibilityContrastColor =
|
||||
ColorFromUIColorForSpecificTraitCollection(uiColor, darkModeAccessibilityContrastTraitCollection);
|
||||
|
||||
static UITraitCollection *lightModeAccessibilityContrastTraitCollection =
|
||||
[UITraitCollection traitCollectionWithTraitsFromCollections:@[
|
||||
lightModeTraitCollection,
|
||||
[UITraitCollection traitCollectionWithAccessibilityContrast:UIAccessibilityContrastHigh]
|
||||
]];
|
||||
auto lightAccessibilityContrastColor =
|
||||
ColorFromUIColorForSpecificTraitCollection(uiColor, lightModeAccessibilityContrastTraitCollection);
|
||||
return facebook::react::hash_combine(
|
||||
darkColor,
|
||||
lightColor,
|
||||
darkAccessibilityContrastColor,
|
||||
lightAccessibilityContrastColor,
|
||||
UIColorIsP3ColorSpace(uiColor));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
Color::Color(int32_t color)
|
||||
{
|
||||
uiColor_ = wrapManagedObject(UIColorFromInt32(color));
|
||||
uiColorHashValue_ = facebook::react::hash_combine(color, 0);
|
||||
}
|
||||
|
||||
Color::Color(const DynamicColor &dynamicColor)
|
||||
{
|
||||
uiColor_ = wrapManagedObject(UIColorFromDynamicColor(dynamicColor));
|
||||
uiColorHashValue_ = facebook::react::hash_combine(
|
||||
dynamicColor.darkColor,
|
||||
dynamicColor.lightColor,
|
||||
dynamicColor.highContrastDarkColor,
|
||||
dynamicColor.highContrastLightColor,
|
||||
0);
|
||||
}
|
||||
|
||||
Color::Color(const ColorComponents &components)
|
||||
{
|
||||
uiColor_ = wrapManagedObject(UIColorFromComponentsColor(components));
|
||||
uiColorHashValue_ = facebook::react::hash_combine(
|
||||
ColorFromColorComponents(components), components.colorSpace == ColorSpace::DisplayP3);
|
||||
}
|
||||
|
||||
Color::Color(std::shared_ptr<void> uiColor)
|
||||
{
|
||||
UIColor *color = ((UIColor *)unwrapManagedObject(uiColor));
|
||||
if (color) {
|
||||
auto colorHash = hashFromUIColor(uiColor);
|
||||
uiColorHashValue_ = colorHash;
|
||||
}
|
||||
uiColor_ = std::move(uiColor);
|
||||
}
|
||||
|
||||
bool Color::operator==(const Color &other) const
|
||||
{
|
||||
return (!uiColor_ && !other.uiColor_) ||
|
||||
(uiColor_ && other.uiColor_ &&
|
||||
[unwrapManagedObject(getUIColor()) isEqual:unwrapManagedObject(other.getUIColor())]);
|
||||
(uiColor_ && other.uiColor_ && (uiColorHashValue_ == other.uiColorHashValue_));
|
||||
}
|
||||
|
||||
bool Color::operator!=(const Color &other) const
|
||||
@@ -142,6 +229,17 @@ float Color::getChannel(int channelId) const
|
||||
return static_cast<float>(rgba[channelId]);
|
||||
}
|
||||
|
||||
int32_t Color::getUIColorHash() const
|
||||
{
|
||||
return uiColorHashValue_;
|
||||
}
|
||||
|
||||
Color Color::createSemanticColor(std::vector<std::string> &semanticItems)
|
||||
{
|
||||
auto semanticColor = RCTPlatformColorFromSemanticItems(semanticItems);
|
||||
return Color(wrapManagedObject(semanticColor));
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ SharedColor parsePlatformColor(const ContextContainer &contextContainer, int32_t
|
||||
auto items = (std::unordered_map<std::string, RawValue>)value;
|
||||
if (items.find("semantic") != items.end() && items.at("semantic").hasType<std::vector<std::string>>()) {
|
||||
auto semanticItems = (std::vector<std::string>)items.at("semantic");
|
||||
return {wrapManagedObject(RCTPlatformColorFromSemanticItems(semanticItems))};
|
||||
return SharedColor(Color::createSemanticColor(semanticItems));
|
||||
} else if (
|
||||
items.find("dynamic") != items.end() &&
|
||||
items.at("dynamic").hasType<std::unordered_map<std::string, RawValue>>()) {
|
||||
|
||||
+7
-1
@@ -8,9 +8,15 @@
|
||||
#pragma once
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <react/renderer/graphics/HostPlatformColor.h>
|
||||
#import <vector>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
struct ColorComponents;
|
||||
struct Color;
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
||||
facebook::react::ColorComponents RCTPlatformColorComponentsFromSemanticItems(
|
||||
std::vector<std::string>& semanticItems);
|
||||
UIColor* RCTPlatformColorFromSemanticItems(
|
||||
|
||||
+1
@@ -9,6 +9,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <react/renderer/graphics/HostPlatformColor.h>
|
||||
#import <react/utils/ManagedObjectWrapper.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
Reference in New Issue
Block a user