diff --git a/NvimView/NvimView.xcodeproj/project.pbxproj b/NvimView/NvimView.xcodeproj/project.pbxproj index 40456763..bc8bfc4c 100644 --- a/NvimView/NvimView.xcodeproj/project.pbxproj +++ b/NvimView/NvimView.xcodeproj/project.pbxproj @@ -470,7 +470,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 287; + CURRENT_PROJECT_VERSION = 288; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -530,7 +530,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 287; + CURRENT_PROJECT_VERSION = 288; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -557,7 +557,7 @@ COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 287; + DYLIB_CURRENT_VERSION = 288; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac"; FRAMEWORK_VERSION = A; @@ -579,7 +579,7 @@ COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 287; + DYLIB_CURRENT_VERSION = 288; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac"; FRAMEWORK_VERSION = A; diff --git a/NvimView/NvimView/Info.plist b/NvimView/NvimView/Info.plist index e3674b7b..8cc63bfa 100644 --- a/NvimView/NvimView/Info.plist +++ b/NvimView/NvimView/Info.plist @@ -15,9 +15,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - SNAPSHOT-287 + SNAPSHOT-288 CFBundleVersion - 287 + 288 NSHumanReadableCopyright Copyright © 2017 Tae Won Ha. All rights reserved. NSPrincipalClass diff --git a/NvimView/NvimView/MMCoreTextView.h b/NvimView/NvimView/MMCoreTextView.h index 82e05767..c6aca758 100644 --- a/NvimView/NvimView/MMCoreTextView.h +++ b/NvimView/NvimView/MMCoreTextView.h @@ -3,12 +3,9 @@ void recurseDraw( const unichar *chars, - CGGlyph *glyphs, - CGPoint *positions, - UniCharCount length, + CGGlyph *glyphs, CGPoint *positions, UniCharCount length, CGContextRef context, CTFontRef fontRef, NSMutableArray *fontCache, - BOOL isComposing, BOOL useLigatures ); diff --git a/NvimView/NvimView/MMCoreTextView.m b/NvimView/NvimView/MMCoreTextView.m index 3a4fe8ac..98c7572d 100644 --- a/NvimView/NvimView/MMCoreTextView.m +++ b/NvimView/NvimView/MMCoreTextView.m @@ -9,7 +9,7 @@ */ /** - * Extracted from 351faf929e4abe32ea4cc31078d1a625fc86a69f of MacVim, 2018-07-03 + * Extracted from snapshot-146 of MacVim * https://github.com/macvim-dev/macvim * See VIM.LICENSE */ @@ -20,9 +20,7 @@ #import "MMCoreTextView.h" -// @formatter:off - - static CTFontRef + static CTFontRef lookupFont(NSMutableArray *fontCache, const unichar *chars, UniCharCount count, CTFontRef currFontRef) { @@ -58,20 +56,15 @@ lookupFont(NSMutableArray *fontCache, const unichar *chars, UniCharCount count, attributedStringForString(NSString *string, const CTFontRef font, BOOL useLigatures) { - NSDictionary *attrs = nil; - if (useLigatures) { - attrs = [NSDictionary dictionaryWithObjectsAndKeys: - (id)font, kCTFontAttributeName, - // 2 - full ligatures including rare - // 1 - basic ligatures - // 0 - only ligatures essential for proper rendering of text - // this option seems to render ligatures for some - // monospace fonts with ligatures, eg Iosevka, ... - [NSNumber numberWithInt:1], - kCTLigatureAttributeName, - nil - ]; - } + 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); @@ -79,7 +72,7 @@ attributedStringForString(NSString *string, const CTFontRef font, static UniCharCount fetchGlyphsAndAdvances(const CTLineRef line, CGGlyph *glyphs, CGSize *advances, - CGPoint *positions, UniCharCount length) + UniCharCount length) { NSArray *glyphRuns = (NSArray*)CTLineGetGlyphRuns(line); @@ -89,23 +82,19 @@ fetchGlyphsAndAdvances(const CTLineRef line, CGGlyph *glyphs, CGSize *advances, CTRunRef run = (CTRunRef)item; CFIndex count = CTRunGetGlyphCount(run); - if (count > 0) { - if (count > length - offset) - count = length - offset; + if (count > 0 && count - offset > length) + count = length - offset; - CFRange range = CFRangeMake(0, count); + CFRange range = CFRangeMake(0, count); - if (glyphs != NULL) - CTRunGetGlyphs(run, range, &glyphs[offset]); - if (advances != NULL) - CTRunGetAdvances(run, range, &advances[offset]); - if (positions != NULL) - CTRunGetPositions(run, range, &positions[offset]); + if (glyphs != NULL) + CTRunGetGlyphs(run, range, &glyphs[offset]); + if (advances != NULL) + CTRunGetAdvances(run, range, &advances[offset]); - offset += count; - if (offset >= length) - break; - } + offset += count; + if (offset >= length) + break; } return offset; @@ -128,28 +117,78 @@ gatherGlyphs(CGGlyph glyphs[], UniCharCount count) } static UniCharCount -composeGlyphsForChars(const unichar *chars, CGGlyph *glyphs, - CGPoint *positions, UniCharCount length, CTFontRef font, - BOOL isComposing, BOOL useLigatures) +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 composedText = attributedStringForString(plainText, - font, - useLigatures); + CFAttributedStringRef ligatureText = attributedStringForString(plainText, + font, YES); - CTLineRef line = CTLineCreateWithAttributedString(composedText); + CTLineRef ligature = CTLineCreateWithAttributedString(ligatureText); - // get the (composing)glyphs and advances for the new text - UniCharCount offset = fetchGlyphsAndAdvances(line, glyphs, NULL, - isComposing ? positions : NULL, - length); + CGSize ligatureRanges[length], regularRanges[length]; - CFRelease(composedText); - CFRelease(line); + // 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); - // as ligatures composing characters it is required to adjust the + 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; } @@ -157,12 +196,18 @@ composeGlyphsForChars(const unichar *chars, CGGlyph *glyphs, void recurseDraw(const unichar *chars, CGGlyph *glyphs, CGPoint *positions, UniCharCount length, CGContextRef context, CTFontRef fontRef, - NSMutableArray *fontCache, BOOL isComposing, BOOL useLigatures) + NSMutableArray *fontCache, BOOL useLigatures) { if (CTFontGetGlyphsForCharacters(fontRef, chars, glyphs, length)) { // All chars were mapped to glyphs, so draw all at once and return. - length = composeGlyphsForChars(chars, glyphs, positions, length, - fontRef, isComposing, useLigatures); + 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; } @@ -223,7 +268,7 @@ recurseDraw(const unichar *chars, CGGlyph *glyphs, CGPoint *positions, return; recurseDraw(chars, glyphs, positions, attemptedCount, context, - fallback, fontCache, isComposing, useLigatures); + fallback, fontCache, useLigatures); // If only a portion of the invalid range was rendered above, // the remaining range needs to be attempted by subsequent @@ -247,6 +292,4 @@ recurseDraw(const unichar *chars, CGGlyph *glyphs, CGPoint *positions, } } -// @formatter:on - #pragma clang diagnostic pop diff --git a/NvimView/NvimView/TextDrawer.m b/NvimView/NvimView/TextDrawer.m index 352fac8e..a391e44d 100644 --- a/NvimView/NvimView/TextDrawer.m +++ b/NvimView/NvimView/TextDrawer.m @@ -192,7 +192,7 @@ static CGColorRef color_for(NSInteger value) { const UniChar *bEnd = unichars + unilength; UniCharCount choppedLength; bool wide; - bool pWide = false; + bool pWide = NO; while (b < bEnd) { wide = CFStringIsSurrogateHighCharacter(*b) || CFStringIsSurrogateLowCharacter(*b); @@ -200,8 +200,7 @@ static CGColorRef color_for(NSInteger value) { choppedLength = b - bStart; // NSString *logged = [NSString stringWithCharacters:bStart length:choppedLength]; // NSLog(@"C(%d,%p..%p)[%@]", pWide, bStart, b, logged); - // We use isComposing = false to retain the old behavior of Macvim's recurseDraw - recurseDraw(bStart, glyphs, p, choppedLength, context, fontWithTraits, _fontLookupCache, false, _usesLigatures); + recurseDraw(bStart, glyphs, p, choppedLength, context, fontWithTraits, _fontLookupCache, _usesLigatures); UniCharCount step = pWide ? choppedLength / 2 : choppedLength; p += step; g += step; @@ -215,8 +214,7 @@ static CGColorRef color_for(NSInteger value) { choppedLength = b - bStart; // NSString *logged = [NSString stringWithCharacters:bStart length:choppedLength]; // NSLog(@"T(%d,%p..%p)[%@]", pWide, bStart, b, logged); - // We use isComposing = false to retain the old behavior of Macvim's recurseDraw - recurseDraw(bStart, glyphs, p, choppedLength, context, fontWithTraits, _fontLookupCache, false, _usesLigatures); + recurseDraw(bStart, glyphs, p, choppedLength, context, fontWithTraits, _fontLookupCache, _usesLigatures); } // NSLog(@"S(-,%p..%p)[%@]", unichars, unichars + unilength, string); diff --git a/VimR/VimR.xcodeproj/project.pbxproj b/VimR/VimR.xcodeproj/project.pbxproj index 2d9d0be2..111153bb 100644 --- a/VimR/VimR.xcodeproj/project.pbxproj +++ b/VimR/VimR.xcodeproj/project.pbxproj @@ -1234,7 +1234,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 287; + CURRENT_PROJECT_VERSION = 288; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -1291,7 +1291,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 287; + CURRENT_PROJECT_VERSION = 288; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; diff --git a/VimR/VimR/Info.plist b/VimR/VimR/Info.plist index 169e08bf..ad90124c 100644 --- a/VimR/VimR/Info.plist +++ b/VimR/VimR/Info.plist @@ -1224,7 +1224,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - SNAPSHOT-287 + SNAPSHOT-288 CFBundleSignature ???? CFBundleURLTypes @@ -1241,7 +1241,7 @@ CFBundleVersion - 287 + 288 LSApplicationCategoryType public.app-category.productivity LSMinimumSystemVersion diff --git a/VimR/VimRTests/Info.plist b/VimR/VimRTests/Info.plist index d945dfcc..6f081c21 100644 --- a/VimR/VimRTests/Info.plist +++ b/VimR/VimRTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - SNAPSHOT-287 + SNAPSHOT-288 CFBundleSignature ???? CFBundleVersion - 287 + 288 diff --git a/appcast_snapshot.xml b/appcast_snapshot.xml index 28a1b03c..967bc588 100644 --- a/appcast_snapshot.xml +++ b/appcast_snapshot.xml @@ -7,22 +7,25 @@ Most recent changes with links to updates for VimR. en - SNAPSHOT-287 + SNAPSHOT-288 -
  • GH-659: Bugfix (introduced in a snapshot): Turning off ligatures does not really turn off ligatures.
  • +
  • GH-659: Bugfix (introduced in a snapshot): Turning off ligatures does not really turn off ligatures.
      +
    • Reverts the update on MMCoreTextView.
    • +
    +
  • ]]>
    - https://github.com/qvacua/vimr/releases/tag/snapshot/287 + https://github.com/qvacua/vimr/releases/tag/snapshot/288 - 2018-07-17T21:47:39.216538 + 2018-07-18T17:04:18.666713 10.10.0 -
    diff --git a/resources/release-notes.md b/resources/release-notes.md index 4e0e03a7..1df38ad6 100644 --- a/resources/release-notes.md +++ b/resources/release-notes.md @@ -7,7 +7,6 @@ * Dependencies updates: - ReactiveX/RxSwift@4.2.0 - httpswift/swifter@1.4.2 - - `MMCoreTextView` of MacVim: macvim-dev/macvim@351faf929e4abe32ea4cc31078d1a625fc86a69f # 0.24.0-282