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

Qutebrowser is incompatible with pdfjs-4.1 #8170

Open
bodograumann opened this issue Apr 22, 2024 · 7 comments · May be fixed by #8199
Open

Qutebrowser is incompatible with pdfjs-4.1 #8170

bodograumann opened this issue Apr 22, 2024 · 7 comments · May be fixed by #8199
Milestone

Comments

@bodograumann
Copy link

Version info:

qutebrowser v3.1.0
Git commit: 
Backend: QtWebEngine 6.7, based on Chromium 118.0.5993.220 (from api)
Qt: 6.7.0

Does the bug happen if you start with --temp-basedir?: Yes

Description

After upgrading pdfjs from 4.0 to 4.1, it does not work with pdfjs anymore. Instead the following error occurs, when trying to open a pdf file:

JS:  [qute://pdfjs/web/viewer.mjs:2057] Uncaught TypeError: Promise.withResolvers is not a function
JS:  [qute://pdfjs/web/viewer.html?filename=tmp[…]&file=&source=[…]] Uncaught TypeError: Cannot read properties of undefined (reading 'set')

Related: mozilla/pdf.js#17932

How to reproduce

Open any pdf file with qutebrowser (3.1.0 e.g.) and pdfjs 4.1.

@The-Compiler
Copy link
Member

Looks like it's API that was added only quite recently in Chromium 119: JavaScript built-in: Promise: withResolvers | Can I use... Support tables for HTML5, CSS3, etc

But Qt 6.7 is based on 118, which is why it's not available.

Looks like it's easy to polyfill:

So we should probably do that for our PDF.js glue code.

@The-Compiler
Copy link
Member

With

diff --git i/qutebrowser/browser/pdfjs.py w/qutebrowser/browser/pdfjs.py
index 841285deb..cf06f9aff 100644
--- i/qutebrowser/browser/pdfjs.py
+++ w/qutebrowser/browser/pdfjs.py
@@ -83,6 +83,17 @@ def _generate_pdfjs_script(filename):
     js_url = javascript.to_js(url.toString(urlutils.FormatOption.ENCODED))
 
     return jinja.js_environment.from_string("""
+        if (typeof Promise.withResolvers === 'undefined') {
+            Promise.withResolvers = function () {
+                let resolve, reject
+                const promise = new Promise((res, rej) => {
+                    resolve = res
+                    reject = rej
+                })
+                return { promise, resolve, reject }
+            }
+        }
+
         document.addEventListener("DOMContentLoaded", function() {
             if (typeof window.PDFJS !== 'undefined') {
                 // v1.x

The same issue pops up in qute://pdfjs/build/pdf.worker.mjs instead... I suppose we could patch that on a file-level, but this will probably get a bit more hacky than I thought it would be...

As a workaround, switching to the legacy PDF.js build (pdfjs-legacy on Arch) fixes things.

@toofar
Copy link
Member

toofar commented Apr 26, 2024

You can manipulate the files in flight in qutescheme as well. Inspried by greasemonky scripts that hook fetch() so they can inject code into workers like this.

diff --git i/qutebrowser/browser/qutescheme.py w/qutebrowser/browser/qutescheme.py
index 508d510d706e..b38fc1e98a94 100644
--- i/qutebrowser/browser/qutescheme.py
+++ w/qutebrowser/browser/qutescheme.py
@@ -553,6 +553,21 @@ def qute_pdfjs(url: QUrl) -> _HandlerRet:
             "pdfjs resource requested but not found: {}".format(e.path))
         raise NotFoundError("Can't find pdfjs resource '{}'".format(e.path))
     mimetype = utils.guess_mimetype(url.fileName(), fallback=True)
+
+    if url.path() == '/build/pdf.worker.mjs':
+        data = b"""
+        if (typeof Promise.withResolvers === 'undefined') {
+            Promise.withResolvers = function () {
+                let resolve, reject
+                const promise = new Promise((res, rej) => {
+                    resolve = res
+                    reject = rej
+                })
+                return { promise, resolve, reject }
+            }
+        }
+
+        """ + data
     return mimetype, data

@The-Compiler The-Compiler added this to the v3.2.0 milestone Apr 30, 2024
@toofar
Copy link
Member

toofar commented May 13, 2024

The last two issues with PDF.js have resulted in JS error logs. It looks like these tests would have caught that but it looks like they are skipped in CI. I'm guessing because it has no PDF.js installed?

What do you think about

  1. installing pdfjs in the docker containers
  2. installing libjs-pdf on ubuntu runners*
  3. running scripts/dev/update_3rdparty.py on the windows runner
  4. running scripts/dev/update_3rdparty.py on the bleeding edge CI?

*: debuntu ships a broken pdfjs package it seems, so we get file not found errors for files required for pdf.js, like tooltip images and locale files. Not sure which direction to go on this front, see toofar@afc9c87 for some words.

(Also here is a patch with the polyfill above in a common function.)
diff --git i/qutebrowser/browser/pdfjs.py w/qutebrowser/browser/pdfjs.py
index 841285deb83a..4fca7e81dddd 100644
--- i/qutebrowser/browser/pdfjs.py
+++ w/qutebrowser/browser/pdfjs.py
@@ -69,6 +69,21 @@ def generate_pdfjs_page(filename, url):
     return html
 
 
+def _generate_polyfills():
+    return """
+        if (typeof Promise.withResolvers === 'undefined') {
+            Promise.withResolvers = function () {
+                let resolve, reject
+                const promise = new Promise((res, rej) => {
+                    resolve = res
+                    reject = rej
+                })
+                return { promise, resolve, reject }
+            }
+        }
+    """
+
+
 def _generate_pdfjs_script(filename):
     """Generate the script that shows the pdf with pdf.js.
 
@@ -83,6 +98,8 @@ def _generate_pdfjs_script(filename):
     js_url = javascript.to_js(url.toString(urlutils.FormatOption.ENCODED))
 
     return jinja.js_environment.from_string("""
+        {{ polyfills }}
+
         document.addEventListener("DOMContentLoaded", function() {
             if (typeof window.PDFJS !== 'undefined') {
                 // v1.x
@@ -104,7 +121,7 @@ def _generate_pdfjs_script(filename):
                 });
             }
         });
-    """).render(url=js_url)
+    """).render(url=js_url, polyfills=_generate_polyfills())
 
 
 def get_pdfjs_res_and_path(path):
@@ -148,6 +165,9 @@ def get_pdfjs_res_and_path(path):
             log.misc.warning("OSError while reading PDF.js file: {}".format(e))
             raise PDFJSNotFound(path) from None
 
+    if path == "build/pdf.worker.mjs":
+        content += _generate_polyfills().encode("ascii")
+
     return content, file_path

toofar added a commit to toofar/qutebrowser that referenced this issue May 15, 2024
It's needed for both the main page (which we generate using jinja) and
the worker script.

Closes: qutebrowser#8170
@toofar
Copy link
Member

toofar commented May 17, 2024

Okay, should have a PR up tomorrow. The tests for Qt < 6.5 are failing for some different "new javascript feature" reason and all the ubuntu ones are anyway failing because of #7904. So to get some pdfjs test running on CI but without having to deal with all that breakage my current plan is to install pdfjs in the archlinux based qt6 docker containers and install it from source in the bleeding edge jobs. (And maybe in the windows tests, dunno, seems surplus to requirements.)

Edit: having fun wrangling tests and test environments and CI setups. Might be green now. 😴

@bodograumann
Copy link
Author

Sounds like we should really be using the pdfjs legacy build, instead of introducing moer and more workarounds / polyfills!?

@The-Compiler
Copy link
Member

On Linux, we don't have a choice what people have installed OS-wide. I'm not too worried about older Qt versions (chances are distributions with older Qt have an older PDF.js too), but the newest QtWebEngine should work with the newest PDF.js default build.

toofar added a commit that referenced this issue May 18, 2024
It's needed for both the main page (which we generate using jinja) and
the worker script.

Closes: #8170
toofar added a commit that referenced this issue May 20, 2024
It's needed for both the main page (which we generate using jinja) and
the worker script.

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

Successfully merging a pull request may close this issue.

3 participants