为什么我在 macOS 14 中从 HTML 创建 NSAttributedString 时看到不同的行为,而不是使用 initWithString:attributes: 执行相同的操作?

Why am I seeing different behavior in macOS 14 when creating NSAttributedString from HTML vs doing the same thing with initWithString:attributes:?

提问人:Craig 提问时间:11/4/2023 更新时间:11/5/2023 访问量:25

问:

我让我的用户从他们安装的字体中选择一种字体,然后在我的 macOS App 中在三种不同的上下文中使用该字体。

  1. 字体列表本身用于创建属性化字符串,然后在选项列表中显示该字符串:NSFontDescriptor
    NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithName:@"Candara" size:14];
    NSDictionary *attributes = @{NSFontAttributeName: [NSFont fontWithDescriptor:fontDescriptor size:14]};
    attributedString = [[NSAttributedString alloc] initWithString:@"New Attributed String" attributes:attributes];
  1. 在某些地方,我有一个非常小的 HTML 文档,我在其中将正文字体设置为所选字体,转换为属性字符串,并以 .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];
  1. 最后,我在一些地方有较长的 HTML 文档,这些文档的字体与正文字体相同,并显示在 .WKWebView

多年来,这一切都运作良好。当 macOS 14 出现时,我发现选项 1(使用 Candara 字体用一些文本初始化)工作正常,选项 3(显示大量使用 Candara 字体的 HTML)也是如此。但是选项 2 根本不起作用。输出是所有“未定义字符”字形 - 一个包含问号的框,字符串中的每个字符一个问号。NSAttributedStringWKWebView

当用户选择 Calibri 或 Candara 时,我看到了这种行为,它们都是 Microsoft 字体。我也在 SF Pro 上看到它,这是一种 Apple 字体。任何其他字体都可以。(至少从我目前所看到的情况来看。

提供回退字体(如上图所示的“”)不会更改任何内容。呈现不会回退到回退字体;它似乎真的认为它可以使用 Candara,而显然它不能。serif

这种行为非常肯定地出现在 macOS 14 的推出中,并且主要影响那些选择了 Microsoft Office 字体之一(肯定是 Calibri 和 Candara)的人。但正如我所说,其他字体可以产生这些结果。

HTML Objective-C 字体 nsattributedstring macOS-sonoma

评论

0赞 Cristik 11/5/2023
其他字体似乎以类似的方式运行,也不起作用,至少在我这边不起作用。Proxima Nova

答:

0赞 Cristik 11/5/2023 #1

毫无疑问,这看起来像一个错误,有些字体表现出错误的行为,有些则没有。例如,不存在的字体,或者名称中有拼写错误的字体,只能使用文件,系统会回退到 Times New Roman 字体。

打印有问题的属性字符串会输出以下内容:

> 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;
}

对于某些字体(或某些字符串值),macOS 会回退到 Apple 的 Last Resort 字体。对于某些现有字体来说,这显然是不正确的行为,这就是为什么您会看到这些奇怪的字形,因为 macOS 错误地将字体映射到一种字体,而不是指定的字体,或者至少映射到 CSS 规则中指定的第二种字体。LastResort