Skip to content

Commit 4237cc8

Browse files
committed
Fix potential CoreText font rendering infinite recursion
The function `recurseDraw` is actually a misnomer. It uses recursion in a way that is unnecessary as it's a simple while loop that keeps drawing as many characters as possible until all are drawn. The recursion is just a convenience to invoke the CoreText rendering code. If the API for `CTFontGetGlyphsForCharacters` works as expected, in theory we shouldn't get infinite recursion since `lookupFont` calls the same function, but just for safety and to avoid potential subtle interactions, just kill the recursion and directly draw the texts in the loop to make it easier to reason through. Fix #983.
1 parent 1fedb06 commit 4237cc8

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

src/MacVim/MMCoreTextView.m

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,7 @@ - (void)batchDrawData:(NSData *)data
17101710

17111711
static CTFontRef
17121712
lookupFont(NSMutableArray *fontCache, const unichar *chars, UniCharCount count,
1713-
CTFontRef currFontRef)
1713+
CTFontRef currFontRef, CGGlyph *glyphsOut)
17141714
{
17151715
CGGlyph glyphs[count];
17161716

@@ -1720,7 +1720,10 @@ - (void)batchDrawData:(NSData *)data
17201720
NSFont *font = [fontCache objectAtIndex:i];
17211721

17221722
if (CTFontGetGlyphsForCharacters((CTFontRef)font, chars, glyphs, count))
1723+
{
1724+
memcpy(glyphsOut, glyphs, count * sizeof(CGGlyph*));
17231725
return (CTFontRef)[font retain];
1726+
}
17241727
}
17251728

17261729
// Ask Core Text for a font (can be *very* slow, which is why we cache
@@ -1737,6 +1740,7 @@ - (void)batchDrawData:(NSData *)data
17371740
if (newFontRef)
17381741
[fontCache addObject:(NSFont *)newFontRef];
17391742

1743+
memcpy(glyphsOut, glyphs, count * sizeof(CGGlyph*));
17401744
return newFontRef;
17411745
}
17421746

@@ -1840,6 +1844,8 @@ - (void)batchDrawData:(NSData *)data
18401844
UniCharCount length, CGContextRef context, CTFontRef fontRef,
18411845
NSMutableArray *fontCache, BOOL isComposing, BOOL useLigatures)
18421846
{
1847+
// Note: This function is misnamed. It does not actually use recursion and
1848+
// will be renamed in future.
18431849
if (CTFontGetGlyphsForCharacters(fontRef, chars, glyphs, length)) {
18441850
// All chars were mapped to glyphs, so draw all at once and return.
18451851
length = isComposing || useLigatures
@@ -1897,17 +1903,21 @@ - (void)batchDrawData:(NSData *)data
18971903
CTFontRef fallback = nil;
18981904
while (fallback == nil && attemptedCount > 0) {
18991905
fallback = lookupFont(fontCache, chars, attemptedCount,
1900-
fontRef);
1906+
fontRef, glyphs);
19011907
if (!fallback)
19021908
attemptedCount /= 2;
19031909
}
19041910

19051911
if (!fallback)
19061912
return;
19071913

1908-
recurseDraw(chars, glyphs, positions, attemptedCount, context,
1909-
fallback, fontCache, isComposing, useLigatures);
1914+
UniCharCount actualAttemptLength = isComposing || useLigatures
1915+
? composeGlyphsForChars(chars, glyphs, positions, attemptedCount,
1916+
fallback, isComposing, useLigatures)
1917+
: gatherGlyphs(glyphs, attemptedCount);
1918+
CTFontDrawGlyphs(fallback, glyphs, positions, actualAttemptLength, context);
19101919

1920+
// TODO: This doesn't take into account surrogate pairs for 'p'. Clean this up.
19111921
// If only a portion of the invalid range was rendered above,
19121922
// the remaining range needs to be attempted by subsequent
19131923
// iterations of the draw loop.

0 commit comments

Comments
 (0)