Skip to content

Commit

Permalink
Merge branch 'release-1.6.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
odrobnik committed Aug 16, 2013
2 parents 61a6042 + 718eb0d commit 81a8735
Show file tree
Hide file tree
Showing 20 changed files with 925 additions and 355 deletions.
178 changes: 128 additions & 50 deletions Core/Source/DTCSSStylesheet.m
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ - (id)initWithStyleBlock:(NSString *)css

if (self)
{
_styles = [[NSMutableDictionary alloc] init];
_styles = [[NSMutableDictionary alloc] init];

[self parseStyleBlock:css];
}
Expand All @@ -69,8 +69,8 @@ - (id)initWithStylesheet:(DTCSSStylesheet *)stylesheet

if (self)
{
_styles = [[NSMutableDictionary alloc] init];

_styles = [[NSMutableDictionary alloc] init];
[self mergeStylesheet:stylesheet];
}

Expand Down Expand Up @@ -145,7 +145,7 @@ - (void)_uncompressShorthands:(NSMutableDictionary *)styles
if (listStylePosition != DTCSSListStylePositionInvalid)
{
[styles setObject:oneComponent forKey:@"list-style-position"];

positionWasSet = YES;
continue;
}
Expand All @@ -160,7 +160,7 @@ - (void)_uncompressShorthands:(NSMutableDictionary *)styles
{
NSString *fontStyle = @"normal";
NSArray *validFontStyles = [NSArray arrayWithObjects:@"italic", @"oblique", nil];

NSString *fontVariant = @"normal";
NSArray *validFontVariants = [NSArray arrayWithObjects:@"small-caps", nil];
BOOL fontVariantSet = NO;
Expand All @@ -180,7 +180,7 @@ - (void)_uncompressShorthands:(NSMutableDictionary *)styles
NSMutableString *fontFamily = [NSMutableString string];

NSArray *components = [shortHand componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

for (NSString *oneComponent in components)
{
// try font size keywords
Expand Down Expand Up @@ -216,7 +216,7 @@ - (void)_uncompressShorthands:(NSMutableDictionary *)styles
continue;
}
}

if (fontSizeSet)
{
if ([suffixesToIgnore containsObject:oneComponent])
Expand Down Expand Up @@ -250,9 +250,9 @@ - (void)_uncompressShorthands:(NSMutableDictionary *)styles
}
}
}

[styles removeObjectForKey:@"font"];

// size and family are mandatory, without them this is invalid
if ([fontSize length] && [fontFamily length])
{
Expand Down Expand Up @@ -374,7 +374,7 @@ - (void)_uncompressShorthands:(NSMutableDictionary *)styles
bottomPadding = onlyValue;
leftPadding = onlyValue;
}

// only apply the ones where there is no previous direct setting

if (![styles objectForKey:@"padding-top"])
Expand All @@ -386,7 +386,7 @@ - (void)_uncompressShorthands:(NSMutableDictionary *)styles
{
[styles setObject:rightPadding forKey:@"padding-right"];
}

