"; };
@@ -300,6 +305,8 @@
62AE593219F97CCA0043F069 /* Tokenizing */,
62F873E919E088C90062683C /* HTMLParser.h */,
62F873EA19E088C90062683C /* HTMLParser.m */,
+ 6234BEEC1AABBF1400DEB15F /* HTMLStackOfOpenElements.h */,
+ 6234BEED1AABBF1400DEB15F /* HTMLStackOfOpenElements.m */,
628B7CE61A080E1000602C87 /* HTMLNamespaces.h */,
6223211D1A969B9300BACED5 /* HTMLElementTypes.h */,
6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */,
@@ -391,6 +398,7 @@
624493AC19CD0CBE00BCDDF4 /* HTMLToken.h in Headers */,
6235CEA01AA5170A0026937B /* HTMLMarker.h in Headers */,
62F31FDD19E9DCCF007F0657 /* HTMLTokenizerEntities.h in Headers */,
+ 6234BEEE1AABBF1400DEB15F /* HTMLStackOfOpenElements.h in Headers */,
6279F87419E1808D00F12EE5 /* HTMLElement.h in Headers */,
62AE593F19F9907C0043F069 /* HTMLTagToken.h in Headers */,
623857911A9E772B003A45D9 /* HTMLDocument.h in Headers */,
@@ -556,6 +564,7 @@
62362A3E1A9FA70400301989 /* HTMLText.m in Sources */,
6235CE9D1AA509430026937B /* NSString+HTMLKit.m in Sources */,
6238579D1A9E8934003A45D9 /* HTMLComment.m in Sources */,
+ 6234BEF01AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */,
624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */,
6235CEA21AA5170A0026937B /* HTMLMarker.m in Sources */,
62AE594119F9907C0043F069 /* HTMLTagToken.m in Sources */,
@@ -592,6 +601,7 @@
62362A3D1A9FA70400301989 /* HTMLText.m in Sources */,
6235CE9C1AA509430026937B /* NSString+HTMLKit.m in Sources */,
6238579C1A9E8934003A45D9 /* HTMLComment.m in Sources */,
+ 6234BEEF1AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */,
624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */,
6235CEA11AA5170A0026937B /* HTMLMarker.m in Sources */,
62AE594019F9907C0043F069 /* HTMLTagToken.m in Sources */,
diff --git a/HTMLKit/HTMLParser.m b/HTMLKit/HTMLParser.m
index b201392..eb6d6d1 100644
--- a/HTMLKit/HTMLParser.m
+++ b/HTMLKit/HTMLParser.m
@@ -9,6 +9,7 @@
#import "HTMLParser.h"
#import "HTMLTokenizer.h"
#import "HTMLTokens.h"
+#import "HTMLStackOfOpenElements.h"
#import "HTMLParserInsertionModes.h"
#import "HTMLNodes.h"
#import "HTMLElementTypes.h"
@@ -25,7 +26,7 @@
HTMLInsertionMode _insertionMode;
HTMLInsertionMode _originalInsertionMode;
- NSMutableArray *_stackOfOpenElements;
+ HTMLStackOfOpenElements *_stackOfOpenElements;
NSMutableArray *_listOfActiveFormattingElements;
HTMLDocument *_document;
@@ -57,7 +58,7 @@
_insertionMode = HTMLInsertionModeInitial;
[self setupStateMachine];
- _stackOfOpenElements = [NSMutableArray new];
+ _stackOfOpenElements = [HTMLStackOfOpenElements new];
_listOfActiveFormattingElements = [NSMutableArray new];
_tokenizer = [[HTMLTokenizer alloc] initWithString:string];
@@ -82,7 +83,7 @@
- (HTMLElement *)currentNode
{
- return _stackOfOpenElements.lastObject;
+ return _stackOfOpenElements.currentNode;
}
- (HTMLElement *)adjustedCurrentNode
@@ -117,12 +118,12 @@
- (void)resetInsertionModeAppropriately
{
BOOL last = NO;
- HTMLElement *node = _stackOfOpenElements.lastObject;
+ HTMLElement *node = _stackOfOpenElements.lastNode;
NSUInteger nodeIndex = _stackOfOpenElements.count - 1;
while (YES) {
- if ([_stackOfOpenElements.firstObject isEqual:node]) {
+ if ([_stackOfOpenElements.firstNode isEqual:node]) {
last = YES;
if (_fragmentParsingAlgorithm) {
node = _contextElement;
@@ -135,12 +136,12 @@
NSUInteger ancestorIndex = nodeIndex;
while (YES) {
- if ([ancestor isEqual:_stackOfOpenElements.firstObject]) {
+ if ([ancestor isEqual:_stackOfOpenElements.firstNode]) {
break;
}
ancestorIndex--;
- ancestor = [_stackOfOpenElements objectAtIndex:ancestorIndex];
+ ancestor = _stackOfOpenElements[ancestorIndex];
if ([ancestor.tagName isEqualToString:@"template"]) {
break;
@@ -225,7 +226,7 @@
}
nodeIndex--;
- node = [_stackOfOpenElements objectAtIndex:nodeIndex];
+ node = _stackOfOpenElements[nodeIndex];
}
}
@@ -367,13 +368,13 @@
return nil;
}
if (lastTable == nil) {
- HTMLElement *htmlElement = _stackOfOpenElements.firstObject;
+ HTMLElement *htmlElement = _stackOfOpenElements.firstNode;
return htmlElement;
}
if (lastTable.parentNode != nil) {
return lastTable.parentNode;
}
- NSUInteger lastTableIndex = [_stackOfOpenElements indexOfObject:lastTable];
+ NSUInteger lastTableIndex = [_stackOfOpenElements indexOfElement:lastTable];
HTMLElement *previousNode = _stackOfOpenElements[lastTableIndex];
return previousNode;
} else {
@@ -407,7 +408,7 @@
HTMLElement *element = [self createElementForToken:token inNamespace:HTMLNamespaceHTML];
HTMLNode *adjustedInsertionLocation = [self appropriatePlaceForInsertingANodeWithOverrideTarget:nil];
[adjustedInsertionLocation appendChildNode:element];
- [_stackOfOpenElements addObject:element];
+ [_stackOfOpenElements pushElement:element];
return element;
}
@@ -434,7 +435,7 @@
}
id last = _listOfActiveFormattingElements.lastObject;
- if (last == [HTMLMarker marker] || [_stackOfOpenElements containsObject:last]) {
+ if (last == [HTMLMarker marker] || [_stackOfOpenElements constainsElement:last]) {
return;
}
@@ -465,7 +466,7 @@
create();
}
entry = _listOfActiveFormattingElements[index--];
- if (entry != [HTMLMarker marker] && ![_stackOfOpenElements containsObject:entry]) {
+ if (entry != [HTMLMarker marker] && ![_stackOfOpenElements constainsElement:entry]) {
rewind();
}
};
@@ -480,75 +481,11 @@
}
}
-- (HTMLElement *)hasElementWithTagNameInSpecificScope:(NSString *)tagName
- withAdditionalTypes:(NSDictionary *)additional
-{
- NSMutableDictionary *elementTypes = [NSMutableDictionary dictionaryWithDictionary:additional];
- [elementTypes addEntriesFromDictionary:@{
- @"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)
- }];
-
- for (HTMLElement *node in _stackOfOpenElements.reverseObjectEnumerator) {
- if ([node.tagName isEqualToString:tagName]) {
- return node;
- }
- if ([elementTypes[node.tagName] isEqual:@(node.namespace)]) {
- return nil;
- }
- }
- return nil;
-}
-
-- (HTMLElement *)hasElementWithTagNameInButtonScope:(NSString *)tagName
-{
- return [self hasElementWithTagNameInSpecificScope:tagName
- withAdditionalTypes:@{@"ol": @(HTMLNamespaceHTML),
- @"ul": @(HTMLNamespaceHTML)}];
-}
-
-- (HTMLElement *)hasElementWithTagNameInListScope:(NSString *)tagName
-{
- return [self hasElementWithTagNameInSpecificScope:tagName
- withAdditionalTypes:@{@"button": @(HTMLNamespaceHTML)}];
-}
-
-- (HTMLElement *)hasElementWithTagNameInTableScope:(NSString *)tagName
-{
- return [self hasElementWithTagNameInSpecificScope:tagName
- withAdditionalTypes:@{@"html": @(HTMLNamespaceHTML),
- @"table": @(HTMLNamespaceHTML),
- @"template": @(HTMLNamespaceHTML)}];
-}
-
-- (HTMLElement *)hasElementWithTagNameInSelectScope:(NSString *)tagName
-{
- return [self hasElementWithTagNameInSpecificScope:tagName
- withAdditionalTypes:@{@"optgroup": @(HTMLNamespaceHTML),
- @"option": @(HTMLNamespaceHTML)}];
-}
-
- (void)generateImpliedEndTagsExceptForElement:(NSString *)tagName
{
while ([self.currentNode.tagName isEqualToAny:@"dd", @"dt", @"li", @"option", @"optgroup", @"p", @"rp", @"rt", nil] &&
![self.currentNode.tagName isEqualToString:tagName]) {
- [_stackOfOpenElements removeLastObject];
+ [_stackOfOpenElements popCurrentNode];
}
}
@@ -558,8 +495,8 @@
if (![self.currentNode.tagName isEqualToString:@"p"]) {
[self emitParseError:@"Current node being closed is not a element"];
}
- while (![self.currentNode.tagName isEqualToString:@"p"]) {
- [_stackOfOpenElements removeLastObject];
+ [_stackOfOpenElements popElementsUntilElementPoppedWithTagName:@"p"];
+}
}
[_stackOfOpenElements removeLastObject];
}
@@ -625,7 +562,7 @@
if ([token.asStartTagToken.tagName isEqualToString:@"html"]) {
HTMLElement *html = [self createElementForToken:token.asTagToken inNamespace:HTMLNamespaceHTML];
[_document appendChildNode:html];
- [_stackOfOpenElements addObject:html];
+ [_stackOfOpenElements pushElement:html];
[self switchInsertionMode:HTMLInsertionModeBeforeHead];
return;
}
@@ -642,7 +579,7 @@
HTMLElement *html = [[HTMLElement alloc] initWithTagName:@"html"];
[_document appendChildNode:html];
- [_stackOfOpenElements addObject:html];
+ [_stackOfOpenElements pushElement:html];
[self switchInsertionMode:HTMLInsertionModeBeforeHead];
[self reprocessToken:token];
}
@@ -713,11 +650,11 @@
return;
} else if ([token.asStartTagToken.tagName isEqualToAny:@"base", @"basefont", @"bgsound", @"link", nil]) {
[self insertElementForToken:token.asStartTagToken];
- [_stackOfOpenElements removeLastObject];
+ [_stackOfOpenElements popCurrentNode];
return;
} else if ([token.asStartTagToken.tagName isEqualToString:@"meta"]) {
[self insertElementForToken:token.asStartTagToken];
- [_stackOfOpenElements removeLastObject];
+ [_stackOfOpenElements popCurrentNode];
return;
} else if ([token.asStartTagToken.tagName isEqualToString:@"title"]) {
[self applyGenericParsingAlgorithmForToken:token.asStartTagToken withTokenizerState:HTMLTokenizerStateRCDATA];
@@ -730,7 +667,7 @@
HTMLElement *script = [self createElementForToken:token.asStartTagToken inNamespace:HTMLNamespaceHTML];
#warning Script Element Flags (https://html.spec.whatwg.org/multipage/scripting.html#parser-inserted)
[adjustedInsertionLocation appendChildNode:script];
- [_stackOfOpenElements addObject:script];
+ [_stackOfOpenElements pushElement:script];
_tokenizer.state = HTMLTokenizerStateScriptData;
_originalInsertionMode = _insertionMode;
[self switchInsertionMode:HTMLInsertionModeText];
@@ -743,7 +680,7 @@
#warning Implement HTML Template
case HTMLTokenTypeEndTag:
if ([token.asEndTagToken.tagName isEqualToString:@"head"]) {
- [_stackOfOpenElements removeLastObject];
+ [_stackOfOpenElements popCurrentNode];
[self switchInsertionMode:HTMLInsertionModeAfterHead];
return;
} else if ([token.asEndTagToken.tagName isEqualToAny:@"body", @"html", @"br", nil]) {
@@ -757,7 +694,7 @@
break;
}
- [_stackOfOpenElements removeLastObject];
+ [_stackOfOpenElements popCurrentNode];
[self switchInsertionMode:HTMLInsertionModeAfterHead];
[self reprocessToken:token];
}
@@ -772,7 +709,8 @@
if ([token.asStartTagToken.tagName isEqualToString:@"html"]) {
[self HTMLInsertionModeInBody:token];
return;
- } else if ([token.asStartTagToken.tagName isEqualToAny:@"basefont", @"bgsound", @"link", @"meta", @"noframes", @"style", nil]) {
+ } else if ([token.asStartTagToken.tagName isEqualToAny:@"basefont", @"bgsound", @"link", @"meta", @"noframes",
+ @"style", nil]) {
[self HTMLInsertionModeInHead:token];
return;
} else if ([token.asStartTagToken.tagName isEqualToAny:@"head", @"noscript", nil]) {
@@ -782,7 +720,7 @@
break;
case HTMLTokenTypeEndTag:
if ([token.asEndTagToken.tagName isEqualToString:@"noscript"]) {
- [_stackOfOpenElements removeLastObject];
+ [_stackOfOpenElements popCurrentNode];
[self switchInsertionMode:HTMLInsertionModeInHead];
return;
} else if ([token.asEndTagToken.tagName isEqualToString:@"br"]) {
@@ -801,7 +739,7 @@
}
[self emitParseError:@"Unexpected Tag Token (%@) in