|
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 | } |
@@ -373,35 +388,42 @@ - (void)applyConfirmedLayoutDirectionToSubviews:(hippy::Direction)confirmedLayou |
373 | 388 | } |
374 | 389 |
|
375 | 390 | - (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(hippy::LayoutMeasureMode)widthMode { |
376 | | - @synchronized (self) { |
377 | | - if (isnan(width)) { |
378 | | - width = 0; |
379 | | - } |
| 391 | + if (isnan(width)) { |
| 392 | + width = 0; |
| 393 | + } |
380 | 394 |
|
| 395 | + @synchronized (self) { |
381 | 396 | if (_cachedTextStorage && width == _cachedTextStorageWidth && widthMode == _cachedTextStorageWidthMode) { |
382 | 397 | return _cachedTextStorage; |
383 | 398 | } |
| 399 | + } |
384 | 400 |
|
385 | | - // textContainer |
386 | | - NSTextContainer *textContainer = [NSTextContainer new]; |
387 | | - textContainer.lineFragmentPadding = 0.0; |
| 401 | + // Build attributed string outside of synchronized block to avoid potential deadlock |
| 402 | + // when creating UIFont instances on the main thread. |
| 403 | + NSAttributedString *baseAttributedString = self.attributedString; |
388 | 404 |
|
389 | | - if (_numberOfLines > 0) { |
390 | | - textContainer.lineBreakMode = _ellipsizeMode; |
391 | | - } else { |
392 | | - textContainer.lineBreakMode = NSLineBreakByClipping; |
393 | | - } |
| 405 | + // textContainer |
| 406 | + NSTextContainer *textContainer = [NSTextContainer new]; |
| 407 | + textContainer.lineFragmentPadding = 0.0; |
394 | 408 |
|
395 | | - textContainer.maximumNumberOfLines = _numberOfLines; |
396 | | - textContainer.size = (CGSize) { widthMode == hippy::LayoutMeasureMode::Undefined ? CGFLOAT_MAX : width, CGFLOAT_MAX }; |
397 | | - |
398 | | - // layoutManager && textStorage |
399 | | - NSLayoutManager *layoutManager = [NSLayoutManager new]; |
400 | | - NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedString]; |
401 | | - [textStorage addLayoutManager:layoutManager]; |
402 | | - |
403 | | - layoutManager.delegate = self; |
404 | | - [layoutManager addTextContainer:textContainer]; |
| 409 | + if (_numberOfLines > 0) { |
| 410 | + textContainer.lineBreakMode = _ellipsizeMode; |
| 411 | + } else { |
| 412 | + textContainer.lineBreakMode = NSLineBreakByClipping; |
| 413 | + } |
| 414 | + |
| 415 | + textContainer.maximumNumberOfLines = _numberOfLines; |
| 416 | + textContainer.size = (CGSize) { widthMode == hippy::LayoutMeasureMode::Undefined ? CGFLOAT_MAX : width, CGFLOAT_MAX }; |
| 417 | + |
| 418 | + // layoutManager && textStorage |
| 419 | + NSLayoutManager *layoutManager = [NSLayoutManager new]; |
| 420 | + NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:baseAttributedString]; |
| 421 | + [textStorage addLayoutManager:layoutManager]; |
| 422 | + |
| 423 | + layoutManager.delegate = self; |
| 424 | + [layoutManager addTextContainer:textContainer]; |
| 425 | + |
| 426 | + @synchronized (self) { |
405 | 427 | // start clean collection for this layout build |
406 | 428 | [_pendingBaselineOffsets removeAllObjects]; |
407 | 429 | [_pendingAttachmentBaselineBottoms removeAllObjects]; |
@@ -456,9 +478,9 @@ - (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(hippy::Lay |
456 | 478 | _cachedTextStorageWidth = width; |
457 | 479 | _cachedTextStorageWidthMode = widthMode; |
458 | 480 | _cachedTextStorage = textStorage; |
459 | | - |
460 | | - return textStorage; |
461 | 481 | } |
| 482 | + |
| 483 | + return textStorage; |
462 | 484 | } |
463 | 485 |
|
464 | 486 | - (void)dirtyText:(BOOL)needToDoLayout { |
@@ -561,7 +583,7 @@ - (NSAttributedString *)_attributedStringWithStyleInfo:(HippyAttributedStringSty |
561 | 583 |
|
562 | 584 | UIFont *f = nil; |
563 | 585 | if (styleInfo.fontFamily) { |
564 | | - f = [UIFont fontWithName:styleInfo.fontFamily size:[styleInfo.fontSize floatValue]]; |
| 586 | + f = HippyCreateFontOnMainThread(styleInfo.fontFamily, [styleInfo.fontSize floatValue]); |
565 | 587 | } |
566 | 588 |
|
567 | 589 | UIFont *font = [HippyFont updateFont:f |
|
0 commit comments