1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-25 06:43:24 +03:00

GH-666 Delete MMCoreTextView.m and TextDrawer.m

This commit is contained in:
Tae Won Ha 2018-08-29 18:35:24 +02:00
parent 71fad2ebc2
commit c5e0736efe
11 changed files with 9 additions and 726 deletions

View File

@ -52,13 +52,9 @@
4B90F03A1FD2AFAE008A39E0 /* NvimView+Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F01C1FD2AFAC008A39E0 /* NvimView+Key.swift */; };
4B90F03B1FD2AFAE008A39E0 /* NvimObjectsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F01D1FD2AFAC008A39E0 /* NvimObjectsExtensions.swift */; };
4B90F03C1FD2AFAE008A39E0 /* NvimView+TouchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F01E1FD2AFAC008A39E0 /* NvimView+TouchBar.swift */; };
4B90F03E1FD2AFAE008A39E0 /* MMCoreTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0201FD2AFAD008A39E0 /* MMCoreTextView.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
4B90F03F1FD2AFAE008A39E0 /* NvimView+Draw.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0211FD2AFAD008A39E0 /* NvimView+Draw.swift */; };
4B90F0401FD2AFAE008A39E0 /* TextDrawer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0221FD2AFAD008A39E0 /* TextDrawer.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
4B90F0411FD2AFAE008A39E0 /* TextDrawer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B90F0231FD2AFAD008A39E0 /* TextDrawer.h */; settings = {ATTRIBUTES = (Public, ); }; };
4B90F0421FD2AFAE008A39E0 /* NvimView+UiBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0241FD2AFAD008A39E0 /* NvimView+UiBridge.swift */; };
4B90F0431FD2AFAE008A39E0 /* NvimView+MenuItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0251FD2AFAD008A39E0 /* NvimView+MenuItems.swift */; };
4B90F0441FD2AFAE008A39E0 /* MMCoreTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B90F0261FD2AFAD008A39E0 /* MMCoreTextView.h */; settings = {ATTRIBUTES = (Private, ); }; };
4B90F0451FD2AFAE008A39E0 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0271FD2AFAD008A39E0 /* Logger.swift */; };
4B90F0461FD2AFAE008A39E0 /* Grid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0281FD2AFAD008A39E0 /* Grid.swift */; };
4B90F0521FD2AFD3008A39E0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0511FD2AFD3008A39E0 /* main.m */; };
@ -210,13 +206,9 @@
4B90F01D1FD2AFAC008A39E0 /* NvimObjectsExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NvimObjectsExtensions.swift; sourceTree = "<group>"; };
4B90F01E1FD2AFAC008A39E0 /* NvimView+TouchBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NvimView+TouchBar.swift"; sourceTree = "<group>"; };
4B90F01F1FD2AFAD008A39E0 /* InputTestView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputTestView.swift; sourceTree = "<group>"; };
4B90F0201FD2AFAD008A39E0 /* MMCoreTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMCoreTextView.m; sourceTree = "<group>"; };
4B90F0211FD2AFAD008A39E0 /* NvimView+Draw.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NvimView+Draw.swift"; sourceTree = "<group>"; };
4B90F0221FD2AFAD008A39E0 /* TextDrawer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextDrawer.m; sourceTree = "<group>"; };
4B90F0231FD2AFAD008A39E0 /* TextDrawer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextDrawer.h; sourceTree = "<group>"; };
4B90F0241FD2AFAD008A39E0 /* NvimView+UiBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NvimView+UiBridge.swift"; sourceTree = "<group>"; };
4B90F0251FD2AFAD008A39E0 /* NvimView+MenuItems.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NvimView+MenuItems.swift"; sourceTree = "<group>"; };
4B90F0261FD2AFAD008A39E0 /* MMCoreTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMCoreTextView.h; sourceTree = "<group>"; };
4B90F0271FD2AFAD008A39E0 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
4B90F0281FD2AFAD008A39E0 /* Grid.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Grid.swift; sourceTree = "<group>"; };
4B90F04F1FD2AFD3008A39E0 /* NvimServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = NvimServer; sourceTree = BUILT_PRODUCTS_DIR; };
@ -365,8 +357,6 @@
4B90F01F1FD2AFAD008A39E0 /* InputTestView.swift */,
4B90F0121FD2AFAC008A39E0 /* KeyUtils.swift */,
4B90F0271FD2AFAD008A39E0 /* Logger.swift */,
4B90F0261FD2AFAD008A39E0 /* MMCoreTextView.h */,
4B90F0201FD2AFAD008A39E0 /* MMCoreTextView.m */,
4BD8742F2014C25F0039888E /* NvimAutoCommandEvent.generated.swift */,
4B90F01D1FD2AFAC008A39E0 /* NvimObjectsExtensions.swift */,
4B90F0101FD2AFAC008A39E0 /* NvimView.swift */,
@ -379,8 +369,6 @@
4B90F0111FD2AFAC008A39E0 /* NvimView+Resize.swift */,
4B90F01E1FD2AFAC008A39E0 /* NvimView+TouchBar.swift */,
4B90F0241FD2AFAD008A39E0 /* NvimView+UiBridge.swift */,
4B90F0231FD2AFAD008A39E0 /* TextDrawer.h */,
4B90F0221FD2AFAD008A39E0 /* TextDrawer.m */,
1929B22A0CAD417EC3790F02 /* NvimViewObjects.swift */,
1929BBD7F88AE4F01E626691 /* NvimApiExtension.swift */,
1929B52174EC68D2974B5BAE /* UiBridge.swift */,
@ -443,9 +431,7 @@
buildActionMask = 2147483647;
files = (
4BF18C5D1FD2EEE400DF95D1 /* NvimView.h in Headers */,
4B90F0411FD2AFAE008A39E0 /* TextDrawer.h in Headers */,
4B177886201220F300E32FF0 /* SharedTypes.h in Headers */,
4B90F0441FD2AFAE008A39E0 /* MMCoreTextView.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -633,12 +619,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4B90F03E1FD2AFAE008A39E0 /* MMCoreTextView.m in Sources */,
4B90F03F1FD2AFAE008A39E0 /* NvimView+Draw.swift in Sources */,
4B90F02F1FD2AFAE008A39E0 /* NvimView+Resize.swift in Sources */,
4B90F0461FD2AFAE008A39E0 /* Grid.swift in Sources */,
4B90F0421FD2AFAE008A39E0 /* NvimView+UiBridge.swift in Sources */,
4B90F0401FD2AFAE008A39E0 /* TextDrawer.m in Sources */,
4BD874302014C2600039888E /* NvimAutoCommandEvent.generated.swift in Sources */,
4B90F02E1FD2AFAE008A39E0 /* NvimView.swift in Sources */,
4B90F03C1FD2AFAE008A39E0 /* NvimView+TouchBar.swift in Sources */,

View File

@ -1,11 +0,0 @@
#import <Cocoa/Cocoa.h>
#import <CoreText/CoreText.h>
void recurseDraw(
const unichar *chars,
CGGlyph *glyphs, CGPoint *positions, UniCharCount length,
CGContextRef context,
CTFontRef fontRef,
NSMutableArray *fontCache,
BOOL useLigatures
);

View File

@ -1,295 +0,0 @@
/* vi:set ts=8 sts=4 sw=4 ft=objc:
*
* VIM - Vi IMproved by Bram Moolenaar
* MacVim GUI port by Bjorn Winckler
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
* See README.txt for an overview of the Vim source code.
*/
/**
* Extracted from snapshot-146 of MacVim
* https://github.com/macvim-dev/macvim
* See VIM.LICENSE
*/
// We suppress the following warnings since the original code does have it...
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#import "MMCoreTextView.h"
static CTFontRef
lookupFont(NSMutableArray *fontCache, const unichar *chars, UniCharCount count,
CTFontRef currFontRef)
{
CGGlyph glyphs[count];
// See if font in cache can draw at least one character
NSUInteger i;
for (i = 0; i < [fontCache count]; ++i) {
NSFont *font = [fontCache objectAtIndex:i];
if (CTFontGetGlyphsForCharacters((CTFontRef)font, chars, glyphs, count))
return (CTFontRef)[font retain];
}
// Ask Core Text for a font (can be *very* slow, which is why we cache
// fonts in the first place)
CFRange r = { 0, count };
CFStringRef strRef = CFStringCreateWithCharacters(NULL, chars, count);
CTFontRef newFontRef = CTFontCreateForString(currFontRef, strRef, r);
CFRelease(strRef);
// Verify the font can actually convert all the glyphs.
if (!CTFontGetGlyphsForCharacters(newFontRef, chars, glyphs, count))
return nil;
if (newFontRef)
[fontCache addObject:(NSFont *)newFontRef];
return newFontRef;
}
static CFAttributedStringRef
attributedStringForString(NSString *string, const CTFontRef font,
BOOL useLigatures)
{
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
(id)font, kCTFontAttributeName,
// 2 - full ligatures including rare
// 1 - basic ligatures
// 0 - no ligatures
[NSNumber numberWithInteger:(useLigatures ? 1 : 0)],
kCTLigatureAttributeName,
nil
];
return CFAttributedStringCreate(NULL, (CFStringRef)string,
(CFDictionaryRef)attrs);
}
static UniCharCount
fetchGlyphsAndAdvances(const CTLineRef line, CGGlyph *glyphs, CGSize *advances,
UniCharCount length)
{
NSArray *glyphRuns = (NSArray*)CTLineGetGlyphRuns(line);
// get a hold on the actual character widths and glyphs in line
UniCharCount offset = 0;
for (id item in glyphRuns) {
CTRunRef run = (CTRunRef)item;
CFIndex count = CTRunGetGlyphCount(run);
if (count > 0 && count - offset > length)
count = length - offset;
CFRange range = CFRangeMake(0, count);
if (glyphs != NULL)
CTRunGetGlyphs(run, range, &glyphs[offset]);
if (advances != NULL)
CTRunGetAdvances(run, range, &advances[offset]);
offset += count;
if (offset >= length)
break;
}
return offset;
}
static UniCharCount
gatherGlyphs(CGGlyph glyphs[], UniCharCount count)
{
// Gather scattered glyphs that was happended by Surrogate pair chars
UniCharCount glyphCount = 0;
NSUInteger pos = 0;
NSUInteger i;
for (i = 0; i < count; ++i) {
if (glyphs[i] != 0) {
++glyphCount;
glyphs[pos++] = glyphs[i];
}
}
return glyphCount;
}
static UniCharCount
ligatureGlyphsForChars(const unichar *chars, CGGlyph *glyphs,
CGPoint *positions, UniCharCount length, CTFontRef font)
{
// CoreText has no simple wait of retrieving a ligature for a set of
// UniChars. The way proposed on the CoreText ML is to convert the text to
// an attributed string, create a CTLine from it and retrieve the Glyphs
// from the CTRuns in it.
CGGlyph refGlyphs[length];
CGPoint refPositions[length];
memcpy(refGlyphs, glyphs, sizeof(CGGlyph) * length);
memcpy(refPositions, positions, sizeof(CGSize) * length);
memset(glyphs, 0, sizeof(CGGlyph) * length);
NSString *plainText = [NSString stringWithCharacters:chars length:length];
CFAttributedStringRef ligatureText = attributedStringForString(plainText,
font, YES);
CTLineRef ligature = CTLineCreateWithAttributedString(ligatureText);
CGSize ligatureRanges[length], regularRanges[length];
// get the (ligature)glyphs and advances for the new text
UniCharCount offset = fetchGlyphsAndAdvances(ligature, glyphs,
ligatureRanges, length);
// fetch the advances for the base text
CTFontGetAdvancesForGlyphs(font, kCTFontOrientationDefault, refGlyphs,
regularRanges, length);
CFRelease(ligatureText);
CFRelease(ligature);
// tricky part: compare both advance ranges and chomp positions which are
// covered by a single ligature while keeping glyphs not in the ligature
// font.
#define fequal(a, b) (fabs((a) - (b)) < FLT_EPSILON)
#define fless(a, b)((a) - (b) < FLT_EPSILON) && (fabs((a) - (b)) > FLT_EPSILON)
CFIndex skip = 0;
CFIndex i;
for (i = 0; i < offset && skip + i < length; ++i) {
memcpy(&positions[i], &refPositions[skip + i], sizeof(CGSize));
if (fequal(ligatureRanges[i].width, regularRanges[skip + i].width)) {
// [mostly] same width
continue;
} else if (fless(ligatureRanges[i].width,
regularRanges[skip + i].width)) {
// original is wider than our result - use the original glyph
// FIXME: this is currently the only way to detect emoji (except
// for 'glyph[i] == 5')
glyphs[i] = refGlyphs[skip + i];
continue;
}
// no, that's a ligature
// count how many positions this glyph would take up in the base text
CFIndex j = 0;
float width = ceil(regularRanges[skip + i].width);
while ((int)width < (int)ligatureRanges[i].width
&& skip + i + j < length) {
width += ceil(regularRanges[++j + skip + i].width);
}
skip += j;
}
#undef fless
#undef fequal
// as ligatures combine characters it is required to adjust the
// original length value
return offset;
}
void
recurseDraw(const unichar *chars, CGGlyph *glyphs, CGPoint *positions,
UniCharCount length, CGContextRef context, CTFontRef fontRef,
NSMutableArray *fontCache, BOOL useLigatures)
{
if (CTFontGetGlyphsForCharacters(fontRef, chars, glyphs, length)) {
// All chars were mapped to glyphs, so draw all at once and return.
if (useLigatures) {
length = ligatureGlyphsForChars(chars, glyphs, positions, length,
fontRef);
} else {
// only fixup surrogate pairs if we're not using ligatures
length = gatherGlyphs(glyphs, length);
}
CTFontDrawGlyphs(fontRef, glyphs, positions, length, context);
return;
}
CGGlyph *glyphsEnd = glyphs+length, *g = glyphs;
CGPoint *p = positions;
const unichar *c = chars;
while (glyphs < glyphsEnd) {
if (*g) {
// Draw as many consecutive glyphs as possible in the current font
// (if a glyph is 0 that means it does not exist in the current
// font).
BOOL surrogatePair = NO;
while (*g && g < glyphsEnd) {
if (CFStringIsSurrogateHighCharacter(*c)) {
surrogatePair = YES;
g += 2;
c += 2;
} else {
++g;
++c;
}
++p;
}
int count = g-glyphs;
if (surrogatePair)
count = gatherGlyphs(glyphs, count);
CTFontDrawGlyphs(fontRef, glyphs, positions, count, context);
} else {
// Skip past as many consecutive chars as possible which cannot be
// drawn in the current font.
while (0 == *g && g < glyphsEnd) {
if (CFStringIsSurrogateHighCharacter(*c)) {
g += 2;
c += 2;
} else {
++g;
++c;
}
++p;
}
// Try to find a fallback font that can render the entire
// invalid range. If that fails, repeatedly halve the attempted
// range until a font is found.
UniCharCount count = c - chars;
UniCharCount attemptedCount = count;
CTFontRef fallback = nil;
while (fallback == nil && attemptedCount > 0) {
fallback = lookupFont(fontCache, chars, attemptedCount,
fontRef);
if (!fallback)
attemptedCount /= 2;
}
if (!fallback)
return;
recurseDraw(chars, glyphs, positions, attemptedCount, context,
fallback, fontCache, useLigatures);
// If only a portion of the invalid range was rendered above,
// the remaining range needs to be attempted by subsequent
// iterations of the draw loop.
c -= count - attemptedCount;
g -= count - attemptedCount;
p -= count - attemptedCount;
CFRelease(fallback);
}
if (glyphs == g) {
// No valid chars in the glyphs. Exit from the possible infinite
// recursive call.
break;
}
chars = c;
glyphs = g;
positions = p;
}
}
#pragma clang diagnostic pop

