DirectX Factor

Who’s Afraid of Glyph Runs?

Charles Petzold

Download the Code Sample

Charles PetzoldI first encountered the concept of character glyphs in Windows Presentation Foundation (WPF) some years back. In typography, “glyph” refers to the graphical representation of a character rather than its function in a particular written language, which is indicated by the character’s Unicode value. I knew the WPF Glyphs element and GlyphRun class represented an alternative way to display text, but they seemed to add a layer of unnecessary complexity. The biggest oddity involved referencing a desired font not by a font family name, but by the file path of the actual font file. I’d been coding for Windows since beta versions of 1.0, and I’d never before needed to reference a font by the filename. It simply wasn’t how it’s done.

I quickly concluded that Glyphs and GlyphRun were much too esoteric for mainstream programmers such as myself. Only years later when I began working with the Microsoft XML Paper Specification (XPS) did the rationale behind glyphs become apparent.

The Basic Distinction

Normally when a program requests a font from Windows, it does so using a font family name such as Century Schoolbook and attributes such as italic or bold. At runtime, Windows finds a font file on the user’s system with a font that matches the family name. Italic and bold can either be intrinsic to this font or synthesized by the system. To lay out text, either Windows or the application accesses font metric information that describes the sizes of the font characters.

What happens if two different users have two different font files on their systems that both contain a font with the family name Century Schoolbook, but with somewhat different font metrics? That’s not a real problem. Because text is formatted and laid out at runtime, the actual rendering of these two fonts could be slightly different, but it wouldn’t really matter. Application programs are designed to be flexible in that way.

XPS documents are different, however. Much like PDF, XPS describes a fixed-page document. All the text on each page is already laid out and precisely positioned. If such a document is rendered with a font that is slightly different from the font used to design the page, it won’t look right. This is why XPS documents often contain embedded font files, and why the XPS pages use the Glyphs element to reference these font files and render the text. Any ambiguity is entirely eliminated.

Normally we refer to text characters by character codes. We usually don’t need to know anything about the precise glyph that happens to be displayed as a consequence of using that character code with a particular font. But sometimes it’s important to have more control over the glyphs themselves.

You might assume there’s a one-to-one correspondence between character codes and glyphs in a particular font, and that’s usually the case. But there are very important exceptions: Some font files contain ligatures, which are single glyphs corresponding to character pairs such as fi or fl. Some non-Latin character sets require multiple glyphs to render a single character. In addition, some font files contain alternate glyphs for certain characters—for example, a zero with a slash through it, small capital letters used for lower case or letters with stylistic swashes. These stylistic alternatives are characteristic of a particular font file rather than a font. That’s why getting the right font file is crucial.

If you’re writing a Windows Store application for Windows 8, you can make use of these stylistic alternatives through the Windows Runtime API. Chapter 16 of “Programming Windows, 6th Edition” (O’Reilly Media, 2012) has a program called TypographyDemo that demonstrates how to do just that. But the underlying support for glyphs in Windows 8 is implemented in DirectX, and the power of glyphs themselves is revealed the most in that environment.

The DirectX Glyph Support

Exploring how to display glyphs in DirectX involves tracing a path through several interfaces, methods and structures.

Let’s begin with the ID2D1RenderTarget interface, which contains the basic methods to display 2D graphics and text. This interface defines a DrawGlyphRun method. This method requires a structure of type DWRITE_GLYPH_RUN that describes the glyphs to be displayed, and also references an object of type IDWriteFontFace.

One way to obtain an IDWriteFontFace object is through the CreateFontFace method of IDWriteFactory. That method requires an IDWriteFontFile object, which is obtained through the CreateFontFileReference method of IDWriteFactory.

The CreateFontFileReference method references a font file using a path and filename. However, if you’re using DirectX in a Windows Store application, your app probably won’t have full and free access to the user’s hard drive, and you can’t usually access fonts in that manner. Any font file you reference with CreateFontFileReference will likely be defined as an application resource and be bound into the application’s package.

However, you can’t include just any font file in your application’s package. If a font is part of your application, you must have a license to distribute that font. Fortunately, Microsoft has licensed several font files from Ascender Corp. for the express purpose of allowing you to distribute them with your application. These font files have been used primarily for XNA applications, but they’re also interesting from a glyphs perspective.

Among the downloadable code for this column is a program called GlyphDump that I created based on the DirectX App (XAML) template in Visual Studio Express 2013 Preview. This template creates an application that renders DirectX graphics on a SwapChainPanel.

