Skip to content

Commit 0db547d

Browse files
committed
Fix rendering issues with 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: drew over parts of the existing content as drawing commands were received, without ever redrawing old content. Layer backed views don't preserve content between draws and may be asked to redraw at any time, and layer backing is default on in the 10.14 SDK. This change adds a way to draw to a CGBitmapContext and then display that in the view's layer. 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. Scrolling stacks these actions, which either hangs or overflows the stack when drawn. The new code is controlled by the MMBufferedDrawing user default, which is on by default on macOS >= 10.14 with this change. Fixes #751.
1 parent 63dbd58 commit 0db547d

File tree

7 files changed

+74
-6
lines changed

7 files changed

+74
-6
lines changed

src/MacVim/MMAppController.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ + (void)initialize
248248
[NSNumber numberWithBool:YES], MMNativeFullScreenKey,
249249
[NSNumber numberWithDouble:0.25], MMFullScreenFadeTimeKey,
250250
[NSNumber numberWithBool:NO], MMUseCGLayerAlwaysKey,
251+
@(shouldUseBufferedDrawing()), MMBufferedDrawingKey,
251252
[NSNumber numberWithBool:YES], MMShareFindPboardKey,
252253
nil];
253254

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+
CGContextRef cgContext;
50+
4951
// These are used in MMCoreTextView+ToolTip.m
5052
id trackingRectOwner_; // (not retained)
5153
void *trackingRectUserData_;

src/MacVim/MMCoreTextView.m

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ - (void)dealloc
168168
[drawData release]; drawData = nil;
169169
[fontCache release]; fontCache = nil;
170170

171+
CGContextRelease(cgContext); cgContext = nil;
172+
171173
[helper setTextView:nil];
172174
[helper release]; helper = nil;
173175

@@ -215,6 +217,7 @@ - (void)setDefaultColorsBackground:(NSColor *)bgColor
215217
[defaultForegroundColor release];
216218
defaultForegroundColor = fgColor ? [fgColor retain] : nil;
217219
}
220+
[self setNeedsDisplay:YES];
218221
}
219222

220223
- (NSColor *)defaultBackgroundColor
@@ -444,11 +447,18 @@ - (BOOL)_wantsKeyDownForEvent:(id)event
444447
}
445448

446449
- (void)setFrameSize:(NSSize)newSize {
447-
if (!drawPending && !NSEqualSizes(newSize, self.frame.size) && drawData.count == 0) {
450+
if (NSEqualSizes(newSize, self.bounds.size))
451+
return;
452+
if (!drawPending) {
448453
[NSAnimationContext beginGrouping];
449454
drawPending = YES;
450455
}
451456
[super setFrameSize:newSize];
457+
[self updateCGContext];
458+
}
459+
460+
- (void)viewDidChangeBackingProperties {
461+
[self updateCGContext];
452462
}
453463

454464
- (void)keyDown:(NSEvent *)event
@@ -606,6 +616,26 @@ - (BOOL)isFlipped
606616
return NO;
607617
}
608618

