Directwrite is a fairly powerful text layout API. It supports nearly all of the leading Windows applications and technologies from XAML and Office 2013 Windows Runtime (WinRT) to Internet Explorer 11 and later. It is not a rendering engine in itself, but it has a close relationship with DIRECT2D and is a peer product of direct2d in the DirectX family. Of course, DIRECT2D is the primary hardware accelerated instant mode graphics API.
You can use Directwrite with DIRECT2D to provide hardware-accelerated text rendering. To illustrate, I did not have many writings on Directwrite. I don't want you to think direct2d just directwrite rendering engine. DIRECT2D far more than that. Directwrite has many other features, and in this month's column, I'll show you some of the tasks you can do with directwrite to see how the latest C + + helps simplify the programming model.
Directwrite API
I'll use Directwrite to explore the system font set. First, I need to get the Directwrite factory object. This is the first step in writing any application that will use Directwrite's outstanding typography functionality. As with most Windows APIs, Directwrite also relies on COM base content. I need to call the Dwritecreatefactory function to create the Directwrite factory object. This function returns a COM interface that points to the factory object:
Comptr<idwritefactory2> Factory;
The IDWriteFactory2 interface is the latest version of the Directwrite factory interface that was launched earlier this year with Windows 8.1 and DirectX 11.2. IDWriteFactory2 inherits from IDWriteFactory1, and IDWriteFactory1 inherits from Idwritefactory. The latter is the original Directwrite factory interface, which exposes most of the factory functions.
I will invoke the Dwritecreatefactory function based on the previous Comptr class template:
HR (Dwritecreatefactory (dwrite_factory_type_shared,
__uuidof (Factory),
Reinterpret_cast<iunknown **> (Factory. Getaddressof ()));
Directwrite contains a Windows service that is named Windows Font Caching Service (fontcache). The first parameter indicates whether the obtained factory participates in the font usage of this cross procedure cache. There are two options for dwrite_factory_type_shared and dwrite_factory_type_isolated. Both SHARED and ISOLATED factories can take advantage of cached font data. Only the SHARED factory returns font data to the cache. The second parameter specifies which version of the Directwrite factory interface I want to return in the third and last parameter.
Given the Directwrite factory object, I can directly ask it to provide a system font set:
comptr<idwritefontcollection> fonts;
HR (factory->getsystemfontcollection (Fonts). Getaddressof ()));
The second parameter of the Getsystemfontcollection method is optional, indicating whether it checks for updates or changes to the installed font set. Luckily, this parameter defaults to False, so you don't have to consider it unless you want to make sure that the result set reflects the most recent changes. In the case where the font set is given, I can get the number of font families in the collection, as follows:
unsigned const COUNT = fonts->getfontfamilycount ();
Then I use the Getfontfamily method to retrieve a single font family object from a zero-based index. A font family object represents a set of fonts: They share a name and are of course a design, but the weight, style, and stretch are not the same:
Comptr<idwritefontfamily> family;
HR (fonts->getfontfamily (index, family). Getaddressof ()));
The Idwritefontfamily interface inherits from the Idwritefontlist interface, so I can enumerate the various fonts in the font family. The ability to retrieve font family names is reasonable and useful. However, the series name has been localized, so it's not as straightforward as you expect. First, I need a font family to provide a localized string object that contains a series name for each supported locale:
Comptr<idwritelocalizedstrings> names;
HR (Family->getfamilynames (names). Getaddressof ()));
I can also enumerate series names, but generally only look for names that correspond to the user's default locale. In fact, the Idwritelocalizedstrings interface provides a Findlocalename method to retrieve the index of the localized family name. I start by calling the Getuserdefaultlocalename function to get the user's default locale:
wchar_t locale [locale_name_max_length];
VERIFY (Getuserdefaultlocalename (locale, Countof (locale)));
Then, I pass the default locale to the Idwritelocalizedstrings Findlocalename method to determine if the font family has a localized name for the current user:
unsigned index;
BOOL exists;
HR (Names->findlocalename (locale, &index, &exists));