Wednesday, April 29, 2015

Complex Glyph Positioning

When laying out glyphs, there are a number of vectors that are all relevant to knowing where each glyph visually appears and where each glyph conceptually lies. Let’s start from the beginning.

A glyph is described by a path. A path is described by a collection of Bezier curves. A Bezier curve is described by a collection of control points. These control points are conceptually the same as vector offsets from a glyph origin. Note that this local coordinate system is not affected by any shaping that a complex text system performs.

Similarly, glyphs also have a nominal advance associated with them, which is also unaffected by shaping. This advance is a vector relative to the same glyph origin point.

Enter shaping. Shaping is a process where a complex text system can insert glyphs, delete glyphs, replace glyphs, replace sequences of glyphs with other sequences, and, importantly, move glyphs around. In particular, there are two flavors of “moving glyphs around:”
  1. Modifying the advance of a glyph, which changes placement of all subsequent glyphs in the line
  2. Modifying the origin of a glyph, which change the placement of a single glyph but not any subsequent glyphs.
Therefore, post-shaping, each glyph has two more pieces of information associated with it:
  1. The glyph’s “base advance” (Note that this is different from the nominal advance described earlier, in that shaping has modified the nominal one to create this one)
  2. The glyph’s “origin” which is simply a delta from the original pen location which describes where this glyph should be drawn.
Here is a picture which includes all the pieces at play. The green arrows describe the coordinate system that the control points of the Bezier curves are laid out in. The blue arrows describe the glyphs’ nominal advances. The red arrows describe the glyphs’ base advances, and the purple arrows describe the glyphs’ origin vectors. The red dots represent the original pen location for each glyph.

Note that when laying out glyphs this way, the glyphs are laid out such that their base advances are laid tail-to-head. These base advances then get you an original pen location for that glyph, and all subsequent vectors are relative to that original pen location.

We can then use this information to describe how to answer questions regarding the text.

If we want to know where to draw each glyph, then that is the green dots.

If we want to know where to place the caret between two glyphs, that is the average of
  1. The tip of the left glyph’s blue arrow (Note that this seems to be in the middle of the above “G” but that is just because the diagram is not to scale)
  2. The right glyph’s red dot
(Actually it’s a little more complicated because of ligatures - the caret might actually have to be placed in the middle of a glyph. In this case, we have to ask the font directly where to put the caret).

If we want to know the width of a particular string of text, that is just the tip of the rightmost glyph’s red arrow.

That’s pretty good, but there is one caveat. Most text systems only give you:
  1. The locations of the green dots (Usually in the form of either the positions of them, or delta vectors from one to the next), and
  2. The nominal glyph advances (blue arrows)
This is great for drawing text, but it isn’t sufficient for caret or width measurements because we don’t have access to the red arrows. We can approximate results by pretending that the red arrows are the same as the delta between subsequent green dots, but that doesn’t get us the correct result in all cases. It is particularly bad when characters have diacritics which are drawn as separate glyphs - this can mean negative displacement between green dots and carets that appear in the middle of a character.

No comments:

Post a Comment