| Summary: | Kerning in TTF_RenderText_Blended no longer matches value returned by TTF_GetFontKerningSizeGlyphs. | ||
|---|---|---|---|
| Product: | SDL_ttf | Reporter: | b7874409 |
| Component: | misc | Assignee: | Sam Lantinga <slouken> |
| Status: | RESOLVED FIXED | QA Contact: | Sam Lantinga <slouken> |
| Severity: | normal | ||
| Priority: | P2 | CC: | sylvain.becker |
| Version: | unspecified | ||
| Hardware: | All | ||
| OS: | All | ||
| Attachments: | patch to get side bearing | ||
|
Description
b7874409
2020-05-13 16:50:27 UTC
TTF_GetFontKerningSizeGlyphs can't take into account the left and right side bearing error correction, because it's an accumulation starting from the beginning of the string. It would need to know the whole string. - lsb/rsb isn't always used and loaded. If you used TTF_HINTING_LIGHT_SUBPIXEL, the position is computed a little bit differently. - it's possible to disable kerning with TTF_SetFontKerning() ? - TTF_MeasureText() can help to measure the previous sub-string ? Thanks for your quick reply. A quick explanation of what I'm doing : I'm using TTF_GlyphMetrics and TTF_GetFontKerningSizeGlyphs to calculate where to place the caret in a homemade text input box. This works perfectly with SDL_ttf 2.0.15 but has issues with the latest development version. Thanks for explaining why TTF_GetFontKerningSizeGlyphs can't take into account the left and right side bearing error correction. I'm using TTF_HINTING_LIGHT and can see a difference in kerning between SDL_ttf 2.0.15 and the latest development version. Disabling kerning with TTF_SetFontKerning() avoids the problem but I'd rather not do that if possible. I don't think TTF_MeasureText() will help with my problem. Can't TTF_MeasureText() be used for that to measure the previous sub-string ? see bug #4515. Maybe I have misunderstood the purpose of TTF_MeasureText but I can't see how it would help in my situation. Given a character index I must place the caret at the correct location. (with an index of 0 the caret is at the very start of the line, with an index of 1 it is just after the first character, etc). I'm also using TTF_GlyphMetrics and TTF_GetFontKerningSizeGlyphs along with TTF_RenderGlyph_Blended to reproduce the behaviour of TTF_RenderText_Blended but with added features such as changing the colour of individual glyphs within the line. As far as I can see both my caret placement code and custom TTF_RenderText_Blended now need to use lsb_delta and rsb_delta to match the behaviour of SDL_ttf. So I either need a way to access lsb_delta and rsb_delta or a way to disable their use within the SDL_ttf code (making TTF_RenderText_Blended produce the same results as in SDL_ttf 2.0.15). Sorry if I have misunderstood any of your suggestions and thanks again for your help. Not sure, but what about calling TTF_MeasureText with a very big "measure_width", "extent" should give you the size of the string. Or simply TTF_SizeText. If you want to place a caret at n-th position: measure the string for n-1 first chars, and draw the caret. If you want to replace the n-th, measure the string of n char of the string and replace going backward ? I think that using TTF_SizeText in that way would result in the caret being too far to the right in some situations involving minx/kerning/etc such as placing the caret between the letters A and V in the string "AV". Also my custom TTF_RenderText_Blended that I mentioned in my previous message produces a result that looks identical to the real TTF_RenderText_Blended in SDL_ttf 2.0.15 but I can't make it match the result of the new TTF_RenderText_Blended from the Mercurial version. I think the most simple solution would be to provide some way to disable the new more accurate positioning algorithm that takes into account left and right side bearing error correction in SDL_ttf (at runtime). Or providing a way to obtain lsb_delta and rsb_delta, but I'm not sure what that would involve exactly. It should be easy to provide access to lsb/rsb but then you need to re-do the same steps as in the library to compute the advance. And you have to look at the source inside or freetype doc. And in the end, it should be the same as calling TTF_SizeText(). Even without lsb/rsb, you should somewhere in your code compute the advance and do something similar to TTF_SizeText(). Can you modify you SDL_ttf.c to see if setting lsb_delta and rsb_delta to 0 really solve the issue ? (here: https://hg.libsdl.org/SDL_ttf/file/b4347abd4fbc/SDL_ttf.c#l1774 ) do you have a test-case showing how it looks ? Disabling the lsb/rsb is also possible but it's pity not to have the real precision that freetype provides. I understand that with access to lsb/rsb I would need to re-do the same steps as in the library to compute the advance. As I explained in a previous message calling TTF_SizeText() would result in the caret being too far to the right in some situations. That might not look too bad with my caret placement code but it definitely wouldn't be acceptable in my custom TTF_RenderText_Blended(). I'm currenty using TTF_GlyphMetrics() and TTF_GetFontKerningSizeGlyphs() in my code to compute the advance a bit like TTF_SizeText() but I'm also taking into account the following character if there is one. Setting lsb_delta and rsb_delta to 0 in SDL_ttf.c doesn't appear to make a difference. When rendering the string "AVAVAVAVAVAVAVAVAVAV" with SDL_ttf 2.0.15 and again with the latest development version there is an obvious difference in spacing between the letters but setting lsb_delta and rsb_delta to 0 in SDL_ttf.c doesn't restore the behaviour of 2.0.15. I still think it would be useful to provide access to lsb_delta and rsb_delta for situations where they do affect the kerning but there seems to be another cause for the change in spacing between characters. Created attachment 4341 [details]
patch to get side bearing
Here's a patch to get the font side bearing lsb/rsb. Only compilation is tested, but it's only a getter functionality. let me know
For the caret: I see now. but it depends on whether you want to place it after the n-1'th char or before the n'th char. (which is a difference position when there is a kerning)
=> Maybe you can try to get the size of the n char string, and go backward of 1 char ?
Thanks for the patch to get the font side bearing lsb/rsb, I'll test it soon. Thanks also for the suggestions concerning the caret placement but my code worked with previous versions of SDL_ttf and should still work with the latest development version if I take into account lsb/rsb and figure out why the kerning is now different even after setting lsb_delta and rsb_delta to 0. Concerning the difference in kerning, could it be because TTF_Size_Internal() used to call FT_Get_Kerning() with FT_KERNING_DEFAULT then bitshift the result but now calls it with FT_KERNING_UNFITTED with no bitshift, while TTF_GetFontKerningSizeGlyphs() stills calls it with FT_KERNING_DEFAULT and bitshifts the result ? I used FT_KERNING_UNFITTED because it matches what FreeType did in the examples. But you're right, the other call FT_Get_Kerning() should probably use the same thing to be coherent (mainly to cross check the values). http://git.savannah.gnu.org/cgit/freetype/freetype2-demos.git/tree/src/ftcommon.c#n1578 Also, the kerning value shifted becomes wrong: you can't use it with lsb/rsb -> you need to update the previous patch so that you also get a kerning value with full precision. eg: add a parameter + call error = FT_Get_Kerning(font->face, prev_glyph->index, glyph->index, FT_KERNING_UNFITTED,, &delta); OK, so the call to FT_Get_Kerning() in TTF_GetFontKerningSizeGlyphs() should use FT_KERNING_UNFITTED to be coherent. I'm sorry, but I'm not sure I understand the second part of your message (after the link). I mean you cannot use the kerning value (delta.x >> 6) returned from TTF_GetFontKerningSizeGlyphs() to mimic the advance algorithm in TTF_Size() function. because it's truncated, you need to get the kerning delta.x, compute, and truncate in the end. Thanks for the explanation. I changed FT_KERNING_DEFAULT to FT_KERNING_UNFITTED in TTF_GetFontKerningSizeGlyphs() and the result now appears to be consistent with what is done internally. But then I discovered another change in spacing between SDL_ttf 2.0.15 and the latest development version. After that I decided to rewrite my code to use TTF_SizeText() in some areas and to do things very differently in other areas. As a result I no longer need access to lsb_delta and rsb_delta. It would probably still be a good idea to update TTF_GetFontKerningSizeGlyphs() to use FT_KERNING_UNFITTED for consistency. Thanks again for everything. Ok great! So now you use TTF_SizeText() with your latest modification, and do you still rely on TTF_GetFontKerningSizeGlyphs() ? BTW: https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_kerning_mode FT_KERNING_DEFAULT: Return grid-fitted kerning distances in 26.6 fractional pixels. FT_KERNING_UNFITTED: Return un-grid-fitted kerning distances in 26.6 fractional pixels. I don't remember exactly, but some font has lsb/rsb delta, some hasn't, and/or it can depends on hinting + size font. So it worth trying with various fonts. I'm not sure if TTF_GetFontKerningSizeGlyphs() should really switch to FT_KERNING_UNFITTED for consistency. I switched TTF_Size() to FT_KERNING_UNFITTED to have the correct positioning, based on the FT2-demos example, but I don't really know what people are doing with TTF_GetFontKerningSizeGlyphs(). If TTF_GetFontKerningSizeGlyphs() gives the kerning to reproduce what TTF_Size() does, then yes. but it should also gives the lsb/rsb, and untruncated kerning. And that should be a new API for backward compatibility. I no longer rely on TTF_GetFontKerningSizeGlyphs() or TTF_GlyphMetrics() which should avoid my code from breaking in the future if the behaviour of SDL_ttf changes again. Yes, the fonts, hinting settings and sizes I quickly tested didn't appear to have lsb/rsb delta, but my code should now work in all situations as long as TTF_SizeText() returns the correct result (which seems to be the case). I understand about TTF_GetFontKerningSizeGlyphs(). A new function that gives the lsb/rsb and untruncated kerning might be useful in some situations but as I said previously I no longer need it in my current code. My code now works with the latest unmodified development version of SDL_ttf. ok great so marked as fixed, I'll wait if there is more issues about TTF_GetFontKerningSizeGlyphs() and the need of having those lsb/rsb values etc. |