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

[api-minor] Fallback to the built-in font renderer when font loading fails #10539

Merged
merged 3 commits into from Feb 12, 2019

Conversation

Snuffleupagus
Copy link
Collaborator

@Snuffleupagus Snuffleupagus commented Feb 11, 2019

After PR #9340 all glyphs are now re-mapped to a Private Use Area (PUA) which means that if a font fails to load, for whatever reason[1], all glyphs in the font will now render as Unicode glyph outlines.
This obviously doesn't look good, to say the least, and might be seen as a "regression" since previously many glyphs were left in their original positions which provided a slightly better fallback[2].

Hence this patch, which implements a general fallback to the PDF.js built-in font renderer for fonts that fail to load (i.e. are rejected by the sanitizer). One caveat here is that this only works for the Font Loading API, since it's easy to handle errors in that case[3].

The solution implemented in this patch does not in any way delay the loading of valid fonts, which was the problem with my previous attempt at a solution, and will only require a bit of extra work/waiting for those fonts that actually fail to load.

Please note: This patch doesn't fix any of the underlying PDF.js font conversion bugs that's responsible for creating corrupt font files, however it does improve rendering in a number of cases; refer to this possibly incomplete list:


[1] Usually because the PDF.js font conversion code wasn't able to parse the font file correctly.

[2] Glyphs fell back to some default font, which while not accurate was more useful than the current state.

[3] Furthermore I'm not sure how to implement this generally, assuming that's even possible, and don't really have time/interest to look into it either.

