5

CreateTextFormat的文档没有说明字体回退选择,但如果选择了默认(NULL = 系统)集合,那么 DirectWrite 显然实现了字体回退。例如,如果我将在 Gabriola 字体中找不到的两个字形添加到 DirectWrite SDK 演示应用程序使用的测试字符串中,那么 DirectWrite 会从 Segoe UI Symbol 字体中挑选缺少的字形。这发生在基本DrawText调用和自定义渲染器(对字体回退没有自定义),如下所示(唯一的修改是测试字符串):

在此处输入图像描述

复选标记和白星来自 Segoe UI Symbol,而不是来自 Gabriola,即使在演示应用程序中只指定了 Gabriola。那么,有谁知道 DirectWrite(CreateTextFormat)如何选择后备字体?

更新。我看到有一个GetSystemFontFallback可以列出备用字体,但它仅在 Windows 8.1 中可用(因为它在 IDWriteFactory2 中)。我猜他们已经注意到 API 在枚举后备字体方面的差距。所以我猜在 Windows 8.1 之前没有办法做到这一点,但如果有人知道黑客/解决方法......

更新2。引用MSFT 员工的话:

DirectWrite 具有未从注册表读取或以任何方式可配置的后备数据。不过,在 Windows 8.1 中,引入了 API,允许应用指定自己的回退。(它类似于用于创建复合字体定义的 WPF API。)

这仍然不能准确解释硬编码算法/替换方案实际上是什么。

4

1 回答 1

3

IDWriteTextLayout调用IDWriteFontFallback::MapCharacters将每个 Unicode 字符映射到字体系列的有序列表,这些字体系列会一直尝试直到满足该字符。想象一个循环逐个读取每个字符,将代码点值和语言标记映射到 Unicode 范围,并在 cmap 表中支持该字符的第一个字体处停止。伪代码:

for each ch in text
    if ch is a combining mark or other similar extending character
        if the previously selected font supports the combining mark too
            use the previously selected font
            continue
        endif
    endif
    find first mapping for ch within the Unicode range, which matches
        the current language and base font family too (if pertinent)
    if mapping found
        for each font in mapping (starting with first listed)
            if ch in font cmap
                use current font
            endif
        endfor
    else
        use base font and undefined (.notdef) glyph
    endif
endfor

还有逻辑来确定后备语言环境(例如 for zh-Hans/Hant或一般ja匹配更具体的ja-jp)。它有点类似于(但不那么复杂)CSS为浏览器[http://www.w3.org/TR/css3-fonts/#font-matching-algorithm]指定的字体回退算法,并且类似于使用的回退算法通过 WPF/XAML/Silverlight。

请参阅IDWriteFontFallbackBuilder::AddMapping用于构建自定义后备列表的 API (Win 8.1+),以了解所使用的输入。

有关示例数据,请参见 C:\Windows\Fonts\GlobalUserInterface.CompositeFont(注意此文件实际上是用于 WPF,与 DWrite 使用的定义不完全相同)。

<FontFamilyMap
    Unicode  = "3000-30FF, 31F0-31FF"
    Language = "ja"
    Target   = "Meiryo UI, Meiryo, Microsoft YaHei UI, Microsoft YaHei, MS Gothic, MingLiu, Arial Unicode MS"
    Scale    = "1.0" />
于 2015-07-02T09:11:33.043 回答