View File

@ -272,7 +272,6 @@ extension NvimView {
}
func updateFontMetaData(_ newFont: NSFont) {
self.drawer.font = newFont
self.runDrawer.baseFont = newFont
self.cellSize = FontUtils.cellSize(

View File

@ -214,14 +214,14 @@ extension NvimView {
}
@IBAction func makeFontBigger(_ sender: Any?) {
let curFont = self.drawer.font
let curFont = self.runDrawer.baseFont
let font = NSFontManager.shared
.convert(curFont, toSize: min(curFont.pointSize + 1, NvimView.maxFontSize))
self.updateFontMetaData(font)
}
@IBAction func makeFontSmaller(_ sender: Any?) {
let curFont = self.drawer.font
let curFont = self.runDrawer.baseFont
let font = NSFontManager.shared
.convert(curFont, toSize: max(curFont.pointSize - 1, NvimView.minFontSize))
self.updateFontMetaData(font)

View File

@ -14,5 +14,4 @@ FOUNDATION_EXPORT const unsigned char NvimViewVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <NvimView/PublicHeader.h>
// TODO: this header should not be public, but we cannot use a bridging header in a framework.
#import <NvimView/TextDrawer.h>
#import <NvimView/SharedTypes.h>

View File

@ -124,7 +124,6 @@ public class NvimView: NSView,
public var usesLigatures = false {
didSet {
self.drawer.usesLigatures = self.usesLigatures
self.runDrawer.usesLigatures = self.usesLigatures
self.needsDisplay = true
}
@ -141,7 +140,6 @@ public class NvimView: NSView,
}
self._linespacing = newValue
self.drawer.linespacing = self.linespacing
self.runDrawer.linespacing = self.linespacing
self.updateFontMetaData(self._font)
@ -198,7 +196,6 @@ public class NvimView: NSView,
}
public init(frame rect: NSRect, config: Config) {
self.drawer = TextDrawer(font: self._font)
self.runDrawer = AttributesRunDrawer(
baseFont: self._font,
linespacing: self._linespacing,
@ -347,7 +344,6 @@ public class NvimView: NSView,
let ugrid = UGrid()
let cellAttributesCollection = CellAttributesCollection()
let drawer: TextDrawer
let runDrawer: AttributesRunDrawer
var markedText: String?

View File

@ -5,7 +5,13 @@
import Cocoa
extension OldCellAttributes: CustomStringConvertible, Equatable {
struct OldCellAttributes: CustomStringConvertible, Equatable {
var fontTrait: FontTrait
var foreground: Int
var background: Int
var special: Int
var reverse: Bool
public static var debug: OldCellAttributes {
return OldCellAttributes(fontTrait: [], foreground: 0, background: 0, special: 0, reverse: false)

View File

@ -1,39 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Cocoa/Cocoa.h>
#import <CoreText/CoreText.h>
#import "SharedTypes.h"
typedef struct {
FontTrait fontTrait;
NSInteger foreground;
NSInteger background;
NSInteger special;
bool reverse;
} OldCellAttributes;
@interface TextDrawer : NSObject
@property (nonatomic, nonnull, retain) NSFont *font;
@property (nonatomic) bool usesLigatures;
@property (nonatomic, readonly) CGFloat baselineOffset;
@property (nonatomic, readonly) CGFloat leading;
@property (nonatomic, readonly) CGFloat descent;
@property (nonatomic) CGFloat linespacing;
@property (nonatomic, readonly) CGSize cellSize;
- (instancetype _Nonnull)initWithFont:(NSFont *_Nonnull)font;
- (void)drawString:(NSString *_Nonnull)string
positions:(CGPoint *_Nonnull)positions positionsCount:(NSInteger)positionsCount
highlightAttrs:(OldCellAttributes)attrs
context:(CGContextRef _Nonnull)context;
@end

View File

@ -1,278 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*
* Almost a verbatim copy from MacVim by Bjorn Winckler
* See VIM.LICENSE
*/
#import "TextDrawer.h"
#import "MMCoreTextView.h"
#define ALPHA(color_code) (((color_code >> 24) & 0xff) / 255.0f)
#define RED(color_code) (((color_code >> 16) & 0xff) / 255.0f)
#define GREEN(color_code) (((color_code >> 8) & 0xff) / 255.0f)
#define BLUE(color_code) (((color_code ) & 0xff) / 255.0f)
static dispatch_once_t token;
static NSCache *colorCache;
static CGColorRef color_for(NSInteger value) {
NSColor *color = [colorCache objectForKey:@(value)];
if (color != nil) {
return color.CGColor;
}
color = [NSColor colorWithSRGBRed:RED(value) green:GREEN(value) blue:BLUE(value) alpha:1];
[colorCache setObject:color forKey:@(value)];
return color.CGColor;
}
@implementation TextDrawer {
NSLayoutManager *_layoutManager;
NSFont *_font;
CGFloat _ascent;
CGFloat _underlinePosition;
CGFloat _underlineThickness;
CGFloat _linespacing;
NSMutableArray *_fontLookupCache;
NSMutableDictionary *_fontTraitCache;
}
- (CGFloat)baselineOffset {
return _cellSize.height - _ascent;
}
- (void)setLinespacing:(CGFloat)linespacing {
// FIXME: reasonable min and max
_linespacing = linespacing;
_cellSize = [self cellSizeWithFont:_font linespacing:_linespacing];
}
- (void)setFont:(NSFont *)font {
[_font autorelease];
_font = [font retain];
[_fontTraitCache removeAllObjects];
[_fontLookupCache removeAllObjects];
_cellSize = [self cellSizeWithFont:font linespacing:_linespacing];
_ascent = CTFontGetAscent((CTFontRef) _font);
_leading = CTFontGetLeading((CTFontRef) _font);
_descent = CTFontGetDescent((CTFontRef) _font);
_underlinePosition = CTFontGetUnderlinePosition((CTFontRef) _font); // This seems to take the thickness into account
// TODO: Maybe we should use 0.5 or 1 as minimum thickness for Retina and non-Retina, respectively.
_underlineThickness = CTFontGetUnderlineThickness((CTFontRef) _font);
}
- (instancetype _Nonnull)initWithFont:(NSFont *_Nonnull)font {
dispatch_once (&token, ^{
colorCache = [NSCache new];
colorCache.countLimit = 1000;
});
self = [super init];
if (self == nil) {
return nil;
}
_usesLigatures = NO;
_linespacing = 1;
_layoutManager = [[NSLayoutManager alloc] init];
_fontLookupCache = [[NSMutableArray alloc] init];
_fontTraitCache = [[NSMutableDictionary alloc] init];
self.font = font;
return self;
}
- (void)dealloc {
[_layoutManager release];
[_font release];
[_fontLookupCache release];
[_fontTraitCache release];
[super dealloc];
}
/**
* We assume that the background is drawn elsewhere and that the caller has already called
*
* CGContextSetTextMatrix(context, CGAffineTransformIdentity); // or some other matrix
* CGContextSetTextDrawingMode(context, kCGTextFill); // or some other mode
*/
- (void)drawString:(NSString *_Nonnull)string
positions:(CGPoint *_Nonnull)positions
positionsCount:(NSInteger)positionsCount
highlightAttrs:(OldCellAttributes)attrs
context:(CGContextRef _Nonnull)context
{
CGContextSaveGState(context);
[self drawString:string positions:positions
fontTrait:attrs.fontTrait foreground:attrs.foreground
context:context];
if (attrs.fontTrait & FontTraitUnderline) {
[self drawUnderline:positions count:positionsCount color:attrs.foreground context:context];
}
if (attrs.fontTrait & FontTraitUndercurl) {
[self drawUntercurl:positions count:positionsCount color:attrs.special context:context];
}
CGContextRestoreGState(context);
}
- (void)drawUntercurl:(const CGPoint *_Nonnull)positions
count:(NSInteger)count
color:(NSInteger)color
context:(CGContextRef _Nonnull)context
{
CGFloat x0 = positions[0].x;
CGFloat y0 = positions[0].y - 0.1 * _cellSize.height;
CGFloat w = _cellSize.width;
CGFloat h = 0.5 * _descent;
CGContextMoveToPoint(context, x0, y0);
for (int k = 0; k < count; k++) {
CGContextAddCurveToPoint(context, x0 + 0.25 * w, y0, x0 + 0.25 * w, y0 + h, x0 + 0.5 * w, y0 + h);
CGContextAddCurveToPoint(context, x0 + 0.75 * w, y0 + h, x0 + 0.75 * w, y0, x0 + w, y0);
x0 += w;
}
CGContextSetStrokeColorWithColor(context, color_for(color));
CGContextStrokePath(context);
}
- (void)drawUnderline:(const CGPoint *_Nonnull)positions
count:(NSInteger)count
color:(NSInteger)color
context:(CGContextRef _Nonnull)context
{
CGContextSetFillColorWithColor(context, color_for(color));
CGRect rect = {
{positions[0].x, positions[0].y + _underlinePosition},
{count * _cellSize.width, _underlineThickness}
};
CGContextFillRect(context, rect);
}
- (void)drawString:(NSString *_Nonnull)nsstring
positions:(CGPoint *_Nonnull)positions
fontTrait:(FontTrait)fontTrait
foreground:(NSInteger)foreground
context:(CGContextRef _Nonnull)context
{
CFStringRef string = (CFStringRef) nsstring;
UniChar *unibuffer = NULL;
UniCharCount unilength = (UniCharCount) CFStringGetLength(string);
const UniChar *unichars = CFStringGetCharactersPtr(string);
if (unichars == NULL) {
unibuffer = malloc(unilength * sizeof(UniChar));
CFStringGetCharacters(string, CFRangeMake(0, unilength), unibuffer);
unichars = unibuffer;
}
CGGlyph *glyphs = malloc(unilength * sizeof(CGGlyph));
CTFontRef fontWithTraits = [self fontWithTrait:fontTrait];
CGContextSetFillColorWithColor(context, color_for(foreground));
CGGlyph *g = glyphs;
CGPoint *p = positions;
const UniChar *b = unichars;
const UniChar *bStart = unichars;
const UniChar *bEnd = unichars + unilength;
UniCharCount choppedLength;
bool wide;
bool pWide = NO;
while (b < bEnd) {
wide = CFStringIsSurrogateHighCharacter(*b) || CFStringIsSurrogateLowCharacter(*b);
if ((b > unichars) && (wide != pWide)) {
choppedLength = b - bStart;
// NSString *logged = [NSString stringWithCharacters:bStart length:choppedLength];
// NSLog(@"C(%d,%p..%p)[%@]", pWide, bStart, b, logged);
recurseDraw(bStart, glyphs, p, choppedLength, context, fontWithTraits, _fontLookupCache, _usesLigatures);
UniCharCount step = pWide ? choppedLength / 2 : choppedLength;
p += step;
g += step;
bStart = b;
}
pWide = wide;
b++;
}
if (bStart < bEnd) {
choppedLength = b - bStart;
// NSString *logged = [NSString stringWithCharacters:bStart length:choppedLength];
// NSLog(@"T(%d,%p..%p)[%@]", pWide, bStart, b, logged);
recurseDraw(bStart, glyphs, p, choppedLength, context, fontWithTraits, _fontLookupCache, _usesLigatures);
}
// NSLog(@"S(-,%p..%p)[%@]", unichars, unichars + unilength, string);
CFRelease(fontWithTraits);
free(glyphs);
if (unibuffer != NULL) {
free(unibuffer);
}
}
- (CGSize)cellSizeWithFont:(NSFont *)font linespacing:(CGFloat)linespacing {
// cf. https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/FontHandling/FontHandling.html
CGFloat ascent = CTFontGetAscent((CTFontRef) _font);
CGFloat descent = CTFontGetDescent((CTFontRef) _font);
CGFloat leading = CTFontGetLeading((CTFontRef) _font);
CGSize result = CGSizeMake(
round([@"m" sizeWithAttributes:@{ NSFontAttributeName : _font }].width),
ceil(linespacing * (ascent + descent + leading))
);
return result;
}
/**
* The caller _must_ CFRelease the returned CTFont!
*/
- (CTFontRef)fontWithTrait:(FontTrait)fontTrait {
if (fontTrait == FontTraitNone) {
return CFRetain(_font);
}
CTFontSymbolicTraits traits = (CTFontSymbolicTraits) 0;
if (fontTrait & FontTraitBold) {
traits |= kCTFontBoldTrait;
}
if (fontTrait & FontTraitItalic) {
traits |= kCTFontItalicTrait;
}
if (traits == 0) {
return CFRetain(_font);
}
NSFont *cachedFont = _fontTraitCache[@(traits)];
if (cachedFont != nil) {
return CFRetain(cachedFont);
}
CTFontRef fontWithTraits = CTFontCreateCopyWithSymbolicTraits((CTFontRef) _font, 0.0, NULL, traits, traits);
if (fontWithTraits == NULL) {
return CFRetain(_font);
}
_fontTraitCache[@(traits)] = (NSFont *) fontWithTraits;
return fontWithTraits;
}
@end

View File

@ -1,78 +0,0 @@
VIM LICENSE
I) There are no restrictions on distributing unmodified copies of Vim except
that they must include this license text. You can also distribute
unmodified parts of Vim, likewise unrestricted except that they must
include this license text. You are also allowed to include executables
that you made from the unmodified Vim sources, plus your own usage
examples and Vim scripts.
II) It is allowed to distribute a modified (or extended) version of Vim,
including executables and/or source code, when the following four
conditions are met:
1) This license text must be included unmodified.
2) The modified Vim must be distributed in one of the following five ways:
a) If you make changes to Vim yourself, you must clearly describe in
the distribution how to contact you. When the maintainer asks you
(in any way) for a copy of the modified Vim you distributed, you
must make your changes, including source code, available to the
maintainer without fee. The maintainer reserves the right to
include your changes in the official version of Vim. What the
maintainer will do with your changes and under what license they
will be distributed is negotiable. If there has been no negotiation
then this license, or a later version, also applies to your changes.
The current maintainer is Bram Moolenaar <Bram@vim.org>. If this
changes it will be announced in appropriate places (most likely
vim.sf.net, www.vim.org and/or comp.editors). When it is completely
impossible to contact the maintainer, the obligation to send him
your changes ceases. Once the maintainer has confirmed that he has
received your changes they will not have to be sent again.
b) If you have received a modified Vim that was distributed as
mentioned under a) you are allowed to further distribute it
unmodified, as mentioned at I). If you make additional changes the
text under a) applies to those changes.
c) Provide all the changes, including source code, with every copy of
the modified Vim you distribute. This may be done in the form of a
context diff. You can choose what license to use for new code you
add. The changes and their license must not restrict others from
making their own changes to the official version of Vim.
d) When you have a modified Vim which includes changes as mentioned
under c), you can distribute it without the source code for the
changes if the following three conditions are met:
- The license that applies to the changes permits you to distribute
the changes to the Vim maintainer without fee or restriction, and
permits the Vim maintainer to include the changes in the official
version of Vim without fee or restriction.
- You keep the changes for at least three years after last
distributing the corresponding modified Vim. When the maintainer
or someone who you distributed the modified Vim to asks you (in
any way) for the changes within this period, you must make them
available to him.
- You clearly describe in the distribution how to contact you. This
contact information must remain valid for at least three years
after last distributing the corresponding modified Vim, or as long
as possible.
e) When the GNU General Public License (GPL) applies to the changes,
you can distribute the modified Vim under the GNU GPL version 2 or
any later version.
3) A message must be added, at least in the output of the ":version"
command and in the intro screen, such that the user of the modified Vim
is able to see that it was modified. When distributing as mentioned
under 2)e) adding the message is only required for as far as this does
not conflict with the license used for the changes.
4) The contact information as required under 2)a) and 2)d) must not be
removed or changed, except that the person himself can make
corrections.
III) If you distribute a modified version of Vim, you are encouraged to use
the Vim license for your changes and make them available to the
maintainer, including the source code. The preferred way to do this is
by e-mail or by uploading the files to a server and e-mailing the URL.
If the number of changes is small (e.g., a modified Makefile) e-mailing a
context diff will do. The e-mail address to be used is
<maintainer@vim.org>
IV) It is not allowed to remove this license from the distribution of the Vim
sources, parts of it or from a modified version. You may use this
license for previous Vim releases instead of the license that they came
with, at your option.