Search code examples
c#sharpdxdirectwrite

Why does DrawTextLayout ignore brushes from SetDrawingEffect in SharpDX?


My goal is to draw text in a single layout with certain ranges different sizes and opacities. The ID2D1RenderTarget::DrawTextLayout method seems to be the way to go.

The documentation for the defaultForegroundBrush parameter:

The brush used to paint any text in textLayout that does not already have a brush associated with it as a drawing effect (specified by the IDWriteTextLayout::SetDrawingEffect method).

According to the Remarks section of the IDWriteTextLayout::SetDrawingEffect method,

An ID2D1Brush, such as a color or gradient brush, can be set as a drawing effect if you are using the ID2D1RenderTarget::DrawTextLayout to draw text and that brush will be used to draw the specified range of text.

This drawing effect is associated with the specified range and will be passed back to the application by way of the callback when the range is drawn at drawing time.

It sounds like ID2D1RenderTarget::DrawTextLayout will definitely use any brush set by IDWriteTextLayout::SetDrawingEffect. This unmanaged C++ answer seems to corroborate this idea.

However, in practice, DrawTextLayout ignores any SolidColorBrush I set using SetDrawingEffect. I get styles and sizes in the appropriate ranges, but everything is painted using the default brush.

I worked around this by implementing a custom text renderer (gist) which is dead simple and drew exactly what I expected from ID2D1RenderTarget::DrawTextLayout as per the documentation. I would have been satisfied but the performance of a TextRendererBase and DrawGlyphRun are more than 25% slower than ID2D1RenderTarget::DrawTextLayout.

What might be causing this issue? Can I use color as the documentation suggests and still use ID2D1RenderTarget::DrawTextLayout?


Solution

  • instead of:

    layout.SetDrawingEffect(myBrush, new TextRange(1, 5));
    

    call it like this:

    layout.SetDrawingEffect(myBrush.NativePointer, new TextRange(1, 5));