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

glyphs without decimals #1397

Closed
wants to merge 1 commit into from
Closed

glyphs without decimals #1397

wants to merge 1 commit into from

Conversation

rvilarl
Copy link
Collaborator

@rvilarl rvilarl commented May 29, 2022

Removal from decimals in glyphs separated in a new PR.

@rvilarl rvilarl requested review from ronyeh and 0xfe May 29, 2022 06:02
@ronyeh
Copy link
Collaborator

ronyeh commented May 29, 2022

Sorry for the dumb question. Does this affect anything in the final output? I don't think we should be rounding to integer if the original OTF specifies a decimal point. We should keep the paths and font outlines as true to the original OTF files as possible, and scale at the last possible moment.

@rvilarl
Copy link
Collaborator Author

rvilarl commented May 29, 2022

No visual differences. This is only rounding internal bounding box calculations.

Can we put the rounding changes into a separate PR please? (also, use toFixed(3) instead of rounding. The precision came straight from the font files, and I'm guessing they support high zoom levels.)

Hi Mohit, the decimals come from a bounding box calculation. The glyphs themselves did not have decimals as they already rounded using Fix:

  function fix(f, invert = false) {
    return Math.round((f / pointSize) * scale) * (invert ? -1 : 1);
  }

ToFixed returns a string and uses strings in general for the calculation. I think that this is less efficient but if you want I can test. Please also note that the function fix above uses Math.round

See #1395 (comment) for more details

@AaronDavidNewman
Copy link
Collaborator

I don't think we should be rounding to integer if the original OTF specifies a decimal point

@ronyeh OTF are binary files, they are stored as uint 8 or 16:

https://docs.microsoft.com/en-us/typography/opentype/spec/glyf

The coordinates are x/y within a box, the size of which is determined in the font file. So rounding only happens when we scale them.

I have not been following this too closely, but I think there's been some optimization in this area lately by @tommadams.

@rvilarl rvilarl added 4.0.4 4.1 and removed 4.0.4 labels Jun 2, 2022
@0xfe
Copy link
Owner

0xfe commented Jun 6, 2022

@rvilarl The bounding boxes are used for placement though, and it's not clear if this will make a difference at higher zoom levels.

I agree that the digits after the decimal are too many, but how about pruning to 3 digits instead of removing them completely?

@rvilarl
Copy link
Collaborator Author

rvilarl commented Jun 6, 2022

@0xfe well I do not understand why we remove them completely for the path and not for the bounding box.

  function fix(f, invert = false) {
    return Math.round((f / pointSize) * scale) * (invert ? -1 : 1);
  }

Why should the bounding box treated more strictly than the pah? And there is no visual difference. And as Aaron said "So rounding only happens when we scale them."

@0xfe
Copy link
Owner

0xfe commented Jun 6, 2022

Oh, I didn't realize that it applied to paths too -- is that during runtime? Do we only call fix when we scale?

@rvilarl
Copy link
Collaborator Author

rvilarl commented Jun 6, 2022

@0xfe fix is used by fontgen_smufl.js in the offline conversion of OTF to JavaScript for all the numbers in the paths.

@ronyeh
Copy link
Collaborator

ronyeh commented Jun 7, 2022

Thanks for the discussion.

I looked into this, and it seems like we have been rounding path points to the nearest integer since SMuFL fonts were introduced. Here is the 3.0.9 version of font gen:

https://github.com/0xfe/vexflow/blob/3.0.9/tools/smufl/smufl_fontgen.js

You see that the fix() function includes Math.round(), and this is done to all of the points in the path for every glyph.

However, the bounding boxes are not rounded.

Here are our options:

  1. Do nothing and leave it as is. There seems to be no problem with leaving the bounding boxes with decimal points. Since this PR doesn't introduce a detectable visual diff, all it means is that our glyph files look a bit "cleaner".
  2. Merge this PR, but understand that the integers in our glyph files aren't exactly "correct" anyways, because our fontgen script scales the paths and bounding boxes, and then rounds them to the nearest int so they look cleaner. Then, at runtime, more scaling happens, and then the final path points are rounded to 3 decimal points.

Long term, I think the truly correct solution would be to:

  1. Refactor the font gen script so that the glyphs are extracted at full resolution. The SMuFL OTFs are designed on a 1000 x 1000 grid, and all the path points and bounding boxes should be integers.
  2. At runtime, scale the paths down at the last possible moment, to 3 decimal points of precision.

In my investigation into this (September 2021), I found that the final scale factor would be around 4% of the original 1000pt font size for the glyphs.

See: #1158 (comment)

The original smufl_fontgen was extracting paths at 72pt and then scaling the coordinates by 20. It turns out all I had to do was multiply my scale factor by 1.44 to get an identical result. 72 * 20 / 1000.

Currently, the notehead transforms look somewhat like: transform="translate(258.5144654098348 150) scale(0.0404352 0.0404352)"

So we are scaling glyphs down to about 4% of their original size.

@rvilarl
Copy link
Collaborator Author

rvilarl commented Jun 7, 2022

@ronyeh what would you recommend? This also speaks in favour of #1399 or direct usage of FontFace, does not it?

@ronyeh
Copy link
Collaborator

ronyeh commented Jun 8, 2022

I think my recommendation would be to leave it as is (i.e., close this PR without merge), since this is just a cosmetic change to the glyph files' bounding box fields, with no detectable visual change in the output.

I understand Mohit's desire to keep VexFlow pure, without having a runtime dependency on the opentype.js library.

Perhaps someday we can extract the pure OTF paths and scale them only at the last possible moment (at runtime). Or maybe the FontFace API will have wide enough support that we can drop the glyphs files and use the OTFs directly.

It seems like browser support is pretty good for FontFace:

Safari iOS / Mac might be the only ones with incomplete support.

I think this would be a good goal for a future version of VexFlow (e.g., VexFlow 5):

  • vexflow.js is just the logic / formatter / layout engine.
  • vexflow-bravura-metrics.js / vexflow-leland-metrics.js / vexflow-abcdef-metrics.js are the hint files for laying out each particular font.
  • Then, the above library loads the correct OTF at runtime via FontFace and uses native browser APIs to place the glyphs.

@rvilarl rvilarl closed this Jun 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants