Skip to content

Commit

Permalink
#69: avoiding crash if font is missing
Browse files Browse the repository at this point in the history
  • Loading branch information
Coeur committed Mar 5, 2018
1 parent dfa3f0a commit 4ff58c9
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 44 deletions.
2 changes: 2 additions & 0 deletions TSMarkdownParser.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,7 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TSMarkdownParser/TSMarkdownParser-Prefix.pch";
INFOPLIST_FILE = "TSMarkdownParserTests/TSMarkdownParserTests-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
PRODUCT_NAME = TSMarkdownParser;
WRAPPER_EXTENSION = xctest;
};
Expand Down Expand Up @@ -1188,6 +1189,7 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TSMarkdownParser/TSMarkdownParser-Prefix.pch";
INFOPLIST_FILE = "TSMarkdownParserTests/TSMarkdownParserTests-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
PRODUCT_NAME = TSMarkdownParser;
WRAPPER_EXTENSION = xctest;
};
Expand Down
125 changes: 81 additions & 44 deletions TSMarkdownParser/TSMarkdownParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
#import "TSMarkdownParser.h"
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
@implementation UIColor (ts)
/// code compatibility layer for macOS 10.7 and 10.8
+ (UIColor *)colorWithSRGBRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha {
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
@end
#else
#import <AppKit/AppKit.h>
typedef NSColor UIColor;
Expand Down Expand Up @@ -47,24 +53,26 @@ - (instancetype)init {
@{ NSFontAttributeName: [UIFont boldSystemFontOfSize:13] } ];
#endif

#if TARGET_OS_IPHONE
_emphasisAttributes = @{ NSFontAttributeName: [UIFont italicSystemFontOfSize:defaultSize] };
#else
_emphasisAttributes = @{ NSFontAttributeName: [[NSFontManager sharedFontManager] convertFont:[UIFont systemFontOfSize:defaultSize] toHaveTrait:NSItalicFontMask] };
#endif

_listAttributes = @[];
_quoteAttributes = @[@{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Italic" size:defaultSize]}];
// #69: avoiding crash if font is missing
_quoteAttributes = @[@{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Italic" size:defaultSize] ?: [_emphasisAttributes objectForKey:NSFontAttributeName]}];

_imageAttributes = @{};
_linkAttributes = @{ NSForegroundColorAttributeName: [UIColor blueColor],
NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle) };

// Courier New and Courier are the only monospace fonts compatible with watchOS 2
_monospaceAttributes = @{ NSFontAttributeName: [UIFont fontWithName:@"Courier New" size:defaultSize],
NSForegroundColorAttributeName: [UIColor colorWithRed:0.95 green:0.54 blue:0.55 alpha:1] };
// #69: avoiding crash if font is missing
_monospaceAttributes = @{ NSFontAttributeName: [UIFont fontWithName:@"Courier New" size:defaultSize] ?: [UIFont fontWithName:@"Courier" size:defaultSize] ?: [UIFont systemFontOfSize:defaultSize],
NSForegroundColorAttributeName: [UIColor colorWithSRGBRed:0.95 green:0.54 blue:0.55 alpha:1] };
_strongAttributes = @{ NSFontAttributeName: [UIFont boldSystemFontOfSize:defaultSize] };

#if TARGET_OS_IPHONE
_emphasisAttributes = @{ NSFontAttributeName: [UIFont italicSystemFontOfSize:defaultSize] };
#else
_emphasisAttributes = @{ NSFontAttributeName: [[NSFontManager sharedFontManager] convertFont:[UIFont systemFontOfSize:defaultSize] toHaveTrait:NSItalicFontMask] };
#endif

return self;
}

Expand Down Expand Up @@ -109,25 +117,39 @@ + (instancetype)standardParser {
/* bracket parsing */

[defaultParser addImageParsingWithLinkFormattingBlock:^(NSMutableAttributedString *attributedString, NSRange range, NSString * _Nullable link) {
UIImage *image = [UIImage imageNamed:link];
if (image) {
NSTextAttachment *imageAttachment = [NSTextAttachment new];
imageAttachment.image = image;
imageAttachment.bounds = CGRectMake(0, -5, image.size.width, image.size.height);
NSAttributedString *imgStr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
[attributedString replaceCharactersInRange:range withAttributedString:imgStr];
} else {
if (!weakParser.skipLinkAttribute) {
NSURL *url = [NSURL URLWithString:link] ?: [NSURL URLWithString:
[link stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
if (url.scheme) {
[attributedString addAttribute:NSLinkAttributeName
value:url
range:range];
}
#if !TARGET_OS_IPHONE
#if defined(__MAC_10_13)
// macOS 10.11+ test compatible with Xcode 9+
// NSTextAttachment works on macOS 10.10 but is tricky for image support
if (@available(macOS 10.11, iOS 7.0, watchOS 2.0, tvOS 9.0, *)) {
#else
// macOS 10.11+ test compatible with Xcode 8-
// NSTextAttachment works on macOS 10.10 but is tricky for image support
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_10_Max) {
#endif
#else
{
#endif
UIImage *image = [UIImage imageNamed:link];
if (image) {
NSTextAttachment *imageAttachment = [NSTextAttachment new];
imageAttachment.image = image;
imageAttachment.bounds = CGRectMake(0, -5, image.size.width, image.size.height);
NSAttributedString *imgStr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
[attributedString replaceCharactersInRange:range withAttributedString:imgStr];
return;
}
}
if (!weakParser.skipLinkAttribute) {
NSURL *url = [NSURL URLWithString:link] ?: [NSURL URLWithString:
[link stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
if (url.scheme) {
[attributedString addAttribute:NSLinkAttributeName
value:url
range:range];
}
[attributedString addAttributes:weakParser.imageAttributes range:range];
}
[attributedString addAttributes:weakParser.imageAttributes range:range];
}];

[defaultParser addLinkParsingWithLinkFormattingBlock:^(NSMutableAttributedString *attributedString, NSRange range, NSString * _Nullable link) {
Expand Down Expand Up @@ -197,7 +219,8 @@ + (void)addAttributes:(NSArray<NSDictionary<NSString *, id> *> *)attributesArray
{
if (!attributesArray.count)
return;
NSDictionary<NSString *, id> *attributes = level < attributesArray.count ? attributesArray[level] : attributesArray.lastObject;
// 'objectAtIndexedSubscript:' is only available on macOS 10.8 or newer
NSDictionary<NSString *, id> *attributes = level < attributesArray.count ? [attributesArray objectAtIndex:level] : attributesArray.lastObject;
[attributedString addAttributes:attributes range:range];
}

Expand Down Expand Up @@ -298,25 +321,39 @@ - (void)addImageParsingWithImageFormattingBlock:(TSMarkdownParserFormattingBlock
NSUInteger imagePathStart = [attributedString.string rangeOfString:@"(" options:(NSStringCompareOptions)0 range:match.range].location;
NSRange linkRange = NSMakeRange(imagePathStart, match.range.length + match.range.location - imagePathStart - 1);
NSString *imagePath = [attributedString.string substringWithRange:NSMakeRange(linkRange.location + 1, linkRange.length - 1)];
UIImage *image = [UIImage imageNamed:imagePath];
if (image) {
NSTextAttachment *imageAttachment = [NSTextAttachment new];
imageAttachment.image = image;
imageAttachment.bounds = CGRectMake(0, -5, image.size.width, image.size.height);
NSAttributedString *imgStr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
[attributedString replaceCharactersInRange:match.range withAttributedString:imgStr];
if (formattingBlock) {
formattingBlock(attributedString, NSMakeRange(match.range.location, imgStr.length));
}
} else {
NSUInteger linkTextEndLocation = [attributedString.string rangeOfString:@"]" options:(NSStringCompareOptions)0 range:match.range].location;
NSRange linkTextRange = NSMakeRange(match.range.location + 2, linkTextEndLocation - match.range.location - 2);
NSString *alternativeText = [attributedString.string substringWithRange:linkTextRange];
[attributedString replaceCharactersInRange:match.range withString:alternativeText];
if (alternativeFormattingBlock) {
alternativeFormattingBlock(attributedString, NSMakeRange(match.range.location, alternativeText.length));
#if !TARGET_OS_IPHONE
#if defined(__MAC_10_13)
// macOS 10.11+ test compatible with Xcode 9+
// NSTextAttachment works on macOS 10.10 but is tricky for image support
if (@available(macOS 10.11, iOS 7.0, watchOS 2.0, tvOS 9.0, *)) {
#else
// macOS 10.11+ test compatible with Xcode 8-
// NSTextAttachment works on macOS 10.10 but is tricky for image support
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_10_Max) {
#endif
#else
{
#endif
UIImage *image = [UIImage imageNamed:imagePath];
if (image) {
NSTextAttachment *imageAttachment = [NSTextAttachment new];
imageAttachment.image = image;
imageAttachment.bounds = CGRectMake(0, -5, image.size.width, image.size.height);
NSAttributedString *imgStr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
[attributedString replaceCharactersInRange:match.range withAttributedString:imgStr];
if (formattingBlock) {
formattingBlock(attributedString, NSMakeRange(match.range.location, imgStr.length));
}
return;
}
}
NSUInteger linkTextEndLocation = [attributedString.string rangeOfString:@"]" options:(NSStringCompareOptions)0 range:match.range].location;
NSRange linkTextRange = NSMakeRange(match.range.location + 2, linkTextEndLocation - match.range.location - 2);
NSString *alternativeText = [attributedString.string substringWithRange:linkTextRange];
[attributedString replaceCharactersInRange:match.range withString:alternativeText];
if (alternativeFormattingBlock) {
alternativeFormattingBlock(attributedString, NSMakeRange(match.range.location, alternativeText.length));
}
}];
}

Expand Down

0 comments on commit 4ff58c9

Please sign in to comment.