I let my user choose a font from their installed fonts, then use that font in three different contexts in my macOS app.
NSFontDescriptor
to create an attributed string, then displays that in the list of choices: NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithName:@"Candara" size:14];
NSDictionary *attributes = @{NSFontAttributeName: [NSFont fontWithDescriptor:fontDescriptor size:14]};
attributedString = [[NSAttributedString alloc] initWithString:@"New Attributed String" attributes:attributes];
NSTextField
. NSString *htmlString = @"<!DOCTYPE html>"
"<html>"
"<head>"
"<style>"
"body { font-family: 'Candara', serif; font-size: 14px; }"
"</style>"
"</head>"
"<body>"
"<p>Text with <b>bold</b> or <i>italics</i> maybe.</p>"
"</body>"
"</html>";
NSData *htmlData = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)};
NSError *error;
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:htmlData
options:options
documentAttributes:nil
error:&error];
WKWebView
.This was all working well for years. When macOS 14 came along, what I find is that option 1 (initializing an NSAttributedString
with some text using the Candara font) works fine, as does option 3 (displaying a lot of HTML that uses the Candara font in a WKWebView
). But option 2 doesn't work at all. The output is all the "undefined character" glyph — a box containing a question mark, one for each character in the string.
I'm seeing this behavior when the user selects Calibri or Candara, which are both Microsoft fonts. I'm also seeing it with SF Pro, which is an Apple font. Any other font is fine. (At least from what I've seen so far.)
Providing a fallback font (as shown above with "serif
") doesn't change anything. The rendering does not fall back to the fallback font; it seems to really think it can use Candara when obviously it can't.
This behavior very definitely appeared with the introduction of macOS 14, and mostly affects those who have chosen one of the Microsoft Office fonts (Calibri and Candara for sure). But as I said, other fonts can produce these results.
Definitively this looks like a bug, some fonts exhibit the buggy behavior some don't. For example non-existing fonts, or maybe fonts with typos in names, work just file, the system falls back to the Times New Roman font.
Printing a problematic attributed string outputs this:
> po attributedString
Text with bold or italics maybe.
{
NSFont = "\"LastResort 14.00 pt. P [] (0x7ff575f14980) fobj=0x7ff575f14980, spc=16.06\"";
NSKern = 0;
NSParagraphStyle = "Alignment Natural, LineSpacing 0, ParagraphSpacing 14, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode WordWrapping, Tabs (\n), DefaultTabInterval 36, Blocks (\n), Lists (\n), BaseWritingDirection LeftToRight, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
NSStrokeColor = "sRGB IEC61966-2.1 colorspace 0 0 0 1";
NSStrokeWidth = 0;
}
For some fonts (or perhaps some string values), macOS falls back to Apple's Last Resort font font. This is clearly the incorrect behaviour for some of the existing fonts, and this is why you see those odd glyphs, as macOS incorrectly maps the font to the LastResort
one, instead to the specified font, or at least to the second font specified in the CSS rule.