1

The following is laid out using an IDWriteTextLayout with dimensions 250x100. It simply contains 150 of the Arabic letter U+062A, with no spaces, using Calibri 24 (normal weight/style/stretch). The blue box shows the 250x100 layout area (the text overflows because I haven't set a trimming mode), the green box shows the laid out dimensions from the metrics, the pink box takes overhang metrics into account, and the grey boxes are from hit testing every character.

Not using any IDWriteTypography object.

Compare that to the following, where the only difference is that I've called IDWriteTextLayout::SetTypography and passed an empty IDWriteTypography object which was created by IDWriteFactory::CreateTypography and not modified at all.

Using an empty IDWriteTypography object.

Just looking at the appearance of the text, the last character on each line has assumed the Arabic "end" contextual form, which I believe is generally applied to the last character of a word (I don't know Arabic). In what I can only currently guess is a bug in DirectWrite, this has caused the text to actually hang outside both the specified layout area and the area returned by the metrics (the amount that it hangs outside the box seems equal to the extra width added by the change in contextual form).

From other experimentation, it seems that setting an empty IDWriteTypography object has the effect of disabling every possible font feature. So by disabling some typographical font feature which is apparently enabled by default, I've caused it to use the "end" form for characters at the end of lines, even if they're not at the end of words. Which font feature is controlling this behavior? I've tried tweaking the IDWriteTypography instance to enable (set its value to 1) every font feature listed in the documentation one at a time, and none of them result in the old appearance. Is the relevant feature one of the ones that actually uses an integral value rather than a boolean?

My goal here is to use an IDWriteTypography object on my IDWriteTextLayout for unrelated reasons, but avoid having the text hang outside of the layout area. So alternatively, is there some other way to work around that behavior?

Jayonas
  • 401
  • 2
  • 12

1 Answers1

1

You've got a lot going on here that makes me think this is somewhat of an XY Problem, but I can at least answer the specific question about which font feature controls word-final forms in Arabic. That is the "Terminal Forms", or 'fina' feature. It is an essential, non-optional feature of Arabic script and is not only "on by default", it is not possible to disable it with Windows text layout. That is why you don't see anything in the DWRITE_FONT_FEATURE_TAG enumeration corresponding to it.

To my initial point about XY Problem: do you realistically expect cases like this (a single repeating caracter occupying the entire contents of a text box)? Perhaps you'd be better served testing with more realistic text: for example, the output from a multilingual "lorem-ipsum" generator? While DWrite is pretty robust, I very much doubt that its designers sought to achieve perfection with extreme cases such as this. You can probably find lots of oddball cases that are DWrite "bugs", using totally unrealistic text.

Community
  • 1
  • 1
djangodude
  • 5,362
  • 3
  • 27
  • 39
  • That definitely answers the question, thanks. The fact that it's not a feature exposed to the API makes me feel better about not being able to find it. However, I'm left pretty confused as to why DirectWrite is exhibiting different behavior with regards to this feature depending on whether or not I set a typography object. If it's a required feature of Arabic then it sounds like DirectWrite should enable it no matter what I do, but I actually had to do extra work (set a Typography object) for it to become enabled. – Jayonas Sep 15 '15 at 15:57
  • Re XY problem: no, I generally don't expect such cases in real world usage. However, I'm rendering text entered by the user (this is basically for a text editor) so I have to account for them. It's not so rare for someone just playing around to enter gibberish with no spaces (which I simplified to a run of one char), and it's a little disconcerting that doing so easily causes the text to overflow its bounds, which are very obvious in my app. My core problem is to use a typography object while avoiding that behavior, which I was hoping to do by resetting the value of the relevant font feature. – Jayonas Sep 15 '15 at 16:08
  • In the case that is failing (overlapping bounds where there are end-of-line terminal forms), I believe you've disabled something like word-wrapping (its Arabic equivalent). In the initial case (default shaping), it appears to be doing the right thing (considering the very unusual input). I agree that people are probably going to play around on it; I don't agree that trying to have it absolutely perfect for every possible case is the right approach. You could end up sinking a huge amount of time to "fix" a case that is totally unrealistic; waste of effort to do, IMHO. – djangodude Sep 15 '15 at 16:19
  • Any idea what kind of Arabic word-wrapping I might have disabled? Seems like it must be another inaccessible font feature. I agree that attempting some kind of fix at this point is likely wasted effort, especially because it'd have to be pretty hacky, but I think the time spent to investigate this far was worthwhile. I'll just have to decide if this overflow problem is worth the gains I get from using a typography object. In the end, though, I don't think it's unreasonable to expect the rendered text to both stay in bounds and match the returned metrics, even with such unusual input. – Jayonas Sep 15 '15 at 16:50
  • Actually it could be DWRITE_WORD_WRAPPING setting, see https://msdn.microsoft.com/en-us/library/windows/desktop/dd368146(v=vs.85).aspx – djangodude Sep 15 '15 at 18:23
  • Thanks for the suggestion. I didn't set `DWRITE_WORD_WRAPPING` on either of the screenshots, and unfortunately none of the options improve the problem. `NO_WRAP` and `WHOLE_WORD` both cause all the text to remain on a single line and overflow leftward, which is as I'd expect, but I need the wrapping behavior. The remaining three options all give the same result as the second screenshot, where the leading edge of the wrapping lines spills outside the bounds and metrics due to the extra width of the end forms. – Jayonas Sep 16 '15 at 19:00