Skip to content

Commit 99efd8f

Browse files
committed
Fix rendering issues when built against the 10.14 SDK.
Before this commit, the Core Text renderer relied on a legacy behavior of NSView to keep its content across draws. setNeedsDisplayInRect: could be used to draw over parts of the existing content as drawing commands were received without needing to redraw old content. Layer-backed views lose this behavior and may be asked to redraw any or all of their content at any time, and layer backing becomes the default for apps built against the macOS 10.14 SDK. This change adds a way to draw to an intermediate NSImage and then create a layer contents from that image. It's similar to the CGLayer path, but I wasn't able to get the CGLayer path to work without hanging or crashing when I scrolled. My best guess from looking at stack traces is that using CGContextDrawLayerInRect to draw a layer into itself doesn't actually copy pixels, but adds the self-draw as an action to be performed when the CGLayer is drawn into a bitmap context. After a bunch of scrolling, these actions stack deeper and deeper and either hang or overflow the stack when drawn. When on, the new code skips -drawRect: by returning YES from -wantsUpdateLayer. -updateLayer draws into an NSImage and then creates a layer contents from the NSImage. On my machine, scrolling a large document seems to be faster and use less CPU vs drawRect, which is promising. The new code is controlled by the MMUseCALayer user default, which is on by default in this change. Fixes #751.
1 parent 8b2dcf4 commit 99efd8f

File tree

5 files changed

+37
-1
lines changed

5 files changed

+37
-1
lines changed

src/MacVim/MMAppController.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ + (void)initialize
234234
[NSNumber numberWithBool:YES], MMNativeFullScreenKey,
235235
[NSNumber numberWithDouble:0.25], MMFullScreenFadeTimeKey,
236236
[NSNumber numberWithBool:NO], MMUseCGLayerAlwaysKey,
237+
[NSNumber numberWithBool:YES], MMUseCALayerKey,
237238
[NSNumber numberWithBool:YES], MMShareFindPboardKey,
238239
nil];
239240

src/MacVim/MMCoreTextView.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
CGContextRef cgLayerContext;
4747
NSLock *cgLayerLock;
4848

49+
NSImage *contentsImage;
50+
4951
// These are used in MMCoreTextView+ToolTip.m
5052
id trackingRectOwner_; // (not retained)
5153
void *trackingRectUserData_;

src/MacVim/MMCoreTextView.m

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ - (id)initWithFrame:(NSRect)frame
137137
boolForKey:MMUseCGLayerAlwaysKey];
138138
cgLayerLock = [NSLock new];
139139

140+
if ([[NSUserDefaults standardUserDefaults]
141+
boolForKey:MMUseCALayerKey]) {
142+
self.wantsLayer = YES;
143+
contentsImage = [[NSImage alloc] initWithSize:frame.size];
144+
}
145+
140146
// NOTE! It does not matter which font is set here, Vim will set its
141147
// own font on startup anyway. Just set some bogus values.
142148
font = [[NSFont userFixedPitchFontOfSize:0] retain];
@@ -448,6 +454,7 @@ - (void)setFrameSize:(NSSize)newSize {
448454
[NSAnimationContext beginGrouping];
449455
drawPending = YES;
450456
}
457+
[contentsImage setSize:newSize];
451458
[super setFrameSize:newSize];
452459
}
453460

@@ -606,6 +613,19 @@ - (BOOL)isFlipped
606613
return NO;
607614
}
608615

616+
- (BOOL)wantsUpdateLayer {
617+
return contentsImage != nil;
618+
}
619+
620+
- (void)updateLayer {
621+
[contentsImage lockFocus];
622+
for (NSData* data in drawData)
623+
[self batchDrawData:data];
624+
[drawData removeAllObjects];
625+
[contentsImage unlockFocus];
626+
self.layer.contents = [contentsImage layerContentsForContentsScale:self.layer.contentsScale];
627+
}
628+
609629
- (void)drawRect:(NSRect)rect
610630
{
611631
NSGraphicsContext *context = [NSGraphicsContext currentContext];
@@ -669,6 +689,9 @@ - (void)performBatchDrawWithData:(NSData *)data
669689

670690
- (void)setCGLayerEnabled:(BOOL)enabled
671691
{
692+
if (contentsImage)
693+
return;
694+
672695
cgLayerEnabled = enabled;
673696

674697
if (!cgLayerEnabled)
@@ -1491,7 +1514,15 @@ - (void)drawString:(const UniChar *)chars length:(UniCharCount)length
14911514

14921515
- (void)scrollRect:(NSRect)rect lineCount:(int)count
14931516
{
1494-
if (cgLayerEnabled) {
1517+
if (contentsImage) {
1518+
// Toggle focus to commit any fresh drawing before drawing the image onto itself.
1519+
[contentsImage unlockFocus];
1520+
[contentsImage lockFocus];
1521+
[contentsImage drawInRect:NSOffsetRect(rect, 0, -count * cellSize.height)
1522+
fromRect:rect
1523+
operation:NSCompositingOperationCopy
1524+
fraction:1.0];
1525+
} else if (cgLayerEnabled) {
14951526
CGContextRef context = [self getCGContext];
14961527
int yOffset = count * cellSize.height;
14971528
NSRect clipRect = rect;

src/MacVim/Miscellaneous.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ extern NSString *MMNativeFullScreenKey;
5353
extern NSString *MMUseMouseTimeKey;
5454
extern NSString *MMFullScreenFadeTimeKey;
5555
extern NSString *MMUseCGLayerAlwaysKey;
56+
extern NSString *MMUseCALayerKey;
5657

5758

5859
// Enum for MMUntitledWindowKey

src/MacVim/Miscellaneous.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
NSString *MMUseMouseTimeKey = @"MMUseMouseTime";
5050
NSString *MMFullScreenFadeTimeKey = @"MMFullScreenFadeTime";
5151
NSString *MMUseCGLayerAlwaysKey = @"MMUseCGLayerAlways";
52+
NSString *MMUseCALayerKey = @"MMUseCALayer";
5253

5354

5455

0 commit comments

Comments
 (0)