While investigating some odd behavior, I discovered that in FreeType if a
TrueType glyf contains instructions which read/modify/write a CVT entry and
the glyph is loaded more than once the modified values persist across
calls. The persistence is in the (TT_SizeRec_) size.cvt since
TT_Load_Context sets exec.cvt to size.cvt.

The size.cvt can be reset from the face.cvt in tt_size_run_prep which is
called from tt_loader_init either directly or through
tt_size_ready_bytecode. However this is only done if the cvt isn't ready or
the rendering mode changed. If FT_Load_Glyph is called twice with the same
FT_Face/FT_Size and the same flags the modified values will persist across
the calls. This can lead to unexpected behavior where outlines hint
differently depending on the order they are loaded.

I'm not sure if this is supposed to work this way. I don't think it should,
but this doesn't seem to be addressed by any existing specification or
documentation. It seems like TT_Load_Context should make a copy of
size.cvt, or if a write is done to the cvt while hinting a glyph the
size.cvt should be marked not ready so it will be recalculated, or some
other copy/regenerate on write scheme.

I have one font in the wild which triggers this, Galasio-Bold. The fpgm
defines a few subroutines which use WCVTP which get called by a few glyphs.
The updates usually are stable, but with certain matrix which scale in y
the updates no longer round to the same pixel value and start adding up.
However, this can be abused for more interesting effects as well if used on
purpose.

I haven't investigated other parts of size, but it is possible that the
other pointers which are shared might also have this issue. For example
function_defs, instruction_defs, storage, and twilight.

Reply via email to