I created a new filter (and corresponding folder) in the GlyphDump project named Fonts, and added the 10 font files licensed from Ascender Corp. A ListBox in DirectXPage.xaml explicitly lists the family names of these fonts, with Tag properties referencing the filenames. When one is selected, the program constructs the path and name of the font file like so:

Package::Current->InstalledLocation->Path +
  "\\Fonts\\" + filename;

The GlyphDumpRenderer class then uses that path to create an IDWriteFontFile object and an IDWriteFontFace object.

The rest of the job occurs in the Render method, as shown in Figure 1.

Figure 1 The Render Method in GlyphDump

bool GlyphDumpRenderer::Render()
{
  if (!m_needsRedraw)
      return false;
  ID2D1DeviceContext* context = m_deviceResources->GetD2DDeviceContext();
  context->SaveDrawingState(m_stateBlock.Get());
  context->BeginDraw();
  context->Clear(ColorF(ColorF::White));
  context->SetTransform(m_deviceResources->GetOrientationTransform2D());
  if (m_fontFace != nullptr)
  {
    Windows::Foundation::Size outputBounds = m_deviceResources->GetOutputBounds();
    uint16 glyphCount = m_fontFace->GetGlyphCount();
    int rows = (glyphCount + 16) / 16;
    float boxHeight = outputBounds.Height / (rows + 1);
    float boxWidth = outputBounds.Width / 17;
    // Define entire structure except glyphIndices
    DWRITE_GLYPH_RUN glyphRun;
    glyphRun.fontFace = m_fontFace.Get();
    glyphRun.fontEmSize = 0.75f * min(boxHeight, boxWidth);
    glyphRun.glyphCount = 1;
    glyphRun.glyphAdvances = nullptr;
    glyphRun.glyphOffsets = nullptr;
    glyphRun.isSideways = false;
    glyphRun.bidiLevel = 0;
    for (uint16 index = 0; index < glyphCount; index++)
    {
      glyphRun.glyphIndices = &index;
      context->DrawGlyphRun(Point2F(((index) % 16 + 0.5f) * boxWidth,
                                    ((index) / 16 + 1) * boxHeight),
                                    &glyphRun,
                                    m_blackBrush.Get());
    }
  }
  // We ignore D2DERR_RECREATE_TARGET here. This error indicates
  // that the device is lost. It will be handled during
  // the next call to Present.
  HRESULT hr = context->EndDraw();
  if (hr != D2DERR_RECREATE_TARGET)
  {
    DX::ThrowIfFailed(hr);
  }
  context->RestoreDrawingState(m_stateBlock.Get());
  m_needsRedraw = false;
  return true;
}

This Render method displays all the glyphs in the selected font file in rows of 16 glyphs each, so it attempts to calculate a fontEmSize value sufficiently small for that display. (For some fonts with many glyphs, this won’t work well.) Normally the glyphIndices field of the DWRITE_GLYPH_RUN structure is an array of glyph indices. Here I’m only displaying one glyph at a time.

The DrawGlyphRun method requires a coordinate point, the DWRITE_GLYPH_RUN structure and a brush. The coordinate indicates where the left edge of the glyph’s baseline is to be positioned. Notice I said “baseline.” This is different from most text display methods, which require specifying the top-left corner of the first character.

Figure 2 shows perhaps the most interesting font of this batch, which has a family name of Pescadero and a font filename of Pesca.ttf.

The GlyphDump Program Showing the Pescadero Font
Figure 2 The GlyphDump Program Showing the Pescadero Font

Before writing this program, I had never seen a display like this. It starts out looking something like a traditional ASCII table, but then there are a bunch of glyphs for numeric subscripting and superscripting, and a whole collection of ligatures of various sorts, plus capital letters with decorative swashes.

Obviously, the glyphIndices field of DWRITE_GLYPH_RUN isn’t the same as a character code. These are indices that reference the actual glyphs within the font file, and these glyphs don’t even need to be in any kind of rational order.

Text with Glyphs

You might already see some utility in being able to display text using a specific font file with glyph indices rather than character codes. You can specify exactly what glyphs you want.

The FancyTitle project demonstrates this. The idea here is that you have a program that’s mostly XAML-based, but you want a fancy title using some ligatures and swashes from the Pescadero font. The project includes the Pesca.ttf file, and the XAML file defines the SwapChainPanel to have a width of 778 and a height of 54, values I chose empirically based on the size of the rendered text.

