Skip to content

Commit

Permalink
feat(ios): add HippyFontChangeTriggerNotification for native font update
Browse files Browse the repository at this point in the history
  • Loading branch information
wwwcg committed Oct 10, 2024
1 parent 112453d commit 8ec3a0e
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 91 deletions.
23 changes: 20 additions & 3 deletions renderer/native/ios/renderer/HippyComponentMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
*/

#import <Foundation/Foundation.h>

#import "HippyComponent.h"

#include <memory>

namespace hippy {
Expand All @@ -39,6 +37,7 @@ typedef NS_ENUM(NSUInteger, HippyComponentReferenceType) {
HippyComponentReferenceTypeWeak,
};

/// A structure that holds all root and components information
@interface HippyComponentMap : NSObject

/// Whether all recorded elements are strongly referenced,
Expand All @@ -62,27 +61,45 @@ typedef NS_ENUM(NSUInteger, HippyComponentReferenceType) {
rootNode:(std::weak_ptr<hippy::RootNode>)rootNode
forTag:(NSNumber *)tag;

/// Remove root component
/// - Parameter tag: hippyTag
- (void)removeRootComponentWithTag:(NSNumber *)tag;

/// Whether contain root component with given tag
/// - Parameter tag: hippyTag
- (BOOL)containRootComponentWithTag:(NSNumber *)tag;

/// Get all rootTags
- (NSArray<NSNumber *> *)allRootTags;

/// Get all root components
- (NSArray<id<HippyComponent>> *)rootComponents;

/// Get root component with given tag
/// - Parameter tag: hippyTag
- (__kindof id<HippyComponent>)rootComponentForTag:(NSNumber *)tag;

/// Get RootNode for given tag
/// - Parameter tag: hippyTag
- (std::weak_ptr<hippy::RootNode>)rootNodeForTag:(NSNumber *)tag;


#pragma mark -
#pragma mark - Components manage

/// Add a component to ComponentMap
- (void)addComponent:(__kindof id<HippyComponent>)component forRootTag:(NSNumber *)tag;

/// Remove one component from ComponentMap
- (void)removeComponent:(__kindof id<HippyComponent>)component forRootTag:(NSNumber *)tag;

/// Get all components for given root tag
/// - Parameter tag: hippyTag
- (NSDictionary<NSNumber *, __kindof id<HippyComponent>> *)componentsForRootTag:(NSNumber *)tag;

/// Get specific component on rootTag with given tag
/// - Parameters:
/// - componentTag: hippyTag
/// - tag: rootTag
- (__kindof id<HippyComponent>)componentForTag:(NSNumber *)componentTag onRootTag:(NSNumber *)tag;


Expand Down
4 changes: 4 additions & 0 deletions renderer/native/ios/renderer/HippyComponentMap.mm
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ - (BOOL)containRootComponentWithTag:(NSNumber *)tag {
return nil != rootComponent;
}

- (NSArray<NSNumber *> *)allRootTags {
return [[_rootComponentsMap keyEnumerator] allObjects];
}

- (NSArray<id<HippyComponent>> *)rootComponents {
return [[_rootComponentsMap objectEnumerator] allObjects];
}
Expand Down
10 changes: 6 additions & 4 deletions renderer/native/ios/renderer/HippyFont.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@
variant:(NSArray<NSString *> *)variant
scaleMultiplier:(CGFloat)scaleMultiplier;

+ (UIFont *)updateFont:(UIFont *)font withFamily:(NSString *)family;
+ (UIFont *)updateFont:(UIFont *)font withSize:(NSNumber *)size;
+ (UIFont *)updateFont:(UIFont *)font withWeight:(NSString *)weight;
+ (UIFont *)updateFont:(UIFont *)font withStyle:(NSString *)style;
/// Get the
/// JS side usually pass a `fontName` instead of `fontFamily`
/// If not match, the original value is returned.
///
/// - Parameter fontFamily: NSString *
+ (NSString *)familyNameWithCSSNameMatching:(NSString *)fontName;

@end

Expand Down
28 changes: 13 additions & 15 deletions renderer/native/ios/renderer/HippyFont.mm
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ @implementation HippyConvert (NativeRenderFont)

+ (UIFont *)UIFont:(id)json {
json = [self NSDictionary:json];
return [HippyFont updateFont:nil withFamily:[HippyConvert NSString:json[@"fontFamily"]] size:[HippyConvert NSNumber:json[@"fontSize"]]
return [HippyFont updateFont:nil
withFamily:[HippyConvert NSString:json[@"fontFamily"]]
size:[HippyConvert NSNumber:json[@"fontSize"]]
weight:[HippyConvert NSString:json[@"fontWeight"]]
style:[HippyConvert NSString:json[@"fontStyle"]]
variant:[HippyConvert NSStringArray:json[@"fontVariant"]]
Expand Down Expand Up @@ -322,20 +324,16 @@ + (UIFont *)updateFont:(UIFont *)font
return font;
}

+ (UIFont *)updateFont:(UIFont *)font withFamily:(NSString *)family {
return [self updateFont:font withFamily:family size:nil weight:nil style:nil variant:nil scaleMultiplier:1];
}

+ (UIFont *)updateFont:(UIFont *)font withSize:(NSNumber *)size {
return [self updateFont:font withFamily:nil size:size weight:nil style:nil variant:nil scaleMultiplier:1];
}

+ (UIFont *)updateFont:(UIFont *)font withWeight:(NSString *)weight {
return [self updateFont:font withFamily:nil size:nil weight:weight style:nil variant:nil scaleMultiplier:1];
}

+ (UIFont *)updateFont:(UIFont *)font withStyle:(NSString *)style {
return [self updateFont:font withFamily:nil size:nil weight:nil style:style variant:nil scaleMultiplier:1];
+ (NSString *)familyNameWithCSSNameMatching:(NSString *)fontName {
NSString *familyName = fontName;
if (fontName && ![[UIFont familyNames] containsObject:fontName]) {
// Not a real FamilyName
// Using CSS name matching semantics.
// fontSize here is just a placeholder for getting font.
UIFont *cssFont = [UIFont fontWithName:fontName size:14.0];
familyName = cssFont.familyName;
}
return familyName;
}

@end
9 changes: 9 additions & 0 deletions renderer/native/ios/renderer/HippyUIManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ HIPPY_EXTERN NSString *const HippyUIManagerRootViewTagKey;
*/
HIPPY_EXTERN NSString *const HippyUIManagerDidEndBatchNotification;

/**
* This notification can be sent when the font is registered or modified on the native side
* and hippy needs to be refreshed.
*
* `notification.object` can carry rootTag to filter the RootView that needs to be refreshed.
* Default value nil indicating that a refresh is required.
*/
HIPPY_EXTERN NSString *const HippyFontChangeTriggerNotification;



/// The HippyUIManager responsible for updating the view hierarchy.
Expand Down
54 changes: 54 additions & 0 deletions renderer/native/ios/renderer/HippyUIManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
#import "HippyModuleMethod.h"
#import "HippyBridge+Private.h"
#import "HippyJSExecutor.h"
#import "HippyShadowText.h"
#import "HippyShadowTextView.h"
#import "dom/root_node.h"
#import "objc/runtime.h"
#import <os/lock.h>
Expand Down Expand Up @@ -181,6 +183,7 @@ - (void)setUiManager:(HippyUIManager *)uiManager;
NSString *const HippyUIManagerRootViewKey = @"HippyUIManagerRootViewKey";
NSString *const HippyUIManagerRootViewTagKey = @"HippyUIManagerRootViewTagKey";
NSString *const HippyUIManagerDidEndBatchNotification = @"HippyUIManagerDidEndBatchNotification";
NSString *const HippyFontChangeTriggerNotification = @"HippyFontChangeTriggerNotification";

@interface HippyUIManager() {
NSMutableArray<HippyViewManagerUIBlock> *_pendingUIBlocks;
Expand Down Expand Up @@ -233,6 +236,10 @@ - (void)initContext {
_componentDataLock = OS_UNFAIR_LOCK_INIT;
HippyScreenScale();
HippyScreenSize();
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onFontChangedFromNative:)
name:HippyFontChangeTriggerNotification
object:nil];
}

- (void)invalidate {
Expand Down Expand Up @@ -1484,6 +1491,53 @@ - (void)domEventDidHandle:(const std::string &)eventName forNode:(int32_t)tag on
// no op
}


#pragma mark - Font Refresh

- (void)onFontChangedFromNative:(NSNotification *)notification {
NSNumber *targetRootTag = notification.object;
if ((targetRootTag != nil) && ![self.viewRegistry containRootComponentWithTag:targetRootTag]) {
// do compare if notification has target RootView.
return;
}

__weak __typeof(self)weakSelf = self;
[self.bridge.javaScriptExecutor executeAsyncBlockOnJavaScriptQueue:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf) {
return;
}

NSArray<NSNumber *> *allRootTags;
if (targetRootTag != nil) {
allRootTags = [NSArray arrayWithObject:targetRootTag];
} else {
// UIManager may have more than one Root
allRootTags = strongSelf->_shadowViewRegistry.allRootTags;
}

for (NSNumber *rootTag in allRootTags) {
NSArray<HippyShadowView *> *shadowViews = [strongSelf->_shadowViewRegistry componentsForRootTag:rootTag].allValues;
Class shadowTextClass = [HippyShadowText class];
Class shadowTextViewClass = [HippyShadowTextView class];
for (HippyShadowView *shadowView in shadowViews) {
if ([shadowView isKindOfClass:shadowTextClass] ||
[shadowView isKindOfClass:shadowTextViewClass]) {
[shadowView dirtyText:NO];
[shadowView dirtyPropagation:NativeRenderUpdateLifecycleLayoutDirtied];
}
}
// do layout and refresh UI
auto domManager = self.domManager.lock();
if (domManager) {
auto rootNode = [strongSelf->_shadowViewRegistry rootNodeForTag:rootTag];
domManager->DoLayout(rootNode);
domManager->EndBatch(rootNode);
}
}
}];
}

@end


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,7 @@ - (void)dirtyText:(BOOL)needToDoLayout {
BOOL isJSTaskRunner = (domManager->GetTaskRunner() && footstone::TaskRunner::GetCurrentTaskRunner());
if (isJSTaskRunner) {
domNodeAction();
}
else {
} else {
std::vector<std::function<void()>> ops = {domNodeAction};
domManager->PostTask(hippy::dom::Scene(std::move(ops)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@

@interface HippyBaseTextInput : HippyView

/// Font property - FontSize
@property (nonatomic, strong) NSNumber *fontSize;
/// Font property - FontWeight
@property (nonatomic, strong) NSString *fontWeight;
/// Font property - FontStyle
@property (nonatomic, strong) NSString *fontStyle;
/// Font property - FontFamily
@property (nonatomic, strong) NSString *fontFamily;

@property (nonatomic, strong) UIFont *font;
@property (nonatomic, assign) UIEdgeInsets contentInset;
@property (nonatomic, copy) NSString *value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/

#import "HippyBaseTextInput.h"
#import "HippyFont.h"

static NSString *const kKeyboardHeightKey = @"keyboardHeight";

Expand Down Expand Up @@ -95,4 +96,56 @@ - (void)setOnKeyboardHeightChanged:(HippyDirectEventBlock)onKeyboardHeightChange
}
}


#pragma mark - Hippy Update Callback

- (void)hippyBridgeDidFinishTransaction {
// Use this opportunity to update font if needed.
[self layoutIfNeeded];
}

- (void)layoutSubviews {
[super layoutSubviews];
[self rebuildAndUpdateFont];
}


#pragma mark - Font Related

- (void)setFontSize:(NSNumber *)fontSize {
_fontSize = fontSize;
[self setNeedsLayout];
}

- (void)setFontStyle:(NSString *)fontStyle {
_fontStyle = fontStyle;
[self setNeedsLayout];
}

- (void)setFontWeight:(NSString *)fontWeight {
_fontWeight = fontWeight;
[self setNeedsLayout];
}

- (void)setFontFamily:(NSString *)fontFamily {
_fontFamily = fontFamily;
[self setNeedsLayout];
}

- (void)rebuildAndUpdateFont {
// Convert fontName to fontFamily if needed
CGFloat scaleMultiplier = 1.0; // scale not supported
NSString *familyName = [HippyFont familyNameWithCSSNameMatching:self.fontFamily];
UIFont *font = [HippyFont updateFont:self.font
withFamily:familyName
size:self.fontSize
weight:self.fontWeight
style:self.fontStyle
variant:nil
scaleMultiplier:scaleMultiplier];
if (self.font != font) {
self.font = font;
}
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,20 @@
@property (nonatomic, copy) NSString *text;
@property (nonatomic, copy) NSString *placeholder;

@property (nonatomic, strong) UIFont *font;

/// ParagraphStyles - lineHeight
@property (nonatomic, strong) NSNumber *lineHeight;
/// ParagraphStyles - lineSpacing
@property (nonatomic, strong) NSNumber *lineSpacing;
/// ParagraphStyles - lineHeightMultiple
@property (nonatomic, strong) NSNumber *lineHeightMultiple;

/// Font property - FontSize
@property (nonatomic, strong) NSNumber *fontSize;
/// Font property - FontWeight
@property (nonatomic, strong) NSString *fontWeight;
/// Font property - FontStyle
@property (nonatomic, strong) NSString *fontStyle;
/// Font property - FontFamily
@property (nonatomic, strong) NSString *fontFamily;

@end
Loading

0 comments on commit 8ec3a0e

Please sign in to comment.