Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Match VSFilter behavior by introducing rounding error for position at glyph run boundaries #21

Open
rcombs opened this issue Jan 20, 2014 · 4 comments

Comments

@rcombs
Copy link
Member

rcombs commented Jan 20, 2014

VSFilter rounds off position values to either pixels or ⅛-pixels (not sure which?) at glyph run boundaries. We don't, which creates some incompatibilities when scripts try to make up for the difference by adding \fscx or similar to other layers. In some cases (like heavy kara), it can result in a shift by multiple px due to the (lack of) accumulated error. We may be able to replicate this behavior by detecting glyph runs slightly earlier, then converting positions to storage pixels, simulating the rounding, then converting back.

@astiob
Copy link
Member

astiob commented Jan 25, 2014

I see you edited this issue. But the pictures in this issue will not be fixed by adding the rounding: the “border” is a single run, and each karaoke syllable has its own \pos. These \poses don’t match the positions of those syllables in the “border” layer, and adding rounding won’t change this.

@rcombs
Copy link
Member Author

rcombs commented Jan 25, 2014

Oh, heh, you're right. Maybe I should actually read the script before assuming it demonstrates an issue… Lemme clean this mess up.

@astiob
Copy link
Member

astiob commented May 17, 2014

Started for vertical rounding in astiob@rounding. Vertical rounding at video resolution should match now; other resolutions need a little bit more work but should be easy enough. Horizontal rounding is harder, because (as mentioned above) we detect glyph runs too late.

@astiob
Copy link
Member

astiob commented Apr 9, 2023

Turns out vertical rounding is tricky, too: it depends on font size and involves a peculiar sequence of rounding steps.

Using “d6” and “d3” to mean “6/3 bits in the fractional part”, VSFilter does the following:

  1. Request font of size trunc(\fs × 64 + 0.5) integer units from GDI. (Roughly equivalent to \fs in d6 fixed point.)
  2. Read ascender and descender heights from GDI in those same integer units. (It is anyone’s guess how exactly GDI rounds the metrics if this involves a non-integer scaling factor from the font’s native metric units.)
  3. Divide the ascender and separately the descender by 8, rounding half towards plus infinity. (Convert d6 to d3 with rounding.)
  4. Multiply the ascender and separately the descender by \fscy percent, truncating any fractions towards zero.
  5. For blank lines, halve the scaled ascender and separately the descender, truncating any fractions again towards zero.
  6. Use the sum of ascender and descender as the line height. [1] [2]

For vector drawings, steps 1–4 are replaced by:

  1. Read \pbo as an integer (truncating any fraction towards zero).
  2. Read the drawing’s coordinates into d6 fixed point, truncating any smaller fractions towards zero.
  3. Scale the nominal coordinates to video resolution, still in d6 fixed point, truncating any smaller fractions again towards zero.
  4. Scale the integer \pbo to video resolution as d6 fixed point, truncating any smaller fractions towards zero. Use this as the descender height.
  5. Convert the drawing’s video-resolution d6 height-minus-pbo to d3, rounding half towards plus infinity. Use this as the ascender height.

All in all, multiple rounding steps are involved, and multiple of them may even involve d3 truncation.

For example, I almost published a file with a long scrolling event that contains multiple paragraphs separated by full blank lines (\N\N\N to compensate for the halving), and each blank half-line in VSFilter is 1/8 px shorter than you’d expect due to the truncation. Over multiple paragraphs, this adds up to a clearly visible difference of several pixels. (And I’m lucky that only one truncation step has an effect in this case: if I had other \fs or \fscy values, the difference could be even bigger!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants