Skip to content
Closed
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 @@ -162,6 +162,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
fontSize: true,
fontStyle: true,
fontVariant: {process: processFontVariant},
fontVariationSettings: true,
fontWeight: true,
includeFontPadding: true,
letterSpacing: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,7 @@ export type ____TextStyle_InternalCore = $ReadOnly<{
fontStyle?: 'normal' | 'italic',
fontWeight?: ____FontWeight_Internal,
fontVariant?: ____FontVariantArray_Internal | string,
fontVariationSettings?: string,
textShadowOffset?: $ReadOnly<{
width: number,
height: number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ - (RCTShadowView *)shadowView
RCT_REMAP_SHADOW_PROPERTY(fontWeight, textAttributes.fontWeight, NSString)
RCT_REMAP_SHADOW_PROPERTY(fontStyle, textAttributes.fontStyle, NSString)
RCT_REMAP_SHADOW_PROPERTY(fontVariant, textAttributes.fontVariant, NSArray)
RCT_REMAP_SHADOW_PROPERTY(fontVariationSettings, textAttributes.fontVariationSettings, NSString)
RCT_REMAP_SHADOW_PROPERTY(allowFontScaling, textAttributes.allowFontScaling, BOOL)
RCT_REMAP_SHADOW_PROPERTY(dynamicTypeRamp, textAttributes.dynamicTypeRamp, RCTDynamicTypeRamp)
RCT_REMAP_SHADOW_PROPERTY(maxFontSizeMultiplier, textAttributes.maxFontSizeMultiplier, CGFloat)
Expand Down
1 change: 1 addition & 0 deletions packages/react-native/Libraries/Text/RCTTextAttributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ extern NSString *const RCTTextAttributesTagAttributeName;
@property (nonatomic, copy, nullable) NSString *fontWeight;
@property (nonatomic, copy, nullable) NSString *fontStyle;
@property (nonatomic, copy, nullable) NSArray<NSString *> *fontVariant;
@property (nonatomic, copy, nullable) NSString *fontVariationSettings;
@property (nonatomic, assign) BOOL allowFontScaling;
@property (nonatomic, assign) RCTDynamicTypeRamp dynamicTypeRamp;
@property (nonatomic, assign) CGFloat letterSpacing;
Expand Down
2 changes: 2 additions & 0 deletions packages/react-native/Libraries/Text/RCTTextAttributes.mm
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ - (void)applyTextAttributes:(RCTTextAttributes *)textAttributes
_fontWeight = textAttributes->_fontWeight ?: _fontWeight;
_fontStyle = textAttributes->_fontStyle ?: _fontStyle;
_fontVariant = textAttributes->_fontVariant ?: _fontVariant;
_fontVariationSettings = textAttributes->_fontVariationSettings ?: _fontVariationSettings;
_allowFontScaling = textAttributes->_allowFontScaling || _allowFontScaling; // *
_dynamicTypeRamp = textAttributes->_dynamicTypeRamp != RCTDynamicTypeRampUndefined ? textAttributes->_dynamicTypeRamp
: _dynamicTypeRamp;
Expand Down Expand Up @@ -223,6 +224,7 @@ - (UIFont *)effectiveFont
weight:_fontWeight
style:_fontStyle
variant:_fontVariant
fontVariationSettings:_fontVariationSettings
scaleMultiplier:self.effectiveFontSizeMultiplier];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7773,6 +7773,7 @@ export type ____TextStyle_InternalCore = $ReadOnly<{
fontStyle?: \\"normal\\" | \\"italic\\",
fontWeight?: ____FontWeight_Internal,
fontVariant?: ____FontVariantArray_Internal | string,
fontVariationSettings?: string,
textShadowOffset?: $ReadOnly<{
width: number,
height: number,
Expand Down
1 change: 1 addition & 0 deletions packages/react-native/React/Views/RCTFont.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ RCT_EXTERN BOOL RCTHasFontHandlerSet(void);
weight:(NSString *)weight
style:(NSString *)style
variant:(NSArray<NSString *> *)variant
fontVariationSettings:(NSString *)fontVariationSettings
scaleMultiplier:(CGFloat)scaleMultiplier;

+ (UIFont *)updateFont:(UIFont *)font withFamily:(NSString *)family;
Expand Down
79 changes: 75 additions & 4 deletions packages/react-native/React/Views/RCTFont.mm
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ + (UIFont *)UIFont:(id)json
weight:[RCTConvert NSString:json[@"fontWeight"]]
style:[RCTConvert NSString:json[@"fontStyle"]]
variant:[RCTConvert NSStringArray:json[@"fontVariant"]]
fontVariationSettings:[RCTConvert NSString:json[@"fontVariationSettings"]]
scaleMultiplier:1];
}

Expand Down Expand Up @@ -378,12 +379,27 @@ + (RCTFontVariantDescriptor *)RCTFontVariantDescriptor:(id)json

@implementation RCTFont

+ (NSNumber *)openTypeTagToNumber:(NSString *)tag {
if (tag.length != 4) {
return nil;
}

NSData *data = [tag dataUsingEncoding:NSUTF8StringEncoding];
const char *bytes = (const char *)[data bytes];

uint32_t value = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];

return @(value);
}


