Fixed some issues with zero fontSizeMultiplier causing RCTSHadowText measure function to return an infinite height

Summary:The default value for fontSizeMultiplier was zero. Although this was usually overriden with the correct value (typically 1.0), it sometimes wasn't resulting in a divide-by-zero in the text height calculation.

This diff corrects that bug by setting 1.0 as the default, and guarding against zero values being set.

I also fixed some suspicious logic that seemed to assume the result of BOOL && CGFloat would be 0 or the CGFloat value, which is true in JS but not in C (it would always be 0 or 1).

Reviewed By: javache

Differential Revision: D3179196

fb-gh-sync-id: cc09b104c9087fc1a2f45d8d3f70af221c2ad823
fbshipit-source-id: cc09b104c9087fc1a2f45d8d3f70af221c2ad823
This commit is contained in:
Nick Lockwood 2016-04-21 03:56:41 -07:00 committed by Facebook Github Bot 8
parent 99705440a0
commit 362738a776
2 changed files with 15 additions and 12 deletions

View File

@ -58,6 +58,7 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
_opacity = 1.0; _opacity = 1.0;
_cachedTextStorageWidth = -1; _cachedTextStorageWidth = -1;
_cachedTextStorageWidthMode = -1; _cachedTextStorageWidthMode = -1;
_fontSizeMultiplier = 1.0;
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(contentSizeMultiplierDidChange:) selector:@selector(contentSizeMultiplierDidChange:)
name:RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification name:RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification
@ -92,8 +93,7 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
UIEdgeInsets padding = self.paddingAsInsets; UIEdgeInsets padding = self.paddingAsInsets;
CGFloat width = self.frame.size.width - (padding.left + padding.right); CGFloat width = self.frame.size.width - (padding.left + padding.right);
// HACK (t10802067) NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:isnan(width) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY];
[applierBlocks addObject:^(NSDictionary<NSNumber *, RCTText *> *viewRegistry) { [applierBlocks addObject:^(NSDictionary<NSNumber *, RCTText *> *viewRegistry) {
RCTText *view = viewRegistry[self.reactTag]; RCTText *view = viewRegistry[self.reactTag];
view.textStorage = textStorage; view.textStorage = textStorage;
@ -241,7 +241,7 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
UIFont *font = [RCTConvert UIFont:nil withFamily:fontFamily UIFont *font = [RCTConvert UIFont:nil withFamily:fontFamily
size:fontSize weight:fontWeight style:fontStyle size:fontSize weight:fontWeight style:fontStyle
scaleMultiplier:(_allowFontScaling && _fontSizeMultiplier > 0.0 ? _fontSizeMultiplier : 1.0)]; scaleMultiplier:_allowFontScaling ? _fontSizeMultiplier : 1.0];
[self _addAttribute:NSFontAttributeName withValue:font toAttributedString:attributedString]; [self _addAttribute:NSFontAttributeName withValue:font toAttributedString:attributedString];
[self _addAttribute:NSKernAttributeName withValue:letterSpacing toAttributedString:attributedString]; [self _addAttribute:NSKernAttributeName withValue:letterSpacing toAttributedString:attributedString];
[self _addAttribute:RCTReactTagAttributeName withValue:self.reactTag toAttributedString:attributedString]; [self _addAttribute:RCTReactTagAttributeName withValue:self.reactTag toAttributedString:attributedString];
@ -279,11 +279,13 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
self.lineHeight = 0.0; self.lineHeight = 0.0;
} }
CGFloat fontSizeMultiplier = _allowFontScaling ? _fontSizeMultiplier : 1.0;
// check for lineHeight on each of our children, update the max as we go (in self.lineHeight) // check for lineHeight on each of our children, update the max as we go (in self.lineHeight)
[attributedString enumerateAttribute:NSParagraphStyleAttributeName inRange:(NSRange){0, attributedString.length} options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { [attributedString enumerateAttribute:NSParagraphStyleAttributeName inRange:(NSRange){0, attributedString.length} options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
if (value) { if (value) {
NSParagraphStyle *paragraphStyle = (NSParagraphStyle *)value; NSParagraphStyle *paragraphStyle = (NSParagraphStyle *)value;
CGFloat maximumLineHeight = round(paragraphStyle.maximumLineHeight / self.fontSizeMultiplier); CGFloat maximumLineHeight = round(paragraphStyle.maximumLineHeight / fontSizeMultiplier);
if (maximumLineHeight > self.lineHeight) { if (maximumLineHeight > self.lineHeight) {
self.lineHeight = maximumLineHeight; self.lineHeight = maximumLineHeight;
} }
@ -299,7 +301,7 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new]; NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.alignment = _textAlign; paragraphStyle.alignment = _textAlign;
paragraphStyle.baseWritingDirection = _writingDirection; paragraphStyle.baseWritingDirection = _writingDirection;
CGFloat lineHeight = round(_lineHeight * (_allowFontScaling && self.fontSizeMultiplier > 0.0 ? self.fontSizeMultiplier : 1.0)); CGFloat lineHeight = round(_lineHeight * fontSizeMultiplier);
paragraphStyle.minimumLineHeight = lineHeight; paragraphStyle.minimumLineHeight = lineHeight;
paragraphStyle.maximumLineHeight = lineHeight; paragraphStyle.maximumLineHeight = lineHeight;
[attributedString addAttribute:NSParagraphStyleAttributeName [attributedString addAttribute:NSParagraphStyleAttributeName
@ -400,6 +402,10 @@ RCT_TEXT_PROPERTY(TextShadowColor, _textShadowColor, UIColor *);
- (void)setFontSizeMultiplier:(CGFloat)fontSizeMultiplier - (void)setFontSizeMultiplier:(CGFloat)fontSizeMultiplier
{ {
_fontSizeMultiplier = fontSizeMultiplier; _fontSizeMultiplier = fontSizeMultiplier;
if (_fontSizeMultiplier == 0) {
RCTLogError(@"fontSizeMultiplier value must be > zero.");
_fontSizeMultiplier = 1.0;
}
for (RCTShadowView *child in [self reactSubviews]) { for (RCTShadowView *child in [self reactSubviews]) {
if ([child isKindOfClass:[RCTShadowText class]]) { if ([child isKindOfClass:[RCTShadowText class]]) {
((RCTShadowText *)child).fontSizeMultiplier = fontSizeMultiplier; ((RCTShadowText *)child).fontSizeMultiplier = fontSizeMultiplier;

View File

@ -115,10 +115,9 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
/** /**
* NOTE: this logic is included to support rich text editing inside multiline * NOTE: this logic is included to support rich text editing inside multiline
* `<TextInput>` controls, a feature which is not yet supported in open source. * `<TextInput>` controls. It is required in order to ensure that the
* It is required in order to ensure that the textStorage (aka attributed * textStorage (aka attributed string) is copied over from the RCTShadowText
* string) is copied over from the RCTShadowText to the RCTText view in time * to the RCTText view in time to be used to update the editable text content.
* to be used to update the editable text content.
*/ */
if (textViewTagsToUpdate.count) { if (textViewTagsToUpdate.count) {
@ -136,9 +135,7 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
UIEdgeInsets padding = shadowText.paddingAsInsets; UIEdgeInsets padding = shadowText.paddingAsInsets;
CGFloat width = shadowText.frame.size.width - (padding.left + padding.right); CGFloat width = shadowText.frame.size.width - (padding.left + padding.right);
// HACK (t10802067) NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:isnan(width) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY];
[uiBlocks addObject:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTTextView *> *viewRegistry) { [uiBlocks addObject:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTTextView *> *viewRegistry) {
RCTTextView *textView = viewRegistry[reactTag]; RCTTextView *textView = viewRegistry[reactTag];
RCTText *text; RCTText *text;