Files
Calixte Denizet 55f52ae46f Bug 1655525 - Show a fallback for embedded PDFs when PDF.js is disabled. r=fluent-reviewers,bolsson,farre
When PDF.js is disabled, 'object' and 'embed' loads cannot invoke the configured PDF handler, so the element only renders its own fallback content and the PDF is silently dropped.
Register a dedicated PdfEmbedFallbackStreamConverter for those loads. It serves a script-free resource://pdf.js page for TYPE_OBJECT requests and cancels the unused PDF download once that page has loaded, or as soon as the frame is torn down if that happens first.
Activating its button sends a request to PdfEmbedFallbackParent, which reloads the fallback document's PDF URI in its browsing context. The parent takes the URI from the fallback's WindowGlobalParent and the triggering principal from the embedder's WindowGlobalParent; the stream converter forwards only the original request's referrer. The parent must start the load because the fallback is served on the PDF's own channel, so site isolation displays it in the PDF site's process, which cannot use the embedder's principal to initiate the load. The reload arrives as TYPE_SUBDOCUMENT, which the fallback converter declines, so the PDF goes through the usual handler selection.
That selection cannot honor "Open in Firefox", which is the action stored for PDFs by default and the one the viewer restores whenever it runs: nsExternalAppHandler treats nsIMIMEInfo::handleInternally as an action it knows how to perform, so it does not ask the user, and nsIMIMEInfo::LaunchWithFile then has no application to launch, leaving a local PDF on the launch error path. Ask the user what to do instead when a PDF would be handled internally while the viewer is disabled. Top-level loads reach the same dead end, so they are fixed as well.
Because the stream converter contract is now creatable while the viewer is disabled, nsContentUtils::IsPDFJSEnabled() reads the pdfjs.disabled pref instead of trying to create a converter, and PDF is treated as a document for object/embed when either the viewer or the fallback is enabled. Both converters now reject a missing channel explicitly, since they cannot decide how the PDF must be handled without one.
Treating it as a document also overrides the fallback content the author provided: an 'object' with a PDF and its own children now shows this page instead of them. The trade-off is deliberate: that content is meant for browsers which cannot open the PDF at all, while this page still offers to. Setting pdfjs.embedFallback to false restores it.
The whole feature is gated on pdfjs.embedFallback, mirrored to StaticPrefs since nsContentUtils reads it as well. The page is built on the in-content design system, which is desktop-only, so the pref defaults to false on Android, where neither the converter nor the actor is registered.

Differential Revision: https://phabricator.services.mozilla.com/D316050
2026-08-21 17:07:12 +00:00

35 lines
1.2 KiB
HTML

<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'none'; script-src 'none'; worker-src 'none'; style-src resource://pdf.js/embedFallback.css chrome://global/skin/; base-uri 'none'; form-action 'none';"
/>
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css" />
<link rel="stylesheet" href="resource://pdf.js/embedFallback.css" />
<link rel="localization" href="toolkit/pdfviewer/embedFallback.ftl" />
</head>
<body>
<div id="fallbackContainer">
<p
id="fallbackMessage"
dir="auto"
data-l10n-id="pdfjs-embed-fallback-message"
></p>
<button
id="fallbackOpenButton"
class="primary"
type="button"
dir="auto"
data-l10n-id="pdfjs-embed-fallback-open-button"
></button>
</div>
</body>
</html>