Because the display requirements of this project are simple, I removed the FancyTitleMain class and the rendering classes, leaving the DirectXPage class to render to the SwapChainPanel. (However, I had to modify DeviceResources slightly to make IDeviceNotify a ref class interface so that DirectXPage could implement IDevice­Notify and be notified when the output device is lost and recreated.)

The text output shown in Figure 3 has 24 characters, but only 22 glyphs. You’ll recognize the ligatures and the swashes from Figure 2.

The FancyTitle Output
Figure 3 The FancyTitle Output

I’ve made the DirectX background Alice Blue so you can see that the SwapChainPanel is barely larger than the text. Of course, it’s possible to anticipate the size of the output exactly because the font file is part of the application and the glyphs are being accessed directly.

You can get ligatures and alternative glyphs without using DrawGlyphRun. You can also get them with less precision using the TextBlock element in the Windows Runtime, as the Typography­Demo program from my Windows 8 book demonstrates. In DirectWrite, you can use the SetTypography method of IDWriteTextLayout with an IDWriteTypography object, which ultimately references a member of the extensive DWRITE_FONT_FEATURE_TAG enumeration. But these techniques aren’t quite as certain as specifying the glyphs precisely.

How do you get italics and boldface with DrawGlyphRun? In many cases, different font files will contain italic and bold variations of a font. Among the fonts included by the GlyphDump program are a couple of Bold fonts and a Light font. However, you also have the option to simulate oblique and bold characters using DWRITE_FONT_SIMULATIONS flags in CreateFontFace.

Advances and Offsets

Both GlyphDump and FancyTitle set two of the fields in DWRITE_GLYPH_RUN to nullptr. These two fields are named glyphAdvances and glyphOffsets.

When you display an array of glyphs, you specify the origin of the first character’s left baseline. For each successive character, the horizontal coordinate of the origin is automatically increased based on the width of the character. (A similar process occurs when displaying sideways text.) This increase is known as an “advance.”

You can obtain the advances that DirectX uses for spacing characters by calling the GetDesignGlyphMetrics method of IDWriteFontFace. The result is an array of DWRITE_GLYPH_METRICS structures, one for each glyph index in which you’re interested . The advanceWidth field of that structure indicates the advance relative to the designUnitsPerEm field of the DWRITE_FONT_METRICS structure obtained from the GetMetrics method of IDWriteFontFace, and which also includes vertical metrics applicable to all glyphs within a particular font.

Or, you can call the GetDesignGlyphAdvances method of IDWriteFontFace1, which also provides advances relative to the designUnitsPerEm value. Divide the values by designUnitsPerEm (which is often a nice round value such as 2,048) and then multiply by the em size specified in DWRITE_GLYPH_RUN.

The glyphAdvances array is commonly used to space characters closer together or further apart than the design metrics indicate. If you decide to use it, you’ll need to set glyphAdvances to an array of values that’s at least the size of the array of glyph indices, minus one. An advance isn’t needed on the final glyph because nothing is displayed beyond that.

The glyphOffsets field is an array of DWRITE_GLYPH_OFFSET structures, one for each character. The two fields are advanceOffset and ascenderOffset, which indicate a desired offset (to the right and up, respectively) relative to the character’s normal location. This facility is often used in XPS files to position multiple glyphs of a particular font all over the page.

The CenteredGlyphDump program demonstrates how to use the glyphOffsets field to display the entire array of glyphs from a particular font file with a single DrawGlyphRun call:

context->DrawGlyphRun(Point2F(), &m_glyphRun, m_blackBrush.Get());

The coordinate passed to DrawGlyphRun is (0, 0), and glyphAdvances is set to an array of zero values to inhibit advancing successive glyphs. The position of each glyph is entirely governed by glyphOffsets. This position is based on glyph metrics to center each glyph in its column. Figure 4 shows the result.

The CenteredGlyphDump Program
Figure 4 The CenteredGlyphDump Program

Providing Your Own Font Loader

If a font file is part of an application package, it’s fairly easy to derive a file path you can use with CreateFontReference. But what if you have a font that’s located in an XPS or EPUB package, or perhaps in isolated storage or in the cloud?

