@@ -150,6 +150,7 @@ - (void)dealloc
150150
151151 if (glyphs) { free (glyphs); glyphs = NULL ; }
152152 if (advances) { free (advances); advances = NULL ; }
153+ if (positions) { free (positions); positions = NULL ; }
153154
154155 [super dealloc ];
155156}
@@ -307,7 +308,23 @@ - (void)setWideFont:(NSFont *)newFont
307308 // NOTE: No need to set point size etc. since this is taken from the
308309 // regular font when drawing.
309310 [fontWide release ];
310- fontWide = [newFont retain ];
311+
312+ emojiEnabled = [[self vimController ] emojiEnabled ];
313+ if (emojiEnabled) {
314+ // Use 'Apple Color Emoji' font for rendering emoji
315+ CGFloat size = [newFont pointSize ];
316+ NSFontDescriptor *emojiDesc = [NSFontDescriptor
317+ fontDescriptorWithName: @" Apple Color Emoji" size: size];
318+ NSFontDescriptor *newFontDesc = [newFont fontDescriptor ];
319+ NSDictionary *attrs = [NSDictionary
320+ dictionaryWithObject: [NSArray arrayWithObject: newFontDesc]
321+ forKey: NSFontCascadeListAttribute ];
322+ NSFontDescriptor *desc =
323+ [emojiDesc fontDescriptorByAddingAttributes: attrs];
324+ fontWide = [[NSFont fontWithDescriptor: desc size: size] retain ];
325+ } else {
326+ fontWide = [newFont retain ];
327+ }
311328 }
312329}
313330
@@ -1017,19 +1034,60 @@ - (void)batchDrawData:(NSData *)data
10171034 return newFontRef;
10181035}
10191036
1037+ static UniCharCount
1038+ gatherGlyphs (CGGlyph glyphs[], UniCharCount count)
1039+ {
1040+ // Gather scattered glyphs that was happended by Surrogate pair chars
1041+ UniCharCount glyphLength = 0 ;
1042+ NSUInteger pos = NSIntegerMax;
1043+ NSUInteger i;
1044+ for (i = 0 ; i < count; ++i) {
1045+ if (glyphs[i] == 0 ) {
1046+ pos = i;
1047+ } else {
1048+ ++glyphLength;
1049+ if (pos != NSIntegerMax)
1050+ glyphs[pos++] = glyphs[i];
1051+ }
1052+ }
1053+ return glyphLength;
1054+ }
1055+
1056+ static void
1057+ drawGlyphs (CTFontRef fontRef, const CGGlyph glyphs[], const CGSize advances[],
1058+ CGPoint positions[], size_t count, CGContextRef context)
1059+ {
1060+ CGAffineTransform matrix =
1061+ CGAffineTransformInvert (CGContextGetTextMatrix (context));
1062+ positions[0 ] = CGPointZero;
1063+ NSUInteger i;
1064+ for (i = 1 ; i < count; ++i) {
1065+ CGSize advance = CGSizeApplyAffineTransform (advances[i - 1 ], matrix);
1066+ positions[i].x = positions[i - 1 ].x + advance.width ;
1067+ positions[i].y = positions[i - 1 ].y + advance.height ;
1068+ }
1069+ CTFontDrawGlyphs (fontRef, glyphs, positions, count, context);
1070+ }
1071+
10201072 static void
10211073recurseDraw (const unichar *chars, CGGlyph *glyphs, CGSize *advances,
1022- UniCharCount length, CGContextRef context, CTFontRef fontRef,
1023- float x, float y, NSMutableArray *fontCache)
1074+ CGPoint *positions, UniCharCount length, CGContextRef context,
1075+ CTFontRef fontRef, float x, float y, NSMutableArray *fontCache,
1076+ BOOL emojiEnabled)
10241077{
10251078
10261079 if (CTFontGetGlyphsForCharacters (fontRef, chars, glyphs, length)) {
10271080 // All chars were mapped to glyphs, so draw all at once and return.
1028- CGFontRef cgFontRef = CTFontCopyGraphicsFont (fontRef, NULL );
1029- CGContextSetFont (context, cgFontRef);
10301081 CGContextSetTextPosition (context, x, y);
1031- CGContextShowGlyphsWithAdvances (context, glyphs, advances, length);
1032- CGFontRelease (cgFontRef);
1082+ if (emojiEnabled) {
1083+ length = gatherGlyphs (glyphs, length);
1084+ drawGlyphs (fontRef, glyphs, advances, positions, length, context);
1085+ } else {
1086+ CGFontRef cgFontRef = CTFontCopyGraphicsFont (fontRef, NULL );
1087+ CGContextSetFont (context, cgFontRef);
1088+ CGContextShowGlyphsWithAdvances (context, glyphs, advances, length);
1089+ CGFontRelease (cgFontRef);
1090+ }
10331091 return ;
10341092 }
10351093
@@ -1042,25 +1100,45 @@ - (void)batchDrawData:(NSData *)data
10421100 // Draw as many consecutive glyphs as possible in the current font
10431101 // (if a glyph is 0 that means it does not exist in the current
10441102 // font).
1103+ BOOL surrogatePair = NO ;
10451104 while (*g && g < glyphsEnd) {
1046- ++g;
1047- ++c;
1105+ if (emojiEnabled && CFStringIsSurrogateHighCharacter (*c)) {
1106+ surrogatePair = YES ;
1107+ g += 2 ;
1108+ c += 2 ;
1109+ } else {
1110+ ++g;
1111+ ++c;
1112+ }
10481113 x += a->width ;
10491114 ++a;
10501115 }
10511116
10521117 int count = g-glyphs;
1053- CGFontRef cgFontRef = CTFontCopyGraphicsFont (fontRef, NULL );
1054- CGContextSetFont (context, cgFontRef);
10551118 CGContextSetTextPosition (context, x0, y);
1056- CGContextShowGlyphsWithAdvances (context, glyphs, advances, count);
1057- CGFontRelease (cgFontRef);
1119+ if (emojiEnabled) {
1120+ if (surrogatePair)
1121+ count = gatherGlyphs (glyphs, count);
1122+ drawGlyphs (fontRef,
1123+ glyphs, advances, positions, count, context);
1124+ } else {
1125+ CGFontRef cgFontRef = CTFontCopyGraphicsFont (fontRef, NULL );
1126+ CGContextSetFont (context, cgFontRef);
1127+ CGContextShowGlyphsWithAdvances (
1128+ context, glyphs, advances, count);
1129+ CGFontRelease (cgFontRef);
1130+ }
10581131 } else {
10591132 // Skip past as many consecutive chars as possible which cannot be
10601133 // drawn in the current font.
10611134 while (0 == *g && g < glyphsEnd) {
1062- ++g;
1063- ++c;
1135+ if (emojiEnabled && CFStringIsSurrogateHighCharacter (*c)) {
1136+ g += 2 ;
1137+ c += 2 ;
1138+ } else {
1139+ ++g;
1140+ ++c;
1141+ }
10641142 x += a->width ;
10651143 ++a;
10661144 }
@@ -1071,8 +1149,8 @@ - (void)batchDrawData:(NSData *)data
10711149 if (!newFontRef)
10721150 return ;
10731151
1074- recurseDraw (chars, glyphs, advances, count, context, newFontRef ,
1075- x0, y, fontCache);
1152+ recurseDraw (chars, glyphs, advances, positions, count, context ,
1153+ newFontRef, x0, y, fontCache, emojiEnabled );
10761154
10771155 CFRelease (newFontRef);
10781156 }
@@ -1160,8 +1238,10 @@ - (void)drawString:(const UniChar *)chars length:(UniCharCount)length
11601238 if (length > maxlen) {
11611239 if (glyphs) free (glyphs);
11621240 if (advances) free (advances);
1241+ if (positions) free (positions);
11631242 glyphs = (CGGlyph*)malloc (length*sizeof (CGGlyph));
11641243 advances = (CGSize*)calloc (length, sizeof (CGSize));
1244+ positions = (CGPoint*)calloc (length, sizeof (CGPoint));
11651245 maxlen = length;
11661246 }
11671247
@@ -1191,8 +1271,8 @@ - (void)drawString:(const UniChar *)chars length:(UniCharCount)length
11911271 }
11921272 }
11931273
1194- recurseDraw (chars, glyphs, advances, length, context, fontRef, x,
1195- y+fontDescent, fontCache);
1274+ recurseDraw (chars, glyphs, advances, positions, length, context, fontRef, x,
1275+ y+fontDescent, fontCache, emojiEnabled );
11961276
11971277 CFRelease (fontRef);
11981278 CGContextRestoreGState (context);
0 commit comments