Skip to content

Commit 4ff58c9

Browse files
committed
#69: avoiding crash if font is missing
1 parent dfa3f0a commit 4ff58c9

File tree

2 files changed

+83
-44
lines changed

2 files changed

+83
-44
lines changed

TSMarkdownParser.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,7 @@
10601060
GCC_PRECOMPILE_PREFIX_HEADER = YES;
10611061
GCC_PREFIX_HEADER = "TSMarkdownParser/TSMarkdownParser-Prefix.pch";
10621062
INFOPLIST_FILE = "TSMarkdownParserTests/TSMarkdownParserTests-Info.plist";
1063+
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
10631064
PRODUCT_NAME = TSMarkdownParser;
10641065
WRAPPER_EXTENSION = xctest;
10651066
};
@@ -1188,6 +1189,7 @@
11881189
GCC_PRECOMPILE_PREFIX_HEADER = YES;
11891190
GCC_PREFIX_HEADER = "TSMarkdownParser/TSMarkdownParser-Prefix.pch";
11901191
INFOPLIST_FILE = "TSMarkdownParserTests/TSMarkdownParserTests-Info.plist";
1192+
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
11911193
PRODUCT_NAME = TSMarkdownParser;
11921194
WRAPPER_EXTENSION = xctest;
11931195
};

TSMarkdownParser/TSMarkdownParser.m

Lines changed: 81 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
#import "TSMarkdownParser.h"
1010
#if TARGET_OS_IPHONE
1111
#import <UIKit/UIKit.h>
12+
@implementation UIColor (ts)
13+
/// code compatibility layer for macOS 10.7 and 10.8
14+
+ (UIColor *)colorWithSRGBRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha {
15+
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
16+
}
17+
@end
1218
#else
1319
#import <AppKit/AppKit.h>
1420
typedef NSColor UIColor;
@@ -47,24 +53,26 @@ - (instancetype)init {
4753
@{ NSFontAttributeName: [UIFont boldSystemFontOfSize:13] } ];
4854
#endif
4955