As long as you can write code that accesses the font file, DirectX can access it. You’ll need to provide two classes, one that implements IDWriteFontFileLoader and another that implements IDWriteFontFileStream. Generally, the class that implements IDWriteFontFileLoader is a singleton that accesses all the font files your application will need, and assigns each of them a key. The CreateStreamFromKey method in your IDWriteFontFileLoader implementation returns an instance of IDWriteFontStream for each font file.

To use these two classes, you first instantiate a single instance of the class that implements IDWriteFontFileLoader and pass it to the RegisterFontFileLoader of your IDWriteFactory object. Then, instead of calling CreateFontFileReference to obtain an IDWriteFontFile object, call CreateCustomFontFileReference with this IDWriteFontFileLoader instance and a key identifying the particular font file you want.

This technique is demonstrated in the CenteredGlyphDump program. The project includes two classes—PrivateFontFileLoader and PrivateFontFileStream—that implement the two interfaces. The classes access font files in the application package, but they could be adapted for other purposes.

It’s likely your IDWriteFontFileLoader implementation will need to make file I/O calls, and in a Windows Store application, these calls must be asynchronous. It makes a lot of sense for the IDWriteFontFileLoader class to define an asynchronous method that loads all the fonts into memory, and for the IDWriteFontFileStream to simply return pointers to these memory blocks. This is the approach I took with PrivateFontFileLoader and PrivateFontFileStream, after closely examining the Direct2D Magazine App Sample among the Microsoft sample code for Windows 8.1.

For the key to identify each file, I used the filename. After the asynchronous loading method in PrivateFontFileLoader is finished, the CenteredGlyphDump program obtains these filenames for the ListBox. That’s why only the filenames are displayed in Figure 4. The program is ignorant of the font family names associated with each file.

From Characters to Glyphs

Of course, displaying text by referencing glyphs is fine if you know exactly what glyphs you need, but can you display normal Unicode characters using DrawGlyphRun?

You can, because IDWriteFontFace has a GetGlyphIndices method that converts character codes to glyph indices for the particular font file. In doing this, it picks the default glyph for each character code, so you won’t get any of the fancy alternatives.

But the character codes you pass to GetGlyphIndices are in a form perhaps unique in all of Windows. Instead of 16-bit character codes (as is the case when you’re normally working with Unicode character strings), you need to create an array of 32-bit character codes. As you may know, Unicode is actually a 21-bit character set, but characters are commonly stored as 16-bit values (called UTF-16), which means that some characters comprise two 16-bit values. But GetGlyphIndices wants 32-bit values. Unless your character string has characters with codes above 0xFFFF, you can simply transfer values from one array to another.

If you’re dealing with normal characters from the Latin alphabet, you can also assume that there’s a one-to-one correspondence between characters and glyphs. Otherwise, you might need to create a larger output array to receive the indices.

This simple technique is demonstrated by the HelloGlyphRun project. Figure 5 shows the code that loads a font file and sets up a DWRITE_GLYPH_RUN structure. The Update method adjusts the glyph offsets to achieve a kind of rippling effect of the text.

Figure 5 Defining a DWRITE_GLYPH_RUN from a Character String

// Convert string to glyph indices
std::wstring str = L"Hello, Glyph Run!";
uint32 glyphCount = str.length();
std::vector<uint32> str32(glyphCount);
for (uint32 i = 0; i < glyphCount; i++)
     str32[i] = str[i];
m_glyphIndices = std::vector<uint16>(glyphCount);
m_fontFace->GetGlyphIndices(str32.data(), glyphCount, m_glyphIndices.data());
// Allocate array for offsets (set during Update)
m_glyphOffsets = std::vector<DWRITE_GLYPH_OFFSET>(glyphCount);
// Get output bounds
Windows::Foundation::Size outputBounds = m_deviceResources->GetOutputBounds();
// Define fields of DWRITE_GLYPH_RUN structure
m_glyphRun.fontFace = m_fontFace.Get();
m_glyphRun.fontEmSize = outputBounds.Width / 8; // Empirical
m_glyphRun.glyphCount = glyphCount;
m_glyphRun.glyphIndices = m_glyphIndices.data();
m_glyphRun.glyphAdvances = nullptr;
m_glyphRun.glyphOffsets = m_glyphOffsets.data();
m_glyphRun.isSideways = false;
m_glyphRun.bidiLevel = 0;

