@@ -125,6 +125,7 @@ - (id)initWithFrame:(NSRect)frame
125125 antialias = YES ;
126126
127127 drawData = [[NSMutableArray alloc ] init ];
128+ fontCache = [[NSMutableArray alloc ] init ];
128129
129130 helper = [[MMTextViewHelper alloc ] init ];
130131 [helper setTextView: self ];
@@ -142,6 +143,7 @@ - (void)dealloc
142143 [defaultBackgroundColor release ]; defaultBackgroundColor = nil ;
143144 [defaultForegroundColor release ]; defaultForegroundColor = nil ;
144145 [drawData release ]; drawData = nil ;
146+ [fontCache release ]; fontCache = nil ;
145147
146148 [helper setTextView: nil ];
147149 [helper release ]; helper = nil ;
@@ -291,6 +293,8 @@ - (void)setFont:(NSFont *)newFont
291293 cellSize.height = linespace + defaultLineHeightForFont (font);
292294
293295 fontDescent = ceil (CTFontGetDescent (fontRef));
296+
297+ [fontCache removeAllObjects ];
294298}
295299
296300- (void )setWideFont : (NSFont *)newFont
@@ -986,15 +990,42 @@ - (void)batchDrawData:(NSData *)data
986990#endif
987991}
988992
993+ static CTFontRef
994+ lookupFont (NSMutableArray *fontCache, const unichar *chars,
995+ CTFontRef currFontRef)
996+ {
997+ // See if font in cache can draw at least one character
998+ NSUInteger i;
999+ for (i = 0 ; i < [fontCache count ]; ++i) {
1000+ NSFont *font = [fontCache objectAtIndex: i];
1001+ CGGlyph glyphs[1 ];
1002+
1003+ if (CTFontGetGlyphsForCharacters ((CTFontRef)font, chars, glyphs, 1 ))
1004+ return (CTFontRef)[font retain ];
1005+ }
1006+
1007+ // Ask Core Text for a font (can be *very* slow, which is why we cache
1008+ // fonts in the first place)
1009+ CFRange r = { 0 , 1 };
1010+ CFStringRef strRef = CFStringCreateWithCharacters (NULL , chars, 1 );
1011+ CTFontRef newFontRef = CTFontCreateForString (currFontRef, strRef, r);
1012+ CFRelease (strRef);
1013+
1014+ if (newFontRef)
1015+ [fontCache addObject: (NSFont *)newFontRef];
1016+
1017+ return newFontRef;
1018+ }
1019+
9891020 static void
9901021recurseDraw (const unichar *chars, CGGlyph *glyphs, CGSize *advances,
9911022 UniCharCount length, CGContextRef context, CTFontRef fontRef,
992- float x, float y)
1023+ float x, float y, NSMutableArray *fontCache )
9931024{
994- CGFontRef cgFontRef = CTFontCopyGraphicsFont (fontRef, NULL );
9951025
9961026 if (CTFontGetGlyphsForCharacters (fontRef, chars, glyphs, length)) {
9971027 // All chars were mapped to glyphs, so draw all at once and return.
1028+ CGFontRef cgFontRef = CTFontCopyGraphicsFont (fontRef, NULL );
9981029 CGContextSetFont (context, cgFontRef);
9991030 CGContextSetTextPosition (context, x, y);
10001031 CGContextShowGlyphsWithAdvances (context, glyphs, advances, length);
@@ -1019,9 +1050,11 @@ - (void)batchDrawData:(NSData *)data
10191050 }
10201051
10211052 int count = g-glyphs;
1053+ CGFontRef cgFontRef = CTFontCopyGraphicsFont (fontRef, NULL );
10221054 CGContextSetFont (context, cgFontRef);
10231055 CGContextSetTextPosition (context, x0, y);
10241056 CGContextShowGlyphsWithAdvances (context, glyphs, advances, count);
1057+ CGFontRelease (cgFontRef);
10251058 } else {
10261059 // Skip past as many consecutive chars as possible which cannot be
10271060 // drawn in the current font.
@@ -1034,18 +1067,12 @@ - (void)batchDrawData:(NSData *)data
10341067
10351068 // Figure out which font to draw these chars with.
10361069 UniCharCount count = c - chars;
1037- CFRange r = { 0 , count };
1038- CFStringRef strRef = CFStringCreateWithCharactersNoCopy (
1039- NULL , chars, count, kCFAllocatorNull );
1040- CTFontRef newFontRef = CTFontCreateForString (fontRef, strRef, r);
1041- CFRelease (strRef);
1042- if (!newFontRef) {
1043- CGFontRelease (cgFontRef);
1070+ CTFontRef newFontRef = lookupFont (fontCache, chars, fontRef);
1071+ if (!newFontRef)
10441072 return ;
1045- }
10461073
10471074 recurseDraw (chars, glyphs, advances, count, context, newFontRef,
1048- x0, y);
1075+ x0, y, fontCache );
10491076
10501077 CFRelease (newFontRef);
10511078 }
@@ -1055,8 +1082,6 @@ - (void)batchDrawData:(NSData *)data
10551082 advances = a;
10561083 x0 = x;
10571084 }
1058-
1059- CGFontRelease (cgFontRef);
10601085}
10611086
10621087- (void )drawString : (const UniChar *)chars length : (UniCharCount)length
@@ -1167,7 +1192,7 @@ - (void)drawString:(const UniChar *)chars length:(UniCharCount)length
11671192 }
11681193
11691194 recurseDraw (chars, glyphs, advances, length, context, fontRef, x,
1170- y+fontDescent);
1195+ y+fontDescent, fontCache );
11711196
11721197 CFRelease (fontRef);
11731198 CGContextRestoreGState (context);
@@ -1251,7 +1276,6 @@ - (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape
12511276{
12521277 CGContextRef context = [[NSGraphicsContext currentContext ] graphicsPort ];
12531278 NSRect rect = [self rectForRow: row column: col numRows: 1 numColumns: 1 ];
1254- CGRect clipRect = *(CGRect *)▭
12551279
12561280 CGContextSaveGState (context);
12571281
@@ -1272,18 +1296,16 @@ - (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape
12721296 // over into adjacent display cells and it may look ugly.
12731297 CGContextSetShouldAntialias (context, NO );
12741298
1275- // Even though antialiasing is disabled and we adjust the rect to fit
1276- // inside the display cell it still happens on Retina displays (only) that
1277- // the cursor bleeds over into the neighboring cells. To work around this
1278- // issue we enable clipping.
1279- CGContextClipToRect (context, clipRect);
1280-
12811299 if (MMInsertionPointHollow == shape) {
12821300 // When stroking a rect its size is effectively 1 pixel wider/higher
12831301 // than we want so make it smaller to avoid having it bleed over into
12841302 // the adjacent display cell.
1303+ // We also have to shift the rect by half a point otherwise it will be
1304+ // partially drawn outside its bounds on a Retina display.
12851305 rect.size .width -= 1 ;
12861306 rect.size .height -= 1 ;
1307+ rect.origin .x += 0.5 ;
1308+ rect.origin .y += 0.5 ;
12871309
12881310 CGContextSetRGBStrokeColor (context, RED (color), GREEN (color),
12891311 BLUE (color), ALPHA (color));
0 commit comments