+ (UIFont *)updateFont:(UIFont *)font
withFamily:(NSString *)family
size:(NSNumber *)size
weight:(NSString *)weight
style:(NSString *)style
variant:(NSArray<RCTFontVariantDescriptor *> *)variant
fontVariationSettings:(NSString *)fontVariationSettings
scaleMultiplier:(CGFloat)scaleMultiplier
{
// Defaults
Expand Down Expand Up @@ -499,27 +515,82 @@ + (UIFont *)updateFont:(UIFont *)font
font = [UIFont fontWithDescriptor:fontDescriptor size:fontSize];
}

if (fontVariationSettings) {
NSArray<NSString *> *variationSettings = [fontVariationSettings componentsSeparatedByString:@","];
for (NSString *variationSetting in variationSettings) {
NSString *trimmedSetting = [variationSetting stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSArray<NSString *> *setting = [trimmedSetting componentsSeparatedByString:@" "];

if (setting.count != 2) {
NSLog(@"Error: Setting does not contain exactly 2 components. Setting: %@", setting);
continue;
}

NSString *attribute = [[[setting[0]
stringByReplacingOccurrencesOfString:@"\"" withString:@""]
stringByReplacingOccurrencesOfString:@"\'" withString:@""]
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

NSString *value = [setting[1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

if (attribute.length == 0 || value.length == 0) {
NSLog(@"Error: Invalid attribute or value. Attribute: %@, Value: %@", attribute, value);
continue;
}

NSNumber *tag = [RCTFont openTypeTagToNumber:attribute];
if (!tag) {
NSLog(@"Error: Invalid attribute in fontVariationSettings: %@", attribute);
continue;
}

NSNumber *valueNumber = @([value intValue]);
NSDictionary<NSNumber *, NSNumber *> *variations = @{tag: valueNumber};

UIFontDescriptor *fontDescriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:@{
UIFontDescriptorNameAttribute: familyName,
(NSString *)kCTFontVariationAttribute: variations
}];

if (!fontDescriptor) {
NSLog(@"Error: Could not create font descriptor with variations. Variations: %@", variations);
continue;
}

UIFontDescriptor *existingFontDescriptors = font.fontDescriptor;
UIFontDescriptor *mergedFontDescriptor = [existingFontDescriptors fontDescriptorByAddingAttributes:fontDescriptor.fontAttributes];
font = [UIFont fontWithDescriptor:mergedFontDescriptor size:fontSize];
}
}

return font;
}

+ (UIFont *)updateFont:(UIFont *)font withFamily:(NSString *)family
{
return [self updateFont:font withFamily:family size:nil weight:nil style:nil variant:nil scaleMultiplier:1];
return [self updateFont:font withFamily:family size:nil weight:nil style:nil variant:nil fontVariationSettings:nil scaleMultiplier:1];
}

+ (UIFont *)updateFont:(UIFont *)font withSize:(NSNumber *)size
{
return [self updateFont:font withFamily:nil size:size weight:nil style:nil variant:nil scaleMultiplier:1];
return [self updateFont:font withFamily:nil size:size weight:nil style:nil variant:nil fontVariationSettings:nil scaleMultiplier:1];
}

+ (UIFont *)updateFont:(UIFont *)font withWeight:(NSString *)weight
{
return [self updateFont:font withFamily:nil size:nil weight:weight style:nil variant:nil scaleMultiplier:1];
return [self updateFont:font withFamily:nil size:nil weight:weight style:nil variant:nil fontVariationSettings:nil scaleMultiplier:1];
}

+ (UIFont *)updateFont:(UIFont *)font withStyle:(NSString *)style
{
return [self updateFont:font withFamily:nil size:nil weight:nil style:style variant:nil scaleMultiplier:1];
return [self updateFont:font withFamily:nil size:nil weight:nil style:style variant:nil fontVariationSettings:nil scaleMultiplier:1];
}

+ (UIFont *)updateFont:(UIFont *)font withFontVariationSettings:(NSString *)fontVariationSettings
{
return [self updateFont:font withFamily:nil size:nil weight:nil style:nil variant:nil fontVariationSettings:fontVariationSettings scaleMultiplier:1];
}



@end
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ void TextAttributes::apply(TextAttributes textAttributes) {
fontVariant = textAttributes.fontVariant.has_value()
? textAttributes.fontVariant
: fontVariant;
fontVariationSettings = !textAttributes.fontVariationSettings.empty()
? textAttributes.fontVariationSettings : fontVariationSettings;
allowFontScaling = textAttributes.allowFontScaling.has_value()
? textAttributes.allowFontScaling
: allowFontScaling;
Expand Down Expand Up @@ -124,6 +126,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const {
fontWeight,
fontStyle,
fontVariant,
fontVariationSettings,
allowFontScaling,
dynamicTypeRamp,
alignment,
Expand All @@ -148,6 +151,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const {
rhs.fontWeight,
rhs.fontStyle,
rhs.fontVariant,
rhs.fontVariationSettings,
rhs.allowFontScaling,
rhs.dynamicTypeRamp,
rhs.alignment,
Expand Down Expand Up @@ -207,6 +211,7 @@ SharedDebugStringConvertibleList TextAttributes::getDebugProps() const {
debugStringConvertibleItem("fontWeight", fontWeight),
debugStringConvertibleItem("fontStyle", fontStyle),
debugStringConvertibleItem("fontVariant", fontVariant),
debugStringConvertibleItem("fontVariationSettings", fontVariationSettings),
debugStringConvertibleItem("allowFontScaling", allowFontScaling),
debugStringConvertibleItem("dynamicTypeRamp", dynamicTypeRamp),
debugStringConvertibleItem("letterSpacing", letterSpacing),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class TextAttributes : public DebugStringConvertible {
std::optional<FontWeight> fontWeight{};
std::optional<FontStyle> fontStyle{};
std::optional<FontVariant> fontVariant{};
std::string fontVariationSettings{""};
std::optional<bool> allowFontScaling{};
std::optional<DynamicTypeRamp> dynamicTypeRamp{};
Float letterSpacing{std::numeric_limits<Float>::quiet_NaN()};
Expand Down Expand Up @@ -120,6 +121,7 @@ struct hash<facebook::react::TextAttributes> {
textAttributes.fontWeight,
textAttributes.fontStyle,
textAttributes.fontVariant,
textAttributes.fontVariationSettings,
textAttributes.allowFontScaling,
textAttributes.letterSpacing,
textAttributes.textTransform,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ static TextAttributes convertRawProp(
"fontVariant",
sourceTextAttributes.fontVariant,
defaultTextAttributes.fontVariant);
textAttributes.fontVariationSettings = convertRawProp(
context,
rawProps,
"fontVariationSettings",
sourceTextAttributes.fontVariationSettings,
defaultTextAttributes.fontVariationSettings);

textAttributes.allowFontScaling = convertRawProp(
context,
rawProps,
Expand Down Expand Up @@ -258,6 +265,8 @@ void BaseTextProps::setProp(
defaults, value, textAttributes, fontStyle, "fontStyle");
REBUILD_FIELD_SWITCH_CASE(
defaults, value, textAttributes, fontVariant, "fontVariant");
REBUILD_FIELD_SWITCH_CASE(
defaults, value, textAttributes, fontVariationSettings, "fontVariationSettings");
REBUILD_FIELD_SWITCH_CASE(
defaults, value, textAttributes, allowFontScaling, "allowFontScaling");
REBUILD_FIELD_SWITCH_CASE(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ inline bool areTextAttributesEquivalentLayoutWise(
lhs.fontWeight,
lhs.fontStyle,
lhs.fontVariant,
lhs.fontVariationSettings,
lhs.allowFontScaling,
lhs.dynamicTypeRamp,
lhs.alignment) ==
Expand All @@ -101,6 +102,7 @@ inline bool areTextAttributesEquivalentLayoutWise(
rhs.fontWeight,
rhs.fontStyle,
rhs.fontVariant,
rhs.fontVariationSettings,
rhs.allowFontScaling,
rhs.dynamicTypeRamp,
rhs.alignment) &&
Expand All @@ -121,6 +123,7 @@ inline size_t textAttributesHashLayoutWise(
textAttributes.fontWeight,
textAttributes.fontStyle,
textAttributes.fontVariant,
textAttributes.fontVariationSettings,
textAttributes.allowFontScaling,
textAttributes.dynamicTypeRamp,
textAttributes.letterSpacing,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex
inline static UIFont *RCTEffectiveFontFromTextAttributes(const TextAttributes &textAttributes)
{
NSString *fontFamily = [NSString stringWithUTF8String:textAttributes.fontFamily.c_str()];
NSString *fontVariationSettings = [NSString stringWithUTF8String:textAttributes.fontVariationSettings.c_str()];

RCTFontProperties fontProperties;
fontProperties.family = fontFamily;
Expand All @@ -146,6 +147,8 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex
fontProperties.variant = textAttributes.fontVariant.has_value()
? RCTFontVariantFromFontVariant(textAttributes.fontVariant.value())
: RCTFontVariantUndefined;
fontProperties.fontVariationSettings = fontVariationSettings;

fontProperties.weight = textAttributes.fontWeight.has_value()
? RCTUIFontWeightFromInteger((NSInteger)textAttributes.fontWeight.value())
: NAN;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct RCTFontProperties {
UIFontWeight weight = NAN;
RCTFontStyle style = RCTFontStyleUndefined;
RCTFontVariant variant = RCTFontVariantUndefined;
NSString *fontVariationSettings = nil;
CGFloat sizeMultiplier = NAN;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ static RCTFontProperties RCTDefaultFontProperties()
return defaultFontProperties;
}

static NSNumber *openTypeTagToNumber(NSString *tag) {
if (tag.length != 4) {
NSLog(@"Error: Tag must be exactly 4 characters long");
return nil;
}

const unsigned char* bytes = (const unsigned char*)[tag cStringUsingEncoding:NSUTF8StringEncoding];

uint32_t value = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];

return @(value);
}

static RCTFontProperties RCTResolveFontProperties(
RCTFontProperties fontProperties,
RCTFontProperties baseFontProperties)
Expand Down Expand Up @@ -207,6 +220,53 @@ static RCTFontStyle RCTGetFontStyle(UIFont *font)
fontDescriptorByAddingAttributes:@{UIFontDescriptorFeatureSettingsAttribute : fontFeatures}];
font = [UIFont fontWithDescriptor:fontDescriptor size:effectiveFontSize];
}


if (fontProperties.fontVariationSettings) {
NSArray<NSString *> *variationSettings = [fontProperties.fontVariationSettings componentsSeparatedByString:@","];
for (NSString *variationSetting in variationSettings) {
NSString *trimmedSetting = [variationSetting stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSArray<NSString *> *setting = [trimmedSetting componentsSeparatedByString:@" "];

if (setting.count != 2) {
NSLog(@"Error: Setting does not contain exactly 2 components. Setting: %@", setting);
continue;
}

NSString *attribute = [[[setting[0]
stringByReplacingOccurrencesOfString:@"\"" withString:@""]
stringByReplacingOccurrencesOfString:@"\'" withString:@""]
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

NSString *value = [setting[1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

if (attribute.length == 0 || value.length == 0) {
NSLog(@"Error: Invalid attribute or value. Attribute: %@, Value: %@", attribute, value);
continue;
}

NSNumber *tag = openTypeTagToNumber(attribute);
if (!tag) {
NSLog(@"Error: Invalid attribute in fontVariationSettings: %@", attribute);
continue;
}

NSNumber *valueNumber = @([value intValue]);
NSDictionary<NSNumber *, NSNumber *> *variations = @{tag: valueNumber};

UIFontDescriptor *fontDescriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:@{
UIFontDescriptorNameAttribute: fontProperties.family,
(NSString *)kCTFontVariationAttribute: variations
}];

if (!fontDescriptor) {
NSLog(@"Error: Could not create font descriptor with variations. Variations: %@", variations);
continue;
}

UIFontDescriptor *existingFontDescriptors = font.fontDescriptor;
UIFontDescriptor *mergedFontDescriptor = [existingFontDescriptors fontDescriptorByAddingAttributes:fontDescriptor.fontAttributes];
font = [UIFont fontWithDescriptor:mergedFontDescriptor size:effectiveFontSize];
}
}
return font;
}
Binary file added packages/rn-tester/MaterialSymbolsSharp.ttf
Binary file not shown.
5 changes: 5 additions & 0 deletions packages/rn-tester/RNTester/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
<string>You need to add NSLocationWhenInUseUsageDescription key in Info.plist to enable geolocation, otherwise it is going to *fail silently*!</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>You need to add NSPhotoLibraryUsageDescription key in Info.plist to enable photo library usage, otherwise it is going to *fail silently*!</string>
<key>UIAppFonts</key>
<array>
<string>Inter.ttf</string>
<string>MaterialSymbolsSharp.ttf</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
Expand Down
Binary file added packages/rn-tester/RNTester/Inter.ttf
Binary file not shown.
Loading