Skip to content

Commit 58558bd

Browse files
author
René Köcher
committed
Improve handling of emoji characters along ligatures.
1 parent 201c6b7 commit 58558bd

File tree

1 file changed

+29
-19
lines changed

1 file changed

+29
-19
lines changed

src/MacVim/MMCoreTextView.m

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ - (void)batchDrawData:(NSData *)data
10511051
nil
10521052
];
10531053

1054-
return CFAttributedStringCreate(NULL, string, attrs);
1054+
return CFAttributedStringCreate(NULL, (CFStringRef)string, (CFDictionaryRef)attrs);
10551055
}
10561056

10571057
static UniCharCount
@@ -1109,37 +1109,47 @@ - (void)batchDrawData:(NSData *)data
11091109
* The way proposed on the CoreText ML is to convert the text to an attributed
11101110
* string, create a CTLine from it and retrieve the Glyphs from the CTRuns in it.
11111111
*/
1112-
NSString *plainText = [NSString stringWithCharacters:chars length:*length];
1113-
1114-
CFAttributedStringRef regularText = attributedStringForString(plainText, font, NO);
1115-
CFAttributedStringRef ligatureText = attributedStringForString(plainText, font, YES);
1116-
1112+
CGGlyph refGlyphs[*length];
11171113
CGPoint refPositions[*length];
1114+
1115+
memcpy(refGlyphs, glyphs, sizeof(CGGlyph) * (*length));
11181116
memcpy(refPositions, positions, sizeof(CGSize) * (*length));
11191117

1120-
CTLineRef regular = CTLineCreateWithAttributedString((CFAttributedStringRef)regularText);
1121-
CTLineRef ligature = CTLineCreateWithAttributedString((CFAttributedStringRef)ligatureText);
1118+
memset(glyphs, 0, sizeof(CGGlyph) * (*length));
11221119

1123-
CFRelease(regularText);
1124-
CFRelease(ligatureText);
1120+
NSString *plainText = [NSString stringWithCharacters:chars length:*length];
1121+
CFAttributedStringRef ligatureText = attributedStringForString(plainText, font, YES);
1122+
1123+
CTLineRef ligature = CTLineCreateWithAttributedString(ligatureText);
11251124

11261125
CGSize ligatureRanges[*length], regularRanges[*length];
11271126

11281127
// get the (ligature)glyphs and advances for the new text
11291128
UniCharCount offset = fetchGlyphsAndAdvances(ligature, glyphs, ligatureRanges, length);
1130-
// do the same but only for the advances for the base text
1131-
fetchGlyphsAndAdvances(regular, NULL, regularRanges, length);
1129+
// fetch the advances for the base text
1130+
CTFontGetAdvancesForGlyphs(font, kCTFontOrientationDefault, refGlyphs, regularRanges, *length);
1131+
1132+
CFRelease(ligatureText);
1133+
CFRelease(ligature);
11321134

11331135
// tricky part: compare both advance ranges and chomp positions which
1134-
// are covered by a single ligature
1136+
// are covered by a single ligature while keeping glyphs not in the ligature font.
11351137
#define fequal(a, b) (fabs( (a) - (b) ) < FLT_EPSILON)
1138+
#define fless(a, b)((a) - (b) < FLT_EPSILON) && (fabs( (a) - (b) ) > FLT_EPSILON)
1139+
11361140
CFIndex skip = 0;
11371141
for( CFIndex i = 0; i < offset && skip + i < *length; ++i ) {
11381142
memcpy(&positions[i], &refPositions[skip + i], sizeof(CGSize));
11391143

11401144
if( fequal(ligatureRanges[i].width, regularRanges[skip + i].width) ) {
11411145
// [mostly] same width
11421146
continue;
1147+
1148+
} else if( fless(ligatureRanges[i].width, regularRanges[skip + i].width) ) {
1149+
// original is wider than our result - use the original glyph
1150+
// FIXME: this is currently the only way to detect emoji (except for 'glyph[i] == 5')
1151+
glyphs[i] = refGlyphs[skip + i];
1152+
continue;
11431153
}
11441154

11451155
// no, that's a ligature
@@ -1154,14 +1164,13 @@ - (void)batchDrawData:(NSData *)data
11541164
}
11551165
skip += j;
11561166
}
1167+
1168+
#undef fless
11571169
#undef fequal
11581170

11591171
// as ligatures combine characters it is required to adjust the
11601172
// original length value
11611173
*length = offset;
1162-
1163-
CFRelease(regular);
1164-
CFRelease(ligature);
11651174
}
11661175

11671176
static void
@@ -1171,10 +1180,11 @@ - (void)batchDrawData:(NSData *)data
11711180
{
11721181
if (CTFontGetGlyphsForCharacters(fontRef, chars, glyphs, length)) {
11731182
// All chars were mapped to glyphs, so draw all at once and return.
1174-
length = gatherGlyphs(glyphs, length);
11751183
if (useLigatures) {
1176-
memset(glyphs, 0, sizeof(CGGlyph) * length);
1177-
ligatureGlyphsForChars(chars, glyphs, positions, &length, fontRef);
1184+
ligatureGlyphsForChars(chars, glyphs, positions, &length, fontRef);
1185+
} else {
1186+
// only fixup surrogate pairs if we're not using ligatures
1187+
length = gatherGlyphs(glyphs, length);
11781188
}
11791189

11801190
CTFontDrawGlyphs(fontRef, glyphs, positions, length, context);

0 commit comments

Comments
 (0)