Welcome

首页 / 软件开发 / C++ / 借助 C++ 进行 Windows 开发:使用 DirectWrite 和最新 C++ 管理字体

借助 C++ 进行 Windows 开发:使用 DirectWrite 和最新 C++ 管理字体2014-04-03 MSDN Kenny KerrDirectWrite 是一种相当强大的文本布局 API。 它支持从 XAML 和 Office 2013 的 Windows 运行 时 (WinRT) 实现到 Internet Explorer 11 和更高版本的几乎所有领先 Windows 应用程序和技术。 它 本身并不是呈现引擎,但与 Direct2D 有很近的关系,是 Direct2D 在 DirectX 系列中的同级产品。 当然,Direct2D 是首要的硬件加速即时模式图形 API。

您可以将 DirectWrite 与 Direct2D 结合使用,以提供硬件加速的文本呈现。 说明一下,之前我 在 DirectWrite 方面的著述并不多。 我不希望您认为 Direct2D 只是 DirectWrite 呈现引擎。 Direct2D 远不只如此。 DirectWrite 还有其他很多功能,在本月的专栏中,我将演示一些使用 DirectWrite 可 以完成的任务,看看最新 C++ 是如何帮助简化编程模型的。
DirectWrite API

我将使用 DirectWrite 探究系统字体集。 首先,我需要获取 DirectWrite 工厂对象。 这是编写 任 何要使用 DirectWrite 的出色排版功能的应用程序的第一步。 与大多数 Windows API 相同, DirectWrite 也依赖于 COM 基础内容。 我需要调用 DWriteCreateFactory 函数来创建 DirectWrite 工厂对象。 此函数返回一个指向该工厂对象的 COM 接口:

ComPtr<IDWriteFactory2> factory;

IDWriteFactory2 接口是今年早些时候随 Windows 8.1 和 DirectX 11.2 推出的最新版本 DirectWrite 工厂接口。 IDWriteFactory2 继承自 IDWrite­Factory1,而 IDWrite­Factory1 继承自 IDWriteFactory。 后者是原始的 DirectWrite 工厂接口,它公开了大部分工厂功能。

我将基于前面的 ComPtr 类模板调用 DWriteCreateFactory 函数:

HR(DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED,
 __uuidof(factory),
reinterpret_cast<IUnknown **>(factory.GetAddressOf())));

DirectWrite 包含一项名为 Windows 字体缓存服务 (FontCache) 的 Windows 服务。 第一个参数 指 示获得的工厂是否参与此跨过程缓存的字体使用。 有 DWRITE_FACTORY_TYPE_SHARED 和 DWRITE_FACTORY_TYPE_ISOLATED 两个选项。 SHARED 和 ISOLATED 工厂都可以利用已缓存的字体数据 。 只有 SHARED 工厂向缓存返回字体数据。 第二个参数具体指示我希望在第三个和最后一个参数中返回 哪 个版本的 DirectWrite 工厂接口。

在 DirectWrite 工厂对象给定的情况下,我可以直接要求其提供系统字体集:

             ComPtr<IDWriteFontCollection> fonts;
   HR(factory->GetSystemFontCollection(fonts.GetAddressOf()));

GetSystemFontCollection 方法的第二个参数是可选的,指示其是否检查已安装字体集的更新或更 改 。 幸运的是,这个参数默认为 false,因此,除非要确保结果集反映最近的更改,否则不必考虑它。 在字体集给定的情况下,我可以获取集合中的字体系列数,如下所示:

             unsigned const count = fonts- >GetFontFamilyCount();

然后我使用 GetFontFamily 方法通过从零开始的索引检索单个字体系列对象。 一个字体系列对象 表 示这样一组字体:它们共享一个名称,当然也是一种设计,但粗细、样式和拉伸并不相同:

             ComPtr<IDWriteFontFamily> family;
   HR(fonts->GetFontFamily(index, family.GetAddressOf()));

IDWriteFontFamily 接口继承自 IDWriteFontList 接口,因此,我可以枚举该字体系列中的各种字 体。 能够检索字体系列名称合乎情理并且非常有用。 不过,系列名称已经过本地化,所以它并不像您 期待的那样简单直接。 首先,我需要字体系列提供一个本地化字符串对象,该对象针对每种支持的区 域 设置均包含一个系列名称:

             ComPtr<IDWriteLocalizedStrings> names;
   HR(family->GetFamilyNames(names.GetAddressOf()));

我也可以枚举系列名称,但一般只查找用户默认区域设置对应的名称。 事实上, IDWriteLocalizedStrings 接口提供了 FindLocaleName 方法来检索本地化系列名称的索引。 我从调 用 GetUserDefaultLocaleName 函数以获取用户默认区域设置开始:

             wchar_t locale [LOCALE_NAME_MAX_LENGTH];
   VERIFY(GetUserDefaultLocaleName(locale, countof(locale)));

然后,我将默认区域设置传递给 IDWriteLocalizedStrings FindLocaleName 方法,确定该字体系 列 是否有针对当前用户本地化的名称:

             unsigned index;
   BOOL exists;
   HR(names->FindLocaleName(locale, &index, &exists));