mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Fabric: Fixes UB/broken font weight management on iOS
Summary: Address Sanitizer told me that I have UB in `RCTUIFontWeightFromFloat` and it was right. After a short investigation, I find out that the original assumption that `UIFontWeight` values are practically numbers from 100 to 900 was incorrect. In my simulator, it's something like from `-1` to `+1` (irregularly!). So, the whole subsystem worked only by accident. This diff fixes that; now we never assume which actual values `UIFontWeight` constants have. I will publish code style fixes as a separate diff (otherwise it will be really hard to review). Reviewed By: JoshuaGross Differential Revision: D15756620 fbshipit-source-id: d7f888e85815d863487c6b68a960e39fd473e095
This commit is contained in:
committed by
Facebook Github Bot
parent
3bf068ac93
commit
c34e554275
@@ -32,6 +32,23 @@ using namespace facebook::react;
|
||||
|
||||
@end
|
||||
|
||||
inline static UIFontWeight RCTUIFontWeightFromInteger(NSInteger fontWeight) {
|
||||
assert(fontWeight > 50);
|
||||
assert(fontWeight < 950);
|
||||
|
||||
static UIFontWeight weights[] = {/* ~100 */ UIFontWeightUltraLight,
|
||||
/* ~200 */ UIFontWeightThin,
|
||||
/* ~300 */ UIFontWeightLight,
|
||||
/* ~400 */ UIFontWeightRegular,
|
||||
/* ~500 */ UIFontWeightMedium,
|
||||
/* ~600 */ UIFontWeightSemibold,
|
||||
/* ~700 */ UIFontWeightBold,
|
||||
/* ~800 */ UIFontWeightHeavy,
|
||||
/* ~900 */ UIFontWeightBlack};
|
||||
// The expression is designed to convert something like 760 or 830 to 7.
|
||||
return weights[(fontWeight + 50) / 100 - 1];
|
||||
}
|
||||
|
||||
inline static UIFont *RCTEffectiveFontFromTextAttributes(
|
||||
const TextAttributes &textAttributes) {
|
||||
NSString *fontFamily =
|
||||
@@ -46,9 +63,9 @@ inline static UIFont *RCTEffectiveFontFromTextAttributes(
|
||||
: RCTFontStyleUndefined;
|
||||
fontProperties.variant = textAttributes.fontVariant.hasValue()
|
||||
? RCTFontVariantFromFontVariant(textAttributes.fontVariant.value())
|
||||
: RCTFontVariantDefault;
|
||||
: RCTFontVariantUndefined;
|
||||
fontProperties.weight = textAttributes.fontWeight.hasValue()
|
||||
? CGFloat(textAttributes.fontWeight.value())
|
||||
? RCTUIFontWeightFromInteger((NSInteger)textAttributes.fontWeight.value())
|
||||
: NAN;
|
||||
fontProperties.sizeMultiplier = textAttributes.fontSizeMultiplier;
|
||||
|
||||
|
||||
@@ -27,12 +27,12 @@ typedef NS_OPTIONS(NSInteger, RCTFontVariant) {
|
||||
};
|
||||
|
||||
struct RCTFontProperties {
|
||||
NSString *family;
|
||||
CGFloat size;
|
||||
UIFontWeight weight;
|
||||
RCTFontStyle style;
|
||||
RCTFontVariant variant;
|
||||
CGFloat sizeMultiplier;
|
||||
NSString *family = nil;
|
||||
CGFloat size = NAN;
|
||||
UIFontWeight weight = NAN;
|
||||
RCTFontStyle style = RCTFontStyleUndefined;
|
||||
RCTFontVariant variant = RCTFontVariantUndefined;
|
||||
CGFloat sizeMultiplier = NAN;
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -9,15 +9,18 @@
|
||||
|
||||
#import <cmath>
|
||||
#import <mutex>
|
||||
#import <algorithm>
|
||||
#import <limits>
|
||||
|
||||
static RCTFontProperties RCTDefaultFontProperties() {
|
||||
static RCTFontProperties defaultFontProperties;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
defaultFontProperties.size = 14;
|
||||
defaultFontProperties.family =
|
||||
[UIFont systemFontOfSize:defaultFontProperties.size].familyName;
|
||||
defaultFontProperties.size = 14;
|
||||
defaultFontProperties.weight = UIFontWeightRegular;
|
||||
defaultFontProperties.style = RCTFontStyleNormal;
|
||||
defaultFontProperties.variant = RCTFontVariantDefault;
|
||||
defaultFontProperties.sizeMultiplier = 1.0;
|
||||
@@ -27,24 +30,22 @@ static RCTFontProperties RCTDefaultFontProperties() {
|
||||
}
|
||||
|
||||
static RCTFontProperties RCTResolveFontProperties(
|
||||
RCTFontProperties fontProperties) {
|
||||
RCTFontProperties defaultFontProperties = RCTDefaultFontProperties();
|
||||
fontProperties.family = fontProperties.family.length &&
|
||||
![fontProperties.family isEqualToString:@"System"]
|
||||
RCTFontProperties fontProperties, RCTFontProperties baseFontProperties) {
|
||||
fontProperties.family = fontProperties.family.length
|
||||
? fontProperties.family
|
||||
: defaultFontProperties.family;
|
||||
: baseFontProperties.family;
|
||||
fontProperties.size = !isnan(fontProperties.size)
|
||||
? fontProperties.size
|
||||
: defaultFontProperties.size;
|
||||
: baseFontProperties.size;
|
||||
fontProperties.weight = !isnan(fontProperties.weight)
|
||||
? fontProperties.weight
|
||||
: defaultFontProperties.weight;
|
||||
: baseFontProperties.weight;
|
||||
fontProperties.style = fontProperties.style != RCTFontStyleUndefined
|
||||
? fontProperties.style
|
||||
: defaultFontProperties.style;
|
||||
: baseFontProperties.style;
|
||||
fontProperties.variant = fontProperties.variant != RCTFontVariantUndefined
|
||||
? fontProperties.variant
|
||||
: defaultFontProperties.variant;
|
||||
: baseFontProperties.variant;
|
||||
return fontProperties;
|
||||
}
|
||||
|
||||
@@ -71,23 +72,6 @@ static NSArray *RCTFontFeatures(RCTFontVariant fontVariant) {
|
||||
return @[];
|
||||
}
|
||||
|
||||
static UIFontWeight RCTUIFontWeightFromFloat(CGFloat fontWeight) {
|
||||
// Note: Even if the underlying type of `UIFontWeight` is `CGFloat`
|
||||
// and UIKit uses the same numerical notation, we have to use exact
|
||||
// `UIFontWeight*` constants to make it work properly (because
|
||||
// float values comparison is tricky).
|
||||
static UIFontWeight weights[] = {/* ~100 */ UIFontWeightUltraLight,
|
||||
/* ~200 */ UIFontWeightThin,
|
||||
/* ~300 */ UIFontWeightLight,
|
||||
/* ~400 */ UIFontWeightRegular,
|
||||
/* ~500 */ UIFontWeightMedium,
|
||||
/* ~600 */ UIFontWeightSemibold,
|
||||
/* ~700 */ UIFontWeightBold,
|
||||
/* ~800 */ UIFontWeightHeavy,
|
||||
/* ~900 */ UIFontWeightBlack};
|
||||
return weights[std::llround((fontWeight / 100) - 1)];
|
||||
}
|
||||
|
||||
static UIFont *RCTDefaultFontWithFontProperties(
|
||||
RCTFontProperties fontProperties) {
|
||||
static NSCache *fontCache;
|
||||
@@ -109,7 +93,7 @@ static UIFont *RCTDefaultFontWithFontProperties(
|
||||
if (!font) {
|
||||
font = [UIFont
|
||||
systemFontOfSize:fontProperties.size
|
||||
weight:RCTUIFontWeightFromFloat(fontProperties.weight)];
|
||||
weight:fontProperties.weight];
|
||||
|
||||
if (fontProperties.variant == RCTFontStyleItalic) {
|
||||
UIFontDescriptor *fontDescriptor = [font fontDescriptor];
|
||||
@@ -135,7 +119,7 @@ static UIFont *RCTDefaultFontWithFontProperties(
|
||||
|
||||
UIFont *RCTFontWithFontProperties(RCTFontProperties fontProperties) {
|
||||
RCTFontProperties defaultFontProperties = RCTDefaultFontProperties();
|
||||
fontProperties = RCTResolveFontProperties(fontProperties);
|
||||
fontProperties = RCTResolveFontProperties(fontProperties, defaultFontProperties);
|
||||
|
||||
assert(!isnan(fontProperties.sizeMultiplier));
|
||||
CGFloat effectiveFontSize =
|
||||
@@ -158,7 +142,7 @@ UIFont *RCTFontWithFontProperties(RCTFontProperties fontProperties) {
|
||||
// Failback to system font.
|
||||
font = [UIFont
|
||||
systemFontOfSize:effectiveFontSize
|
||||
weight:RCTUIFontWeightFromFloat(fontProperties.weight)];
|
||||
weight:fontProperties.weight];
|
||||
}
|
||||
} else {
|
||||
// Get the closest font that matches the given weight for the fontFamily
|
||||
|
||||
Reference in New Issue
Block a user