diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 502c0c7..dbd4fed 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -25,6 +25,9 @@ 62362A3C1A9FA70400301989 /* HTMLText.h in Headers */ = {isa = PBXBuildFile; fileRef = 62362A3A1A9FA70400301989 /* HTMLText.h */; }; 62362A3D1A9FA70400301989 /* HTMLText.m in Sources */ = {isa = PBXBuildFile; fileRef = 62362A3B1A9FA70400301989 /* HTMLText.m */; }; 62362A3E1A9FA70400301989 /* HTMLText.m in Sources */ = {isa = PBXBuildFile; fileRef = 62362A3B1A9FA70400301989 /* HTMLText.m */; }; + 62363C3D1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h in Headers */ = {isa = PBXBuildFile; fileRef = 62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */; }; + 62363C3E1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */ = {isa = PBXBuildFile; fileRef = 62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */; }; + 62363C3F1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */ = {isa = PBXBuildFile; fileRef = 62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */; }; 6238039F1AB63A8C008A53D0 /* HTMLEOFToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238039D1AB63A8C008A53D0 /* HTMLEOFToken.h */; }; 623803A01AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238039E1AB63A8C008A53D0 /* HTMLEOFToken.m */; }; 623803A11AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238039E1AB63A8C008A53D0 /* HTMLEOFToken.m */; }; @@ -146,6 +149,8 @@ 62362A3A1A9FA70400301989 /* HTMLText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLText.h; sourceTree = ""; }; 62362A3B1A9FA70400301989 /* HTMLText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLText.m; sourceTree = ""; }; 62362A3F1A9FDE8A00301989 /* HTMLNodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLNodes.h; sourceTree = ""; }; + 62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLListOfActiveFormattingElements.h; sourceTree = ""; }; + 62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLListOfActiveFormattingElements.m; sourceTree = ""; }; 623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLQuirksMode.h; sourceTree = ""; }; 6238039D1AB63A8C008A53D0 /* HTMLEOFToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLEOFToken.h; sourceTree = ""; }; 6238039E1AB63A8C008A53D0 /* HTMLEOFToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLEOFToken.m; sourceTree = ""; }; @@ -323,6 +328,8 @@ 62F873EA19E088C90062683C /* HTMLParser.m */, 6234BEEC1AABBF1400DEB15F /* HTMLStackOfOpenElements.h */, 6234BEED1AABBF1400DEB15F /* HTMLStackOfOpenElements.m */, + 62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */, + 62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */, 628B7CE61A080E1000602C87 /* HTMLNamespaces.h */, 6223211D1A969B9300BACED5 /* HTMLElementTypes.h */, 6234C3361AB3BF710046F527 /* HTMLElementAdjustment.h */, @@ -436,6 +443,7 @@ 62AE593519F97D880043F069 /* HTMLParseErrorToken.h in Headers */, 62AE594919F9948A0043F069 /* HTMLCharacterToken.h in Headers */, 623857961A9E8606003A45D9 /* HTMLDocumentType.h in Headers */, + 62363C3D1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h in Headers */, 62362A3C1A9FA70400301989 /* HTMLText.h in Headers */, 6234584E1A9D2FA4009BD491 /* HTMLNode.h in Headers */, ); @@ -596,6 +604,7 @@ 6234248A1AB467B200726190 /* HTMLOrderedDictionary.m in Sources */, 62AE594119F9907C0043F069 /* HTMLTagToken.m in Sources */, 62AE594619F992F30043F069 /* HTMLCommentToken.m in Sources */, + 62363C3F1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */, 62AE593C19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */, 6238C9871AB8D6330006512E /* HTMLKitExceptions.m in Sources */, 62F873ED19E088C90062683C /* HTMLParser.m in Sources */, @@ -636,6 +645,7 @@ 623424891AB467B200726190 /* HTMLOrderedDictionary.m in Sources */, 62AE594019F9907C0043F069 /* HTMLTagToken.m in Sources */, 62AE594519F992F30043F069 /* HTMLCommentToken.m in Sources */, + 62363C3E1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */, 62AE593B19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */, 6238C9861AB8D6330006512E /* HTMLKitExceptions.m in Sources */, 62F873EC19E088C90062683C /* HTMLParser.m in Sources */, diff --git a/HTMLKit/HTMLListOfActiveFormattingElements.h b/HTMLKit/HTMLListOfActiveFormattingElements.h new file mode 100644 index 0000000..7b4446d --- /dev/null +++ b/HTMLKit/HTMLListOfActiveFormattingElements.h @@ -0,0 +1,36 @@ +// +// HTMLListOfActiveFormattingElements.h +// HTMLKit +// +// Created by Iska on 22/03/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import +#import "HTMLElement.h" + +@interface HTMLListOfActiveFormattingElements : NSObject + +- (id)objectAtIndexedSubscript:(NSUInteger)index; +- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx; +- (NSUInteger)indexOfElement:(id)node; + +- (void)addElement:(HTMLElement *)element; +- (void)removeElement:(id)element; +- (BOOL)containsElement:(id)element; + +- (void)insertElement:(HTMLElement *)element atIndex:(NSUInteger)index; +- (void)replaceElementAtIndex:(NSUInteger)index withElement:(HTMLElement *)element; + +- (id)lastEntry; + +- (void)addMarker; +- (void)clearUptoLastMarker; + +- (NSUInteger)count; +- (BOOL)isEmpty; + +- (NSEnumerator *)enumerator; +- (NSEnumerator *)reverseObjectEnumerator; + +@end diff --git a/HTMLKit/HTMLListOfActiveFormattingElements.m b/HTMLKit/HTMLListOfActiveFormattingElements.m new file mode 100644 index 0000000..6994d05 --- /dev/null +++ b/HTMLKit/HTMLListOfActiveFormattingElements.m @@ -0,0 +1,122 @@ +// +// HTMLListOfActiveFormattingElements.m +// HTMLKit +// +// Created by Iska on 22/03/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import "HTMLListOfActiveFormattingElements.h" +#import "HTMLMarker.h" + +@interface HTMLListOfActiveFormattingElements () +{ + NSMutableArray *_list; +} +@end + +@implementation HTMLListOfActiveFormattingElements + +- (instancetype)init +{ + self = [super init]; + if (self) { + _list = [NSMutableArray new]; + } + return self; +} + +#pragma mark - Access + +- (id)objectAtIndexedSubscript:(NSUInteger)index; +{ + return [_list objectAtIndex:index]; +} + +- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx +{ + [_list setObject:obj atIndexedSubscript:idx]; +} + +- (NSUInteger)indexOfElement:(id)node +{ + return [_list indexOfObject:node]; +} + +- (void)addElement:(HTMLElement *)element +{ + [_list addObject:element]; +} + +- (void)removeElement:(id)element +{ + [_list removeObject:element]; +} + +- (BOOL)containsElement:(id)element +{ + return [_list containsObject:element]; +} + +- (void)insertElement:(HTMLElement *)element atIndex:(NSUInteger)index +{ + [_list insertObject:element atIndex:index]; +} + +- (void)replaceElementAtIndex:(NSUInteger)index withElement:(HTMLElement *)element +{ + [_list replaceObjectAtIndex:index withObject:element]; +} + +- (id)lastEntry +{ + return _list.lastObject; +} + +#pragma mark - Acrions + +- (void)addMarker +{ + [_list addObject:[HTMLMarker marker]]; +} + +- (void)clearUptoLastMarker +{ + while (_list.lastObject != [HTMLMarker marker]) { + [_list removeLastObject]; + } + [_list removeLastObject]; +} + +#pragma mark - Count + +- (NSUInteger)count +{ + return _list.count; +} + +- (BOOL)isEmpty +{ + return _list.count == 0; +} + +#pragma mark - Enumeraiton + +- (NSEnumerator *)enumerator +{ + return _list.objectEnumerator; +} + +- (NSEnumerator *)reverseObjectEnumerator +{ + return _list.reverseObjectEnumerator; +} + +#pragma mark - NSFastEnumeration + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len +{ + return [_list countByEnumeratingWithState:state objects:buffer count:len]; +} + +@end diff --git a/HTMLKit/HTMLParser.m b/HTMLKit/HTMLParser.m index 795bc9a..a58e3f0 100644 --- a/HTMLKit/HTMLParser.m +++ b/HTMLKit/HTMLParser.m @@ -10,6 +10,7 @@ #import "HTMLTokenizer.h" #import "HTMLTokens.h" #import "HTMLStackOfOpenElements.h" +#import "HTMLListOfActiveFormattingElements.h" #import "HTMLParserInsertionModes.h" #import "HTMLNodes.h" #import "HTMLElementTypes.h" @@ -36,7 +37,7 @@ HTMLInsertionMode _originalInsertionMode; HTMLStackOfOpenElements *_stackOfOpenElements; - NSMutableArray *_listOfActiveFormattingElements; + HTMLListOfActiveFormattingElements *_listOfActiveFormattingElements; HTMLDocument *_document; @@ -70,7 +71,8 @@ [self setupStateMachine]; _stackOfOpenElements = [HTMLStackOfOpenElements new]; - _listOfActiveFormattingElements = [NSMutableArray new]; + _listOfActiveFormattingElements = [HTMLListOfActiveFormattingElements new]; + _tokenizer = [[HTMLTokenizer alloc] initWithString:string]; _tokenizer.parser = self; @@ -337,11 +339,11 @@ - (void)reconstructActiveFormattingElements { - if (_listOfActiveFormattingElements.count == 0) { + if (_listOfActiveFormattingElements.isEmpty) { return; } - id last = _listOfActiveFormattingElements.lastObject; + id last = _listOfActiveFormattingElements.lastEntry; if (last == [HTMLMarker marker] || [_stackOfOpenElements constainsElement:last]) { return; } @@ -362,7 +364,7 @@ HTMLStartTagToken *token = [[HTMLStartTagToken alloc] initWithTagName:entry.tagName attributes:entry.attributes]; HTMLElement *element = [self insertElementForToken:token]; - [_listOfActiveFormattingElements replaceObjectAtIndex:index withObject:element]; + [_listOfActiveFormattingElements replaceElementAtIndex:index withElement:element]; if (index++ != _listOfActiveFormattingElements.count) { advance(); } @@ -381,13 +383,6 @@ rewind(); } -- (void)clearListOfActiveFormattingElementsUptoLastMarker -{ - while (_listOfActiveFormattingElements.lastObject != [HTMLMarker marker]) { - [_listOfActiveFormattingElements removeLastObject]; - } -} - - (void)generateImpliedEndTagsExceptForElement:(NSString *)tagName { while ([self.currentNode.tagName isEqualToAny:@"dd", @"dt", @"li", @"option", @"optgroup", @"p", @"rp", @"rt", nil] && @@ -407,8 +402,8 @@ - (BOOL)runAdoptionAgencyAlgorithmForTagName:(NSString *)tagName { - if ([self.currentNode.tagName isEqualTo:tagName] && - ![_listOfActiveFormattingElements containsObject:self.currentNode]) { + if ([self.currentNode.tagName isEqualToString:tagName] && + ![_listOfActiveFormattingElements containsElement:self.currentNode]) { [_stackOfOpenElements popCurrentNode]; return NO; } @@ -431,7 +426,7 @@ if (![_stackOfOpenElements constainsElement:formattingElement]) { [self emitParseError:@"Formatting element is not in the Stack of Open Elements"]; - [_listOfActiveFormattingElements removeObject:formattingElement]; + [_listOfActiveFormattingElements removeElement:formattingElement]; return NO; } @@ -458,22 +453,22 @@ if (furthestBlock == nil) { [_stackOfOpenElements popElementsUntilElementPopped:formattingElement]; - [_listOfActiveFormattingElements removeObject:formattingElement]; + [_listOfActiveFormattingElements removeElement:formattingElement]; return NO; } HTMLElement *commonAncestor = _stackOfOpenElements[formattingElementIndex - 1]; - NSUInteger bookmark = [_listOfActiveFormattingElements indexOfObject:formattingElement]; + NSUInteger bookmark = [_listOfActiveFormattingElements indexOfElement:formattingElement]; HTMLElement *node = furthestBlock; HTMLElement *lastNode = furthestBlock; for (int innerLoopCounter = 0; innerLoopCounter < 3; innerLoopCounter ++) { NSUInteger nodeStackIndex = [_stackOfOpenElements indexOfElement:node]; - NSUInteger nodeListIndex = [_listOfActiveFormattingElements indexOfObject:node]; + NSUInteger stackIndex = [_stackOfOpenElements indexOfElement:node]; node = _stackOfOpenElements[nodeStackIndex - 1]; - if (![_listOfActiveFormattingElements containsObject:node]) { + if (![_listOfActiveFormattingElements containsElement:node]) { [_stackOfOpenElements removeElement:node]; continue; } @@ -483,8 +478,8 @@ } HTMLElement *newElement = [node copy]; - [_listOfActiveFormattingElements replaceObjectAtIndex:nodeListIndex withObject:newElement]; - [_stackOfOpenElements replaceElementAtIndex:nodeStackIndex withElement:newElement]; + [_listOfActiveFormattingElements replaceElementAtIndex:listIndex withElement:newElement]; + [_stackOfOpenElements replaceElementAtIndex:stackIndex withElement:newElement]; node = newElement; if ([lastNode isEqual:furthestBlock]) { @@ -506,8 +501,8 @@ } [furthestBlock appendNode:newElement]; - [_listOfActiveFormattingElements removeObject:formattingElement]; - [_listOfActiveFormattingElements insertObject:newElement atIndex:bookmark]; + [_listOfActiveFormattingElements removeElement:formattingElement]; + [_listOfActiveFormattingElements insertElement:newElement atIndex:bookmark-1]; [_stackOfOpenElements removeElement:formattingElement]; NSUInteger furthestBlockIndex = [_stackOfOpenElements indexOfElement:furthestBlock]; [_stackOfOpenElements insertElement:newElement atIndex:furthestBlockIndex]; @@ -515,14 +510,6 @@ return NO; } -- (void)clearListOfActiveFormattingElementsUpToLastMarker -{ - while (![_listOfActiveFormattingElements.lastObject isEqual:[HTMLMarker marker]]) { - [_listOfActiveFormattingElements removeLastObject]; - } - [_listOfActiveFormattingElements removeLastObject]; -} - - (void)closeTheCell { [self generateImpliedEndTagsExceptForElement:nil]; @@ -530,7 +517,7 @@ [self emitParseError:@"Misnested Cell"]; } [_stackOfOpenElements popElementsUntilAnElementPoppedWithAnyOfTagNames:@[@"td", @"th"]]; - [self clearListOfActiveFormattingElementsUpToLastMarker]; + [_listOfActiveFormattingElements clearUptoLastMarker]; [self switchInsertionMode:HTMLInsertionModeInRow]; } @@ -1169,17 +1156,17 @@ [self processAnyOtherEndTagTokenInBody:token.asTagToken]; return; } - [_listOfActiveFormattingElements removeObject:element]; + [_listOfActiveFormattingElements removeElement:element]; [_stackOfOpenElements removeElement:element]; } [self reconstructActiveFormattingElements]; HTMLElement *a = [self insertElementForToken:token]; - [_listOfActiveFormattingElements addObject:a]; + [_listOfActiveFormattingElements addElement:a]; } else if ([tagName isEqualToAny:@"b", @"big", @"code", @"em", @"font", @"i", @"s", @"small", @"strike", @"strong", @"tt", @"u", nil]) { [self reconstructActiveFormattingElements]; HTMLElement *element = [self insertElementForToken:token]; - [_listOfActiveFormattingElements addObject:element]; + [_listOfActiveFormattingElements addElement:element]; } else if ([tagName isEqualToString:@"nobr"]) { [self reconstructActiveFormattingElements]; if ([_stackOfOpenElements hasElementInScopeWithTagName:@"nobr"]) { @@ -1456,7 +1443,7 @@ [self emitParseError:@"Unexpected nested (%@) element in ", tagName]; } [_stackOfOpenElements popElementsUntilAnElementPoppedWithAnyOfTagNames:@[@"applet", @"marquee", @"object"]]; - [self clearListOfActiveFormattingElementsUpToLastMarker]; + [_listOfActiveFormattingElements clearUptoLastMarker]; } else if ([tagName isEqualToString:@"br"]) { [self emitParseError:@"Unexpected End Tag Token (br) in "]; HTMLStartTagToken *brToken = [[HTMLStartTagToken alloc] initWithTagName:@"br"]; @@ -1658,7 +1645,7 @@ [self emitParseError:@"Unexpected nested (caption) element in "]; } [_stackOfOpenElements popElementsUntilElementPoppedWithTagName:@"caption"]; - [self clearListOfActiveFormattingElementsUpToLastMarker]; + [_listOfActiveFormattingElements clearUptoLastMarker]; [self switchInsertionMode:HTMLInsertionModeInTable]; if (reprocess) { @@ -1839,7 +1826,7 @@ [_stackOfOpenElements clearBackToTableContext]; [self insertElementForToken:token.asTagToken]; [self switchInsertionMode:HTMLInsertionModeInCell]; - [_listOfActiveFormattingElements addObject:[HTMLMarker marker]]; + [_listOfActiveFormattingElements addMarker]; } else if ([token.asTagToken.tagName isEqualToAny:@"caption", @"col", @"colgroup", @"tbody", @"tfoot", @"thead", @"tr", nil]) { common(@"tr", YES); @@ -1882,7 +1869,7 @@ [self emitParseError:@"Unexpected nested (%@) element in ", token.asTagToken.tagName]; } [_stackOfOpenElements popElementsUntilElementPoppedWithTagName:token.asTagToken.tagName]; - [self clearListOfActiveFormattingElementsUpToLastMarker]; + [_listOfActiveFormattingElements clearUptoLastMarker]; [self switchInsertionMode:HTMLInsertionModeInRow]; } } else if ([token.asTagToken.tagName isEqualToAny:@"body", @"caption", @"col", @"colgroup",