diff --git a/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate b/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate index c64b844..b4fb2a8 100644 Binary files a/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate and b/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/IJSVGExample/IJSVGExample/test.svg b/IJSVGExample/IJSVGExample/test.svg index 2e93f67..1951576 100644 --- a/IJSVGExample/IJSVGExample/test.svg +++ b/IJSVGExample/IJSVGExample/test.svg @@ -16,21 +16,14 @@ - - - - - + + diff --git a/source/IJSVGStyleSheetSelector.m b/source/IJSVGStyleSheetSelector.m index c47bd84..f716e56 100644 --- a/source/IJSVGStyleSheetSelector.m +++ b/source/IJSVGStyleSheetSelector.m @@ -18,6 +18,18 @@ [super dealloc]; } +- (BOOL)combinatorIsGreedy:(IJSVGStyleSheetSelectorCombinator)combinator +{ + return combinator == IJSVGStyleSheetSelectorCombinatorDescendant || + combinator == IJSVGStyleSheetSelectorCombinatorPrecededSibling; +} + +- (BOOL)isAncestorOperator:(IJSVGStyleSheetSelectorCombinator)combinator +{ + return combinator == IJSVGStyleSheetSelectorCombinatorDescendant || + combinator == IJSVGStyleSheetSelectorCombinatorDirectDescendant; +} + - (IJSVGStyleSheetSelectorCombinator)combinatorForUnichar:(unichar)aChar { if(aChar == '+') @@ -35,12 +47,12 @@ { selector = [string copy]; _rawSelectors = [[NSMutableArray alloc] init]; - [self compile]; + [self _compile]; } return self; } -- (void)compile +- (void)_compile { NSUInteger length = selector.length; NSMutableArray * sels = [[[NSMutableArray alloc] init] autorelease]; @@ -148,10 +160,9 @@ } // now its compiled, we need to reverse the selectors [_rawSelectors addObjectsFromArray:[sels reverseObjectEnumerator].allObjects]; - NSLog(@"%@",_rawSelectors); } -- (IJSVGNode *)previousNode:(IJSVGNode *)node +- (IJSVGNode *)_previousNode:(IJSVGNode *)node { IJSVGGroup * group = (IJSVGGroup *)node.parentNode; if([group isKindOfClass:[IJSVGGroup class]] == NO) @@ -162,7 +173,7 @@ return group.children[currentIndex-1]; } -- (IJSVGNode *)nextNode:(IJSVGNode *)node +- (IJSVGNode *)_nextNode:(IJSVGNode *)node { IJSVGGroup * group = (IJSVGGroup *)node.parentNode; if([group isKindOfClass:[IJSVGGroup class]] == NO) @@ -173,9 +184,24 @@ return group.children[currentIndex+1]; } -- (BOOL)_matchesNode:(IJSVGNode *)node - rawSelector:(IJSVGStyleSheetSelectorRaw *)rawSelector - combinator:(IJSVGStyleSheetSelectorCombinator)combinator +- (IJSVGStyleSheetSelectorRaw *)_previousSelector:(IJSVGStyleSheetSelectorRaw *)aSelector +{ + NSInteger index = [_rawSelectors indexOfObject:aSelector]; + if(index == 0) + return nil; + return _rawSelectors[index-1]; +} + +- (IJSVGStyleSheetSelectorRaw *)_nextSelector:(IJSVGStyleSheetSelectorRaw *)aSelector +{ + NSInteger index = [_rawSelectors indexOfObject:aSelector]; + if(index == _rawSelectors.count-1) + return nil; + return _rawSelectors[index+1]; +} + +- (BOOL)_match:(IJSVGNode *)node + selector:(IJSVGStyleSheetSelectorRaw *)rawSelector { // return no if the tag is set but doesnt match the node if(rawSelector.tag != nil && [rawSelector.tag isEqualToString:node.name] == NO) @@ -194,115 +220,80 @@ [rawSelector.identifier isEqualToString:node.identifier] == NO) return NO; - // if we get here, the rest match, so we need to check any combinator... - if(combinator != IJSVGStyleSheetSelectorCombinatorDescendant) { + return YES; +} + +- (BOOL)_matches:(IJSVGNode *)aNode + selector:(IJSVGStyleSheetSelectorRaw *)rawSelector +{ + IJSVGNode * prevNode = aNode; + IJSVGStyleSheetSelectorRaw * aSelector = rawSelector; + + while(aSelector != nil) { - // the parent node must be of type group in order to actually have children - IJSVGGroup * group = (IJSVGGroup *)node.parentNode; + IJSVGNode * workingNode = nil; - // are we actually a group? - if([group isKindOfClass:[IJSVGGroup class]]) { + // for adjacent node, the content to test against + // is the previous sibling + if(rawSelector.combinator == IJSVGStyleSheetSelectorCombinatorNextSibling || + rawSelector.combinator == IJSVGStyleSheetSelectorCombinatorPrecededSibling) { + workingNode = [self _previousNode:prevNode]; + } + + // for descedant combinators and child, the element + // to test against is the parent node + else { - // work out next and previous - IJSVGNode * previousNode = [self previousNode:node]; - IJSVGNode * nextNode = [self nextNode:node]; - - // work out what to do for each combinator - switch (rawSelector.combinator) { - - // > direct decendant - case IJSVGStyleSheetSelectorCombinatorDirectDescendant: { - if([self _matchesNode:group - rawSelector:[self previousSelector:rawSelector] - combinator:IJSVGStyleSheetSelectorCombinatorDescendant]) - return YES; - break; - } - - // + next sibling - case IJSVGStyleSheetSelectorCombinatorNextSibling: { - if( previousNode.type == node.type ) - return YES; - break; - } - - // ~ previous sibling - case IJSVGStyleSheetSelectorCombinatorPrecededSibling: { - if( nextNode.type == node.type ) - return YES; - break; - } - - default: - return NO; + // find the parent + IJSVGGroup * possibleParent = (IJSVGGroup *)prevNode.parentNode; + if(possibleParent != nil) { + workingNode = possibleParent; } } - return NO; + + // no node - just kill + if(workingNode == nil) + return NO; + + // test the working node against the current selector + if([self _match:workingNode + selector:aSelector]) { + + // check for greedy + IJSVGStyleSheetSelectorRaw * nSelector = [self _nextSelector:rawSelector]; + + if([self combinatorIsGreedy:aSelector.combinator] && + nSelector.combinator != rawSelector.combinator && + (rawSelector.combinator == IJSVGStyleSheetSelectorCombinatorPrecededSibling + && [self isAncestorOperator:nSelector.combinator]) == NO) { + // just do a quick dirty check + if([self _matches:workingNode selector:rawSelector]) { + return YES; + } + } + + // get the next selector + aSelector = [self _nextSelector:aSelector]; + } else { + + // is its greedy, if we didnt match, just return NO + if([self combinatorIsGreedy:aSelector.combinator] == NO) { + return NO; + } + } + prevNode = workingNode; } return YES; } -- (IJSVGStyleSheetSelectorRaw *)previousSelector:(IJSVGStyleSheetSelectorRaw *)aSelector -{ - NSInteger index = [_rawSelectors indexOfObject:aSelector]; - if(index == 0) - return nil; - return _rawSelectors[--index]; -} - -- (IJSVGStyleSheetSelectorRaw *)nextSelector:(IJSVGStyleSheetSelectorRaw *)aSelector -{ - NSInteger index = [_rawSelectors indexOfObject:aSelector]; - if(index == _rawSelectors.count-1) - return nil; - return _rawSelectors[++index]; -} - (BOOL)matchesNode:(IJSVGNode *)node { - // grab the list of remaing selectors - IJSVGNode * checkNode = node; - for(IJSVGStyleSheetSelectorRaw * rawSelector in _rawSelectors) { - - BOOL basicMatch = [self _matchesNode:checkNode - rawSelector:rawSelector - combinator:IJSVGStyleSheetSelectorCombinatorDescendant]; - - // simple, just return NO - if(!basicMatch) - return NO; - - // requires more then just a standard descendant - if(rawSelector.combinator != IJSVGStyleSheetSelectorCombinatorDescendant) { - - basicMatch = [self _matchesNode:checkNode - rawSelector:rawSelector - combinator:rawSelector.combinator]; - if(!basicMatch) - return NO; - - } else { - - IJSVGNode * pNode = checkNode; - BOOL found = NO; - for(;;) { - pNode = pNode.parentNode; - if(pNode == nil) - return NO; - basicMatch = [self _matchesNode:checkNode - rawSelector:rawSelector - combinator:rawSelector.combinator]; - if(basicMatch) { - found = YES; - break; - } else { - return NO; - } - } - } - - } - return YES; + IJSVGStyleSheetSelectorRaw * raw = _rawSelectors[0]; + if([self _match:node selector:raw] && + ([self _matches:node selector:raw] || _rawSelectors.count == 1 )) + return YES; + return NO; } @end