mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-07 15:37:14 +02:00
Make the Core Text renderer faster
This change reworks `MMCoreTextView` to keep track of the state of the
screen instead of drawing to the screen or to an image. This lets
`drawRect:` draw any part of the view at any time, as needed.
This change came about when the old strategy stopped working: The old
strategy calls `drawRect:` for the entire view to handle any draw
command from the backend, but drew only the changes on top of the old
content of the view. This did not work in new versions of macOS that use
layers, because `drawRect:` is now expected to fill the entire rect with
new content. If it doesn't, the rest of the view will just contain
garbage. bbad3edf5a worked around this
issue by adding an intermediate CGImage which was preserved between
draws. This fixed the problem but made rendering slower.
With the change, the intermediate image is no longer needed and
rendering is much faster overall, which resolves #796.
As part of this change, font substitution is now handled by Core Text,
which changes which fallback fonts are used in some cases but matches
other macOS apps.
This commit is contained in:
@@ -248,8 +248,6 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
[NSNumber numberWithBool:NO], MMSuppressTerminationAlertKey,
|
||||
[NSNumber numberWithBool:YES], MMNativeFullScreenKey,
|
||||
[NSNumber numberWithDouble:0.25], MMFullScreenFadeTimeKey,
|
||||
[NSNumber numberWithBool:NO], MMUseCGLayerAlwaysKey,
|
||||
@(shouldUseBufferedDrawing()), MMBufferedDrawingKey,
|
||||
[NSNumber numberWithBool:YES], MMShareFindPboardKey,
|
||||
nil];
|
||||
|
||||
|
||||
@@ -31,42 +31,13 @@
|
||||
BOOL antialias;
|
||||
BOOL ligatures;
|
||||
BOOL thinStrokes;
|
||||
BOOL drawPending;
|
||||
NSMutableArray *drawData;
|
||||
|
||||
MMTextViewHelper *helper;
|
||||
|
||||
unsigned maxlen;
|
||||
CGGlyph *glyphs;
|
||||
CGPoint *positions;
|
||||
NSMutableArray *fontCache;
|
||||
|
||||
// Issue draws onto an CGImage that caches the drawn results instead of
|
||||
// directly in drawRect:. This is the default behavior in cases where simply
|
||||
// drawing incrementally in drawRect: doesn't work. Those cases are:
|
||||
// 1. Non-native fullscreen
|
||||
// 2. 10.14+ (views are always layer-backed which means the view buffer will
|
||||
// be cleared and we can't incrementally draw in drawRect:)
|
||||
//
|
||||
// This can be configured by setting MMBufferedDrawingKey in user defaults.
|
||||
BOOL cgBufferDrawEnabled;
|
||||
BOOL cgBufferDrawNeedsUpdateContext;
|
||||
CGContextRef cgContext;
|
||||
NSMutableDictionary<NSNumber *, NSFont *> *fontVariants;
|
||||
NSMutableSet<NSString *> *characterStrings;
|
||||
NSMutableDictionary<NSNumber *,NSCache<NSString *,id> *> *characterLines;
|
||||
|
||||
// *Deprecated*
|
||||
// Draw onto a CGLayer instead of lazily updating the view's buffer in
|
||||
// drawRect: which is error-prone and relying on undocumented behaviors
|
||||
// (that the OS will preserve the old buffer).
|
||||
//
|
||||
// This is deprecated. Use cgBufferDrawEnabled instead which is more
|
||||
// efficient.
|
||||
//
|
||||
// This can be configured by setting MMUseCGLayerAlwaysKey in user defaults.
|
||||
BOOL cgLayerEnabled;
|
||||
CGLayerRef cgLayer;
|
||||
CGContextRef cgLayerContext;
|
||||
NSLock *cgLayerLock;
|
||||
|
||||
// These are used in MMCoreTextView+ToolTip.m
|
||||
id trackingRectOwner_; // (not retained)
|
||||
void *trackingRectUserData_;
|
||||
@@ -113,13 +84,10 @@
|
||||
- (BOOL)convertPoint:(NSPoint)point toRow:(int *)row column:(int *)column;
|
||||
- (NSRect)rectForRow:(int)row column:(int)column numRows:(int)nr
|
||||
numColumns:(int)nc;
|
||||
- (void)setCGLayerEnabled:(BOOL)enabled;
|
||||
- (BOOL)getCGLayerEnabled;
|
||||
|
||||
//
|
||||
// NSTextView methods
|
||||
//
|
||||
- (void)setFrameSize:(NSSize)newSize;
|
||||
- (void)keyDown:(NSEvent *)event;
|
||||
- (void)insertText:(id)string;
|
||||
- (void)doCommandBySelector:(SEL)selector;
|
||||
|
||||
+399
-1099
File diff suppressed because it is too large
Load Diff
@@ -34,9 +34,6 @@
|
||||
// Controls the speed of the fade in and out.
|
||||
double fadeTime;
|
||||
double fadeReservationTime;
|
||||
|
||||
// For pre-10.14 we manually sets CGLayer mode, so need to remember the original state
|
||||
BOOL origCGLayerEnabled;
|
||||
}
|
||||
|
||||
- (MMFullScreenWindow *)initWithWindow:(NSWindow *)t view:(MMVimView *)v
|
||||
|
||||
@@ -113,8 +113,6 @@ enum {
|
||||
fadeTime = MIN(fadeTime, 0.5 * (kCGMaxDisplayReservationInterval - 1));
|
||||
fadeReservationTime = 2.0 * fadeTime + 1;
|
||||
|
||||
origCGLayerEnabled = NO;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -174,11 +172,6 @@ enum {
|
||||
oldPosition = [view frame].origin;
|
||||
|
||||
[view removeFromSuperviewWithoutNeedingDisplay];
|
||||
if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_12) {
|
||||
// This shouldn't do much in 10.14+.
|
||||
origCGLayerEnabled = [[view textView] getCGLayerEnabled];
|
||||
[[view textView] setCGLayerEnabled:YES];
|
||||
}
|
||||
[[self contentView] addSubview:view];
|
||||
[self setInitialFirstResponder:[view textView]];
|
||||
|
||||
@@ -295,9 +288,6 @@ enum {
|
||||
[view setFrameOrigin:oldPosition];
|
||||
[self close];
|
||||
|
||||
if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_12)
|
||||
[[view textView] setCGLayerEnabled:origCGLayerEnabled];
|
||||
|
||||
// Set the text view to initial first responder, otherwise the 'plus'
|
||||
// button on the tabline steals the first responder status.
|
||||
[target setInitialFirstResponder:[view textView]];
|
||||
|
||||
@@ -73,6 +73,4 @@
|
||||
// NOT IMPLEMENTED (only in Core Text renderer)
|
||||
- (void)deleteSign:(NSString *)signName;
|
||||
- (void)setToolTipAtMousePoint:(NSString *)string;
|
||||
- (void)setCGLayerEnabled:(BOOL)enabled;
|
||||
- (BOOL)getCGLayerEnabled;
|
||||
@end
|
||||
|
||||
@@ -522,16 +522,6 @@
|
||||
// ONLY in Core Text!
|
||||
}
|
||||
|
||||
- (void)setCGLayerEnabled:(BOOL)enabled
|
||||
{
|
||||
// ONLY in Core Text!
|
||||
}
|
||||
|
||||
- (BOOL)getCGLayerEnabled
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isOpaque
|
||||
{
|
||||
return NO;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define GREEN(argb) (((argb>>8) & 0xff)/255.0f)
|
||||
#define RED(argb) (((argb>>16) & 0xff)/255.0f)
|
||||
#define ALPHA(argb) (((argb>>24) & 0xff)/255.0f)
|
||||
#define COMPONENTS(argb) ((CGFloat[]){RED(argb), GREEN(argb), BLUE(argb), ALPHA(argb)})
|
||||
|
||||
|
||||
@interface MMTextViewHelper : NSObject {
|
||||
|
||||
@@ -170,6 +170,7 @@
|
||||
// on whether the tabline separator is visible or not.
|
||||
NSView *contentView = [win contentView];
|
||||
[contentView setAutoresizesSubviews:YES];
|
||||
contentView.wantsLayer = YES;
|
||||
|
||||
vimView = [[MMVimView alloc] initWithFrame:[contentView frame]
|
||||
vimController:vimController];
|
||||
@@ -205,15 +206,6 @@
|
||||
if ([win respondsToSelector:@selector(_setContentHasShadow:)])
|
||||
[win _setContentHasShadow:NO];
|
||||
|
||||
if (!(styleMask & NSWindowStyleMaskTitled)) {
|
||||
// In the no titlebar mode (aka borderless), we need to set CGLayer
|
||||
// mode since otherwise the legacy renderer would not render properly.
|
||||
// For more reference see MMFullscreenWindow's enterFullscreen:
|
||||
// This shouldn't do much in 10.14+.
|
||||
if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_12)
|
||||
[[vimView textView] setCGLayerEnabled:YES];
|
||||
}
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
|
||||
// Building on Mac OS X 10.7 or greater.
|
||||
|
||||
@@ -652,7 +644,7 @@
|
||||
if (fullScreenWindow)
|
||||
[fullScreenWindow setOpaque:isOpaque];
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
|
||||
if (@available(macos 10.14, *)) {
|
||||
// We usually don't really need to change the background color of the
|
||||
// window, but in 10.14+ we switched to using layer-backed drawing.
|
||||
@@ -792,6 +784,20 @@
|
||||
// Do it last so whatever resizing we have done above will take effect
|
||||
// immediate too instead of waiting till next frame.
|
||||
[vimView finishPlaceScrollbars];
|
||||
|
||||
// Work around a bug which affects macOS 10.14 and older.
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
|
||||
if (@available(macos 10.15, *)) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// Ensure that the app waits until the next frame to commit the current
|
||||
// CATransaction. Without this, layer-backed views display as soon as
|
||||
// the thread returns to the event loop, potentially drawing *many*
|
||||
// times for a single screen update. The app correctly waits to draw
|
||||
// when a window needs display, so mark the window as needing display.
|
||||
self.window.viewsNeedDisplay = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showTabBar:(BOOL)on
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
# define NSAlertStyleInformational NSInformationalAlertStyle
|
||||
# define NSAlertStyleWarning NSWarningAlertStyle
|
||||
# define NSCompositingOperationSourceOver NSCompositeSourceOver
|
||||
# define NSCompositingOperationDifference NSCompositeDifference
|
||||
# define NSControlSizeRegular NSRegularControlSize
|
||||
# define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
|
||||
# define NSEventModifierFlagCommand NSCommandKeyMask
|
||||
@@ -367,6 +368,7 @@ extern NSString *VimFindPboardType;
|
||||
|
||||
|
||||
@interface NSColor (MMExtras)
|
||||
@property(readonly) unsigned argbInt;
|
||||
+ (NSColor *)colorWithRgbInt:(unsigned)rgb;
|
||||
+ (NSColor *)colorWithArgbInt:(unsigned)argb;
|
||||
@end
|
||||
|
||||
@@ -157,6 +157,14 @@ debugStringForMessageQueue(NSArray *queue)
|
||||
|
||||
@implementation NSColor (MMExtras)
|
||||
|
||||
- (unsigned)argbInt {
|
||||
CGFloat rf, gf, bf, af;
|
||||
[[self colorUsingColorSpace:NSColorSpace.deviceRGBColorSpace]
|
||||
getRed:&rf green:&gf blue:&bf alpha:&af];
|
||||
unsigned r = rf * 255, g = gf * 255, b = bf * 255, a = af*255;
|
||||
return a<<24 | r<<16 | g<<8 | b;
|
||||
}
|
||||
|
||||
+ (NSColor *)colorWithRgbInt:(unsigned)rgb
|
||||
{
|
||||
float r = ((rgb>>16) & 0xff)/255.0f;
|
||||
|
||||
@@ -55,8 +55,6 @@ extern NSString *MMSuppressTerminationAlertKey;
|
||||
extern NSString *MMNativeFullScreenKey;
|
||||
extern NSString *MMUseMouseTimeKey;
|
||||
extern NSString *MMFullScreenFadeTimeKey;
|
||||
extern NSString *MMUseCGLayerAlwaysKey;
|
||||
extern NSString *MMBufferedDrawingKey;
|
||||
|
||||
|
||||
// Enum for MMUntitledWindowKey
|
||||
@@ -168,6 +166,5 @@ NSArray *normalizeFilenames(NSArray *filenames);
|
||||
|
||||
BOOL shouldUseYosemiteTabBarStyle();
|
||||
BOOL shouldUseMojaveTabBarStyle();
|
||||
BOOL shouldUseBufferedDrawing();
|
||||
|
||||
int getCurrentAppearance(NSAppearance *appearance);
|
||||
|
||||
@@ -51,8 +51,6 @@ NSString *MMSuppressTerminationAlertKey = @"MMSuppressTerminationAlert";
|
||||
NSString *MMNativeFullScreenKey = @"MMNativeFullScreen";
|
||||
NSString *MMUseMouseTimeKey = @"MMUseMouseTime";
|
||||
NSString *MMFullScreenFadeTimeKey = @"MMFullScreenFadeTime";
|
||||
NSString *MMUseCGLayerAlwaysKey = @"MMUseCGLayerAlways";
|
||||
NSString *MMBufferedDrawingKey = @"MMBufferedDrawing";
|
||||
|
||||
|
||||
|
||||
@@ -326,18 +324,6 @@ shouldUseMojaveTabBarStyle()
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL
|
||||
shouldUseBufferedDrawing()
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||
if (@available(macos 10.14, *)) {
|
||||
return YES;
|
||||
}
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
getCurrentAppearance(NSAppearance *appearance){
|
||||
int flag = 0; // for macOS 10.13 or eariler always return 0;
|
||||
|
||||
-29
@@ -19,9 +19,6 @@
|
||||
|
||||
#include "vim.h"
|
||||
|
||||
#ifdef FEAT_GUI_MACVIM
|
||||
static void redraw_for_ligatures(win_T *wp);
|
||||
#endif
|
||||
static int scrolljump_value(void);
|
||||
static int check_top_offset(void);
|
||||
static void curs_rows(win_T *wp);
|
||||
@@ -162,29 +159,6 @@ redraw_for_cursorline(win_T *wp)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FEAT_GUI_MACVIM
|
||||
/*
|
||||
* Redraw when 'macligatures' is set.
|
||||
* This is basically the same as when 'cursorline'
|
||||
* or 'relativenumber' is set but unconditional.
|
||||
*/
|
||||
static void
|
||||
redraw_for_ligatures(wp)
|
||||
win_T *wp;
|
||||
{
|
||||
/* Only if ligatures are on but neither
|
||||
* 'cursorline' nor 'relativenumber'.
|
||||
*/
|
||||
if (p_macligatures
|
||||
&& (wp->w_p_rnu == 0
|
||||
#ifdef FEAT_SYN_HL
|
||||
&& wp->w_p_cul == 0
|
||||
#endif
|
||||
))
|
||||
redraw_win_later(wp, CLEAR);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update curwin->w_topline and redraw if necessary.
|
||||
* Used to update the screen before printing a message.
|
||||
@@ -809,9 +783,6 @@ curs_rows(win_T *wp)
|
||||
}
|
||||
|
||||
redraw_for_cursorline(curwin);
|
||||
#ifdef FEAT_GUI_MACVIM
|
||||
redraw_for_ligatures(curwin);
|
||||
#endif
|
||||
wp->w_valid |= VALID_CROW|VALID_CHEIGHT;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user