One of the patches in https://bugzilla.mozilla.org/show_bug.cgi?id=1202902, specifically [`Mass replace toplevel 'let' with 'var' in preparation for global lexical scope. (rs=jorendorff)`](https://hg.mozilla.org/mozilla-central/rev/380817d573cd), touches PDF.js code. Unfortunately it was landed upstream without, as far as I can tell, notifying us about it.
This patch uplifts the relevant changes to avoid future merge conflicts, and for consistency also tweaks `PdfJs-stub.jsm`.
As explained in
https://github.com/mozilla/pdf.js/issues/6174#issuecomment-118502802.
To verify that this patch works:
1. Build the Chrome extension (node make chromium)
2. Load the Chrome extension (at chrome://extensions)
3. Visit https://robwu.nl/pdfjs/issue6174/.
4. Verify that PDF.js is not used to load the PDF. Either Chrome's
default PDF Viewer is used, or the PDF is offered as a file download.
Fixes https://bugzilla.mozilla.org/show_bug.cgi?id=1170063.
The bug only mentions the <kbd>Meta</kbd> key, but given that a similar situation can occur for <kbd>Ctrl</kbd>, it seemed reasonable to also handle that case in the same patch.
The only possible caveat with the patch is that because of the use of `shadow`, things won't work perfectly if either of the prefs are changed *while* the viewer is active. In this case a reload is required in order for it to work correctly, but given that the issue this patch fixes should be quite rare anyway, that seems OK.
For some reason, https://bugzilla.mozilla.org/show_bug.cgi?id=1167053 changed methods of `NetUtil` yet *again*. This patch thus attempts to handle those changes, while keeping the addon backwards compatible.
I've tested this using all current Firefox versions (Nightly, Aurora/DevEdition, Beta, Release, ESR), and things still appears to work correctly.
This patch removes the only remaining CPOW usage from the code-base, and should thus fix https://bugzilla.mozilla.org/show_bug.cgi?id=1071082.
*Note:* This will not fix the "Open With Different Viewer" button in e10s, since clicking it still fails with `frontWindow is null` in the console, but I do believe that that issue is somewhat orthogonal to the current patch.
This checks for both prefs on the understanding that we need to work on older versions of Firefox. If that isn't the case, the first part of the if isn't necessary. This should only land if bug 639134 is resolved - I'd make the patch part of that bug, but AIUI pdfjs's canonical repo is on github, so...
As of Firefox 35, isContentWindowPrivate should be used for DOM windows instead of isWindowPrivate.
See https://bugzilla.mozilla.org/show_bug.cgi?id=1069059 and
http://hg.mozilla.org/mozilla-central/diff/324798b60ba3/toolkit/modules/PrivateBrowsingUtils.jsm
Without this fix, you will get the following error message when Firefox+PDF.js is started:
>
WARNING: content window passed to PrivateBrowsingUtils.isWindowPrivate. Use isContentWindowPrivate instead (but only for frame scripts).
pbu_isWindowPrivate@resource://gre/modules/PrivateBrowsingUtils.jsm:25:14
ChromeActions.prototype.isInPrivateBrowsing@resource://pdf.js/PdfStreamConverter.jsm:237:12
xhr_onreadystatechange@resource://pdf.js/PdfStreamConverter.jsm:545:30
NetworkManager_requestRange@resource://pdf.js/network.js:95:7
NetworkManager_requestRange@resource://pdf.js/network.js:81:14
RangedChromeActions_requestDataRange@resource://pdf.js/PdfStreamConverter.jsm:596:1
RequestListener.prototype.receive@resource://pdf.js/PdfStreamConverter.jsm:705:5
PdfStreamConverter.prototype.onStartRequest/proxy.onStopRequest/<@resource://pdf.js/PdfStreamConverter.jsm:909:11
FirefoxComClosure/<.request@resource://pdf.js/web/viewer.js:529:14
PdfDataRangeTransport_requestDataRange@resource://pdf.js/web/viewer.js:2977:9
transportDataRange@resource://pdf.js/build/pdf.js:2122:13
messageHandlerComObjOnMessage@resource://pdf.js/build/pdf.js:1219:9
Remove pageAction logic from extension router, and put it in a
separate file. The pageAction URL parsing logic has been simplified,
and all pageAction-related files have been moved to a separate directory.
document.documentElement.style is null in some XML documents.
The previous snippet caused the following error:
Uncaught TypeError: Cannot use 'in' operator to search for 'animation' in null
To fix this bug, `'animation' in document.documentElement.style` has been
replaced with `CSS.supports('animation', '9s')`. This method was introduced
in Chromium 28, but it is not necessary to detect whether this method is
supported because the required createShadowRoot method for embeds is not
available in Chromium 32 and earlier.
If a user downgrades from Chromium 35+ to 34, then the PDF Viewer
extension will not work any more because the extension assumes
that certain features were available based on the cached feature
detection results.
To resolve this problem, all feature detection scripts run again
if the browser was downgraded.
"text/javascript" is not a correct MIME type (the correct one is
"application/javascript") but it's not even needed; all browsers default
to the correct type and treat it as executable JS when type is ommited.
Since not all browsers recognize the "application/javascript" MIME type
the only way to both stay compliant and to support all popular browsers
is to omit the type. It's also shorter this way.
http://crbug.com/280464 has been resolved, so we can now use redirectUrl at
onHeadersReceived.
For backwards-compatibility, the code for the original method has not been
removed, and a feature detection script was added that detects whether the
desired feature is available.
Use streamsPrivate API when available.
When the API is not available, the extension will still work on
on http/https/file URLs, but not for POST requests or FTP.
As of writing, the Chromium project has still not whitelisted
the PDF Viewer extension in the Chrome Web Store.
(extension ID oemmndcbldboiebfnladdacbdfmadadm)
Request to whitelist PDF.js in Chromium:
https://code.google.com/p/chromium/issues/detail?id=326949
Opera 19 has whitelisted the PDF Viewer extension from
https://addons.opera.com/extensions/details/pdf-viewer/
(extension ID encfpfilknmenlmjemepncnlbbjlabkc)
(https://github.com/Rob--W/pdf.js/issues/1#issuecomment-32357302)
If you want to test the streamsPrivate feature in Chrome,
edit the build/extensions/manifest.json and add the "key" again
(see this commit for the value of this "key" field).
When a new incognito session is started, the onExecuteMimeTypeHandler event is
often not dispatched in time. Instead, it's triggered in the non-incognito profile.
This commit offers a work-around that allows new incognito instances to view PDF files.
Also:
- Use webNavigation.getAllFrames to find out whether the navigation has
already started. This is (at least) needed for top-level navigation to
a stream. The webNavigation.onErrorOccurred event has become obsolete,
and has been removed.
This is needed for propagating the extension's permissions
to the extension's iframe, in the rare event that the PDF is
loaded in a sub frame, and the extension does not have access to the
top frame. For instance, when a http:-PDF file is embedded in a
local file, while "Allow access to local URLs" is disabled.
Note: Propagating permissions by inserting content scripts is an
undocumented feature (http://crbug.com/302548).
Whenever it breaks, the issue (cross-domain permissions for XHR)
can be solved by using a content script that gets the blob using
the XMLHttpRequest API, followed by `postMessage` (via transferables)
to efficiently pass the arraybuffer back to the PDF Viewer.
This method captures all application/pdf streams, loads the viewer
and passes the stream to the PDF.js viewer.
This commit shows a proof of concept using the chrome.streamsPrivate API.
Advantages of new method:
- Access to the response body of the original request, thus fewer
network requests.
- PDFs from non-GET requests (e.g. POST) are now supported.
- FTP files are also supported.
Possible improvements:
- Use declared content scripts instead of dynamic chrome.tabs.executeScript.
This allows the extension to render the viewer in frames when the
extension is disallowed to run executeScript for the top URL.
- Use chrome.declarativeWebRequest instead of webRequest, and replace
background page with event page (don't forget to profile the
difference & will the background/event page still work as intended?).