if (![styles objectForKey:@"padding-bottom"])
{
[styles setObject:bottomPadding forKey:@"padding-bottom"];
Expand All @@ -406,7 +406,7 @@ - (void)_addStyleRule:(NSString *)rule withSelector:(NSString*)selectors
{
NSArray *split = [selectors componentsSeparatedByString:@","];

for (NSString *selector in split)
for (NSString *selector in split)
{
NSString *cleanSelector = [selector stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

Expand All @@ -415,22 +415,57 @@ - (void)_addStyleRule:(NSString *)rule withSelector:(NSString*)selectors
// remove !important, we're ignoring these
for (NSString *oneKey in [ruleDictionary allKeys])
{
NSString *value = [ruleDictionary objectForKey:oneKey];

NSRange rangeOfImportant = [value rangeOfString:@"!important" options:NSCaseInsensitiveSearch];

if (rangeOfImportant.location != NSNotFound)
id value = [ruleDictionary objectForKey:oneKey];
if ([value isKindOfClass:[NSString class]])
{
value = [value stringByReplacingCharactersInRange:rangeOfImportant withString:@""];
value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSRange rangeOfImportant = [value rangeOfString:@"!important" options:NSCaseInsensitiveSearch];

[ruleDictionary setObject:value forKey:oneKey];
if (rangeOfImportant.location != NSNotFound)
{
value = [value stringByReplacingCharactersInRange:rangeOfImportant withString:@""];
value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

[ruleDictionary setObject:value forKey:oneKey];
}

} else if ([value isKindOfClass:[NSArray class]]) {

NSMutableArray *newVal;

for (NSUInteger i = 0; i < [value count]; ++i)
{
NSString *s = [value objectAtIndex:i];

NSRange rangeOfImportant = [s rangeOfString:@"!important" options:NSCaseInsensitiveSearch];

if (rangeOfImportant.location != NSNotFound)
{
s = [s stringByReplacingCharactersInRange:rangeOfImportant withString:@""];
s = [s stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

if (!newVal) {

if ([value isKindOfClass:[NSMutableArray class]]) {
newVal = value;
} else {
newVal = [value mutableCopy];
}
}

newVal[i] = s;
}
}

if (newVal) {

[ruleDictionary setObject:newVal forKey:oneKey];
}
}
}

// need to uncompress because otherwise we might get shorthands and non-shorthands together
[self _uncompressShorthands:ruleDictionary];

// check if there is a pseudo selector
NSRange colonRange = [cleanSelector rangeOfString:@":"];
NSString *pseudoSelector = nil;
Expand All @@ -443,16 +478,7 @@ - (void)_addStyleRule:(NSString *)rule withSelector:(NSString*)selectors
// prefix all rules with the pseudo-selector
for (NSString *oneRuleKey in [ruleDictionary allKeys])
{
// remove double quotes
NSString *value = [ruleDictionary objectForKey:oneRuleKey];

if ([value hasPrefix:@"\""] && [value hasSuffix:@"\""])
{
// treat as HTML string, remove quotes
NSRange range = NSMakeRange(1, [value length]-2);

value = [[value substringWithRange:range] stringByAddingHTMLEntities];
}
id value = [ruleDictionary objectForKey:oneRuleKey];

// prefix key with the pseudo selector
NSString *prefixedKey = [NSString stringWithFormat:@"%@:%@", pseudoSelector, oneRuleKey];
Expand All @@ -463,18 +489,18 @@ - (void)_addStyleRule:(NSString *)rule withSelector:(NSString*)selectors

NSDictionary *existingRulesForSelector = [_styles objectForKey:cleanSelector];

if (existingRulesForSelector)
if (existingRulesForSelector)
{
// substitute new rules over old ones
NSMutableDictionary *tmpDict = [existingRulesForSelector mutableCopy];

// append new rules
[tmpDict addEntriesFromDictionary:ruleDictionary];

// save it
[_styles setObject:tmpDict forKey:cleanSelector];
}
else
else
{
[_styles setObject:ruleDictionary forKey:cleanSelector];
}
Expand Down Expand Up @@ -538,7 +564,7 @@ - (void)parseStyleBlock:(NSString*)css
{
// If we start a new rule...

if (braceLevel == 0)
if (braceLevel == 0)
{
// Grab the selector (we'll process it in a moment)
selector = [css substringWithRange:NSMakeRange(braceMarker, i-braceMarker)];
Expand All @@ -552,10 +578,10 @@ - (void)parseStyleBlock:(NSString*)css
}

// A closing brace!
else if (c == '}')
else if (c == '}')
{
// If we finished a rule...
if (braceLevel == 1)
if (braceLevel == 1)
{
NSString *rule = [css substringWithRange:NSMakeRange(braceMarker, i-braceMarker)];

Expand Down Expand Up @@ -612,7 +638,7 @@ - (NSDictionary *)mergedStyleDictionaryForElement:(DTHTMLElement *)element match
// Get based on element
NSDictionary *byTagName = [self.styles objectForKey:element.name];

if (byTagName)
if (byTagName)
{
[tmpDict addEntriesFromDictionary:byTagName];
}
Expand All @@ -621,32 +647,37 @@ - (NSDictionary *)mergedStyleDictionaryForElement:(DTHTMLElement *)element match
NSString *classString = [element.attributes objectForKey:@"class"];
NSArray *classes = [classString componentsSeparatedByString:@" "];

// Find all classes by walking up the heirarchy and compute possible selector combinations
NSArray *ancestorClassArrays = [self findAncestorClassArraysForElement:element];
NSArray *cascadedSelectors = [self computeCascadedClassSelectorsWithAncestorClasses:ancestorClassArrays];

NSMutableSet *tmpMatchedSelectors;

if (matchedSelectors)
{
tmpMatchedSelectors = [[NSMutableSet alloc] init];
}

for (NSString *class in classes)
for (NSString *class in classes)
{
NSString *classRule = [NSString stringWithFormat:@".%@", class];
NSString *classAndTagRule = [NSString stringWithFormat:@"%@.%@", element.name, class];

NSDictionary *byClass = [_styles objectForKey:classRule];
NSDictionary *byClassAndName = [_styles objectForKey:classAndTagRule];

if (byClass)
if (byClassAndName)
{
[tmpDict addEntriesFromDictionary:byClass];

[tmpMatchedSelectors addObject:classRule];
[tmpDict addEntriesFromDictionary:byClassAndName];
[tmpMatchedSelectors addObject:classAndTagRule];
}

if (byClassAndName)
//This covers the "by class" only case (e.g. .foo)
for (NSString *cascadedSelector in cascadedSelectors)
{
[tmpDict addEntriesFromDictionary:byClassAndName];
[tmpMatchedSelectors addObject:classAndTagRule];
NSDictionary *byCascadedClassName = [_styles objectForKey:cascadedSelector];
if (byCascadedClassName)
{
[tmpDict addEntriesFromDictionary:byCascadedClassName];
[tmpMatchedSelectors addObject:cascadedSelector];
}
}
}

Expand Down Expand Up @@ -693,6 +724,53 @@ - (NSDictionary *)styles
return _styles;
}

- (NSArray *)findAncestorClassArraysForElement:(DTHTMLElement *)element
{
// Walk up the heirarchy looking for parents with class attributes then compute cascades
NSMutableArray *ancestorClassArrays = [NSMutableArray array];

DTHTMLElement *currentElement = element;
while (currentElement != nil)
{
NSString *currentElementClassString = [currentElement.attributes objectForKey:@"class"];
NSArray *currentElementClasses = [currentElementClassString componentsSeparatedByString:@" "];
if (currentElementClasses.count)
{
[ancestorClassArrays insertObject:currentElementClasses atIndex:0];
}

currentElement = currentElement.parentElement;
}

return ancestorClassArrays;
}

- (NSArray *)computeCascadedClassSelectorsWithAncestorClasses:(NSArray *)ancestorClasses
{
NSMutableOrderedSet *cascadedSelectors = [[NSMutableOrderedSet alloc] init];

if (ancestorClasses.count) {
NSArray *classes = ancestorClasses[0];

// Find selector combinations for all ancestors that are leaves of the ancesor the current class array belongs to
NSArray *remainingAncessorClasses = [ancestorClasses subarrayWithRange:NSMakeRange(1, ancestorClasses.count - 1)];
NSArray *descendentSelectors = [self computeCascadedClassSelectorsWithAncestorClasses:remainingAncessorClasses];

for (NSString *class in classes)
{
[cascadedSelectors addObject:[NSString stringWithFormat:@".%@", class]];

for (NSString *descendentSelector in descendentSelectors)
{
[cascadedSelectors addObject:[NSString stringWithFormat:@"%@", descendentSelector]];
[cascadedSelectors addObject:[NSString stringWithFormat:@".%@ %@", class, descendentSelector]];
}
}
}

return [cascadedSelectors array];
}

#pragma mark NSCopying

- (id)copyWithZone:(NSZone *)zone
Expand Down
15 changes: 15 additions & 0 deletions Core/Source/DTCompatibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@
#define DTCORETEXT_SUPPORT_NS_ATTRIBUTES 1
#endif

// iOS before 5.0 has leak in CoreText replacing attributes
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
#define DTCORETEXT_NEEDS_ATTRIBUTE_REPLACEMENT_LEAK_FIX 1
#endif

// iOS 7 bug (rdar://14684188) workaround, can be removed once this bug is fixed
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1
#define DTCORETEXT_FIX_14684188 1
#endif

#endif


Expand All @@ -44,6 +54,11 @@
// Mac supports NS-Style Text Attributes since 10.0
#define DTCORETEXT_SUPPORT_NS_ATTRIBUTES 1

// theoretically MacOS before 10.8 might have a leak in CoreText replacing attributes
#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_7
#define DTCORETEXT_NEEDS_ATTRIBUTE_REPLACEMENT_LEAK_FIX 1
#endif

// NSValue has sizeValue on Mac, CGSizeValue on iOS
#define CGSizeValue sizeValue

Expand Down
1 change: 0 additions & 1 deletion Core/Source/DTCoreText.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#import "DTImage+HTML.h"

// common utilities
#import "DTUtils.h"
#if TARGET_OS_IPHONE
#import "DTCoreTextFunctions.h"
#endif
Expand Down
Loading

0 comments on commit 81a8735

Please sign in to comment.