Low-level text rendering in WPF is achieved by implementing a TextSource class that returns TextRun objects which have TextRunProperties describing the formatting of the text. The TextSource is passed to a TextFormatter, which reads the runs and the properties and lays out the glyphs appropriately.
Recently we received a bug report that the furtive pataḥ was not being positioned correctly: it was centred under the consonant instead of being displayed to the right. However, this only happened when it was laid out by using the TextFormatter directly, instead of using a high-level class like TextBlock or FormattedText. Thus, we knew it was a bug in our code, and not a fundamental Hebrew display problem in WPF.
One inconvenience when using the low-level text formatting APIs is that many of the public types are abstract base classes that have to be implemented almost entirely from scratch. TextRunTypographyProperties, in particular, has over 40 abstract properties that must be implemented.
I eventually traced the problem to the use of typography properties. If the
TextRunProperties.TypographyProperties property is null
, WPF uses a default set of typography properties
(this produced the correct output); otherwise it uses the properties from that
instance (this produced the incorrect output). Further investigation revealed
that setting the
TextRunTypographyProperties.ContextualAlternates property to true
caused the pataḥ to be
positioned correctly.
When we first implemented our own TextRunTypographyProperties class, we just
let .NET initialise all the properties to their default values (false, 0,
etc.), and then turned on a couple of properties we wanted: standard ligatures
and old-style numerals. However, there are four properties that are documented
as being true
by default: ContextualAlternates, ContextualLigatures, Kerning,
and StandardLigatures.
Strictly speaking, the documentation is incorrect: these properties can’t be
true by default, because TextRunTypographyProperties is an abstract class that
has no default implementation. But if you are providing your own
implementation, it would be wise to heed the documentation and set those
properties to true
by default.
Posted by Bradley Grainger on December 22, 2009