Skip to content

Commit e748f28

Browse files
committed
feat: faster html generation
1 parent 81e5803 commit e748f28

File tree

1 file changed

+101
-69
lines changed

1 file changed

+101
-69
lines changed

ios/inputParser/EnrichedHTMLParser.mm

Lines changed: 101 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
@implementation EnrichedHTMLParser {
77
NSDictionary<NSNumber *, id<BaseStyleProtocol>> *_styles;
8-
NSArray<NSNumber *> *_inlineOrder;
9-
NSArray<NSNumber *> *_paragraphOrder;
8+
NSArray<id<BaseStyleProtocol>> *_inlineStyles;
9+
NSArray<id<BaseStyleProtocol>> *_paragraphStyles;
1010
}
1111

1212
- (instancetype)initWithStyles:(NSDictionary<NSNumber *, id> *)stylesDict {
@@ -16,27 +16,27 @@ - (instancetype)initWithStyles:(NSDictionary<NSNumber *, id> *)stylesDict {
1616

1717
_styles = stylesDict ?: @{};
1818

19-
NSMutableArray *inlineArr = [NSMutableArray array];
20-
NSMutableArray *paragraphArr = [NSMutableArray array];
19+
NSMutableArray *inlineStylesArray = [NSMutableArray array];
20+
NSMutableArray *paragraphStylesArray = [NSMutableArray array];
2121

22-
for (NSNumber *type in _styles) {
23-
id<BaseStyleProtocol> style = _styles[type];
22+
NSArray *allKeys = stylesDict.allKeys;
23+
for (NSInteger i = 0; i < allKeys.count; i++) {
24+
NSNumber *key = allKeys[i];
25+
id<BaseStyleProtocol> style = stylesDict[key];
2426
Class cls = style.class;
2527

26-
BOOL isParagraph = ([cls respondsToSelector:@selector(isParagraphStyle)] &&
27-
[cls isParagraphStyle]);
28+
BOOL isParagraph = ([cls respondsToSelector:@selector(isParagraphStyle)]) &&
29+
[cls isParagraphStyle];
2830

29-
if (isParagraph)
30-
[paragraphArr addObject:type];
31-
else
32-
[inlineArr addObject:type];
31+
if (isParagraph) {
32+
[paragraphStylesArray addObject:style];
33+
} else {
34+
[inlineStylesArray addObject:style];
35+
}
3336
}
3437

35-
[inlineArr sortUsingSelector:@selector(compare:)];
36-
[paragraphArr sortUsingSelector:@selector(compare:)];
37-
38-
_inlineOrder = inlineArr.copy;
39-
_paragraphOrder = paragraphArr.copy;
38+
_inlineStyles = inlineStylesArray.copy;
39+
_paragraphStyles = paragraphStylesArray.copy;
4040

4141
return self;
4242
}
@@ -49,10 +49,10 @@ - (NSString *)buildHtmlFromAttributedString:(NSAttributedString *)text
4949

5050
HTMLElement *root = [self buildRootNodeFromAttributedString:text];
5151

52-
NSMutableData *buf = [NSMutableData data];
53-
[self createHtmlFromNode:root into:buf pretify:pretify];
52+
NSMutableData *buffer = [NSMutableData data];
53+
[self createHtmlFromNode:root into:buffer pretify:pretify];
5454

55-
return [[NSString alloc] initWithData:buf encoding:NSUTF8StringEncoding];
55+
return [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding];
5656
}
5757

5858
- (HTMLElement *)buildRootNodeFromAttributedString:(NSAttributedString *)text {
@@ -65,7 +65,7 @@ - (HTMLElement *)buildRootNodeFromAttributedString:(NSAttributedString *)text {
6565
br.tag = "br";
6666
br.selfClosing = YES;
6767

68-
__block NSNumber *previousParagraphType = nil;
68+
__block id<BaseStyleProtocol> previousParagraphStyle = nil;
6969
__block HTMLElement *previousNode = nil;
7070

7171
[plain
@@ -77,37 +77,27 @@ - (HTMLElement *)buildRootNodeFromAttributedString:(NSAttributedString *)text {
7777
BOOL *__unused stop) {
7878
if (paragraphRange.length == 0) {
7979
[root.children addObject:br];
80-
previousParagraphType = nil;
80+
previousParagraphStyle = nil;
8181
previousNode = nil;
8282
return;
8383
}
84-
NSDictionary *attrsAtStart =
85-
[text attributesAtIndex:paragraphRange.location
86-
effectiveRange:nil];
87-
88-
NSNumber *ptype = nil;
89-
for (NSNumber *sty in self->_paragraphOrder) {
90-
id<BaseStyleProtocol> s = self->_styles[sty];
91-
NSString *key = [s.class attributeKey];
92-
id val = attrsAtStart[key];
93-
if (val && [s styleCondition:val
94-
range:paragraphRange]) {
95-
ptype = sty;
96-
break;
97-
}
98-
}
9984

100-
HTMLElement *container =
101-
[self containerForBlock:ptype
102-
reuseLastOf:previousParagraphType
103-
previousNode:previousNode
104-
rootNode:root];
85+
id<BaseStyleProtocol> paragraphStyle =
86+
[self detectParagraphStyle:text
87+
paragraphRange:paragraphRange];
10588

106-
previousParagraphType = ptype;
89+
HTMLElement *container = [self
90+
containerForParagraphStyle:paragraphStyle
91+
previousParagraphStyle:previousParagraphStyle
92+
previousNode:previousNode
93+
rootNode:root];
94+
95+
previousParagraphStyle = paragraphStyle;
10796
previousNode = container;
10897

109-
HTMLElement *target = [self getNextContainer:ptype
110-
currentContainer:container];
98+
HTMLElement *target =
99+
[self nextContainerForParagraphStyle:paragraphStyle
100+
currentContainer:container];
111101

112102
[text
113103
enumerateAttributesInRange:paragraphRange
@@ -128,10 +118,47 @@ - (HTMLElement *)buildRootNodeFromAttributedString:(NSAttributedString *)text {
128118
return root;
129119
}
130120

131-
- (HTMLElement *)containerForBlock:(NSNumber *)currentParagraphType
132-
reuseLastOf:(NSNumber *)previousParagraphType
133-
previousNode:(HTMLElement *)previousNode
134-
rootNode:(HTMLElement *)rootNode {
121+
- (HTMLElement *)nextContainerForParagraphStyle:
122+
(id<BaseStyleProtocol> _Nullable)style
123+
currentContainer:(HTMLElement *)container {
124+
if (!style)
125+
return container;
126+
127+
const char *sub = [style.class subTagName];
128+
if (!sub)
129+
return container;
130+
131+
HTMLElement *inner = [HTMLElement new];
132+
inner.tag = sub;
133+
[container.children addObject:inner];
134+
return inner;
135+
}
136+
137+
- (id<BaseStyleProtocol> _Nullable)
138+
detectParagraphStyle:(NSAttributedString *)text
139+
paragraphRange:(NSRange)paragraphRange {
140+
NSDictionary *attrsAtStart = [text attributesAtIndex:paragraphRange.location
141+
effectiveRange:nil];
142+
id<BaseStyleProtocol> _Nullable foundParagraphStyle = nil;
143+
for (NSInteger i = 0; i < _paragraphStyles.count; i++) {
144+
id<BaseStyleProtocol> paragraphStyle = _paragraphStyles[i];
145+
Class paragraphStyleClass = paragraphStyle.class;
146+
147+
NSAttributedStringKey attributeKey = [paragraphStyleClass attributeKey];
148+
id value = attrsAtStart[attributeKey];
149+
150+
if (value && [paragraphStyle styleCondition:value range:paragraphRange]) {
151+
return paragraphStyle;
152+
}
153+
}
154+
155+
return foundParagraphStyle;
156+
}
157+
158+
- (HTMLElement *)currentParagraphType:(NSNumber *)currentParagraphType
159+
previousParagraphType:(NSNumber *)previousParagraphType
160+
previousNode:(HTMLElement *)previousNode
161+
rootNode:(HTMLElement *)rootNode {
135162
if (!currentParagraphType) {
136163
HTMLElement *outer = [HTMLElement new];
137164
outer.tag = "p";
@@ -156,25 +183,31 @@ - (HTMLElement *)containerForBlock:(NSNumber *)currentParagraphType
156183
return outer;
157184
}
158185

159-
- (HTMLElement *)getNextContainer:(NSNumber *)blockType
160-
currentContainer:(HTMLElement *)container {
161-
162-
if (!blockType)
163-
return container;
164-
165-
id<BaseStyleProtocol> style = _styles[blockType];
186+
- (HTMLElement *)
187+
containerForParagraphStyle:(id<BaseStyleProtocol> _Nullable)currentStyle
188+
previousParagraphStyle:(id<BaseStyleProtocol> _Nullable)previousStyle
189+
previousNode:(HTMLElement *)previousNode
190+
rootNode:(HTMLElement *)rootNode {
191+
if (!currentStyle) {
192+
HTMLElement *outer = [HTMLElement new];
193+
outer.tag = "p";
194+
[rootNode.children addObject:outer];
195+
return outer;
196+
}
166197

167-
const char *subTagName = [style.class subTagName];
198+
BOOL sameStyle = (currentStyle == previousStyle);
199+
Class styleClass = currentStyle.class;
200+
BOOL hasSub = ([styleClass subTagName] != NULL);
168201

169-
if (subTagName) {
170-
HTMLElement *inner = [HTMLElement new];
171-
inner.tag = subTagName;
172-
[container.children addObject:inner];
173-
return inner;
174-
}
202+
if (sameStyle && hasSub)
203+
return previousNode;
175204

176-
return container;
205+
HTMLElement *outer = [HTMLElement new];
206+
outer.tag = [styleClass tagName];
207+
[rootNode.children addObject:outer];
208+
return outer;
177209
}
210+
178211
- (HTMLNode *)getInlineStyleNodes:(NSAttributedString *)text
179212
range:(NSRange)range
180213
attrs:(NSDictionary *)attrs
@@ -184,13 +217,12 @@ - (HTMLNode *)getInlineStyleNodes:(NSAttributedString *)text
184217
textNode.range = range;
185218
HTMLNode *currentNode = textNode;
186219

187-
for (NSNumber *inlineStyleType in _inlineOrder) {
188-
189-
id<BaseStyleProtocol> styleObject = _styles[inlineStyleType];
220+
for (NSInteger i = 0; i < _inlineStyles.count; i++) {
221+
id<BaseStyleProtocol> styleObject = _inlineStyles[i];
190222
Class styleClass = styleObject.class;
191223

192-
NSString *key = [styleClass attributeKey];
193-
id value = attrs[key];
224+
NSAttributedStringKey attributeKey = [styleClass attributeKey];
225+
id value = attrs[attributeKey];
194226

195227
if (!value || ![styleObject styleCondition:value range:range])
196228
continue;

0 commit comments

Comments
 (0)