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;
_cachedTextStorageWidth = -1;
_cachedTextStorageWidthMode = -1;
_fontSizeMultiplier = 1.0;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(contentSizeMultiplierDidChange:)
name:RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification
@ -92,8 +93,7 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
UIEdgeInsets padding = self.paddingAsInsets;
CGFloat width = self.frame.size.width - (padding.left + padding.right);
// HACK (t10802067)
NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:isnan(width) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY];
NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
[applierBlocks addObject:^(NSDictionary<NSNumber *, RCTText *> *viewRegistry) {
RCTText *view = viewRegistry[self.reactTag];
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
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:NSKernAttributeName withValue:letterSpacing 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;
}
CGFloat fontSizeMultiplier = _allowFontScaling ? _fontSizeMultiplier : 1.0;
// 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) {
if (value) {
NSParagraphStyle *paragraphStyle = (NSParagraphStyle *)value;
CGFloat maximumLineHeight = round(paragraphStyle.maximumLineHeight / self.fontSizeMultiplier);
CGFloat maximumLineHeight = round(paragraphStyle.maximumLineHeight / fontSizeMultiplier);
if (maximumLineHeight > self.lineHeight) {
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];
paragraphStyle.alignment = _textAlign;
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.maximumLineHeight = lineHeight;
[attributedString addAttribute:NSParagraphStyleAttributeName
@ -400,6 +402,10 @@ RCT_TEXT_PROPERTY(TextShadowColor, _textShadowColor, UIColor *);
- (void)setFontSizeMultiplier:(CGFloat)fontSizeMultiplier
{
_fontSizeMultiplier = fontSizeMultiplier;
if (_fontSizeMultiplier == 0) {
RCTLogError(@"fontSizeMultiplier value must be > zero.");
_fontSizeMultiplier = 1.0;
}
for (RCTShadowView *child in [self reactSubviews]) {
if ([child isKindOfClass:[RCTShadowText class]]) {
((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
* `<TextInput>` controls, a feature which is not yet supported in open source.
* It is required in order to ensure that the textStorage (aka attributed
* string) is copied over from the RCTShadowText to the RCTText view in time
* to be used to update the editable text content.
* `<TextInput>` controls. It is required in order to ensure that the
* textStorage (aka attributed string) is copied over from the RCTShadowText
* to the RCTText view in time to be used to update the editable text content.
*/
if (textViewTagsToUpdate.count) {
@ -136,9 +135,7 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
UIEdgeInsets padding = shadowText.paddingAsInsets;
CGFloat width = shadowText.frame.size.width - (padding.left + padding.right);
// HACK (t10802067)
NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:isnan(width) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY];
NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
[uiBlocks addObject:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTTextView *> *viewRegistry) {
RCTTextView *textView = viewRegistry[reactTag];
RCTText *text;