From 8379cee44f0114e34882f2e049872a7b6e2dde92 Mon Sep 17 00:00:00 2001 From: iska Date: Mon, 24 Apr 2017 22:36:02 +0200 Subject: [PATCH 01/11] Fix lazy allocation of childNodes Set in HTMLNode The call self.childNodes always allocates the collection even if a nil value is acceptable, i.e. hasChildNodes should return true even if the childNodes Set is nil but should not allocate it yet. Hence self.childNodes should only be used when appending child nodes. --- Sources/HTMLNode.m | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/Sources/HTMLNode.m b/Sources/HTMLNode.m index da9d2b6..7bad7dc 100644 --- a/Sources/HTMLNode.m +++ b/Sources/HTMLNode.m @@ -64,7 +64,7 @@ - (HTMLDocument *)ownerDocument - (void)setOwnerDocument:(HTMLDocument *)ownerDocument { _ownerDocument = ownerDocument; - for (HTMLNode *child in self.childNodes) { + for (HTMLNode *child in _childNodes) { [child setOwnerDocument:ownerDocument]; } } @@ -86,12 +86,12 @@ - (HTMLElement *)parentElement - (HTMLNode *)firstChild { - return self.childNodes.firstObject; + return _childNodes.firstObject; } - (HTMLNode *)lastChild { - return self.childNodes.lastObject; + return _childNodes.lastObject; } - (HTMLNode *)previousSibling @@ -132,7 +132,7 @@ - (HTMLElement *)nextSiblingElement - (NSUInteger)index { - return [self.parentNode indexOfChildNode:self]; + return [_parentNode indexOfChildNode:self]; } - (NSString *)textContent @@ -156,12 +156,16 @@ - (HTMLElement *)asElement - (BOOL)hasChildNodes { - return self.childNodes.count > 0; + return _childNodes.count > 0; } - (BOOL)hasChildNodeOfType:(HTMLNodeType)type { - NSUInteger index = [self.childNodes indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + if (_childNodes == nil) { + return NO; + } + + NSUInteger index = [_childNodes indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { if ([(HTMLNode *)obj nodeType] == type) { *stop = YES; return YES; @@ -174,7 +178,7 @@ - (BOOL)hasChildNodeOfType:(HTMLNodeType)type - (NSUInteger)childNodesCount { - return self.childNodes.count; + return _childNodes.count; } - (BOOL)isEmpty @@ -184,25 +188,25 @@ - (BOOL)isEmpty - (HTMLNode *)childNodeAtIndex:(NSUInteger)index { - return [self.childNodes objectAtIndex:index]; + return [_childNodes objectAtIndex:index]; } - (NSUInteger)childElementsCount { - return [self.childNodes indexesOfObjectsPassingTest:^BOOL(HTMLNode * _Nonnull node, NSUInteger idx, BOOL * _Nonnull stop) { + return [_childNodes indexesOfObjectsPassingTest:^BOOL(HTMLNode * _Nonnull node, NSUInteger idx, BOOL * _Nonnull stop) { return node.nodeType == HTMLNodeElement; }].count; } - (NSUInteger)indexOfChildNode:(HTMLNode *)node { - return [self.childNodes indexOfObject:node]; + return [_childNodes indexOfObject:node]; } - (HTMLElement *)childElementAtIndex:(NSUInteger)index { NSUInteger counter = 0; - for (HTMLNode *node in self.childNodes) { + for (HTMLNode *node in _childNodes) { if (node.nodeType == HTMLNodeElement) { if (counter == index) { return node.asElement; @@ -216,7 +220,7 @@ - (HTMLElement *)childElementAtIndex:(NSUInteger)index - (NSUInteger)indexOfChildElement:(HTMLElement *)element { NSUInteger counter = 0; - for (HTMLNode *node in self.childNodes) { + for (HTMLNode *node in _childNodes) { if (node.nodeType == HTMLNodeElement) { if (node == element) { return counter; @@ -303,7 +307,7 @@ - (void)replaceAllChildNodesWithNode:(HTMLNode *)node - (void)removeFromParentNode { - [self.parentNode removeChildNode:self]; + [_parentNode removeChildNode:self]; } - (HTMLNode *)removeChildNode:(HTMLNode *)child @@ -335,18 +339,18 @@ - (HTMLNode *)removeChildNodeAtIndex:(NSUInteger)index - (void)reparentChildNodesIntoNode:(HTMLNode *)node { - for (HTMLNode *child in self.childNodes) { + for (HTMLNode *child in _childNodes) { [node appendNode:child]; } - [(NSMutableOrderedSet *)self.childNodes removeAllObjects]; + [(NSMutableOrderedSet *)_childNodes removeAllObjects]; } - (void)removeAllChildNodes { - for (HTMLNode *child in self.childNodes) { + for (HTMLNode *child in _childNodes) { [child setParentNode:nil]; } - [(NSMutableOrderedSet *)self.childNodes removeAllObjects]; + [(NSMutableOrderedSet *)_childNodes removeAllObjects]; } - (HTMLDocumentPosition)compareDocumentPositionWithNode:(HTMLNode *)otherNode @@ -417,7 +421,7 @@ - (BOOL)isDescendantOfNode:(HTMLNode *)otherNode return self.nodeType != HTMLNodeDocument && self.ownerDocument == otherNode; } - for (HTMLNode *parentNode = self.parentNode; parentNode; parentNode = parentNode.parentNode) { + for (HTMLNode *parentNode = _parentNode; parentNode; parentNode = parentNode.parentNode) { if (parentNode == otherNode) { return YES; } @@ -439,7 +443,7 @@ - (void)enumerateChildNodesUsingBlock:(void (^)(HTMLNode *node, NSUInteger idx, return; } - [self.childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [_childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { block(obj, idx, stop); }]; } @@ -450,7 +454,7 @@ - (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInte return; } - [self.childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [_childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { if ([obj isKindOfClass:[HTMLElement class]]) { block([obj asElement], idx, stop); } @@ -690,7 +694,7 @@ - (instancetype)cloneNodeDeep:(BOOL)deep HTMLNode *copy = [self copy]; if (deep) { - for (HTMLNode *child in self.childNodes) { + for (HTMLNode *child in _childNodes) { [copy appendNode:[child cloneNodeDeep:YES]]; } } From 1cd1a915d379a0272f96dbed7f4c7e64201d78a0 Mon Sep 17 00:00:00 2001 From: iska Date: Mon, 24 Apr 2017 22:58:49 +0200 Subject: [PATCH 02/11] Replace NSStringFromSelector calls with constants in HTMLNode This should reduce allocations during HTML parsing. See Issue #10 --- Sources/HTMLNode.m | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Sources/HTMLNode.m b/Sources/HTMLNode.m index 7bad7dc..be9bb9e 100644 --- a/Sources/HTMLNode.m +++ b/Sources/HTMLNode.m @@ -19,6 +19,10 @@ #import "HTMLDocument+Private.h" #import "HTMLDOMUtils.h" +NSString * const ValidationNodePreInsertion = @"-ensurePreInsertionValidityOfNode:beforeChildNode:"; +NSString * const ValidationNodeReplacement = @"-ensureReplacementValidityOfChildNode:withNode:"; +NSString * const RemoveChildNode = @"-removeChildNode:"; + @interface HTMLNode () { NSMutableOrderedSet *_childNodes; @@ -315,7 +319,7 @@ - (HTMLNode *)removeChildNode:(HTMLNode *)child if (child.parentNode != self) { [NSException raise:HTMLKitNotFoundError format:@"%@: Not Fount Error, removing non-child node %@. The object can not be found here.", - NSStringFromSelector(_cmd), child]; + RemoveChildNode, child]; } HTMLNode *oldNode = child; @@ -577,18 +581,18 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin - (void)ensurePreInsertionValidityOfNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child { - CheckParentValid(self, NSStringFromSelector(_cmd)); + CheckParentValid(self, ValidationNodePreInsertion); - CheckChildsParent(self, child, NSStringFromSelector(_cmd)); + CheckChildsParent(self, child, ValidationNodePreInsertion); - CheckInsertedNodeValid(node, NSStringFromSelector(_cmd)); + CheckInsertedNodeValid(node, ValidationNodePreInsertion); - CheckInvalidCombination(self, node, NSStringFromSelector(_cmd)); + CheckInvalidCombination(self, node, ValidationNodePreInsertion); void (^ hierarchyError)() = ^{ [NSException raise:HTMLKitHierarchyRequestError format:@"%@: Hierarchy Request Error, inserting (%@) into (%@). The operation would yield an incorrect node tree.", - NSStringFromSelector(_cmd), self, node]; + ValidationNodePreInsertion, self, node]; }; if (self.nodeType == HTMLNodeDocument) { @@ -627,18 +631,18 @@ - (void)ensurePreInsertionValidityOfNode:(HTMLNode *)node beforeChildNode:(HTMLN - (void)ensureReplacementValidityOfChildNode:(HTMLNode *)child withNode:(HTMLNode *)node { - CheckParentValid(self, NSStringFromSelector(_cmd)); + CheckParentValid(self, ValidationNodeReplacement); - CheckChildsParent(self, child, NSStringFromSelector(_cmd)); + CheckChildsParent(self, child, ValidationNodeReplacement); - CheckInsertedNodeValid(node, NSStringFromSelector(_cmd)); + CheckInsertedNodeValid(node, ValidationNodeReplacement); - CheckInvalidCombination(self, node, NSStringFromSelector(_cmd)); + CheckInvalidCombination(self, node, ValidationNodeReplacement); void (^ hierarchyError)() = ^{ [NSException raise:HTMLKitHierarchyRequestError format:@"%@: Hierarchy Request Error. The operation would yield an incorrect node tree.", - NSStringFromSelector(_cmd)]; + ValidationNodeReplacement]; }; void (^ checkParentHasAnotherChildOfType)(HTMLNodeType) = ^ void (HTMLNodeType type) { From 47ec0867a897a54efd20e1a17a29309a2aa7ea24 Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 25 Apr 2017 00:12:39 +0200 Subject: [PATCH 03/11] Improve reverseObjectEnumerator usage while parsing HTML Do not use the `allObjects` call on the reverse enumerators in the Parser and the List of Active Formatting Elements to prevent allocating a new array of the unenumerated objects. This should reduce memory consumption while parsing, see issue #10 --- Sources/HTMLListOfActiveFormattingElements.m | 2 +- Sources/HTMLParser.m | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/HTMLListOfActiveFormattingElements.m b/Sources/HTMLListOfActiveFormattingElements.m index d0fb8b0..665ce8f 100644 --- a/Sources/HTMLListOfActiveFormattingElements.m +++ b/Sources/HTMLListOfActiveFormattingElements.m @@ -46,7 +46,7 @@ - (NSUInteger)indexOfElement:(id)node - (void)addElement:(HTMLElement *)element { NSUInteger existing = 0; - for (HTMLElement *node in _list.reverseObjectEnumerator.allObjects) { + for (HTMLElement *node in _list.reverseObjectEnumerator) { if ([node isEqual:[HTMLMarker marker]]) { break; } diff --git a/Sources/HTMLParser.m b/Sources/HTMLParser.m index 74844bc..3137081 100644 --- a/Sources/HTMLParser.m +++ b/Sources/HTMLParser.m @@ -1272,7 +1272,7 @@ - (void)processStartTagTokenInBody:(HTMLStartTagToken *)token @"dd": @[@"dd", @"dt"], @"dt": @[@"dd", @"dt"]}; - for (HTMLElement *node in _stackOfOpenElements.reverseObjectEnumerator.allObjects) { + for (HTMLElement *node in _stackOfOpenElements.reverseObjectEnumerator) { if ([map[tagName] containsObject:node.tagName]) { [self generateImpliedEndTagsExceptForElement:node.tagName]; if (![self.currentNode.tagName isEqualToString:node.tagName]) { @@ -1590,7 +1590,7 @@ - (void)processEndTagTokenInBody:(HTMLEndTagToken *)token - (void)processAnyOtherEndTagTokenInBody:(HTMLTagToken *)token { - for (HTMLElement *node in _stackOfOpenElements.reverseObjectEnumerator.allObjects) { + for (HTMLElement *node in _stackOfOpenElements.reverseObjectEnumerator) { if ([node.tagName isEqualToString:token.tagName]) { [self generateImpliedEndTagsExceptForElement:token.tagName]; if (![node.tagName isEqualToString:self.currentNode.tagName]) { From 644c180f81655c7ba8fbda14b65993c227677b81 Mon Sep 17 00:00:00 2001 From: iska Date: Wed, 26 Apr 2017 21:31:55 +0200 Subject: [PATCH 04/11] Improve memory allocation/consumption in the Stack of Open Elements Instead of allocating new dictionaries for the scope elements, the scope checks are just unrolled in-place. Now we have 6 almost identical methods that differ only in the inline-check-method. Not optimal but minimal memory and performance penalty. This should reduce memory consumption and increase the performance while parsing, see issue #10 --- Sources/HTMLParser.m | 6 +- Sources/HTMLStackOfOpenElements.m | 163 ++++++++++++++-------- Sources/include/HTMLStackOfOpenElements.h | 6 +- 3 files changed, 110 insertions(+), 65 deletions(-) diff --git a/Sources/HTMLParser.m b/Sources/HTMLParser.m index 3137081..2485650 100644 --- a/Sources/HTMLParser.m +++ b/Sources/HTMLParser.m @@ -1529,7 +1529,7 @@ - (void)processEndTagTokenInBody:(HTMLEndTagToken *)token } [self closePElement]; } else if ([tagName isEqualToString:@"li"]) { - if (![_stackOfOpenElements hasElementInListItemScopeWithTagName:@"li"]) { + if (![_stackOfOpenElements hasElementInListItemScopeWithTagName:tagName]) { [self emitParseError:@"Unexpected
  • element in "]; return; } @@ -1549,7 +1549,7 @@ - (void)processEndTagTokenInBody:(HTMLEndTagToken *)token } [_stackOfOpenElements popElementsUntilElementPoppedWithTagName:tagName]; } else if ([tagName isEqualToAny:@"h1", @"h2", @"h3", @"h4", @"h5", @"h6", nil]) { - if (![_stackOfOpenElements hasAnyElementInScopeWithAnyOfTagNames:@[@"h1", @"h2", @"h3", @"h4", @"h5", @"h6"]]) { + if (![_stackOfOpenElements hasHeaderElementInScope]) { [self emitParseError:@"Unexpected <%@> element in ", tagName]; return; } @@ -1569,7 +1569,7 @@ - (void)processEndTagTokenInBody:(HTMLEndTagToken *)token return; } } else if ([tagName isEqualToAny:@"applet", @"marquee", @"object", nil]) { - if (![_stackOfOpenElements hasAnyElementInScopeWithAnyOfTagNames:@[@"applet", @"marquee", @"object"]]) { + if (![_stackOfOpenElements hasElementInScopeWithTagName:tagName]) { [self emitParseError:@"Unexpected <%@> element in ", tagName]; return; } diff --git a/Sources/HTMLStackOfOpenElements.m b/Sources/HTMLStackOfOpenElements.m index daf1517..7420537 100644 --- a/Sources/HTMLStackOfOpenElements.m +++ b/Sources/HTMLStackOfOpenElements.m @@ -14,7 +14,6 @@ @interface HTMLStackOfOpenElements () { NSMutableArray *_stack; - NSDictionary *_specificScopeElementTypes; } @end @@ -27,26 +26,6 @@ - (instancetype)init self = [super init]; if (self) { _stack = [NSMutableArray new]; - _specificScopeElementTypes = @{ - @"applet": @(HTMLNamespaceHTML), - @"caption": @(HTMLNamespaceHTML), - @"html": @(HTMLNamespaceHTML), - @"table": @(HTMLNamespaceHTML), - @"td": @(HTMLNamespaceHTML), - @"th": @(HTMLNamespaceHTML), - @"marquee": @(HTMLNamespaceHTML), - @"object": @(HTMLNamespaceHTML), - @"template": @(HTMLNamespaceHTML), - @"mi": @(HTMLNamespaceMathML), - @"mo": @(HTMLNamespaceMathML), - @"mn": @(HTMLNamespaceMathML), - @"ms": @(HTMLNamespaceMathML), - @"mtext": @(HTMLNamespaceMathML), - @"annotation-xml": @(HTMLNamespaceMathML), - @"foreignObject": @(HTMLNamespaceSVG), - @"desc": @(HTMLNamespaceSVG), - @"title": @(HTMLNamespaceSVG) - }; } return self; } @@ -195,82 +174,148 @@ - (void)popAll #pragma mark - Element Scope -- (HTMLElement *)hasElementInScopeWithTagName:(NSString *)tagName; +NS_INLINE BOOL IsSpecificScopeElement(HTMLElement *element) { - return [self hasAnyElementInSpecificScopeWithTagNames:@[tagName] andElementTypes:_specificScopeElementTypes]; + switch (element.htmlNamespace) { + case HTMLNamespaceHTML: + return [element.tagName isEqualToAny:@"applet", @"caption", @"html", @"table", @"td", @"th", @"marquee", @"object", @"template", nil]; + case HTMLNamespaceMathML: + return [element.tagName isEqualToAny:@"mi", @"mo", @"mn", @"ms", @"mtext", @"annotation-xml", nil]; + case HTMLNamespaceSVG: + return [element.tagName isEqualToAny:@"foreignObject", @"desc", @"title", nil]; + } } -- (HTMLElement *)hasAnyElementInScopeWithAnyOfTagNames:(NSArray *)tagNames +NS_INLINE BOOL IsHeaderElement(HTMLElement *element) { - return [self hasAnyElementInSpecificScopeWithTagNames:tagNames andElementTypes:_specificScopeElementTypes]; + if (element.htmlNamespace != HTMLNamespaceHTML) { + return NO; + } + + return [element.tagName isEqualToAny:@"h1", @"h2", @"h3", @"h4", @"h5", @"h6", nil]; } -- (HTMLElement *)hasElementInListItemScopeWithTagName:(NSString *)tagName +NS_INLINE BOOL IsTableScopeElement(HTMLElement *element) { - NSMutableDictionary *elementTypes = [NSMutableDictionary dictionaryWithDictionary:_specificScopeElementTypes]; - [elementTypes addEntriesFromDictionary:@{@"ol": @(HTMLNamespaceHTML), - @"ul": @(HTMLNamespaceHTML)}]; + if (element.htmlNamespace != HTMLNamespaceHTML) { + return NO; + } - return [self hasElementInSpecificScopeWithTagName:tagName - andElementTypes:elementTypes]; + return [element.tagName isEqualToAny:@"html", @"table", @"template", nil]; } -- (HTMLElement *)hasElementInButtonScopeWithTagName:(NSString *)tagName +NS_INLINE BOOL IsListItemScopeElement(HTMLElement *element) { - NSMutableDictionary *elementTypes = [NSMutableDictionary dictionaryWithDictionary:_specificScopeElementTypes]; - [elementTypes addEntriesFromDictionary:@{@"button": @(HTMLNamespaceHTML)}]; + if (element.htmlNamespace != HTMLNamespaceHTML) { + return NO; + } + + return [element.tagName isEqualToAny:@"ol", @"ul", nil]; +} + +NS_INLINE BOOL IsSelectScopeElement(HTMLElement *element) +{ + if (element.htmlNamespace != HTMLNamespaceHTML) { + return NO; + } + + return ![element.tagName isEqualToString:@"optgroup"] && ![element.tagName isEqualToString:@"option"]; +} + +NS_INLINE BOOL IsButtonScopeElement(HTMLElement *element) +{ + if (element.htmlNamespace != HTMLNamespaceHTML) { + return NO; + } + + return [element.tagName isEqualToString:@"button"]; +} + +- (HTMLElement *)hasElementInScopeWithTagName:(NSString *)tagName; +{ + for (HTMLElement *node in _stack.reverseObjectEnumerator) { + if (node.htmlNamespace == HTMLNamespaceHTML && [tagName isEqualToString:node.tagName]) { + return node; + } + if (IsSpecificScopeElement(node)) { + return nil; + } + } + return nil; +} - return [self hasElementInSpecificScopeWithTagName:tagName - andElementTypes:elementTypes]; +- (HTMLElement *)hasHeaderElementInScope +{ + for (HTMLElement *node in _stack.reverseObjectEnumerator) { + if (IsHeaderElement(node)) { + return node; + } + if (IsSpecificScopeElement(node)) { + return nil; + } + } + return nil; } - (HTMLElement *)hasElementInTableScopeWithTagName:(NSString *)tagName { - return [self hasElementInSpecificScopeWithTagName:tagName - andElementTypes:@{@"html": @(HTMLNamespaceHTML), - @"table": @(HTMLNamespaceHTML), - @"template": @(HTMLNamespaceHTML)}]; + for (HTMLElement *node in _stack.reverseObjectEnumerator) { + if (node.htmlNamespace == HTMLNamespaceHTML && [tagName isEqualToString:node.tagName]) { + return node; + } + if (IsTableScopeElement(node)) { + return nil; + } + } + return nil; } - (HTMLElement *)hasElementInTableScopeWithAnyOfTagNames:(NSArray *)tagNames { - return [self hasAnyElementInSpecificScopeWithTagNames:tagNames - andElementTypes:@{@"html": @(HTMLNamespaceHTML), - @"table": @(HTMLNamespaceHTML), - @"template": @(HTMLNamespaceHTML)}]; + for (HTMLElement *node in _stack.reverseObjectEnumerator) { + if (node.htmlNamespace == HTMLNamespaceHTML && [tagNames containsObject:node.tagName]) { + return node; + } + if (IsTableScopeElement(node)) { + return nil; + } + } + return nil; } -- (HTMLElement *)hasElementInSelectScopeWithTagName:(NSString *)tagName +- (HTMLElement *)hasElementInListItemScopeWithTagName:(NSString *)tagName { for (HTMLElement *node in _stack.reverseObjectEnumerator) { - if ([node.tagName isEqualToString:tagName]) { + if (node.htmlNamespace == HTMLNamespaceHTML && [tagName isEqualToString:node.tagName]) { return node; } - if (!(node.htmlNamespace == HTMLNamespaceHTML && - [node.tagName isEqualToAny:@"optgroup", @"option", nil])) { + if (IsSpecificScopeElement(node) || IsListItemScopeElement(node)) { return nil; } } return nil; } -- (HTMLElement *)hasElementInSpecificScopeWithTagName:(NSString *)tagName - andElementTypes:(NSDictionary *)elementTypes +- (HTMLElement *)hasElementInButtonScopeWithTagName:(NSString *)tagName { - return [self hasAnyElementInSpecificScopeWithTagNames:@[tagName] andElementTypes:elementTypes]; + for (HTMLElement *node in _stack.reverseObjectEnumerator) { + if (node.htmlNamespace == HTMLNamespaceHTML && [tagName isEqualToString:node.tagName]) { + return node; + } + if (IsSpecificScopeElement(node) || IsButtonScopeElement(node)) { + return nil; + } + } + return nil; } -- (HTMLElement *)hasAnyElementInSpecificScopeWithTagNames:(NSArray *)tagNames - andElementTypes:(NSDictionary *)elementTypes +- (HTMLElement *)hasElementInSelectScopeWithTagName:(NSString *)tagName { for (HTMLElement *node in _stack.reverseObjectEnumerator) { - if ([tagNames containsObject:node.tagName]) { - NSNumber *namespace = elementTypes[node.tagName] ?: @(HTMLNamespaceHTML); - if ([namespace isEqual:@(node.htmlNamespace)]) { - return node; - } + if (node.htmlNamespace == HTMLNamespaceHTML && [tagName isEqualToString:node.tagName]) { + return node; } - if ([elementTypes[node.tagName] isEqual:@(node.htmlNamespace)]) { + if (IsSelectScopeElement(node)) { return nil; } } diff --git a/Sources/include/HTMLStackOfOpenElements.h b/Sources/include/HTMLStackOfOpenElements.h index eccae52..a7f0e0e 100644 --- a/Sources/include/HTMLStackOfOpenElements.h +++ b/Sources/include/HTMLStackOfOpenElements.h @@ -163,11 +163,11 @@ https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-the-specific-scope */ - (HTMLElement *)hasElementInScopeWithTagName:(NSString *)tagName; -- (HTMLElement *)hasAnyElementInScopeWithAnyOfTagNames:(NSArray *)tagNames; -- (HTMLElement *)hasElementInListItemScopeWithTagName:(NSString *)tagName; -- (HTMLElement *)hasElementInButtonScopeWithTagName:(NSString *)tagName; +- (HTMLElement *)hasHeaderElementInScope; - (HTMLElement *)hasElementInTableScopeWithTagName:(NSString *)tagName; - (HTMLElement *)hasElementInTableScopeWithAnyOfTagNames:(NSArray *)tagNames; +- (HTMLElement *)hasElementInListItemScopeWithTagName:(NSString *)tagName; +- (HTMLElement *)hasElementInButtonScopeWithTagName:(NSString *)tagName; - (HTMLElement *)hasElementInSelectScopeWithTagName:(NSString *)tagName; /** From 2446da3a6d8bf6c122a68802c5636e3dbbf56e3c Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 2 May 2017 13:50:35 +0200 Subject: [PATCH 05/11] Update travis xcode image to 8.3 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 313ee3f..0620825 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode8.2 +osx_image: xcode8.3 branches: except: From 514d23f7a04b053dc8407a0fc7200e91dec60a1c Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 2 May 2017 13:52:16 +0200 Subject: [PATCH 06/11] Update SDK versions in travis.yml --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0620825..6521884 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,10 +17,10 @@ env: - MACOS_FRAMEWORK_SCHEME=HTMLKit-macOS - WATCHOS_FRAMEWORK_SCHEME="HTMLKit-watchOS" - TVOS_FRAMEWORK_SCHEME="HTMLKit-tvOS" - - IOS_SDK=iphonesimulator10.2 + - IOS_SDK=iphonesimulator10.3 - MACOS_SDK=macosx10.12 - - WATCHOS_SDK=watchsimulator3.1 - - TVOS_SDK=appletvsimulator10.1 + - WATCHOS_SDK=watchsimulator3.2 + - TVOS_SDK=appletvsimulator10.2 matrix: - DESTINATION="arch=x86_64" SIMULATOR="" SCHEME="$MACOS_FRAMEWORK_SCHEME" SDK="$MACOS_SDK" - DESTINATION="OS=9.0,name=iPhone 6" SIMULATOR="iPhone 6 (9.0)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" From 2cd5098d8ac1aa0612f3d229ea67f0845f683bab Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 2 May 2017 14:01:48 +0200 Subject: [PATCH 07/11] Update destinations and simulators in travis.yml --- .travis.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6521884..980d094 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,15 +23,13 @@ env: - TVOS_SDK=appletvsimulator10.2 matrix: - DESTINATION="arch=x86_64" SIMULATOR="" SCHEME="$MACOS_FRAMEWORK_SCHEME" SDK="$MACOS_SDK" - - DESTINATION="OS=9.0,name=iPhone 6" SIMULATOR="iPhone 6 (9.0)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" - - DESTINATION="OS=9.1,name=iPhone 6 Plus" SIMULATOR="iPhone 6 Plus (9.1)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" - - DESTINATION="OS=9.2,name=iPhone 6S" SIMULATOR="iPhone 6S (9.2)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" + - DESTINATION="OS=8.4,name=iPhone 6 Plus" SIMULATOR="iPhone 6 Plus (8.4)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" - DESTINATION="OS=9.3,name=iPhone 6S Plus" SIMULATOR="iPhone 6S Plus (9.3)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" - - DESTINATION="OS=10.1,name=iPhone 7 Plus" SIMULATOR="iPhone 7 Plus (10.1)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" + - DESTINATION="OS=10.3,name=iPhone 7 Plus" SIMULATOR="iPhone 7 Plus (10.3)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" - DESTINATION="OS=2.2,name=Apple Watch - 42mm" SIMULATOR="Apple Watch - 42mm (2.2)" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" SDK="$WATCHOS_SDK" - - DESTINATION="OS=3.1,name=Apple Watch Series 2 - 42mm" SIMULATOR="Apple Watch Series 2 - 42mm (3.1)" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" SDK="$WATCHOS_SDK" - - DESTINATION="OS=9.0,name=Apple TV 1080p" SIMULATOR="Apple TV 1080p (9.2)" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" - - DESTINATION="OS=10.0,name=Apple TV 1080p" SIMULATOR="Apple TV 1080p (10.0)" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" + - DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SIMULATOR="Apple Watch Series 2 - 42mm (3.2)" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" SDK="$WATCHOS_SDK" + - DESTINATION="OS=9.2,name=Apple TV 1080p" SIMULATOR="Apple TV 1080p (9.2)" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" + - DESTINATION="OS=10.2,name=Apple TV 1080p" SIMULATOR="Apple TV 1080p (10.2)" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" script: - set -o pipefail From eca6098361f9a59a5d7a44b6294a14b4d030ccc1 Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 2 May 2017 15:48:36 +0200 Subject: [PATCH 08/11] Add Changelog entry for HTMLKit 2.0.6 --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f67a6c..dcf1f94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,30 @@ # Change Log +## [2.0.6](https://github.com/iabudiab/HTMLKit/releases/tag/2.0.6) + +Released on 2017.05.02 + +### Added + +- Memory consumption improvements (issue #10) + - Allocate `childNodes` collection in `HTMLNode` only when inserting child nodes + - Replace `NSStringFromSelector` calls with constants in `HTMLNode` validations + - Improve `reverseObjectEnumerator` usage while parsing HTML + - Rewrite internal logic of the `HTMLStackOfOpenElements` to prevent excessive allocations + + ## [2.0.5](https://github.com/iabudiab/HTMLKit/releases/tag/2.0.5) Released on 2017.04.19 ### Fixed + - Xcode 8.3 issue with modulemaps - Temporary workaround (renamed modulemap file) - Memory Leaks in `CSSInputStream` ### Added + - Minor memory consumption improvements - Collections for child nodes or attributes of HTML Nodes or Elements are allocated lazily - Underyling data string of `CharacterData` is allocated on first access @@ -21,10 +36,12 @@ Released on 2017.04.19 Released on 2017.04.2 ### Fixed + - Testing with Swift 3.1 - Fixed by @tali in PR #8 ### Deprecated + - `HTMLRange` initializers with typo - `initWithDowcument:startContainer:startOffset:endContainer:endOffset:` @@ -34,6 +51,7 @@ Released on 2017.04.2 Released on 2017.03.6 ### Fixed + - Compilation for Swift 3.1 - Fixed by @tali in PR #6 @@ -43,6 +61,7 @@ Released on 2017.03.6 Released on 2017.02.26 ### Fixed + - Retain cycles in `HTMLNodeIterator` (issue #4) - Retain cycles in `HTMLRange` (issue #5) - The layout of `HTMLKit` tests module for Swift Package Manager From cc0734e470d9cefa1c24c7bb13fc000d3b501ca1 Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 2 May 2017 15:48:45 +0200 Subject: [PATCH 09/11] Update jazzy.yaml for 2.0.6 --- .jazzy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jazzy.yaml b/.jazzy.yaml index 4bcae51..c95515d 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -1,5 +1,5 @@ module: HTMLKit -module_version: 2.0.5 +module_version: 2.0.6 author: Iskandar Abudiab author_url: https://twitter.com/iabudiab github_url: https://github.com/iabudiab/HTMLKit From 6cd03b4eedfae73d608561be4d759fcf9bdb5682 Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 2 May 2017 15:48:54 +0200 Subject: [PATCH 10/11] Update podspec for 2.0.6 --- HTMLKit.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HTMLKit.podspec b/HTMLKit.podspec index 4991a29..50e830e 100644 --- a/HTMLKit.podspec +++ b/HTMLKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "HTMLKit" - s.version = "2.0.5" + s.version = "2.0.6" s.summary = "HTMLKit, an Objective-C framework for your everyday HTML needs." s.license = "MIT" s.homepage = "https://github.com/iabudiab/HTMLKit" From bf655c7ea241fb99ac9472bfdab05c1fcce83619 Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 2 May 2017 15:49:08 +0200 Subject: [PATCH 11/11] Bump HTMLKit version to 2.0.6 --- Sources/HTMLKit-Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/HTMLKit-Info.plist b/Sources/HTMLKit-Info.plist index 11b6ce9..7b6a588 100644 --- a/Sources/HTMLKit-Info.plist +++ b/Sources/HTMLKit-Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.5 + 2.0.6 CFBundleSignature ???? CFBundleVersion