Although you’ll probably be using DrawGlyphRun only with font files you’re intimately familiar with, it’s possible to determine what type of glyphs are contained in a particular font file at runtime. IDWriteFontFace defines a TryGetFontTable method that accesses tables in the OpenFont file. Use a tag of “cmap” for the character-to-glyph table and “GSUB” for the glyph substitution table, but be prepared to spend many excruciating hours with the OpenType specification to read these tables successfully.

Glyph Runs Using System Fonts

Is DrawGlyphRun only good for font files you supply yourself? At first it would seem so, but you can use it with system fonts as well. Here’s the process: Use the GetSystemFontCollection method of IDWriteFactory to obtain an IDWriteFontCollection object. That object allows you to find all the family names associated with the fonts installed on the system. The GetFontFamily method of IDWriteFontCollection returns an object of type IDWriteFontFamily. From that, you can call GetMatchingFonts or GetFirstMatchingFont to combine the font family with italic, bold and stretch attributes to obtain an IDWriteFont.

Once you have an IDWriteFont object, call CreateFontFace to get an IDWriteFontFace object. That’s the same type of object obtained from CreateFontFace in the earlier programs! From that object you can begin setting up a DWRITE_GLYPH_RUN structure for DrawGlyphRun.

This is demonstrated in the SystemFontGlyphs project. The project uses the GetSystemFontCollection in in its DirectXPage class to fill a ListBox with the system font family names. When an item is selected, an IDWriteFontFace object is derived that’s passed to the renderer.

The SystemFontGlyphsRenderer class builds a DWRITE_GLYPH_RUN structure based on the text “Annoying vibrating text effect.” The Update method is then obliged to set the values of the glyph offsets array to random numbers between -3 and 3, making it seem as if all the characters of the text string are independently vibrating.

There doesn’t seem to be much of a conceptual difference between IDWriteFont and IDWriteFontFace except that IDWriteFont always represents a font that’s part of a font collection (such as the system font collection) while IDWriteFontFace need not. IDWriteFontCollection has a GetFontFromFontFace method that accepts an IDWriteFontFace and returns the corresponding IDWriteFont, but it works only if the font file associated with the IDWriteFontFace is part of the font collection.

Custom Font Collections

Now you’ve seen how you can use DrawGlyphRun with font files that your application loads as well as with system fonts. Is it possible to use the regular text-output methods (DrawText and DrawTextLayout) with your own font files?

Yes, it is. You’ll recall that both DrawText and DrawTextLayout require an IDWriteTextFormat object. You create this using the CreateTextFormat method of IDWriteFactory by specifying both a font family name and a font collection.

Normally you set that font collection argument to nullptr to indicate system fonts. But you can also create a custom font collection by calling the CreateCustomFontCollection method of IDWriteFactory. You’ll need to supply your own class that implements the IDWriteFontCollectionLoader interface, and another class that implements IDWriteFontFileEnumerator.

This is demonstrated in the ResourceFontLayout program. The program also includes the implementations of the IDWriteFontFileLoader and IDWriteFontFileStream interfaces from Centered­GlyphDump. When you obtain the list of font families from this custom font collection, you’ll notice that multiple font files are sometimes consolidated into a single font family.

The Prize at the Bottom of the Box

At this point, the importance of IDWriteFontFace should be quite evident. You can create an IDWriteFontFace object from two directions: either directly from a font file, or by choosing a particular font from a font collection. You then reference this IDWriteFontFace in a DWRITE_GLYPH_RUN structure, or use it to obtain glyph metrics or to access tables in the font file.

IDWriteFontFace also defines a method named GetGlyphRun­Outline. The arguments to this method are very much the same as the fields of the DWRITE_GLYPH_RUN structure, but an additional argument is an IDWriteGeometrySink, which is the same as an ID2D1SimplifiedGeometrySink.

This means you can convert a text string to an ID2D1PathGeometry, and then render and manipulate that geometry in whatever way you want. Figure 6 is a screenshot from the OutlinedCharacters program that shows a character geometry that has been stroked and filled; the same geometry rendered with a dotted style (which is animated to make the dots travel around the characters); and the geometry widened and outlined, in effect, outlining the outlines.

The OutlinedCharacters Program
Figure 6 The OutlinedCharacters Program

And I’m just getting started.


Charles Petzold is a longtime contributor to MSDN Magazine and the author of “Programming Windows, 6th Edition” (O’Reilly Media, 2012), a book about writing applications for Windows 8. His Web site is charlespetzold.com.

Thanks to the following Microsoft technical experts for reviewing this article: Jim Galasyn and Justin Panian

 

Rate: