memononen/nanovg

Fundamental text layout problem in nanovg

mulle-nat opened this issue · 0 comments

The layout and drawing code of nanovg uses fonsTextIterInit and fonsTextIterNext to step through the glyphs. fonsTextIterInit needs to adjust the coordinates for the given origin and alignment (like NVG_ALIGN_CENTER). For that fonsTextIterInit needs to know the width of the text line, to adjust the origin, as the string is always drawn left to right.

fonsTextIterInit calls fonsTextBounds to calculate the width. fonsTextBounds is basically another simpler rover over the glyphs, that calculates the width. But it's calculation is unfortunately not compatible with that of nvgText or nvgTextGlyphPositions:

fontstash

fonsTextBounds:

if (q.x0 < minx) minx = q.x0;
if (q.x1 > maxx) maxx = q.x1;

nanovg

nvgTextGlyphPositions uses iter.x and iter.nextx:

positions[npos].minx = nvg__minf(iter.x, q.x0) * invscale;
positions[npos].maxx = nvg__maxf(iter.nextx, q.x1) * invscale;

So that's where I think the differences in nvgTextBounds happen, as nvgTextBounds relies solely on fonsTextBounds. From a software engineering perspective though, the situation is unfortunate. The decision to use iter.x and iter.nextx is made in nanovg, so it's not transparent to fontstash. But the alignment values are defined and calculated in fontstash, which would need that information for accuracy.

I am currently of the opinion, that using the alignment implementation of fontstash is a mistake and alignment should be done in nanovg. But hacking fonsTextBounds to also use the whatever the values of iter.x and iter.nextx are, could work too...