Having figured out how to render basic text using DirectWrite, I decided to go further and try to figure out how I can apply block-level formatting to paragraphs. Amazingly, it ended up being very easy. Here’s how it goes.

If you consider IDWriteTextFormat to be the thing that applies basic formatting (font family, size, bold/italic/underline) to a block of text, then IDWriteTextLayout is its older, much more featured cousin. This interface lets you apply block-level formatting. Specifically, what it lets you do is apply OpenType features. Let’s take a look at how it works by first creating an instance of this type:

if (SUCCEEDED(hr))
{
  hr = pDWriteFactory->CreateTextLayout(markup, wcslen(markup),
    pTextFormat, width, height, &pTextLayout);
}

You’ll notice that TextFormat participates in the creation of TextLayout, forming a ‘baseline’ for subsequent manipulation. Now that we have the layout, we can also create a Typography object that will let us define the total set of OT features that we want to apply:

if (SUCCEEDED(hr))
{
  pDWriteFactory->CreateTypography(&pTypography);
}

Having a Typography object in play, we can start setting its properties, adding the OT features we want. The syntax is presented below. It does look a bit weird (especially for someone used to C#), but it works:

if (SUCCEEDED(hr))
{
  if (smallCaps)
  {
    DWRITE_FONT_FEATURE feature;
    feature.nameTag = DWRITE_FONT_FEATURE_TAG::DWRITE_FONT_FEATURE_TAG_SMALL_CAPITALS;
    feature.parameter = 1;
    pTypography->AddFontFeature(feature);
  }
}

Now that I have defined small-caps formatting, I need to apply it to a range of characters. The range has a starting point and a character count. In the following code block, I apply it to the whole paragraph:

if (SUCCEEDED(hr))
{
  DWRITE_TEXT_RANGE range;
  range.startPosition = 0;
  range.length = wcslen(markup);
  pTextLayout->SetTypography(pTypography, range);
}

Now, the moment of truth: we need to slightly modify the drawing statement to draw the text layout we have defined:

pRT->DrawTextLayout(D2D1::Point2F(), pTextLayout, pBlackBrush);

That’s it! I bet you want to see an example! Here it is.