619+
- (void)updateCGContext {
620+
if (cgContext || [[NSUserDefaults standardUserDefaults]
621+
boolForKey:MMBufferedDrawingKey]) {
622+
CGContextRelease(cgContext);
623+
NSRect backingRect = [self convertRectToBacking:self.bounds];
624+
cgContext = CGBitmapContextCreate(NULL, NSWidth(backingRect), NSHeight(backingRect), 8, 0, self.window.colorSpace.CGColorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
625+
CGContextScaleCTM(cgContext, self.window.backingScaleFactor, self.window.backingScaleFactor);
626+
}
627+
}
628+
629+
- (BOOL)wantsUpdateLayer {
630+
return cgContext != nil;
631+
}
632+
633+
- (void)updateLayer {
634+
CGImageRef contentsImage = CGBitmapContextCreateImage(cgContext);
635+
self.layer.contents = (id)contentsImage;
636+
CGImageRelease(contentsImage);
637+
}
638+
609639
- (void)drawRect:(NSRect)rect
610640
{
611641
NSGraphicsContext *context = [NSGraphicsContext currentContext];
@@ -653,7 +683,12 @@ - (void)drawRect:(NSRect)rect
653683

654684
- (void)performBatchDrawWithData:(NSData *)data
655685
{
656-
if (cgLayerEnabled && drawData.count == 0 && [self getCGContext]) {
686+
if (cgContext) {
687+
[NSGraphicsContext saveGraphicsState];
688+
NSGraphicsContext.currentContext = [NSGraphicsContext graphicsContextWithCGContext:cgContext flipped:self.flipped];
689+
[self batchDrawData:data];
690+
[NSGraphicsContext restoreGraphicsState];
691+
} else if (cgLayerEnabled && drawData.count == 0 && [self getCGContext]) {
657692
[cgLayerLock lock];
658693
[self batchDrawData:data];
659694
[cgLayerLock unlock];
@@ -669,6 +704,9 @@ - (void)performBatchDrawWithData:(NSData *)data
669704

670705
- (void)setCGLayerEnabled:(BOOL)enabled
671706
{
707+
if (cgContext)
708+
return;
709+
672710
cgLayerEnabled = enabled;
673711

674712
if (!cgLayerEnabled)
@@ -710,13 +748,13 @@ - (CGContextRef)getCGContext
710748

711749
- (void)setNeedsDisplayCGLayerInRect:(CGRect)rect
712750
{
713-
if (cgLayerEnabled)
751+
if (cgLayerEnabled || cgContext)
714752
[self setNeedsDisplayInRect:rect];
715753
}
716754

717755
- (void)setNeedsDisplayCGLayer:(BOOL)flag
718756
{
719-
if (cgLayerEnabled)
757+
if (cgLayerEnabled || cgContext)
720758
[self setNeedsDisplay:flag];
721759
}
722760

@@ -1491,7 +1529,18 @@ - (void)drawString:(const UniChar *)chars length:(UniCharCount)length
14911529

14921530
- (void)scrollRect:(NSRect)rect lineCount:(int)count
14931531
{
1494-
if (cgLayerEnabled) {
1532+
if (cgContext) {
1533+
NSRect fromRect = NSOffsetRect(self.bounds, 0, -count * cellSize.height);
1534+
NSRect toRect = NSOffsetRect(rect, 0, -count * cellSize.height);
1535+
CGContextSaveGState(cgContext);
1536+
CGContextClipToRect(cgContext, toRect);
1537+
CGContextSetBlendMode(cgContext, kCGBlendModeCopy);
1538+
CGImageRef contentsImage = CGBitmapContextCreateImage(cgContext);
1539+
CGContextDrawImage(cgContext, fromRect, contentsImage);
1540+
CGImageRelease(contentsImage);
1541+
CGContextRestoreGState(cgContext);
1542+
[self setNeedsDisplayCGLayerInRect:toRect];
1543+
} else if (cgLayerEnabled) {
14951544
CGContextRef context = [self getCGContext];
14961545
int yOffset = count * cellSize.height;
14971546
NSRect clipRect = rect;

src/MacVim/MMVimView.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ - (void)dealloc
189189

190190
- (BOOL)isOpaque
191191
{
192-
return YES;
192+
return textView.defaultBackgroundColor.alphaComponent == 1;
193193
}
194194

195195
- (void)drawRect:(NSRect)rect
@@ -511,6 +511,7 @@ - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore
511511
MMScroller *sb = [scrollbars objectAtIndex:i];
512512
[sb setNeedsDisplay:YES];
513513
}
514+
[self setNeedsDisplay:YES];
514515
}
515516

516517

src/MacVim/MMWindowController.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore
543543
[decoratedWindow setOpaque:isOpaque];
544544
if (fullScreenWindow)
545545
[fullScreenWindow setOpaque:isOpaque];
546+
[decoratedWindow setBackgroundColor:back];
546547

547548
[vimView setDefaultColorsBackground:back foreground:fore];
548549
}

src/MacVim/Miscellaneous.h

Lines changed: 2 additions & 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 *MMBufferedDrawingKey;
5657

5758

5859
// Enum for MMUntitledWindowKey
@@ -156,3 +157,4 @@ NSArray *normalizeFilenames(NSArray *filenames);
156157

157158
BOOL shouldUseYosemiteTabBarStyle();
158159
BOOL shouldUseMojaveTabBarStyle();
160+
BOOL shouldUseBufferedDrawing();

src/MacVim/Miscellaneous.m

Lines changed: 12 additions & 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 *MMBufferedDrawingKey = @"MMBufferedDrawing";
5253

5354

5455

@@ -316,3 +317,14 @@ - (NSInteger)tag
316317
#endif
317318
return false;
318319
}
320+
321+
BOOL
322+
shouldUseBufferedDrawing()
323+
{
324+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
325+
if (@available(macos 10.14, *)) {
326+
return YES;
327+
}
328+
#endif
329+
return NO;
330+
}

0 commit comments

Comments
 (0)