diff --git a/src/MacVim/MMCoreTextView.m b/src/MacVim/MMCoreTextView.m index c582c46518..32d8496cf4 100644 --- a/src/MacVim/MMCoreTextView.m +++ b/src/MacVim/MMCoreTextView.m @@ -986,26 +986,31 @@ - (void)batchDrawData:(NSData *)data } static CTFontRef -lookupFont(NSMutableArray *fontCache, const unichar *chars, +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]; - CGGlyph glyphs[1]; - if (CTFontGetGlyphsForCharacters((CTFontRef)font, chars, glyphs, 1)) + 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, 1 }; - CFStringRef strRef = CFStringCreateWithCharacters(NULL, chars, 1); + 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]; @@ -1055,16 +1060,33 @@ - (void)batchDrawData:(NSData *)data ++p; } - // Figure out which font to draw these chars with. + // 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; - CTFontRef newFontRef = lookupFont(fontCache, chars, fontRef); - if (!newFontRef) - return; + 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); - recurseDraw(chars, glyphs, positions, count, context, newFontRef, - fontCache); + // 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(newFontRef); + CFRelease(fallback); } chars = c;