[coretext] Compare CGFont and PS name, if CTFont didn't match

See comments.

Fixes vertical text.  CoreText backend is in very good shape now!

Also see:
5a0eed3b50
25f4fb9b56

Fixes http://github.com/behdad/harfbuzz/pull/36
This commit is contained in:
Behdad Esfahbod 2014-08-12 10:32:41 -04:00
parent 5a0eed3b50
commit fd0001d7db
1 changed files with 48 additions and 6 deletions

View File

@ -760,7 +760,7 @@ retry:
/* CoreText does automatic font fallback (AKA "cascading") for characters
* not supported by the requested font, and provides no way to turn it off,
* so we detect if the returned run uses a font other than the requested
* so we must detect if the returned run uses a font other than the requested
* one and fill in the buffer with .notdef glyphs instead of random glyph
* indices from a different font.
*/
@ -768,11 +768,34 @@ retry:
CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
if (!CFEqual (run_ct_font, font_data->ct_font))
{
/* The run doesn't use our main font. See if it uses any of our subfonts
* created to set font features... Only if the font didn't match any of
* those, consider reject the font. What we really want is to check the
* underlying CGFont, but apparently there's no safe way to do that.
* See: http://github.com/behdad/harfbuzz/pull/36 */
/* The run doesn't use our main font instance. We have to figure out
* whether font fallback happened, or this is just CoreText giving us
* another CTFont using the same underlying CGFont. CoreText seems
* to do that in a variety of situations, one of which being vertical
* text, but also perhaps for caching reasons.
*
* First, see if it uses any of our subfonts created to set font features...
*
* Next, compare the CGFont to the one we used to create our fonts.
* Even this doesn't work all the time.
*
* Finally, we compare PS names, which I don't think are unique...
*
* Looks like if we really want to be sure here we have to modify the
* font to change the name table, similar to what we do in the uniscribe
* backend.
*
* However, even that wouldn't work if we were passed in the CGFont to
* begin with.
*
* Webkit uses a slightly different approach: it installs LastResort
* as fallback chain, and then checks PS name of used font against
* LastResort. That one is safe for any font except for LastResort,
* as opposed to ours, which can fail if we are using any uninstalled
* font that has the same name as an installed font.
*
* See: http://github.com/behdad/harfbuzz/pull/36
*/
bool matched = false;
for (unsigned int i = 0; i < range_records.len; i++)
if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
@ -781,6 +804,25 @@ retry:
break;
}
if (!matched)
{
CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
if (run_cg_font)
{
matched = CFEqual (run_cg_font, face_data);
CFRelease (run_cg_font);
}
}
if (!matched)
{
CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
CFRelease (run_ps_name);
CFRelease (font_ps_name);
if (result == kCFCompareEqualTo)
matched = true;
}
if (!matched)
{
CFRange range = CTRunGetStringRange (run);
DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",