Skip to content

Commit c070294

Browse files
fix(ios): apply obliqueness if italics are not supported (#745)
# Summary this fixes #739 - now `NSObliqueness` attribute is applied, when given font does not support proper italics - added `stylingPriority` trait for base styles, so italics can be applied last ## Test Plan Paste some non-latin characters, e.g. "冰淇淋", apply the italic style, everything should look as expected ## Screenshots / Videos The italics are now properly applied https://github.com/user-attachments/assets/ed73f153-98b6-4d6c-bb2b-7d17eed75c25 ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ❌ | | Web | ❌ | ## Checklist - [x] E2E tests are passing - [ ] Required E2E tests have been added (if applicable) --------- Co-authored-by: Mikołaj Szydłowski <9szydlowski9@gmail.com>
1 parent 7fa3793 commit c070294

13 files changed

Lines changed: 243 additions & 19 deletions

File tree

8 Bytes
Loading
21 Bytes
Loading

ios/extensions/ArrayExtension.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#import <Foundation/Foundation.h>
2+
#pragma once
3+
4+
@interface NSArray (ArrayExtension)
5+
- (NSArray *)sortedArrayBySortKey:(NSInteger (^)(id item))sortKeyForItem;
6+
@end

ios/extensions/ArrayExtension.mm

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#import "ArrayExtension.h"
2+
3+
@implementation NSArray (ArrayExtension)
4+
5+
- (NSArray *)sortedArrayBySortKey:(NSInteger (^)(id item))sortKeyForItem {
6+
return [self sortedArrayWithOptions:NSSortStable
7+
usingComparator:^NSComparisonResult(id a, id b) {
8+
NSInteger aKey = sortKeyForItem(a);
9+
NSInteger bKey = sortKeyForItem(b);
10+
if (aKey == bKey) {
11+
return NSOrderedSame;
12+
}
13+
return aKey < bKey ? NSOrderedAscending
14+
: NSOrderedDescending;
15+
}];
16+
}
17+
18+
@end

ios/extensions/FontExtension.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
- (UIFont *)setItalic;
99
- (UIFont *)withFontTraits:(UIFont *)from;
1010
- (UIFont *)setSize:(CGFloat)size;
11+
- (BOOL)coversCharacters:(const unichar *)chars count:(CFIndex)count;
1112
@end

ios/extensions/FontExtension.mm

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#import "FontExtension.h"
2+
#import <CoreText/CoreText.h>
23
#import <React/RCTLog.h>
34

45
@implementation UIFont (FontExtension)
@@ -40,8 +41,6 @@ - (UIFont *)setItalic {
4041
if (fontDescriptor != nullptr) {
4142
return [UIFont fontWithDescriptor:fontDescriptor size:0];
4243
} else {
43-
RCTLogWarn(
44-
@"[EnrichedTextInput]: Couldn't apply italic trait to the font.");
4544
return self;
4645
}
4746
}
@@ -69,4 +68,10 @@ - (UIFont *)setSize:(CGFloat)size {
6968
}
7069
}
7170

71+
- (BOOL)coversCharacters:(const unichar *)chars count:(CFIndex)count {
72+
CGGlyph glyphs[2] = {0, 0};
73+
return CTFontGetGlyphsForCharacters((__bridge CTFontRef)self, chars, glyphs,
74+
count);
75+
}
76+
7277
@end

ios/inputAttributesManager/InputAttributesManager.mm

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#import "InputAttributesManager.h"
22
#import "AlignmentUtils.h"
3+
#import "ArrayExtension.h"
34
#import "AttributeEntry.h"
45
#import "EnrichedTextInputView.h"
56
#import "ParagraphAttributesUtils.h"
67
#import "RangeUtils.h"
78
#import "StyleHeaders.h"
9+
#import "StyleUtils.h"
810
#import "ZeroWidthSpaceUtils.h"
911

1012
@implementation InputAttributesManager {
@@ -99,15 +101,11 @@ - (void)handleDirtyRangesStyling {
99101

100102
// Sort style types so paragraph styles come first. Their broad visual
101103
// attributes (e.g. foreground color, font) are laid down before inline
102-
// styles override them on their specific sub-ranges.
104+
// styles override them on their specific sub-ranges. Inline styles among
105+
// themselves follow their stylePriority.
103106
NSArray *sortedStyleTypes = [presentStyles.allKeys
104-
sortedArrayUsingComparator:^NSComparisonResult(NSNumber *a,
105-
NSNumber *b) {
106-
BOOL aPara = [_input->stylesDict[a] isParagraph];
107-
BOOL bPara = [_input->stylesDict[b] isParagraph];
108-
if (aPara == bPara)
109-
return NSOrderedSame;
110-
return aPara ? NSOrderedAscending : NSOrderedDescending;
107+
sortedArrayBySortKey:^NSInteger(NSNumber *styleType) {
108+
return [_input->stylesDict[styleType] stylePriority];
111109
}];
112110

113111
// re-apply meta-attributes and apply visual styling following the saved

ios/interfaces/StyleBase.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- (BOOL)isParagraph;
1515
- (BOOL)needsZWS;
1616
- (BOOL)appliesStylingToTyping;
17+
- (NSInteger)stylePriority;
1718
- (instancetype)initWithHost:(id<EnrichedViewHost>)host;
1819
- (NSRange)actualUsedRange:(NSRange)range;
1920
- (void)toggle:(NSRange)range;

ios/interfaces/StyleBase.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ - (BOOL)appliesStylingToTyping {
4545
return NO;
4646
}
4747

48+
// determines the order in which the styles are applied
49+
- (NSInteger)stylePriority {
50+
return [self isParagraph] ? 0 : 2;
51+
}
52+
4853
- (instancetype)initWithHost:(id<EnrichedViewHost>)host {
4954
self = [super init];
5055
_host = host;

ios/styles/ItalicStyle.mm

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#import "EnrichedTextInputView.h"
2-
#import "FontExtension.h"
2+
#import "ItalicUtils.h"
33
#import "StyleHeaders.h"
44

55
@implementation ItalicStyle : StyleBase
@@ -16,21 +16,33 @@ - (BOOL)isParagraph {
1616
return NO;
1717
}
1818

19+
// some styles might apply a new font (inline code), so we need to apply
20+
// the italic last, that way we know if the used font supports italics
21+
// or we need to apply a slant
22+
- (NSInteger)stylePriority {
23+
return 3;
24+
}
25+
1926
- (void)applyStyling:(NSRange)range {
27+
if (self.host.textView.textStorage == nullptr || range.length == 0 ||
28+
NSMaxRange(range) > self.host.textView.textStorage.length) {
29+
return;
30+
}
31+
32+
// we process each present font
2033
[self.host.textView.textStorage
2134
enumerateAttribute:NSFontAttributeName
2235
inRange:range
2336
options:0
24-
usingBlock:^(id _Nullable value, NSRange range,
37+
usingBlock:^(id _Nullable value, NSRange fontRange,
2538
BOOL *_Nonnull stop) {
2639
UIFont *font = (UIFont *)value;
27-
if (font != nullptr) {
28-
UIFont *newFont = [font setItalic];
29-
[self.host.textView.textStorage
30-
addAttribute:NSFontAttributeName
31-
value:newFont
32-
range:range];
40+
if (font == nullptr) {
41+
return;
3342
}
43+
[ItalicUtils applyItalicForFont:font
44+
inTextStorage:self.host.textView.textStorage
45+
inRange:fontRange];
3446
}];
3547
}
3648

0 commit comments

Comments
 (0)