56+
#if TARGET_OS_IPHONE
57+
_emphasisAttributes = @{ NSFontAttributeName: [UIFont italicSystemFontOfSize:defaultSize] };
58+
#else
59+
_emphasisAttributes = @{ NSFontAttributeName: [[NSFontManager sharedFontManager] convertFont:[UIFont systemFontOfSize:defaultSize] toHaveTrait:NSItalicFontMask] };
60+
#endif
61+
5062
_listAttributes = @[];
51-
_quoteAttributes = @[@{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Italic" size:defaultSize]}];
63+
// #69: avoiding crash if font is missing
64+
_quoteAttributes = @[@{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Italic" size:defaultSize] ?: [_emphasisAttributes objectForKey:NSFontAttributeName]}];
5265

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

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

62-
#if TARGET_OS_IPHONE
63-
_emphasisAttributes = @{ NSFontAttributeName: [UIFont italicSystemFontOfSize:defaultSize] };
64-
#else
65-
_emphasisAttributes = @{ NSFontAttributeName: [[NSFontManager sharedFontManager] convertFont:[UIFont systemFontOfSize:defaultSize] toHaveTrait:NSItalicFontMask] };
66-
#endif
67-
6876
return self;
6977
}
7078

@@ -109,25 +117,39 @@ + (instancetype)standardParser {
109117
/* bracket parsing */
110118

111119
[defaultParser addImageParsingWithLinkFormattingBlock:^(NSMutableAttributedString *attributedString, NSRange range, NSString * _Nullable link) {
112-
UIImage *image = [UIImage imageNamed:link];
113-
if (image) {
114-
NSTextAttachment *imageAttachment = [NSTextAttachment new];
115-
imageAttachment.image = image;
116-
imageAttachment.bounds = CGRectMake(0, -5, image.size.width, image.size.height);
117-
NSAttributedString *imgStr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
118-
[attributedString replaceCharactersInRange:range withAttributedString:imgStr];
119-
} else {
120-
if (!weakParser.skipLinkAttribute) {
121-
NSURL *url = [NSURL URLWithString:link] ?: [NSURL URLWithString:
122-
[link stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
123-
if (url.scheme) {
124-
[attributedString addAttribute:NSLinkAttributeName
125-
value:url
126-
range:range];
127-
}
120+
#if !TARGET_OS_IPHONE
121+
#if defined(__MAC_10_13)
122+
// macOS 10.11+ test compatible with Xcode 9+
123+
// NSTextAttachment works on macOS 10.10 but is tricky for image support
124+
if (@available(macOS 10.11, iOS 7.0, watchOS 2.0, tvOS 9.0, *)) {
125+
#else
126+
// macOS 10.11+ test compatible with Xcode 8-
127+
// NSTextAttachment works on macOS 10.10 but is tricky for image support
128+
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_10_Max) {
129+
#endif
130+
#else
131+
{
132+
#endif
133+
UIImage *image = [UIImage imageNamed:link];
134+
if (image) {
135+
NSTextAttachment *imageAttachment = [NSTextAttachment new];
136+
imageAttachment.image = image;
137+
imageAttachment.bounds = CGRectMake(0, -5, image.size.width, image.size.height);
138+
NSAttributedString *imgStr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
139+
[attributedString replaceCharactersInRange:range withAttributedString:imgStr];
140+
return;
141+
}
142+
}
143+
if (!weakParser.skipLinkAttribute) {
144+
NSURL *url = [NSURL URLWithString:link] ?: [NSURL URLWithString:
145+
[link stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
146+
if (url.scheme) {
147+
[attributedString addAttribute:NSLinkAttributeName
148+
value:url
149+
range:range];
128150
}
129-
[attributedString addAttributes:weakParser.imageAttributes range:range];
130151
}
152+
[attributedString addAttributes:weakParser.imageAttributes range:range];
131153
}];
132154

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

@@ -298,25 +321,39 @@ - (void)addImageParsingWithImageFormattingBlock:(TSMarkdownParserFormattingBlock
298321
NSUInteger imagePathStart = [attributedString.string rangeOfString:@"(" options:(NSStringCompareOptions)0 range:match.range].location;
299322
NSRange linkRange = NSMakeRange(imagePathStart, match.range.length + match.range.location - imagePathStart - 1);
300323
NSString *imagePath = [attributedString.string substringWithRange:NSMakeRange(linkRange.location + 1, linkRange.length - 1)];
301-
UIImage *image = [UIImage imageNamed:imagePath];
302-
if (image) {
303-
NSTextAttachment *imageAttachment = [NSTextAttachment new];
304-
imageAttachment.image = image;
305-
imageAttachment.bounds = CGRectMake(0, -5, image.size.width, image.size.height);
306-
NSAttributedString *imgStr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
307-
[attributedString replaceCharactersInRange:match.range withAttributedString:imgStr];
308-
if (formattingBlock) {
309-
formattingBlock(attributedString, NSMakeRange(match.range.location, imgStr.length));
310-
}
311-
} else {
312-
NSUInteger linkTextEndLocation = [attributedString.string rangeOfString:@"]" options:(NSStringCompareOptions)0 range:match.range].location;
313-
NSRange linkTextRange = NSMakeRange(match.range.location + 2, linkTextEndLocation - match.range.location - 2);
314-
NSString *alternativeText = [attributedString.string substringWithRange:linkTextRange];
315-
[attributedString replaceCharactersInRange:match.range withString:alternativeText];
316-
if (alternativeFormattingBlock) {
317-
alternativeFormattingBlock(attributedString, NSMakeRange(match.range.location, alternativeText.length));
324+
#if !TARGET_OS_IPHONE
325+
#if defined(__MAC_10_13)
326+
// macOS 10.11+ test compatible with Xcode 9+
327+
// NSTextAttachment works on macOS 10.10 but is tricky for image support
328+
if (@available(macOS 10.11, iOS 7.0, watchOS 2.0, tvOS 9.0, *)) {
329+
#else
330+
// macOS 10.11+ test compatible with Xcode 8-
331+
// NSTextAttachment works on macOS 10.10 but is tricky for image support
332+
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_10_Max) {
333+
#endif
334+
#else
335+
{
336+
#endif
337+
UIImage *image = [UIImage imageNamed:imagePath];
338+
if (image) {
339+
NSTextAttachment *imageAttachment = [NSTextAttachment new];
340+
imageAttachment.image = image;
341+
imageAttachment.bounds = CGRectMake(0, -5, image.size.width, image.size.height);
342+
NSAttributedString *imgStr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
343+
[attributedString replaceCharactersInRange:match.range withAttributedString:imgStr];
344+
if (formattingBlock) {
345+
formattingBlock(attributedString, NSMakeRange(match.range.location, imgStr.length));
346+
}
347+
return;
318348
}
319349
}
350+
NSUInteger linkTextEndLocation = [attributedString.string rangeOfString:@"]" options:(NSStringCompareOptions)0 range:match.range].location;
351+
NSRange linkTextRange = NSMakeRange(match.range.location + 2, linkTextEndLocation - match.range.location - 2);
352+
NSString *alternativeText = [attributedString.string substringWithRange:linkTextRange];
353+
[attributedString replaceCharactersInRange:match.range withString:alternativeText];
354+
if (alternativeFormattingBlock) {
355+
alternativeFormattingBlock(attributedString, NSMakeRange(match.range.location, alternativeText.length));
356+
}
320357
}];
321358
}
322359

0 commit comments

Comments
 (0)