…Loader._queueLoadingCallback` when actually necessary

Currently all fonts are using the `_queueLoadingCallback` method to determine when they have been loaded[1]. However in most cases this is just adding unnecessary overhead, especially with `BaseFontLoader.bind` now being asynchronous, given how fonts are loaded:
 - For fonts loaded using the Font Loading API, it's already possible to easily tell when a font has been loaded simply by checking the `loaded` promise on the FontFace object itself.
 - For browsers, e.g. Firefox, which support synchronous font loading it's already assumed that fonts are immediately available.

Hence the `_queueLoadingCallback` method is moved into the `GenericFontLoader`, such that it's only utilized for fonts which are loaded using CSS.

---
[1] In the "fonts loaded using CSS" case, this is already a hack anyway as outlined in the comments.
…ind`

 - The only existing call-site, of this method, is never passing more than *one* font at a time anyway.
 - As far as I can remember, this functionality has never actually been used (caveat: I didn't check the git history).
 - This allows simplification of the method, especially by making use of the fact that it's now asynchronous.
 - It should be just as easy to call `BaseFontLoader.bind` from within a loop, rather than having the loop in the method itself.
@pdfjsbot
Copy link

From: Bot.io (Windows)


Received

Command cmd_test from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.215.176.217:8877/66d495ecfd2d66e/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_test from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.67.70.0:8877/139b49487237525/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/139b49487237525/output.txt

Total script time: 17.75 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Regression tests: Passed

@pdfjsbot
Copy link

From: Bot.io (Windows)


Success

Full output at http://54.215.176.217:8877/66d495ecfd2d66e/output.txt

Total script time: 25.48 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Regression tests: Passed

@Snuffleupagus Snuffleupagus force-pushed the fallback-disableFontFace-v2 branch 2 times, most recently from 5026599 to 77ebb19 Compare February 11, 2019 09:26
After PR 9340 all glyphs are now re-mapped to a Private Use Area (PUA) which means that if a font fails to load, for whatever reason[1], all glyphs in the font will now render as Unicode glyph outlines.
This obviously doesn't look good, to say the least, and might be seen as a "regression" since previously many glyphs were left in their original positions which provided a slightly better fallback[2].

Hence this patch, which implements a *general* fallback to the PDF.js built-in font renderer for fonts that fail to load (i.e. are rejected by the sanitizer). One caveat here is that this only works for the Font Loading API, since it's easy to handle errors in that case[3].

The solution implemented in this patch does *not* in any way delay the loading of valid fonts, which was the problem with my previous attempt at a solution, and will only require a bit of extra work/waiting for those fonts that actually fail to load.

*Please note:* This patch doesn't fix any of the underlying PDF.js font conversion bugs that's responsible for creating corrupt font files, however it does *improve* rendering in a number of cases; refer to this possibly incomplete list:

[Bug 1524888](https://bugzilla.mozilla.org/show_bug.cgi?id=1524888)
Issue 10175
Issue 10232

---
[1] Usually because the PDF.js font conversion code wasn't able to parse the font file correctly.

[2] Glyphs fell back to some default font, which while not accurate was more useful than the current state.

[3] Furthermore I'm not sure how to implement this generally, assuming that's even possible, and don't really have time/interest to look into it either.
@Snuffleupagus Snuffleupagus changed the title WIP - Fallback to the built-in font renderer when font loading fails Fallback to the built-in font renderer when font loading fails Feb 11, 2019
@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_test from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.67.70.0:8877/2b0970ca53316f4/output.txt

@pdfjsbot
Copy link

From: Bot.io (Windows)


Received

Command cmd_test from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.215.176.217:8877/0357aff3c435d90/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/2b0970ca53316f4/output.txt

Total script time: 17.72 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Regression tests: Passed

@pdfjsbot
Copy link

From: Bot.io (Windows)


Success

Full output at http://54.215.176.217:8877/0357aff3c435d90/output.txt

Total script time: 25.29 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Regression tests: Passed

@Snuffleupagus
Copy link
Collaborator Author

/botio-linux preview

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_preview from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.67.70.0:8877/6499ceb820b7f6b/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/6499ceb820b7f6b/output.txt

Total script time: 1.67 mins

Published

@kalda341
Copy link

This is something that we would really benefit from. We currently have a hacky workaround in our application involving getting the document with {stopAtErrors: true} and attempting to render, catching any errors that occur and re-rendering with different options if we failed.

This is a much nicer solution.

@Snuffleupagus Snuffleupagus changed the title Fallback to the built-in font renderer when font loading fails [api-minor] Fallback to the built-in font renderer when font loading fails Feb 12, 2019
Copy link
Contributor

@brendandahl brendandahl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I forgot we had a cache of all the glyphs, that makes things much easier. It would be great if we could get a follow up bug to add a test case. I am also thinking, for testing, we may want a way to ensure that this path isn't allowed, unless the test specifically allows it (maybe a pref that defaults to enabled?).

@brendandahl brendandahl merged commit 81f5835 into mozilla:master Feb 12, 2019
@Snuffleupagus Snuffleupagus deleted the fallback-disableFontFace-v2 branch February 12, 2019 20:55
@Snuffleupagus
Copy link
Collaborator Author

Looks good! I forgot we had a cache of all the glyphs, that makes things much easier.

Thank you; I'd also forgotten all about the glyphCache, and somehow it popped into my head when I was doing the dishes the other day and everything just fell into place :-)

It would be great if we could get a follow up bug to add a test case.

The reason that I didn't add a test-case here, is that this is nothing more than a work-around. The end goal should still, as far as I'm concerned, be to fix the font bugs that cause us to generate a font file that the OpenType Sanitizer ends up rejecting.

I am also thinking, for testing, we may want a way to ensure that this path isn't allowed, unless the test specifically allows it (maybe a pref that defaults to enabled?).

In an ideal world, where the underlying PDF.js bugs have been fixed, I'm not sure what you'd actually test in that case!? (Unless you somehow corrupted the font file on the main-thread, prior to loading it.)

@brendandahl
Copy link
Contributor

The reason that I didn't add a test-case here, is that this is nothing more than a work-around. The end goal should still, as far as I'm concerned, be to fix the font bugs that cause us to generate a font file that the OpenType Sanitizer ends up rejecting.

I agree, I'd still like to fix the underlying issue and for that specific PDF I have a fix in progress. Though it would still be nice to test this new code path and make sure it always works.

In an ideal world, where the underlying PDF.js bugs have been fixed, I'm not sure what you'd actually test in that case!? (Unless you somehow corrupted the font file on the main-thread, prior to loading it.)

I think we'd need a font that we intentionally never fix. Or an idea I like better is: during the test, the test framework could override the font loading api and intentionally make it fail. We could add an option to test_manifest.json for this.

@Snuffleupagus
Copy link
Collaborator Author

Or an idea I like better is: during the test, the test framework could override the font loading api and intentionally make it fail. We could add an option to test_manifest.json for this.

Totally agree, that seems like the nicest/cleanest solution.

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

Successfully merging this pull request may close these issues.

None yet

5 participants