Skip to content

Commit c0b3ebe

Browse files
authored
refactor(ios): optimize text rendering performance and thread safety (Tencent#4490)
* refactor(ios): optimize text rendering performance and thread safety * fix(ios): handle null exception in Hermes uncaught exception callback
1 parent 0e48248 commit c0b3ebe

File tree

2 files changed

+51
-26
lines changed

2 files changed

+51
-26
lines changed

driver/js/src/napi/hermes/hermes_ctx.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,12 @@ static void HandleJsException(std::shared_ptr<Scope> scope, std::shared_ptr<Herm
9191
FOOTSTONE_DCHECK(engine);
9292
if (engine) {
9393
auto callback = engine->GetVM()->GetUncaughtExceptionCallback();
94+
if (!callback) {
95+
return;
96+
}
9497
auto context = scope->GetContext();
9598
footstone::string_view description("Hermes Engine JS Exception");
96-
footstone::string_view stack(exception->GetMessage());
99+
footstone::string_view stack(exception ? exception->GetMessage() : "");
97100
callback(scope->GetBridge(), description, stack);
98101
}
99102
}

renderer/native/ios/renderer/component/text/HippyShadowText.mm

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,21 @@
5757
CGFloat const HippyTextAutoSizeGranularity = 0.001;
5858
static const CGFloat gDefaultFontSize = 14.0;
5959

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+
6075
static BOOL DirtyTextEqual(BOOL v1, BOOL v2) {
6176
return v1 == v2;
6277
}
@@ -376,35 +391,42 @@ - (void)applyConfirmedLayoutDirectionToSubviews:(hippy::Direction)confirmedLayou
376391
}
377392

378393
- (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+
}
383397

398+
@synchronized (self) {
384399
if (_cachedTextStorage && width == _cachedTextStorageWidth && widthMode == _cachedTextStorageWidthMode) {
385400
return _cachedTextStorage;
386401
}
402+
}
387403

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;
391407

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;
397411

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) {
408430
// start clean collection for this layout build
409431
[_pendingBaselineOffsets removeAllObjects];
410432
[_pendingAttachmentBaselineBottoms removeAllObjects];
@@ -459,9 +481,9 @@ - (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(hippy::Lay
459481
_cachedTextStorageWidth = width;
460482
_cachedTextStorageWidthMode = widthMode;
461483
_cachedTextStorage = textStorage;
462-
463-
return textStorage;
464484
}
485+
486+
return textStorage;
465487
}
466488

467489
- (void)dirtyText:(BOOL)needToDoLayout {
@@ -563,7 +585,7 @@ - (NSAttributedString *)_attributedStringWithStyleInfo:(HippyAttributedStringSty
563585

564586
UIFont *f = nil;
565587
if (styleInfo.fontFamily) {
566-
f = [UIFont fontWithName:styleInfo.fontFamily size:[styleInfo.fontSize floatValue]];
588+
f = HippyCreateFontOnMainThread(styleInfo.fontFamily, [styleInfo.fontSize floatValue]);
567589
}
568590

569591
UIFont *font = [HippyFont updateFont:f

0 commit comments

Comments
 (0)