Skip to content
Snippets Groups Projects
Commit 71addb76 authored by George Nachman's avatar George Nachman
Browse files

A bunch more optimizations. Prepare is almost as fast as finalize now.

parent bb0de1fc
No related branches found
No related tags found
No related merge requests found
Showing with 478 additions and 182 deletions
Loading
Loading
@@ -2459,6 +2459,8 @@
A6EFF2401D21949D00806EEF /* iTermShortcut.m in Sources */ = {isa = PBXBuildFile; fileRef = A6EFF23E1D21949D00806EEF /* iTermShortcut.m */; };
A6EFF2471D21DD0700806EEF /* iTermSessionHotkeyController.h in Headers */ = {isa = PBXBuildFile; fileRef = A6EFF2451D21DD0700806EEF /* iTermSessionHotkeyController.h */; };
A6EFF2481D21DD0700806EEF /* iTermSessionHotkeyController.m in Sources */ = {isa = PBXBuildFile; fileRef = A6EFF2461D21DD0700806EEF /* iTermSessionHotkeyController.m */; };
A6F385DE1FA55E2000739939 /* iTermSmartCursorColor.h in Headers */ = {isa = PBXBuildFile; fileRef = A6F385DC1FA55E2000739939 /* iTermSmartCursorColor.h */; };
A6F385DF1FA55E2000739939 /* iTermSmartCursorColor.m in Sources */ = {isa = PBXBuildFile; fileRef = A6F385DD1FA55E2000739939 /* iTermSmartCursorColor.m */; };
A6F3E96E1D60E4F0000E97C4 /* iTermInitialDirectory.h in Headers */ = {isa = PBXBuildFile; fileRef = A6F3E96C1D60E4F0000E97C4 /* iTermInitialDirectory.h */; };
A6F3E96F1D60E4F0000E97C4 /* iTermInitialDirectory.m in Sources */ = {isa = PBXBuildFile; fileRef = A6F3E96D1D60E4F0000E97C4 /* iTermInitialDirectory.m */; };
A6F981CC1C13783C00EE0B80 /* iTermCPS.h in Headers */ = {isa = PBXBuildFile; fileRef = A6F981CB1C13783C00EE0B80 /* iTermCPS.h */; };
Loading
Loading
@@ -4042,6 +4044,8 @@
A6EFF23E1D21949D00806EEF /* iTermShortcut.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTermShortcut.m; sourceTree = "<group>"; };
A6EFF2451D21DD0700806EEF /* iTermSessionHotkeyController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTermSessionHotkeyController.h; sourceTree = "<group>"; };
A6EFF2461D21DD0700806EEF /* iTermSessionHotkeyController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTermSessionHotkeyController.m; sourceTree = "<group>"; };
A6F385DC1FA55E2000739939 /* iTermSmartCursorColor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = iTermSmartCursorColor.h; sourceTree = "<group>"; };
A6F385DD1FA55E2000739939 /* iTermSmartCursorColor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iTermSmartCursorColor.m; sourceTree = "<group>"; };
A6F3E96C1D60E4F0000E97C4 /* iTermInitialDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTermInitialDirectory.h; sourceTree = "<group>"; };
A6F3E96D1D60E4F0000E97C4 /* iTermInitialDirectory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTermInitialDirectory.m; sourceTree = "<group>"; };
A6F981CB1C13783C00EE0B80 /* iTermCPS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTermCPS.h; sourceTree = "<group>"; };
Loading
Loading
@@ -5375,6 +5379,8 @@
A685D9F81E5B6E100091C3A7 /* PseudoTerminal+TouchBar.h */,
A685D9F91E5B6E100091C3A7 /* PseudoTerminal+TouchBar.m */,
A685D9FC1E5B6EFC0091C3A7 /* PseudoTerminal+Private.h */,
A6F385DC1FA55E2000739939 /* iTermSmartCursorColor.h */,
A6F385DD1FA55E2000739939 /* iTermSmartCursorColor.m */,
);
name = Core;
sourceTree = "<group>";
Loading
Loading
@@ -7070,6 +7076,7 @@
A66719191DCE36C3000CE608 /* iTermShortcut.h in Headers */,
A667191A1DCE36C3000CE608 /* iTermWebSocketFrameBuilder.h in Headers */,
A667191B1DCE36C3000CE608 /* iTermDynamicProfileManager.h in Headers */,
A6F385DE1FA55E2000739939 /* iTermSmartCursorColor.h in Headers */,
A667191C1DCE36C3000CE608 /* iTermAppHotKey.h in Headers */,
A667191D1DCE36C3000CE608 /* iTermHotKeyMigrationHelper.h in Headers */,
A667191E1DCE36C3000CE608 /* iTermCPS.h in Headers */,
Loading
Loading
@@ -8673,6 +8680,7 @@
A66719621DCE3772000CE608 /* iTermSocketAddress.m in Sources */,
53AFFC8E1DD2A04100E6CEC6 /* iTermLSOF.m in Sources */,
A66719671DCE3772000CE608 /* iTermWebSocketFrameBuilder.m in Sources */,
A6F385DF1FA55E2000739939 /* iTermSmartCursorColor.m in Sources */,
A66719651DCE3772000CE608 /* iTermHTTPConnection.m in Sources */,
A67960CE1F81FCB6008A42BC /* iTermTextureArray.m in Sources */,
A67960D31F81FCBB008A42BC /* iTermBroadcastStripesRenderer.m in Sources */,
Loading
Loading
@@ -40,7 +40,11 @@
}
 
