Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ struct Color {
int32_t getColor() const;
std::size_t getUIColorHash() const;

// Returns the UndefinedColor sentinel (null underlying UIColor) on a miss, so
// callers can tell a miss from a name that resolves to transparent. Callers
// reaching into getUIColor() must null-check it.
static Color createSemanticColor(std::vector<std::string> &semanticItems);

std::shared_ptr<void> getUIColor() const
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,12 @@ int32_t ColorFromUIColor(const std::shared_ptr<void> &uiColor)

Color Color::createSemanticColor(std::vector<std::string> &semanticItems)
{
auto semanticColor = RCTPlatformColorFromSemanticItems(semanticItems);
UIColor *semanticColor = RCTPlatformColorFromSemanticItemsOrNil(semanticItems);
if (semanticColor == nil) {
// Undefined-color sentinel on a miss, distinct from a name that resolves to
// transparent (getColor() is still 0, preserving the old render).
return HostPlatformColor::UndefinedColor;
}
return Color(wrapManagedObject(semanticColor));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
#import "PlatformColorParser.h"

#import <react/renderer/core/RawValue.h>
#import <react/renderer/css/CSSColor.h>
#import <react/renderer/css/CSSValueParser.h>
#import <react/renderer/graphics/Color.h>
#import <react/renderer/graphics/HostPlatformColor.h>
#import <react/renderer/graphics/RCTPlatformColorUtils.h>
#import <react/utils/ManagedObjectWrapper.h>
#import <optional>
#import <string>
#import <unordered_map>

Expand Down Expand Up @@ -51,13 +55,39 @@
return SharedColor(color);
}

// nullopt only on a parse failure, so a fallback that resolves to transparent is
// still honored.
static std::optional<SharedColor> fallbackColorFromString(const std::string &fallbackString)
{
auto cssColor = parseCSSProperty<CSSColor>(fallbackString);
if (std::holds_alternative<CSSColor>(cssColor)) {
const auto &c = std::get<CSSColor>(cssColor);
return colorFromRGBA(c.r, c.g, c.b, c.a);
}
return std::nullopt;
}

SharedColor parsePlatformColor(const ContextContainer &contextContainer, int32_t surfaceId, const RawValue &value)
{
if (value.hasType<std::unordered_map<std::string, RawValue>>()) {
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 SharedColor(Color::createSemanticColor(semanticItems));
auto semanticColor = SharedColor(Color::createSemanticColor(semanticItems));
// The sentinel (null UIColor) means a true miss; apply the fallback only
// then, not when a name resolves to transparent.
if (!semanticColor) {
if (items.find("fallback") != items.end() && items.at("fallback").hasType<std::string>()) {
auto fallbackColor = fallbackColorFromString((std::string)items.at("fallback"));
// has_value(), not != 0, so a transparent fallback is kept.
if (fallbackColor.has_value()) {
return *fallbackColor;
}
}
// Miss with no usable fallback: clearColor, never leaking the sentinel.
return clearColor();
}
return semanticColor;
} else if (
items.find("dynamic") != items.end() &&
items.at("dynamic").hasType<std::unordered_map<std::string, RawValue>>()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ struct ColorComponents;
struct Color;
} // namespace facebook::react

NS_ASSUME_NONNULL_BEGIN

facebook::react::ColorComponents RCTPlatformColorComponentsFromSemanticItems(std::vector<std::string> &semanticItems);
UIColor *RCTPlatformColorFromSemanticItems(std::vector<std::string> &semanticItems);
// Like RCTPlatformColorFromSemanticItems but returns nil on a miss, so callers
// can tell a miss from a name that resolves to transparent.
UIColor *_Nullable RCTPlatformColorFromSemanticItemsOrNil(std::vector<std::string> &semanticItems);
// Precondition: `color` is a resolved color, never the miss sentinel, so the
// result stays _Nonnull.
UIColor *RCTPlatformColorFromColor(const facebook::react::Color &color);

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@
return _ColorComponentsFromUIColor(RCTPlatformColorFromSemanticItems(semanticItems));
}

UIColor *RCTPlatformColorFromSemanticItems(std::vector<std::string> &semanticItems)
UIColor *_Nullable RCTPlatformColorFromSemanticItemsOrNil(std::vector<std::string> &semanticItems)
{
for (const auto &semanticCString : semanticItems) {
NSString *semanticNSString = _NSStringFromCString(semanticCString);
Expand All @@ -206,7 +206,15 @@
}
}

return UIColor.clearColor;
return nil;
}

UIColor *RCTPlatformColorFromSemanticItems(std::vector<std::string> &semanticItems)
{
// Non-null contract (e.g. for RCTPlatformColorComponentsFromSemanticItems);
// callers needing to detect a miss use the OrNil variant.
UIColor *uiColor = RCTPlatformColorFromSemanticItemsOrNil(semanticItems);
return uiColor != nil ? uiColor : UIColor.clearColor;
}

UIColor *RCTPlatformColorFromColor(const facebook::react::Color &color)
Expand Down
Loading