From a9c684a0ff45852087310d5218062acfdab673f7 Mon Sep 17 00:00:00 2001 From: Mehdi Mulani Date: Tue, 30 Jan 2018 13:31:04 -0800 Subject: [PATCH] Allow substituting a default font handler Reviewed By: nscoding Differential Revision: D6798995 fbshipit-source-id: 541b4391428d1ee9c0b394033182dc232536c864 --- React/Views/RCTFont.h | 10 +++++++++ React/Views/RCTFont.mm | 51 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/React/Views/RCTFont.h b/React/Views/RCTFont.h index 806f6a2a4d8281..ba34e8f3462b9c 100644 --- a/React/Views/RCTFont.h +++ b/React/Views/RCTFont.h @@ -11,6 +11,16 @@ #import +typedef UIFont *(^RCTFontHandler)(CGFloat fontSize, NSString *fontWeightDescription); + +/** + * React Native will use the System font for rendering by default. If you want to + * provide a different base font, use this override. The font weight supplied to your + * handler will be one of "ultralight", "thin", "light", "regular", "medium", + * "semibold", "extrabold", "bold", "heavy", or "black". + */ +RCT_EXTERN void RCTSetDefaultFontHandler(RCTFontHandler handler); + @interface RCTFont : NSObject /** diff --git a/React/Views/RCTFont.mm b/React/Views/RCTFont.mm index 9f755a0cad9e78..37595dd3fbf42c 100644 --- a/React/Views/RCTFont.mm +++ b/React/Views/RCTFont.mm @@ -7,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ +#import "RCTAssert.h" #import "RCTFont.h" #import "RCTLog.h" @@ -96,6 +97,49 @@ static BOOL isCondensedFont(UIFont *font) return (symbolicTraits & UIFontDescriptorTraitCondensed) != 0; } +static RCTFontHandler defaultFontHandler; + +void RCTSetDefaultFontHandler(RCTFontHandler handler) { + defaultFontHandler = handler; +} + +// We pass a string description of the font weight to the defaultFontHandler because UIFontWeight +// is not defined pre-iOS 8.2. +// Furthermore, UIFontWeight's are lossy floats, so we must use an inexact compare to figure out +// which one we actually have. +static inline BOOL CompareFontWeights(UIFontWeight firstWeight, UIFontWeight secondWeight) { +#if CGFLOAT_IS_DOUBLE + return fabs(firstWeight - secondWeight) < 0.01; +#else + return fabsf(firstWeight - secondWeight) < 0.01; +#endif +} + +static NSString *FontWeightDescriptionFromUIFontWeight(UIFontWeight fontWeight) +{ + if (CompareFontWeights(fontWeight, UIFontWeightUltraLight)) { + return @"ultralight"; + } else if (CompareFontWeights(fontWeight, UIFontWeightThin)) { + return @"thin"; + } else if (CompareFontWeights(fontWeight, UIFontWeightLight)) { + return @"light"; + } else if (CompareFontWeights(fontWeight, UIFontWeightRegular)) { + return @"regular"; + } else if (CompareFontWeights(fontWeight, UIFontWeightMedium)) { + return @"medium"; + } else if (CompareFontWeights(fontWeight, UIFontWeightSemibold)) { + return @"semibold"; + } else if (CompareFontWeights(fontWeight, UIFontWeightBold)) { + return @"bold"; + } else if (CompareFontWeights(fontWeight, UIFontWeightHeavy)) { + return @"heavy"; + } else if (CompareFontWeights(fontWeight, UIFontWeightBlack)) { + return @"black"; + } + RCTAssert(NO, @"Unknown UIFontWeight passed in: %f", fontWeight); + return @"regular"; +} + static UIFont *cachedSystemFont(CGFloat size, RCTFontWeight weight) { static NSCache *fontCache; @@ -112,8 +156,11 @@ static BOOL isCondensedFont(UIFont *font) } if (!font) { - // Only supported on iOS8.2 and above - if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)]) { + if (defaultFontHandler) { + NSString *fontWeightDescription = FontWeightDescriptionFromUIFontWeight(weight); + font = defaultFontHandler(size, fontWeightDescription); + } else if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)]) { + // Only supported on iOS8.2 and above font = [UIFont systemFontOfSize:size weight:weight]; } else { if (weight >= UIFontWeightBold) {