- (id<MTLRenderPipelineState>)newPipelineState {
id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];
static id<MTLLibrary> defaultLibrary;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defaultLibrary = [_device newDefaultLibrary];
});
id <MTLFunction> textVertexShader = [defaultLibrary newFunctionWithName:_vertexFunctionName];
id <MTLFunction> textFragmentShader = [defaultLibrary newFunctionWithName:_fragmentFunctionName];
return [self newPipelineWithBlending:_blending
Loading
Loading
Loading
Loading
@@ -10,8 +10,14 @@
 
@interface iTermMetalRowData : NSObject
@property (nonatomic) int y;
// iTermMetalGlyphKey
@property (nonatomic, strong) NSMutableData *keysData;
// iTermMetalGlyphAttributes
@property (nonatomic, strong) NSMutableData *attributesData;
// vector_float4
@property (nonatomic, strong) NSMutableData *backgroundColorData;
@end
 
Loading
Loading
@@ -2,25 +2,22 @@
 
@implementation iTermBackgroundColorRendererTransientState
 
- (nonnull NSMutableData *)newPerInstanceUniformData {
NSMutableData *data = [[NSMutableData alloc] initWithLength:sizeof(iTermBackgroundColorPIU) * self.gridSize.width * self.gridSize.height];
[self initializePIUData:data];
return data;
- (NSUInteger)sizeOfNewPIUBuffer {
return sizeof(iTermBackgroundColorPIU) * self.gridSize.width * self.gridSize.height;
}
 
- (void)initializePIUData:(NSMutableData *)data {
void *bytes = data.mutableBytes;
- (void)initializePIUBytes:(void *)bytes {
NSInteger i = 0;
vector_float2 cellSize = simd_make_float2(self.cellSize.width, self.cellSize.height);
vector_float4 defaultColor = simd_make_float4(1, 0, 0, 1);
iTermBackgroundColorPIU *pius = (iTermBackgroundColorPIU *)bytes;
for (NSInteger y = 0; y < self.gridSize.height; y++) {
const float rowOffset = (self.gridSize.height - y - 1);
vector_float2 gridCoord = simd_make_float2(0, rowOffset);
for (NSInteger x = 0; x < self.gridSize.width; x++) {
const iTermBackgroundColorPIU uniform = {
.offset = {
x * self.cellSize.width,
(self.gridSize.height - y - 1) * self.cellSize.height
},
.color = (vector_float4){ 1, 0, 0, 1 }
};
memcpy(bytes + i * sizeof(uniform), &uniform, sizeof(uniform));
gridCoord.x = x;
pius[i].offset = gridCoord * cellSize;
pius[i].color = defaultColor;
i++;
}
}
Loading
Loading
@@ -73,10 +70,9 @@
- (void)initializeTransientState:(iTermBackgroundColorRendererTransientState *)tState {
tState.vertexBuffer = [_cellRenderer newQuadOfSize:tState.cellSize];
 
NSMutableData *data = [tState newPerInstanceUniformData];
tState.pius = [_cellRenderer.device newBufferWithLength:data.length
tState.pius = [_cellRenderer.device newBufferWithLength:tState.sizeOfNewPIUBuffer
options:MTLResourceStorageModeShared];
memcpy(tState.pius.contents, data.bytes, data.length);
[tState initializePIUBytes:tState.pius.contents];
}
 
 
Loading
Loading
Loading
Loading
@@ -12,6 +12,15 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) VT100GridCoord coord;
@property (nonatomic) ITermCursorType type;
@property (nonatomic, strong) NSColor *cursorColor;
// Block cursors care about drawing the character overtop the cursor in a
// different color than the character would normally be. If this is set, the
// text color will be changed to that of the `textColor` property.
@property (nonatomic) BOOL shouldDrawText;
@property (nonatomic) vector_float4 textColor;
// This is a "frame" cursor, as seen when the view does not have focus.
@property (nonatomic) BOOL frameOnly;
@end
 
@protocol iTermMetalDriverDataSourcePerFrameState<NSObject>
Loading
Loading
Loading
Loading
@@ -253,6 +253,18 @@ static const NSInteger iTermMetalDriverMaximumNumberOfFramesInFlight = 3;
frameData.transientStates[NSStringFromClass([_backgroundColorRenderer class])];
CGSize cellSize = textState.cellSize;
CGFloat scale = frameData.scale;
iTermMetalCursorInfo *cursorInfo = [frameData.perFrameState metalDriverCursorInfo];
if (cursorInfo.cursorVisible && cursorInfo.shouldDrawText) {
NSLog(@"Cursor on line %d of display", cursorInfo.coord.y);
iTermMetalRowData *rowWithCursor = frameData.rows[cursorInfo.coord.y];
iTermMetalGlyphAttributes *glyphAttributes = (iTermMetalGlyphAttributes *)rowWithCursor.attributesData.mutableBytes;
glyphAttributes[cursorInfo.coord.x].foregroundColor = cursorInfo.textColor;
glyphAttributes[cursorInfo.coord.x].backgroundColor = simd_make_float4(cursorInfo.cursorColor.redComponent,
cursorInfo.cursorColor.greenComponent,
cursorInfo.cursorColor.blueComponent,
1);
}
[frameData.rows enumerateObjectsUsingBlock:^(iTermMetalRowData * _Nonnull rowData, NSUInteger idx, BOOL * _Nonnull stop) {
iTermMetalGlyphKey *glyphKeys = (iTermMetalGlyphKey *)rowData.keysData.mutableBytes;
[textState setGlyphKeysData:rowData.keysData
Loading
Loading
@@ -272,6 +284,15 @@ static const NSInteger iTermMetalDriverMaximumNumberOfFramesInFlight = 3;
[textState willDraw];
}
 
- (void)drawCellRenderer:(id<iTermMetalCellRenderer>)renderer
frameData:(iTermMetalFrameData *)frameData
renderEncoder:(id<MTLRenderCommandEncoder>)renderEncoder {
NSString *className = NSStringFromClass([renderer class]);
iTermMetalCellRendererTransientState *state = frameData.transientStates[className];
assert(state);
[renderer drawWithRenderEncoder:renderEncoder transientState:state];
}
- (void)reallyDrawInView:(MTKView *)view
frameData:(iTermMetalFrameData *)frameData
commandBuffer:(id<MTLCommandBuffer>)commandBuffer {
Loading
Loading
@@ -279,7 +300,7 @@ static const NSInteger iTermMetalDriverMaximumNumberOfFramesInFlight = 3;
 
MTLRenderPassDescriptor *renderPassDescriptor = frameData.renderPassDescriptor;
if (renderPassDescriptor != nil) {
id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
renderEncoder.label = @"Render Terminal";
frameData.drawable.texture.label = @"Drawable";
 
Loading
Loading
@@ -295,32 +316,42 @@ static const NSInteger iTermMetalDriverMaximumNumberOfFramesInFlight = 3;
[renderEncoder setViewport:viewport];
 
// [_backgroundImageRenderer drawWithRenderEncoder:renderEncoder];
// [_backgroundColorRenderer drawWithRenderEncoder:renderEncoder];
[self drawCellRenderer:_backgroundColorRenderer
frameData:frameData
renderEncoder:renderEncoder];
// [_broadcastStripesRenderer drawWithRenderEncoder:renderEncoder];
// [_badgeRenderer drawWithRenderEncoder:renderEncoder];
// [_cursorGuideRenderer drawWithRenderEncoder:renderEncoder];
//
// if (context.cursorInfo.cursorVisible) {
// switch (context.cursorInfo.type) {
// case CURSOR_UNDERLINE:
// [_underlineCursorRenderer drawWithRenderEncoder:renderEncoder];
// break;
// case CURSOR_BOX:
// [_blockCursorRenderer drawWithRenderEncoder:renderEncoder];
// break;
// case CURSOR_VERTICAL:
// [_barCursorRenderer drawWithRenderEncoder:renderEncoder];
// break;
// case CURSOR_DEFAULT:
// break;
// }
// }
iTermMetalCursorInfo *cursorInfo = [frameData.perFrameState metalDriverCursorInfo];
if (cursorInfo.cursorVisible) {
switch (cursorInfo.type) {
case CURSOR_UNDERLINE:
[self drawCellRenderer:_underlineCursorRenderer
frameData:frameData
renderEncoder:renderEncoder];
break;
case CURSOR_BOX:
[self drawCellRenderer:_blockCursorRenderer
frameData:frameData
renderEncoder:renderEncoder];
break;
case CURSOR_VERTICAL:
[self drawCellRenderer:_barCursorRenderer
frameData:frameData
renderEncoder:renderEncoder];
break;
case CURSOR_DEFAULT:
break;
}
}
// [_copyModeCursorRenderer drawWithRenderEncoder:renderEncoder];
 
iTermTextRendererTransientState *textState = frameData.transientStates[NSStringFromClass([_textRenderer class])];
assert(textState);
[_textRenderer drawWithRenderEncoder:renderEncoder
transientState:textState];
[self drawCellRenderer:_textRenderer
frameData:frameData
renderEncoder:renderEncoder];
 
// [_markRenderer drawWithRenderEncoder:renderEncoder];
 
Loading
Loading
Loading
Loading
@@ -333,6 +333,10 @@ typedef void (^PTYTextViewDrawingHookBlock)(iTermTextDrawingHelper *);
 
@property (nonatomic, readonly) double transparencyAlpha;
 
// Number of times -stealKeyFocus has been called since the last time it
// was released with releaseKeyFocus.
@property (nonatomic, readonly) int keyFocusStolenCount;
// Returns the size of a cell for a given font. hspace and vspace are multipliers and the width
// and height.
+ (NSSize)charSizeForFont:(NSFont*)aFont
Loading
Loading
Loading
Loading
@@ -239,10 +239,6 @@ static const int kDragThreshold = 3;
 
NSPoint _mouseLocationToRefuseFirstResponderAt;
 
// Number of times -setalKeyFocus has been called since the last time it
// was released with releaseKeyFocus.
int _keyFocusStolenCount;
iTermNSKeyBindingEmulator *_keyBindingEmulator;
// Detects when the user is trying to scroll in alt screen with the scroll wheel.
Loading
Loading
Loading
Loading
@@ -94,6 +94,7 @@ extern const int kColorMap24bitBase;
- (NSColor *)processedBackgroundColorForBackgroundColor:(NSColor *)color;
- (vector_float4)fastProcessedBackgroundColorForBackgroundColor:(vector_float4)backgroundColor;
- (NSColor *)colorByMutingColor:(NSColor *)color;
- (vector_float4)fastColorByMutingColor:(vector_float4)color;
- (NSColor *)colorByDimmingTextColor:(NSColor *)color;
 
// Returns non-nil profile key name for valid logical colors, ANSI colors, and bright ANSI colors.
Loading
Loading
Loading
Loading
@@ -10,6 +10,7 @@
#import "ITAddressBookMgr.h"
#import "NSColor+iTerm.h"
#include <unordered_map>
#import <simd/simd.h>
 
const int kColorMapForeground = 0;
const int kColorMapBackground = 1;
Loading
Loading
@@ -244,6 +245,28 @@ const int kColorMapAnsiBrightModifier = 8;
CGFloat components[4];
[color getComponents:components];
 
vector_float4 colorVector = simd_make_float4(components[0],
components[1],
components[2],
components[3]);
vector_float4 v = [self commonColorByMutingColor:colorVector];
CGFloat mutedRgb[4] = { v.x, v.y, v.z, v.w };
return [NSColor colorWithColorSpace:color.colorSpace
components:mutedRgb
count:4];
}
- (vector_float4)fastColorByMutingColor:(vector_float4)color {
if (_mutingAmount < 0.01) {
return color;
}
return [self commonColorByMutingColor:color];
}
- (vector_float4)commonColorByMutingColor:(vector_float4)color {
CGFloat components[4] = { color.x, color.y, color.z, color.w };
CGFloat defaultBackgroundComponents[4];
[_map[@(kColorMapBackground)] getComponents:defaultBackgroundComponents];
 
Loading
Loading
@@ -254,9 +277,7 @@ const int kColorMapAnsiBrightModifier = 8;
alpha:_mutingAmount];
mutedRgb[3] = components[3];
 
return [NSColor colorWithColorSpace:color.colorSpace
components:mutedRgb
count:4];
return simd_make_float4(mutedRgb[0], mutedRgb[1], mutedRgb[2], components[3]);
}
 
// There is an issue where where the passed-in color can be in a different color space than the
Loading
Loading
#import <Cocoa/Cocoa.h>
#import "iTermSmartCursorColor.h"
#import "ScreenChar.h"
 
typedef NS_ENUM(NSInteger, ITermCursorType) {
Loading
Loading
@@ -9,14 +11,7 @@ typedef NS_ENUM(NSInteger, ITermCursorType) {
CURSOR_DEFAULT = -1 // Use the default cursor type for a profile. Internally used for DECSTR.
};
 
typedef struct {
screen_char_t chars[3][3];
BOOL valid[3][3];
} iTermCursorNeighbors;
@protocol iTermCursorDelegate <NSObject>
- (iTermCursorNeighbors)cursorNeighbors;
@protocol iTermCursorDelegate <iTermSmartCursorColorDelegate>
 
- (void)cursorDrawCharacterAt:(VT100GridCoord)coord
doubleWidth:(BOOL)doubleWidth
Loading
Loading
@@ -24,14 +19,6 @@ typedef struct {
context:(CGContextRef)ctx
backgroundColor:(NSColor *)backgroundColor;
 
- (NSColor *)cursorColorForCharacter:(screen_char_t)screenChar
wantBackground:(BOOL)wantBackgroundColor
muted:(BOOL)muted;
- (NSColor *)cursorWhiteColor;
- (NSColor *)cursorBlackColor;
- (NSColor *)cursorColorByDimmingSmartColor:(NSColor *)color;
@end
 
@interface iTermCursor : NSObject
Loading
Loading
Loading
Loading
@@ -10,6 +10,7 @@
#import "DebugLogging.h"
#import "NSColor+iTerm.h"
#import "iTermAdvancedSettingsModel.h"
#import "iTermSmartCursorColor.h"
 
@interface iTermUnderlineCursor : iTermCursor
@end
Loading
Loading
@@ -160,7 +161,14 @@
 
@end
 
@implementation iTermBoxCursor
@implementation iTermBoxCursor {
iTermSmartCursorColor *_smartCursorColor;
}
- (void)dealloc {
[_smartCursorColor release];
[super dealloc];
}
 
- (void)drawWithRect:(NSRect)rect
doubleWidth:(BOOL)doubleWidth
Loading
Loading
@@ -175,9 +183,11 @@
 
// Draw the colored box/frame
if (smart) {
iTermCursorNeighbors neighbors = [self.delegate cursorNeighbors];
backgroundColor = [[self smartCursorColorForChar:screenChar
neighbors:neighbors] colorWithAlphaComponent:1.0];
if (_smartCursorColor == nil) {
_smartCursorColor = [[iTermSmartCursorColor alloc] init];
}
_smartCursorColor.delegate = self.delegate;
backgroundColor = [_smartCursorColor backgroundColorForCharacter:screenChar];
}
[backgroundColor set];
const BOOL frameOnly = !focused;
Loading
Loading
@@ -213,13 +223,12 @@
backgroundColor:(NSColor *)backgroundColor
ctx:(CGContextRef)ctx
coord:(VT100GridCoord)coord {
NSColor *proposedForeground = [self.delegate cursorColorForCharacter:screenChar
wantBackground:YES
muted:NO];
proposedForeground = [proposedForeground colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
NSColor *overrideColor = [self overrideColorForSmartCursorWithForegroundColor:proposedForeground
backgroundColor:backgroundColor];
NSColor *regularTextColor = [self.delegate cursorColorForCharacter:screenChar
wantBackground:YES
muted:NO];
NSColor *overrideColor = [_smartCursorColor textColorForCharacter:screenChar
regularTextColor:regularTextColor
smartBackgroundColor:backgroundColor];
[self.delegate cursorDrawCharacterAt:coord
doubleWidth:doubleWidth
overrideColor:overrideColor
Loading
Loading
@@ -228,105 +237,4 @@
 
}
 
- (NSColor *)overrideColorForSmartCursorWithForegroundColor:(NSColor *)proposedForeground
backgroundColor:(NSColor *)backgroundColor {
CGFloat fgBrightness = [proposedForeground perceivedBrightness];
CGFloat bgBrightness = [backgroundColor perceivedBrightness];
const double threshold = [iTermAdvancedSettingsModel smartCursorColorFgThreshold];
if (fabs(fgBrightness - bgBrightness) < threshold) {
// Foreground and background are very similar. Just use black and
// white.
if (bgBrightness < 0.5) {
return [self.delegate cursorWhiteColor];
} else {
return [self.delegate cursorBlackColor];
}
} else {
return proposedForeground;
}
}
#pragma mark - Smart cursor color
- (NSColor *)smartCursorColorForChar:(screen_char_t)screenChar
neighbors:(iTermCursorNeighbors)neighbors {
NSColor *bgColor = [self.delegate cursorColorForCharacter:screenChar
wantBackground:NO
muted:NO];
NSMutableArray* constraints = [NSMutableArray arrayWithCapacity:2];
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
if (neighbors.valid[y][x]) {
[constraints addObject:@([self brightnessOfCharBackground:neighbors.chars[y][x]])];
}
}
}
CGFloat bgBrightness = [bgColor perceivedBrightness];
if ([self minimumDistanceOf:bgBrightness fromAnyValueIn:constraints] <
[iTermAdvancedSettingsModel smartCursorColorBgThreshold]) {
CGFloat b = [self farthestValueFromAnyValueIn:constraints];
bgColor = [NSColor colorWithCalibratedRed:b green:b blue:b alpha:1];
}
return [self.delegate cursorColorByDimmingSmartColor:bgColor];
}
// Return the value in 'values' closest to target.
- (CGFloat)minimumDistanceOf:(CGFloat)target fromAnyValueIn:(NSArray*)values {
CGFloat md = 1;
for (NSNumber* n in values) {
CGFloat dist = fabs(target - [n doubleValue]);
if (dist < md) {
md = dist;
}
}
return md;
}
// Return the value between 0 and 1 that is farthest from any value in 'constraints'.
- (CGFloat)farthestValueFromAnyValueIn:(NSArray*)constraints {
if ([constraints count] == 0) {
return 0;
}
NSArray* sortedConstraints = [constraints sortedArrayUsingSelector:@selector(compare:)];
double minVal = [[sortedConstraints objectAtIndex:0] doubleValue];
double maxVal = [[sortedConstraints lastObject] doubleValue];
CGFloat bestDistance = 0;
CGFloat bestValue = -1;
CGFloat prev = [[sortedConstraints objectAtIndex:0] doubleValue];
for (NSNumber* np in sortedConstraints) {
CGFloat n = [np doubleValue];
const CGFloat dist = fabs(n - prev) / 2;
if (dist > bestDistance) {
bestDistance = dist;
bestValue = (n + prev) / 2;
}
prev = n;
}
if (minVal > bestDistance) {
bestValue = 0;
bestDistance = minVal;
}
if (1 - maxVal > bestDistance) {
bestValue = 1;
bestDistance = 1 - maxVal;
}
DLog(@"Best distance is %f", (float)bestDistance);
return bestValue;
}
- (double)brightnessOfCharBackground:(screen_char_t)c {
return [[self backgroundColorForChar:c] perceivedBrightness];
}
- (NSColor *)backgroundColorForChar:(screen_char_t)c {
c.bold = NO;
c.faint = NO;
return [self.delegate cursorColorForCharacter:c wantBackground:YES muted:YES];
}
@end
Loading
Loading
@@ -11,6 +11,7 @@
#import "iTermColorMap.h"
#import "iTermController.h"
#import "iTermSelection.h"
#import "iTermSmartCursorColor.h"
#import "iTermTextDrawingHelper.h"
#import "NSColor+iTerm.h"
#import "PTYFontInfo.h"
Loading
Loading
@@ -51,7 +52,9 @@ static NSColor *ColorForVector(vector_float4 v) {
return [NSColor colorWithRed:v.x green:v.y blue:v.z alpha:v.w];
}
 
@interface iTermMetalPerFrameState : NSObject<iTermMetalDriverDataSourcePerFrameState> {
@interface iTermMetalPerFrameState : NSObject<
iTermMetalDriverDataSourcePerFrameState,
iTermSmartCursorColorDelegate> {
BOOL _havePreviousCharacterAttributes;
screen_char_t _previousCharacterAttributes;
vector_float4 _lastUnprocessedColor;
Loading
Loading
@@ -75,6 +78,12 @@ static NSColor *ColorForVector(vector_float4 v) {
iTermMetalCursorInfo *_cursorInfo;
iTermThinStrokesSetting _thinStrokes;
BOOL _isRetina;
BOOL _isInKeyWindow;
BOOL _textViewIsActiveSession;
BOOL _shouldDrawFilledInCursor;
VT100GridSize _gridSize;
VT100GridCoordRange _visibleRange;
NSInteger _numberOfScrollbackLines;
}
 
- (instancetype)initWithTextView:(PTYTextView *)textView
Loading
Loading
@@ -115,18 +124,20 @@ static NSColor *ColorForVector(vector_float4 v) {
_lines = [NSMutableArray array];
_selectedIndexes = [NSMutableArray array];
_matches = [NSMutableDictionary dictionary];
VT100GridCoordRange coordRange = [textView.drawingHelper coordRangeForRect:textView.enclosingScrollView.documentVisibleRect];
const int width = coordRange.end.x - coordRange.start.x;
for (int i = coordRange.start.y; i < coordRange.end.y; i++) {
_visibleRange = [textView.drawingHelper coordRangeForRect:textView.enclosingScrollView.documentVisibleRect];
const int width = _visibleRange.end.x - _visibleRange.start.x;
for (int i = _visibleRange.start.y; i < _visibleRange.end.y; i++) {
screen_char_t *line = [screen getLineAtIndex:i];
[_lines addObject:[NSData dataWithBytes:line length:sizeof(screen_char_t) * width]];
[_selectedIndexes addObject:[textView.selection selectedIndexesOnLine:i]];
NSData *findMatches = [textView.drawingHelper.delegate drawingHelperMatchesOnLine:i];
if (findMatches) {
_matches[@(i - coordRange.start.y)] = findMatches;
_matches[@(i - _visibleRange.start.y)] = findMatches;
}
}
 
_gridSize = VT100GridSizeMake(textView.dataSource.width,
textView.dataSource.height);
_colorMap = [textView.colorMap copy];
_asciiFont = textView.primaryFont;
_nonAsciiFont = textView.secondaryFont;
Loading
Loading
@@ -137,18 +148,61 @@ static NSColor *ColorForVector(vector_float4 v) {
_useBrightBold = textView.useBrightBold;
_thinStrokes = textView.thinStrokes;
_isRetina = textView.drawingHelper.isRetina;
_isInKeyWindow = [textView isInKeyWindow];
_textViewIsActiveSession = [textView.delegate textViewIsActiveSession];
_shouldDrawFilledInCursor = ([textView.delegate textViewShouldDrawFilledInCursor] || textView.keyFocusStolenCount);
_numberOfScrollbackLines = textView.dataSource.numberOfScrollbackLines;
iTermSmartCursorColor *smartCursorColor = nil;
if (textView.drawingHelper.useSmartCursorColor) {
smartCursorColor = [[iTermSmartCursorColor alloc] init];
smartCursorColor.delegate = self;
}
_cursorInfo = [[iTermMetalCursorInfo alloc] init];
#warning TODO: blinking cursor
if (textView.cursorVisible && coordRange.end.y >= textView.dataSource.numberOfScrollbackLines) {
const int offset = coordRange.start.y - textView.dataSource.numberOfScrollbackLines;
NSLog(@"Visible range is [%d, %d), have %d lines of scrollback",
(int)_visibleRange.start.y,
(int)_visibleRange.end.y,
(int)_numberOfScrollbackLines);
NSInteger lineWithCursor = textView.dataSource.cursorY - 1 + _numberOfScrollbackLines;
if (textView.cursorVisible && _visibleRange.start.y <= lineWithCursor && lineWithCursor + 1 < _visibleRange.end.y) {
const int offset = _visibleRange.start.y - _numberOfScrollbackLines;
_cursorInfo.cursorVisible = YES;
NSLog(@"Cursor is visible on line %d (%d of visible region)", (int)lineWithCursor, (int)(lineWithCursor - _visibleRange.start.y));
_cursorInfo.type = textView.drawingHelper.cursorType;
_cursorInfo.coord = VT100GridCoordMake(textView.dataSource.cursorX - 1,
textView.dataSource.cursorY - 1 - offset);
#warning handle frame cursor, text color, smart cursor color, and other fancy cursors of various kinds
_cursorInfo.cursorColor = [self backgroundColorForCursor];
if (_cursorInfo.type == CURSOR_BOX) {
_cursorInfo.shouldDrawText = YES;
const screen_char_t *line = (screen_char_t *)_lines[_cursorInfo.coord.y].bytes;
screen_char_t screenChar = line[_cursorInfo.coord.x];
const BOOL focused = ((_isInKeyWindow && _textViewIsActiveSession) || _shouldDrawFilledInCursor);
_cursorInfo.textColor = [self fastCursorColorForCharacter:screenChar
wantBackground:YES
muted:NO];
if (!focused) {
_cursorInfo.frameOnly = YES;
} else if (smartCursorColor) {
_cursorInfo.cursorColor = [smartCursorColor backgroundColorForCharacter:screenChar];
NSColor *regularTextColor = [NSColor colorWithRed:_cursorInfo.textColor.x
green:_cursorInfo.textColor.y
blue:_cursorInfo.textColor.z
alpha:_cursorInfo.textColor.w];
NSColor *smartTextColor = [smartCursorColor textColorForCharacter:screenChar
regularTextColor:regularTextColor
smartBackgroundColor:_cursorInfo.cursorColor];
CGFloat components[4];
[smartTextColor getComponents:components];
_cursorInfo.textColor = simd_make_float4(components[0],
components[1],
components[2],
components[3]);
}
}
} else {
NSLog(@"Cursor is not visible");
_cursorInfo.cursorVisible = NO;
}
}
Loading
Loading
@@ -667,6 +721,111 @@ static NSColor *ColorForVector(vector_float4 v) {
 
#warning TODO: Lots of code was copied from PTYTextView. Make it shared.
 
#pragma mark - iTermSmartCursorColorDelegate
- (iTermCursorNeighbors)cursorNeighbors {
iTermCursorNeighbors neighbors;
memset(&neighbors, 0, sizeof(neighbors));
NSArray *coords = @[ @[ @0, @(-1) ], // Above
@[ @(-1), @0 ], // Left
@[ @1, @0 ], // Right
@[ @0, @1 ] ]; // Below
int prevY = -2;
const screen_char_t *theLine = nil;
for (NSArray *tuple in coords) {
int dx = [tuple[0] intValue];
int dy = [tuple[1] intValue];
int x = _cursorInfo.coord.x + dx;
int y = _cursorInfo.coord.y + dy + _numberOfScrollbackLines;
if (y != prevY) {
if (y >= _visibleRange.start.y && y < _visibleRange.end.y) {
theLine = (const screen_char_t *)_lines[y - _visibleRange.start.y].bytes;
} else {
theLine = nil;
}
}
prevY = y;
int xi = dx + 1;
int yi = dy + 1;
if (theLine && x >= 0 && x < _gridSize.width) {
neighbors.chars[yi][xi] = theLine[x];
neighbors.valid[yi][xi] = YES;
}
}
return neighbors;
}
// TODO: This is copypasta
- (vector_float4)fastCursorColorForCharacter:(screen_char_t)screenChar
wantBackground:(BOOL)wantBackgroundColor
muted:(BOOL)muted {
BOOL isBackground = wantBackgroundColor;
if (_reverseVideo) {
if (wantBackgroundColor &&
screenChar.backgroundColorMode == ColorModeAlternate &&
screenChar.backgroundColor == ALTSEM_DEFAULT) {
isBackground = NO;
} else if (!wantBackgroundColor &&
screenChar.foregroundColorMode == ColorModeAlternate &&
screenChar.foregroundColor == ALTSEM_DEFAULT) {
isBackground = YES;
}
}
vector_float4 color;
if (wantBackgroundColor) {
color = [self colorForCode:screenChar.backgroundColor
green:screenChar.bgGreen
blue:screenChar.bgBlue
colorMode:screenChar.backgroundColorMode
bold:screenChar.bold
faint:screenChar.faint
isBackground:isBackground];
} else {
color = [self colorForCode:screenChar.foregroundColor
green:screenChar.fgGreen
blue:screenChar.fgBlue
colorMode:screenChar.foregroundColorMode
bold:screenChar.bold
faint:screenChar.faint
isBackground:isBackground];
}
if (muted) {
color = [_colorMap fastColorByMutingColor:color];
}
return color;
}
- (NSColor *)cursorColorForCharacter:(screen_char_t)screenChar
wantBackground:(BOOL)wantBackgroundColor
muted:(BOOL)muted {
vector_float4 v = [self fastCursorColorForCharacter:screenChar wantBackground:wantBackgroundColor muted:muted];
return [NSColor colorWithRed:v.x green:v.y blue:v.z alpha:v.w];
}
- (NSColor *)cursorColorByDimmingSmartColor:(NSColor *)color {
return [_colorMap colorByDimmingTextColor:color];
}
- (NSColor *)cursorWhiteColor {
NSColor *whiteColor = [NSColor colorWithCalibratedRed:1
green:1
blue:1
alpha:1];
return [_colorMap colorByDimmingTextColor:whiteColor];
}
- (NSColor *)cursorBlackColor {
NSColor *blackColor = [NSColor colorWithCalibratedRed:0
green:0
blue:0
alpha:1];
return [_colorMap colorByDimmingTextColor:blackColor];
}
 
@end
 
Loading
Loading
//
// iTermSmartCursorColor.h
// iTerm2SharedARC
//
// Created by George Nachman on 10/28/17.
//
#import <Foundation/Foundation.h>
#import "ScreenChar.h"
typedef struct {
screen_char_t chars[3][3];
BOOL valid[3][3];
} iTermCursorNeighbors;
@protocol iTermSmartCursorColorDelegate<NSObject>
- (iTermCursorNeighbors)cursorNeighbors;
- (NSColor *)cursorColorForCharacter:(screen_char_t)screenChar
wantBackground:(BOOL)wantBackgroundColor
muted:(BOOL)muted;
- (NSColor *)cursorColorByDimmingSmartColor:(NSColor *)color;
- (NSColor *)cursorWhiteColor;
- (NSColor *)cursorBlackColor;
@end
@interface iTermSmartCursorColor : NSObject
@property (nonatomic, weak) id<iTermSmartCursorColorDelegate> delegate;
- (NSColor *)backgroundColorForCharacter:(screen_char_t)screenChar;
- (NSColor *)textColorForCharacter:(screen_char_t)screenChar
regularTextColor:(NSColor *)proposedForeground
smartBackgroundColor:(NSColor *)backgroundColor;
@end
//
// iTermSmartCursorColor.m
// iTerm2SharedARC
//
// Created by George Nachman on 10/28/17.
//
#import "iTermSmartCursorColor.h"
#import "DebugLogging.h"
#import "iTermAdvancedSettingsModel.h"
#import "NSColor+iTerm.h"
@implementation iTermSmartCursorColor
- (NSColor *)backgroundColorForCharacter:(screen_char_t)screenChar {
iTermCursorNeighbors neighbors = [self.delegate cursorNeighbors];
NSColor *bgColor = [self.delegate cursorColorForCharacter:screenChar
wantBackground:NO
muted:NO];
NSMutableArray* constraints = [NSMutableArray arrayWithCapacity:2];
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
if (neighbors.valid[y][x]) {
NSLog(@"Background color for dx=%d dy=%d is %@", x-1, y-1, [self backgroundColorForChar:neighbors.chars[y][x]]);
[constraints addObject:@([self brightnessOfCharBackground:neighbors.chars[y][x]])];
}
}
}
CGFloat bgBrightness = [bgColor perceivedBrightness];
if ([self minimumDistanceOf:bgBrightness fromAnyValueIn:constraints] <
[iTermAdvancedSettingsModel smartCursorColorBgThreshold]) {
CGFloat b = [self farthestValueFromAnyValueIn:constraints];
bgColor = [NSColor colorWithCalibratedRed:b green:b blue:b alpha:1];
}
return [[self.delegate cursorColorByDimmingSmartColor:bgColor] colorWithAlphaComponent:1];
}
- (NSColor *)textColorForCharacter:(screen_char_t)screenChar
regularTextColor:(NSColor *)proposedForeground
smartBackgroundColor:(NSColor *)backgroundColor {
proposedForeground = [proposedForeground colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
return [self overrideColorForSmartCursorWithForegroundColor:proposedForeground
backgroundColor:backgroundColor];
}
#pragma mark - Private
// Return the value in 'values' closest to target.
- (CGFloat)minimumDistanceOf:(CGFloat)target fromAnyValueIn:(NSArray*)values {
CGFloat md = 1;
for (NSNumber* n in values) {
CGFloat dist = fabs(target - [n doubleValue]);
if (dist < md) {
md = dist;
}
}
return md;
}
// Return the value between 0 and 1 that is farthest from any value in 'constraints'.
- (CGFloat)farthestValueFromAnyValueIn:(NSArray*)constraints {
if ([constraints count] == 0) {
return 0;
}
NSArray* sortedConstraints = [constraints sortedArrayUsingSelector:@selector(compare:)];
double minVal = [[sortedConstraints objectAtIndex:0] doubleValue];
double maxVal = [[sortedConstraints lastObject] doubleValue];
CGFloat bestDistance = 0;
CGFloat bestValue = -1;
CGFloat prev = [[sortedConstraints objectAtIndex:0] doubleValue];
for (NSNumber* np in sortedConstraints) {
CGFloat n = [np doubleValue];
const CGFloat dist = fabs(n - prev) / 2;
if (dist > bestDistance) {
bestDistance = dist;
bestValue = (n + prev) / 2;
}
prev = n;
}
if (minVal > bestDistance) {
bestValue = 0;
bestDistance = minVal;
}
if (1 - maxVal > bestDistance) {
bestValue = 1;
bestDistance = 1 - maxVal;
}
DLog(@"Best distance is %f", (float)bestDistance);
return bestValue;
}
- (double)brightnessOfCharBackground:(screen_char_t)c {
return [[self backgroundColorForChar:c] perceivedBrightness];
}
- (NSColor *)backgroundColorForChar:(screen_char_t)c {
c.bold = NO;
c.faint = NO;
return [self.delegate cursorColorForCharacter:c wantBackground:YES muted:YES];
}
- (NSColor *)overrideColorForSmartCursorWithForegroundColor:(NSColor *)proposedForeground
backgroundColor:(NSColor *)backgroundColor {
CGFloat fgBrightness = [proposedForeground perceivedBrightness];
CGFloat bgBrightness = [backgroundColor perceivedBrightness];
const double threshold = [iTermAdvancedSettingsModel smartCursorColorFgThreshold];
if (fabs(fgBrightness - bgBrightness) < threshold) {
// Foreground and background are very similar. Just use black and
// white.
if (bgBrightness < 0.5) {
return [self.delegate cursorWhiteColor];
} else {
return [self.delegate cursorBlackColor];
}
} else {
return proposedForeground;
}
}
@end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment