|
57 | 57 | CGFloat const HippyTextAutoSizeGranularity = 0.001; |
58 | 58 | static const CGFloat gDefaultFontSize = 14.0; |
59 | 59 |
|
| 60 | +static UIFont *HippyCreateFontOnMainThread(NSString *fontFamily, CGFloat size) { |
| 61 | + if (!fontFamily) { |
| 62 | + return nil; |
| 63 | + } |
| 64 | + if ([NSThread isMainThread]) { |
| 65 | + return [UIFont fontWithName:fontFamily size:size]; |
| 66 | + } else { |
| 67 | + __block UIFont *font = nil; |
| 68 | + dispatch_sync(dispatch_get_main_queue(), ^{ |
| 69 | + font = [UIFont fontWithName:fontFamily size:size]; |
| 70 | + }); |
| 71 | + return font; |
| 72 | + } |
| 73 | +} |
| 74 | + |
60 | 75 | static BOOL DirtyTextEqual(BOOL v1, BOOL v2) { |
61 | 76 | return v1 == v2; |
62 | 77 | } |
@@ -376,35 +391,42 @@ - (void)applyConfirmedLayoutDirectionToSubviews:(hippy::Direction)confirmedLayou |
376 | 391 | } |
377 | 392 |
|
378 | 393 | - (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(hippy::LayoutMeasureMode)widthMode { |
379 | | - @synchronized (self) { |
380 | | - if (isnan(width)) { |
381 | | - width = 0; |
382 | | - } |
| 394 | + if (isnan(width)) { |
| 395 | + width = 0; |
| 396 | + } |
383 | 397 |
|
| 398 | + @synchronized (self) { |
384 | 399 | if (_cachedTextStorage && width == _cachedTextStorageWidth && widthMode == _cachedTextStorageWidthMode) { |
385 | 400 | return _cachedTextStorage; |
386 | 401 | } |
| 402 | + } |
387 | 403 |
|
388 | | - // textContainer |
389 | | - NSTextContainer *textContainer = [NSTextContainer new]; |
390 | | - textContainer.lineFragmentPadding = 0.0; |
| 404 | + // Build attributed string outside of synchronized block to avoid potential deadlock |
| 405 | + // when creating UIFont instances on the main thread. |
| 406 | + NSAttributedString *baseAttributedString = self.attributedString; |
391 | 407 |
|
392 | | - if (_numberOfLines > 0) { |
393 | | - textContainer.lineBreakMode = _ellipsizeMode; |
394 | | - } else { |
395 | | - textContainer.lineBreakMode = NSLineBreakByClipping; |
396 | | - } |
| 408 | + // textContainer |
| 409 | + NSTextContainer *textContainer = [NSTextContainer new]; |
| 410 | + textContainer.lineFragmentPadding = 0.0; |
397 | 411 |
|
398 | | - textContainer.maximumNumberOfLines = _numberOfLines; |
399 | | - textContainer.size = (CGSize) { widthMode == hippy::LayoutMeasureMode::Undefined ? CGFLOAT_MAX : width, CGFLOAT_MAX }; |
400 | | - |
401 | | - // layoutManager && textStorage |
402 | | - NSLayoutManager *layoutManager = [NSLayoutManager new]; |
403 | | - NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedString]; |
404 | | - [textStorage addLayoutManager:layoutManager]; |
405 | | - |
406 | | - layoutManager.delegate = self; |
407 | | - [layoutManager addTextContainer:textContainer]; |
| 412 | + if (_numberOfLines > 0) { |
| 413 | + textContainer.lineBreakMode = _ellipsizeMode; |
| 414 | + } else { |
| 415 | + textContainer.lineBreakMode = NSLineBreakByClipping; |
| 416 | + } |
| 417 | + |
| 418 | + textContainer.maximumNumberOfLines = _numberOfLines; |
| 419 | + textContainer.size = (CGSize) { widthMode == hippy::LayoutMeasureMode::Undefined ? CGFLOAT_MAX : width, CGFLOAT_MAX }; |
| 420 | + |
| 421 | + // layoutManager && textStorage |
| 422 | + NSLayoutManager *layoutManager = [NSLayoutManager new]; |
| 423 | + NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:baseAttributedString]; |
| 424 | + [textStorage addLayoutManager:layoutManager]; |
| 425 | + |
| 426 | + layoutManager.delegate = self; |
| 427 | + [layoutManager addTextContainer:textContainer]; |
| 428 | + |
| 429 | + @synchronized (self) { |
408 | 430 | // start clean collection for this layout build |
409 | 431 | [_pendingBaselineOffsets removeAllObjects]; |
410 | 432 | [_pendingAttachmentBaselineBottoms removeAllObjects]; |
@@ -459,9 +481,9 @@ - (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(hippy::Lay |
459 | 481 | _cachedTextStorageWidth = width; |
460 | 482 | _cachedTextStorageWidthMode = widthMode; |
461 | 483 | _cachedTextStorage = textStorage; |
462 | | - |
463 | | - return textStorage; |
464 | 484 | } |
| 485 | + |
| 486 | + return textStorage; |
465 | 487 | } |
466 | 488 |
|
467 | 489 | - (void)dirtyText:(BOOL)needToDoLayout { |
@@ -563,7 +585,7 @@ - (NSAttributedString *)_attributedStringWithStyleInfo:(HippyAttributedStringSty |
563 | 585 |
|
564 | 586 | UIFont *f = nil; |
565 | 587 | if (styleInfo.fontFamily) { |
566 | | - f = [UIFont fontWithName:styleInfo.fontFamily size:[styleInfo.fontSize floatValue]]; |
| 588 | + f = HippyCreateFontOnMainThread(styleInfo.fontFamily, [styleInfo.fontSize floatValue]); |
567 | 589 | } |
568 | 590 |
|
569 | 591 | UIFont *font = [HippyFont updateFont:f |
|
0 commit comments