The text editors I know of use the simple hack of (1) dividing the width of the glyph cluster by the number of code points within the cluster (excluding any zero width combining marks), rather than use the GDEF caret positioning information. This includes even Word, which you can tell if you look closely enough below. It's not precise, but since it's simple and close enough at ordinary reading sizes, it's what many do:
(2) I've heard that some may (but don't know which) also use the original glyph advances of the unshaped characters (pre-ligation) and scale them proportionally to the ligature cluster width.
(3) Some text editors may use the GDEF table, but I never knew of any for sure (possibly Adobe In-Design?).
The most challenging aspect of using methods 2 or 3 with IDWriteTextLayout
is that accessing the corresponding IDWriteFontFace
in that run requires quite the indirection because the specific IDWriteFontFace
used (after resolving font family name+WWS+variable font axes) is stored in the layout but not publicly accessible via any "getter" API. The only way you can extract them is by "drawing" the glyph runs via IDWriteTextLayout::Draw
into a user-defined IDWriteTextRenderer
interface to record all the DWRITE_GLYPH_RUN::fontFace
's. Then you could call IDWriteFontFace::GetDesignGlyphAdvances
on the code points or IDWriteFontFace::TryGetFontTable
to read the OpenType GDEF table (which is complex to read). It's a lot of work, and that's because...
The official PadWrite example has the same issue
IDWriteTextLayout
was designed for displaying text rather than editing it. It has some functionality for hit-testing which is useful if you want to display an underlined link in a paragraph and test for it being clicked (in which case the ligature would be whole anyway within a word), or if you want to draw some decorations around some text, but it wasn't really intended for the full editing experience, which includes caret navigation. It was always intended that actual text editing engines (e.g. those used in Word, PowerPoint, OpenOffice, ...) would call the lower level API's, which they do.
The PadWrite sample I wrote is a little misleading because although it supports basic editing, that was just so you can play around with the formatting and see how things worked. It had a long way to go before it could really be an interactive editor. For one (the big one), it completely recreated the IDWriteTextLayout
each edit, which is why the sample only presented a few paragraphs of text, because a full editor with several pages of text would want to incrementally update the text. I don't work on that team anymore, but I've thought of creating a DWrite helper library on GitHub to fill in some hindsight gaps, and if I ever did, I'd probably just ... use method 1 :b.