mirror of
https://github.com/qvacua/vimr.git
synced 2024-12-25 14:52:19 +03:00
GH-666 Delete MMCoreTextView.m and TextDrawer.m
This commit is contained in:
parent
71fad2ebc2
commit
c5e0736efe
@ -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 */,
|
||||
|
@ -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
|
||||
);
|
@ -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
|
@ -272,7 +272,6 @@ extension NvimView {
|
||||
}
|
||||
|
||||
func updateFontMetaData(_ newFont: NSFont) {
|
||||
self.drawer.font = newFont
|
||||
self.runDrawer.baseFont = newFont
|
||||
|
||||
self.cellSize = FontUtils.cellSize(
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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?
|
||||
|
@ -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)
|
||||
|
@ -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
|
@ -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
|
@ -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.
|
Loading…
Reference in New Issue
Block a user