Skip to content

Commit 839f960

Browse files
committed
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 0e01839 commit 839f960

2 files changed

Lines changed: 51 additions & 26 deletions

File tree

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
}
@@ -373,35 +388,42 @@ - (void)applyConfirmedLayoutDirectionToSubviews:(hippy::Direction)confirmedLayou
373388
}
374389

375390
- (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+
}
380394

395+
@synchronized (self) {
381396
if (_cachedTextStorage && width == _cachedTextStorageWidth && widthMode == _cachedTextStorageWidthMode) {
382397
return _cachedTextStorage;
383398
}
399+
}
384400

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

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

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) {
405427
// start clean collection for this layout build
406428
[_pendingBaselineOffsets removeAllObjects];
407429
[_pendingAttachmentBaselineBottoms removeAllObjects];
@@ -456,9 +478,9 @@ - (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(hippy::Lay
456478
_cachedTextStorageWidth = width;
457479
_cachedTextStorageWidthMode = widthMode;
458480
_cachedTextStorage = textStorage;
459-
460-
return textStorage;
461481
}
482+
483+
return textStorage;
462484
}
463485

464486
- (void)dirtyText:(BOOL)needToDoLayout {
@@ -561,7 +583,7 @@ - (NSAttributedString *)_attributedStringWithStyleInfo:(HippyAttributedStringSty
561583

562584
UIFont *f = nil;
563585
if (styleInfo.fontFamily) {
564-
f = [UIFont fontWithName:styleInfo.fontFamily size:[styleInfo.fontSize floatValue]];
586+
f = HippyCreateFontOnMainThread(styleInfo.fontFamily, [styleInfo.fontSize floatValue]);
565587
}
566588

567589
UIFont *font = [HippyFont updateFont:f

0 commit comments

Comments
 (0)