2
2
3
3
@implementation MarkdownLayoutManager
4
4
5
+ - (BOOL )isRange : (NSRange )smallerRange inRange : (NSRange )largerRange {
6
+ NSUInteger start = smallerRange.location ;
7
+ NSUInteger end = start + smallerRange.length ;
8
+ NSUInteger location = largerRange.location ;
9
+ return location >= start && location < end;
10
+ }
11
+
12
+ - (CGRect)rectByAddingPadding : (CGFloat)padding toRect : (CGRect)rect {
13
+ rect.origin .x -= padding;
14
+ rect.origin .y -= padding;
15
+ rect.size .width += padding * 2 ;
16
+ rect.size .height += padding * 2 ;
17
+ return rect;
18
+ }
19
+
5
20
- (void )drawBackgroundForGlyphRange : (NSRange )glyphsToShow atPoint : (CGPoint)origin {
6
21
[super drawBackgroundForGlyphRange: glyphsToShow atPoint: origin];
7
22
23
+ RCTMarkdownStyle *style = [_markdownUtils markdownStyle ];
24
+ [self drawBlockquotesForRanges: [_markdownUtils blockquoteRangesAndLevels ] andGlyphRange: glyphsToShow atPoint: origin withColor: [style blockquoteBorderColor ] width: [style blockquoteBorderWidth ] margin: [style blockquoteMarginLeft ] andPadding: [style blockquotePaddingLeft ]];
25
+ [self drawPreBackgroundForRanges: [_markdownUtils preRanges ] atPoint: origin withColor: [style preBackgroundColor ] borderColor: [style preBorderColor ] borderWidth: [style preBorderWidth ] borderRadius: [style preBorderRadius ] andPadding: [style prePadding ]];
26
+ [self drawCodeBackgroundForRanges: [_markdownUtils codeRanges ] atPoint: origin withColor: [style codeBackgroundColor ] borderColor: [style codeBorderColor ] borderWidth: [style codeBorderWidth ] borderRadius: [style codeBorderRadius ] andPadding: [style codePadding ]];
27
+ }
28
+
29
+ - (void )drawBlockquotesForRanges : (NSArray <NSDictionary*>*)ranges andGlyphRange : (NSRange )glyphsToShow atPoint : (CGPoint)origin withColor : (UIColor*)color width : (CGFloat)width margin : (CGFloat)margin andPadding : (CGFloat)padding {
8
30
[self enumerateLineFragmentsForGlyphRange: glyphsToShow usingBlock: ^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) {
9
31
__block BOOL isBlockquote = NO ;
10
32
__block int currentDepth = 0 ;
11
- RCTMarkdownUtils *markdownUtils = [ self valueForKey: @" markdownUtils " ];
12
- [markdownUtils.blockquoteRangesAndLevels enumerateObjectsUsingBlock: ^(NSDictionary *item, NSUInteger idx, BOOL * _Nonnull stop) {
33
+
34
+ [ranges enumerateObjectsUsingBlock: ^(NSDictionary *item, NSUInteger idx, BOOL * _Nonnull stop) {
13
35
NSRange range = [[item valueForKey: @" range" ] rangeValue ];
14
36
currentDepth = [[item valueForKey: @" depth" ] unsignedIntegerValue ];
15
- NSUInteger start = range.location ;
16
- NSUInteger end = start + range.length ;
17
- NSUInteger location = glyphRange.location ;
18
- if (location >= start && location < end) {
37
+ if ([self isRange: range inRange: glyphRange]) {
19
38
isBlockquote = YES ;
20
39
*stop = YES ;
21
40
}
@@ -24,17 +43,117 @@ - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origi
24
43
CGFloat paddingLeft = origin.x ;
25
44
CGFloat paddingTop = origin.y ;
26
45
CGFloat y = paddingTop + rect.origin .y ;
27
- CGFloat width = markdownUtils.markdownStyle .blockquoteBorderWidth ;
28
46
CGFloat height = rect.size .height ;
29
- CGFloat shift = markdownUtils. markdownStyle . blockquoteMarginLeft + markdownUtils. markdownStyle . blockquoteBorderWidth + markdownUtils. markdownStyle . blockquotePaddingLeft ;
47
+ CGFloat shift = margin + width + padding ;
30
48
for (int level = 0 ; level < currentDepth; level++) {
31
- CGFloat x = paddingLeft + (level * shift) + markdownUtils. markdownStyle . blockquoteMarginLeft ;
49
+ CGFloat x = paddingLeft + (level * shift) + margin ;
32
50
CGRect lineRect = CGRectMake (x, y, width, height);
33
- [markdownUtils.markdownStyle.blockquoteBorderColor setFill ];
51
+ [color setFill ];
34
52
UIRectFill (lineRect);
35
53
}
36
54
}
37
55
}];
38
56
}
39
57
58
+ - (void )drawPreBackgroundForRanges : (NSArray <NSValue*>*)ranges atPoint : (CGPoint)origin withColor : (UIColor*)backgroundColor borderColor : (UIColor*)borderColor borderWidth : (CGFloat)borderWidth borderRadius : (CGFloat)borderRadius andPadding : (CGFloat)padding {
59
+ __block CGRect preRect = CGRectNull;
60
+ [ranges enumerateObjectsUsingBlock: ^(NSValue *item, NSUInteger idx, BOOL * _Nonnull stop) {
61
+ NSRange range = [item rangeValue ];
62
+ // We don't want the trailing ``` to be a part of the block so we need to reduce range by 1.
63
+ // This also breaks one character blocks so we need to check if range is larger.
64
+ if (range.length > 1 ) {
65
+ range.location += 1 ;
66
+ range.length -= 1 ;
67
+ }
68
+
69
+ [self enumerateLineFragmentsForGlyphRange: range usingBlock: ^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) {
70
+ if (CGRectIsNull (preRect)) {
71
+ preRect = usedRect;
72
+ CGFloat paddingLeft = origin.x ;
73
+ preRect.origin .x += paddingLeft;
74
+ CGFloat paddingTop = origin.y ;
75
+ preRect.origin .y += paddingTop;
76
+ } else {
77
+ CGFloat usedWidth = usedRect.size .width ;
78
+ if (usedWidth > preRect.size .width ) {
79
+ preRect.size .width = usedWidth;
80
+ }
81
+ preRect.size .height += usedRect.size .height ;
82
+ }
83
+ }];
84
+
85
+ if (!CGRectIsNull (preRect)) {
86
+ preRect = [self rectByAddingPadding: padding toRect: preRect];
87
+ [self drawBackgroundWithColor: backgroundColor borderColor: borderColor borderWidth: borderWidth andBorderRadius: borderRadius forRect: preRect isLeftOpen: NO isRightOpen: NO ];
88
+ preRect = CGRectNull;
89
+ }
90
+ }];
91
+ }
92
+
93
+ - (void )drawCodeBackgroundForRanges : (NSArray <NSValue*>*)ranges atPoint : (CGPoint)origin withColor : (UIColor*)backgroundColor borderColor : (UIColor*)borderColor borderWidth : (CGFloat)borderWidth borderRadius : (CGFloat)borderRadius andPadding : (CGFloat)padding {
94
+ [ranges enumerateObjectsUsingBlock: ^(NSValue *item, NSUInteger idx, BOOL * _Nonnull stop) {
95
+ NSRange range = [item rangeValue ];
96
+ [self enumerateLineFragmentsForGlyphRange: range usingBlock: ^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) {
97
+ BOOL isLeftSideOpen = YES ;
98
+ BOOL isRightSideOpen = YES ;
99
+
100
+ NSRange adjustedRange = glyphRange;
101
+ if (range.location > adjustedRange.location ) {
102
+ adjustedRange.length -= range.location - adjustedRange.location ;
103
+ adjustedRange.location = range.location ;
104
+ isLeftSideOpen = NO ;
105
+ }
106
+
107
+ NSUInteger rangeEndLocation = range.location + range.length ;
108
+ NSUInteger adjustedRangeEndLocation = adjustedRange.location + adjustedRange.length ;
109
+ if (rangeEndLocation < adjustedRangeEndLocation) {
110
+ adjustedRange.length -= adjustedRangeEndLocation - rangeEndLocation;
111
+ isRightSideOpen = NO ;
112
+ }
113
+
114
+ CGRect codeRect = [self boundingRectForGlyphRange: adjustedRange inTextContainer: textContainer];
115
+ CGFloat paddingLeft = origin.x ;
116
+ codeRect.origin .x += paddingLeft;
117
+ CGFloat paddingTop = origin.y ;
118
+ codeRect.origin .y += paddingTop;
119
+ codeRect = [self rectByAddingPadding: padding toRect: codeRect];
120
+ [self drawBackgroundWithColor: backgroundColor borderColor: borderColor borderWidth: borderWidth andBorderRadius: borderRadius forRect: codeRect isLeftOpen: isLeftSideOpen isRightOpen: isRightSideOpen];
121
+ }];
122
+ }];
123
+ }
124
+
125
+ - (void )drawBackgroundWithColor : (UIColor*)backgroundColor borderColor : (UIColor*)borderColor borderWidth : (CGFloat)borderWidth andBorderRadius : (CGFloat)radius forRect : (CGRect)rect isLeftOpen : (BOOL )isLeftOpen isRightOpen : (BOOL )isRightOpen {
126
+ UIRectCorner corners = 0 ;
127
+ if (!isLeftOpen) {
128
+ corners |= UIRectCornerTopLeft | UIRectCornerBottomLeft;
129
+ }
130
+ if (!isRightOpen) {
131
+ corners |= UIRectCornerTopRight | UIRectCornerBottomRight;
132
+ }
133
+ UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect: rect byRoundingCorners: corners cornerRadii: CGSizeMake (radius, radius)];
134
+
135
+ [backgroundColor setFill ];
136
+ [path fill ];
137
+ [borderColor setStroke ];
138
+ [path setLineWidth: borderWidth];
139
+ [path stroke ];
140
+
141
+ if (isLeftOpen) {
142
+ [self openSideForRect: rect withBorderWidth: borderWidth isLeft: YES ];
143
+ }
144
+ if (isRightOpen) {
145
+ [self openSideForRect: rect withBorderWidth: borderWidth isLeft: NO ];
146
+ }
147
+ }
148
+
149
+ - (void )openSideForRect : (CGRect)rect withBorderWidth : (CGFloat)borderWidth isLeft : (BOOL )isLeft {
150
+ UIBezierPath *path = [[UIBezierPath alloc ] init ];
151
+ CGFloat x = isLeft ? CGRectGetMinX (rect) : CGRectGetMaxX (rect);
152
+ [path moveToPoint: CGPointMake (x, CGRectGetMinY (rect) - borderWidth)];
153
+ [path addLineToPoint: CGPointMake (x, CGRectGetMaxY (rect) + borderWidth)];
154
+ [[UIColor clearColor ] setStroke ];
155
+ [path setLineWidth: borderWidth + 1 ];
156
+ [path strokeWithBlendMode: kCGBlendModeClear alpha: 1.0 ];
157
+ }
158
+
40
159
@end
0 commit comments