Add pdfjs to PM (from basilisk)

This commit is contained in:
K4sum1 2025-09-28 13:15:21 -07:00
commit 32e898e91e
276 changed files with 69821 additions and 0 deletions

View file

@ -1098,6 +1098,18 @@ pref("permissions.manager.defaultsUrl", "resource://app/defaults/permissions");
// (this pref has no effect if more than 6 hours have passed since the last crash)
pref("toolkit.startup.max_resumed_crashes", 3);
// Completely disable pdf.js as an option to preview pdfs within firefox.
// Note: if this is not disabled it does not necessarily mean pdf.js is the pdf
// handler just that it is an option.
pref("pdfjs.disabled", false);
// Used by pdf.js to know the first time firefox is run with it installed so it
// can become the default pdf viewer.
pref("pdfjs.firstRun", true);
// The values of preferredAction and alwaysAskBeforeHandling before pdf.js
// became the default.
pref("pdfjs.previousHandler.preferredAction", 0);
pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
// The maximum amount of decoded image data we'll willingly keep around (we
// might keep around more than this, but we'll try to get down to this value).
// (This is intentionally on the high side; see bug 746055.)

View file

@ -30,6 +30,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "winShellService",
["BookmarkHTMLUtils", "resource://gre/modules/BookmarkHTMLUtils.jsm"],
["BookmarkJSONUtils", "resource://gre/modules/BookmarkJSONUtils.jsm"],
["PageThumbs", "resource://gre/modules/PageThumbs.jsm"],
["PdfJs", "resource://pdf.js/PdfJs.jsm"],
["NewTabUtils", "resource://gre/modules/NewTabUtils.jsm"],
["BrowserNewTabPreloader", "resource:///modules/BrowserNewTabPreloader.jsm"],
#ifdef MOZ_WEBRTC
@ -630,6 +631,20 @@ BrowserGlue.prototype = {
// the first browser window has finished initializing
_onFirstWindowLoaded: function() {
// Initialize PdfJs when running in-process and remote. This only
// happens once since PdfJs registers global hooks. If the PdfJs
// extension is installed the init method below will be overridden
// leaving initialization to the extension.
// parent only: configure default prefs, set up pref observers, register
// pdf content handler, and initializes parent side message manager
// shim for privileged api access.
PdfJs.init(true);
// child only: similar to the call above for parent - register content
// handler and init message manager child shim for privileged api access.
// With older versions of the extension installed, this load will fail
// passively.
Services.ppmm.loadProcessScript("resource://pdf.js/pdfjschildbootstrap.js", true);
#ifdef XP_WIN
// For Windows, initialize the jump list module.
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";

View file

@ -0,0 +1,9 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# 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/.
DIRS += [
'pdfjs',
]

View file

@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View file

@ -0,0 +1,3 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.7.348

View file

@ -0,0 +1 @@
resource pdf.js content/

View file

@ -0,0 +1,349 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals Components, Services, XPCOMUtils, PdfjsChromeUtils,
PdfjsContentUtils, PdfStreamConverter */
"use strict";
var EXPORTED_SYMBOLS = ["PdfJs"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cm = Components.manager;
const Cu = Components.utils;
const PREF_PREFIX = "pdfjs";
const PREF_DISABLED = PREF_PREFIX + ".disabled";
const PREF_MIGRATION_VERSION = PREF_PREFIX + ".migrationVersion";
const PREF_PREVIOUS_ACTION = PREF_PREFIX + ".previousHandler.preferredAction";
const PREF_PREVIOUS_ASK = PREF_PREFIX +
".previousHandler.alwaysAskBeforeHandling";
const PREF_DISABLED_PLUGIN_TYPES = "plugin.disable_full_page_plugin_for_types";
const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged";
const TOPIC_PLUGINS_LIST_UPDATED = "plugins-list-updated";
const TOPIC_PLUGIN_INFO_UPDATED = "plugin-info-updated";
const PDF_CONTENT_TYPE = "application/pdf";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
"@mozilla.org/mime;1",
"nsIMIMEService");
XPCOMUtils.defineLazyServiceGetter(Svc, "pluginHost",
"@mozilla.org/plugin/host;1",
"nsIPluginHost");
XPCOMUtils.defineLazyModuleGetter(this, "PdfjsChromeUtils",
"resource://pdf.js/PdfjsChromeUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PdfjsContentUtils",
"resource://pdf.js/PdfjsContentUtils.jsm");
function getBoolPref(aPref, aDefaultValue) {
try {
return Services.prefs.getBoolPref(aPref);
} catch (ex) {
return aDefaultValue;
}
}
function getIntPref(aPref, aDefaultValue) {
try {
return Services.prefs.getIntPref(aPref);
} catch (ex) {
return aDefaultValue;
}
}
function isDefaultHandler() {
if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
return PdfjsContentUtils.isDefaultHandlerApp();
}
return PdfjsChromeUtils.isDefaultHandlerApp();
}
function initializeDefaultPreferences() {
var DEFAULT_PREFERENCES =
{
"showPreviousViewOnLoad": true,
"defaultZoomValue": "",
"sidebarViewOnLoad": 0,
"enableHandToolOnLoad": false,
"enableWebGL": false,
"pdfBugEnabled": false,
"disableRange": false,
"disableStream": false,
"disableAutoFetch": false,
"disableFontFace": false,
"disableTextLayer": false,
"useOnlyCssZoom": false,
"externalLinkTarget": 0,
"enhanceTextSelection": false,
"renderer": "canvas",
"renderInteractiveForms": false,
"enablePrintAutoRotate": false,
"disablePageLabels": false
}
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + ".");
var defaultValue;
for (var key in DEFAULT_PREFERENCES) {
defaultValue = DEFAULT_PREFERENCES[key];
switch (typeof defaultValue) {
case "boolean":
defaultBranch.setBoolPref(key, defaultValue);
break;
case "number":
defaultBranch.setIntPref(key, defaultValue);
break;
case "string":
defaultBranch.setCharPref(key, defaultValue);
break;
}
}
}
// Register/unregister a constructor as a factory.
function Factory() {}
Factory.prototype = {
register: function register(targetConstructor) {
var proto = targetConstructor.prototype;
this._classID = proto.classID;
var factory = XPCOMUtils._getFactory(targetConstructor);
this._factory = factory;
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(proto.classID, proto.classDescription,
proto.contractID, factory);
if (proto.classID2) {
this._classID2 = proto.classID2;
registrar.registerFactory(proto.classID2, proto.classDescription,
proto.contractID2, factory);
}
},
unregister: function unregister() {
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(this._classID, this._factory);
if (this._classID2) {
registrar.unregisterFactory(this._classID2, this._factory);
}
this._factory = null;
}
};
var PdfJs = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
_registered: false,
_initialized: false,
init: function init(remote) {
if (Services.appinfo.processType !==
Services.appinfo.PROCESS_TYPE_DEFAULT) {
throw new Error("PdfJs.init should only get called " +
"in the parent process.");
}
PdfjsChromeUtils.init();
if (!remote) {
PdfjsContentUtils.init();
}
this.initPrefs();
this.updateRegistration();
},
initPrefs: function initPrefs() {
if (this._initialized) {
return;
}
this._initialized = true;
if (!getBoolPref(PREF_DISABLED, true)) {
this._migrate();
}
// Listen for when pdf.js is completely disabled or a different pdf handler
// is chosen.
Services.prefs.addObserver(PREF_DISABLED, this, false);
Services.prefs.addObserver(PREF_DISABLED_PLUGIN_TYPES, this, false);
Services.obs.addObserver(this, TOPIC_PDFJS_HANDLER_CHANGED, false);
Services.obs.addObserver(this, TOPIC_PLUGINS_LIST_UPDATED, false);
Services.obs.addObserver(this, TOPIC_PLUGIN_INFO_UPDATED, false);
initializeDefaultPreferences();
},
updateRegistration: function updateRegistration() {
if (this.enabled) {
this._ensureRegistered();
} else {
this._ensureUnregistered();
}
},
uninit: function uninit() {
if (this._initialized) {
Services.prefs.removeObserver(PREF_DISABLED, this);
Services.prefs.removeObserver(PREF_DISABLED_PLUGIN_TYPES, this);
Services.obs.removeObserver(this, TOPIC_PDFJS_HANDLER_CHANGED);
Services.obs.removeObserver(this, TOPIC_PLUGINS_LIST_UPDATED);
Services.obs.removeObserver(this, TOPIC_PLUGIN_INFO_UPDATED);
this._initialized = false;
}
this._ensureUnregistered();
},
_migrate: function migrate() {
const VERSION = 2;
var currentVersion = getIntPref(PREF_MIGRATION_VERSION, 0);
if (currentVersion >= VERSION) {
return;
}
// Make pdf.js the default pdf viewer on the first migration.
if (currentVersion < 1) {
this._becomeHandler();
}
if (currentVersion < 2) {
// cleaning up of unused database preference (see #3994)
Services.prefs.clearUserPref(PREF_PREFIX + ".database");
}
Services.prefs.setIntPref(PREF_MIGRATION_VERSION, VERSION);
},
_becomeHandler: function _becomeHandler() {
let handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, "pdf");
let prefs = Services.prefs;
if (handlerInfo.preferredAction !== Ci.nsIHandlerInfo.handleInternally &&
handlerInfo.preferredAction !== false) {
// Store the previous settings of preferredAction and
// alwaysAskBeforeHandling in case we need to revert them in a hotfix that
// would turn pdf.js off.
prefs.setIntPref(PREF_PREVIOUS_ACTION, handlerInfo.preferredAction);
prefs.setBoolPref(PREF_PREVIOUS_ASK, handlerInfo.alwaysAskBeforeHandling);
}
let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].
getService(Ci.nsIHandlerService);
// Change and save mime handler settings.
handlerInfo.alwaysAskBeforeHandling = false;
handlerInfo.preferredAction = Ci.nsIHandlerInfo.handleInternally;
handlerService.store(handlerInfo);
// Also disable any plugins for pdfs.
var stringTypes = "";
var types = [];
if (prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES)) {
stringTypes = prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES);
}
if (stringTypes !== "") {
types = stringTypes.split(",");
}
if (types.indexOf(PDF_CONTENT_TYPE) === -1) {
types.push(PDF_CONTENT_TYPE);
}
prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES, types.join(","));
// Update the category manager in case the plugins are already loaded.
let categoryManager = Cc["@mozilla.org/categorymanager;1"];
categoryManager.getService(Ci.nsICategoryManager).
deleteCategoryEntry("Gecko-Content-Viewers",
PDF_CONTENT_TYPE,
false);
},
// nsIObserver
observe: function observe(aSubject, aTopic, aData) {
this.updateRegistration();
if (Services.appinfo.processType ===
Services.appinfo.PROCESS_TYPE_DEFAULT) {
let jsm = "resource://pdf.js/PdfjsChromeUtils.jsm";
let PdfjsChromeUtils = Components.utils.import(jsm, {}).PdfjsChromeUtils;
PdfjsChromeUtils.notifyChildOfSettingsChange();
}
},
/**
* pdf.js is only enabled if it is both selected as the pdf viewer and if the
* global switch enabling it is true.
* @return {boolean} Whether or not it's enabled.
*/
get enabled() {
var disabled = getBoolPref(PREF_DISABLED, true);
if (disabled) {
return false;
}
// Check if the 'application/pdf' preview handler is configured properly.
if (!isDefaultHandler()) {
return false;
}
// Check if we have disabled plugin handling of 'application/pdf' in prefs
if (Services.prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES)) {
let disabledPluginTypes =
Services.prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES).split(",");
if (disabledPluginTypes.indexOf(PDF_CONTENT_TYPE) >= 0) {
return true;
}
}
// Check if there is an enabled pdf plugin.
// Note: this check is performed last because getPluginTags() triggers
// costly plugin list initialization (bug 881575)
let tags = Cc["@mozilla.org/plugin/host;1"].
getService(Ci.nsIPluginHost).
getPluginTags();
let enabledPluginFound = tags.some(function(tag) {
if (tag.disabled) {
return false;
}
let mimeTypes = tag.getMimeTypes();
return mimeTypes.some(function(mimeType) {
return mimeType === PDF_CONTENT_TYPE;
});
});
// Use pdf.js if pdf plugin is not present or disabled
return !enabledPluginFound;
},
_ensureRegistered: function _ensureRegistered() {
if (this._registered) {
return;
}
this._pdfStreamConverterFactory = new Factory();
Cu.import("resource://pdf.js/PdfStreamConverter.jsm");
this._pdfStreamConverterFactory.register(PdfStreamConverter);
this._registered = true;
},
_ensureUnregistered: function _ensureUnregistered() {
if (!this._registered) {
return;
}
this._pdfStreamConverterFactory.unregister();
Cu.unload("resource://pdf.js/PdfStreamConverter.jsm");
delete this._pdfStreamConverterFactory;
this._registered = false;
}
};

View file

@ -0,0 +1,257 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals Components, Services */
"use strict";
Components.utils.import("resource://gre/modules/Services.jsm");
var EXPORTED_SYMBOLS = ["NetworkManager"];
function log(aMsg) {
var msg = "PdfJsNetwork.jsm: " + (aMsg.join ? aMsg.join("") : aMsg);
Services.console.logStringMessage(msg);
}
var NetworkManager = (function NetworkManagerClosure() {
const OK_RESPONSE = 200;
const PARTIAL_CONTENT_RESPONSE = 206;
function getArrayBuffer(xhr) {
var data = xhr.response;
if (typeof data !== "string") {
return data;
}
var length = data.length;
var array = new Uint8Array(length);
for (var i = 0; i < length; i++) {
array[i] = data.charCodeAt(i) & 0xFF;
}
return array.buffer;
}
class NetworkManagerClass {
constructor(url, args) {
this.url = url;
args = args || {};
this.isHttp = /^https?:/i.test(url);
this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
this.withCredentials = args.withCredentials || false;
this.getXhr = args.getXhr ||
function NetworkManager_getXhr() {
return new XMLHttpRequest();
};
this.currXhrId = 0;
this.pendingRequests = Object.create(null);
this.loadedRequests = Object.create(null);
}
requestRange(begin, end, listeners) {
var args = {
begin,
end,
};
for (var prop in listeners) {
args[prop] = listeners[prop];
}
return this.request(args);
}
requestFull(listeners) {
return this.request(listeners);
}
request(args) {
var xhr = this.getXhr();
var xhrId = this.currXhrId++;
var pendingRequest = this.pendingRequests[xhrId] = {
xhr,
};
xhr.open("GET", this.url);
xhr.withCredentials = this.withCredentials;
for (var property in this.httpHeaders) {
var value = this.httpHeaders[property];
if (typeof value === "undefined") {
continue;
}
xhr.setRequestHeader(property, value);
}
if (this.isHttp && "begin" in args && "end" in args) {
var rangeStr = args.begin + "-" + (args.end - 1);
xhr.setRequestHeader("Range", "bytes=" + rangeStr);
pendingRequest.expectedStatus = 206;
} else {
pendingRequest.expectedStatus = 200;
}
var useMozChunkedLoading = !!args.onProgressiveData;
if (useMozChunkedLoading) {
xhr.responseType = "moz-chunked-arraybuffer";
pendingRequest.onProgressiveData = args.onProgressiveData;
pendingRequest.mozChunked = true;
} else {
xhr.responseType = "arraybuffer";
}
if (args.onError) {
xhr.onerror = function(evt) {
args.onError(xhr.status);
};
}
xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
xhr.onprogress = this.onProgress.bind(this, xhrId);
pendingRequest.onHeadersReceived = args.onHeadersReceived;
pendingRequest.onDone = args.onDone;
pendingRequest.onError = args.onError;
pendingRequest.onProgress = args.onProgress;
xhr.send(null);
return xhrId;
}
onProgress(xhrId, evt) {
var pendingRequest = this.pendingRequests[xhrId];
if (!pendingRequest) {
// Maybe abortRequest was called...
return;
}
if (pendingRequest.mozChunked) {
var chunk = getArrayBuffer(pendingRequest.xhr);
pendingRequest.onProgressiveData(chunk);
}
var onProgress = pendingRequest.onProgress;
if (onProgress) {
onProgress(evt);
}
}
onStateChange(xhrId, evt) {
var pendingRequest = this.pendingRequests[xhrId];
if (!pendingRequest) {
// Maybe abortRequest was called...
return;
}
var xhr = pendingRequest.xhr;
if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
pendingRequest.onHeadersReceived();
delete pendingRequest.onHeadersReceived;
}
if (xhr.readyState !== 4) {
return;
}
if (!(xhrId in this.pendingRequests)) {
// The XHR request might have been aborted in onHeadersReceived()
// callback, in which case we should abort request
return;
}
delete this.pendingRequests[xhrId];
// success status == 0 can be on ftp, file and other protocols
if (xhr.status === 0 && this.isHttp) {
if (pendingRequest.onError) {
pendingRequest.onError(xhr.status);
}
return;
}
var xhrStatus = xhr.status || OK_RESPONSE;
// From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2:
// "A server MAY ignore the Range header". This means it's possible to
// get a 200 rather than a 206 response from a range request.
var ok_response_on_range_request =
xhrStatus === OK_RESPONSE &&
pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
if (!ok_response_on_range_request &&
xhrStatus !== pendingRequest.expectedStatus) {
if (pendingRequest.onError) {
pendingRequest.onError(xhr.status);
}
return;
}
this.loadedRequests[xhrId] = true;
var chunk = getArrayBuffer(xhr);
if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
var rangeHeader = xhr.getResponseHeader("Content-Range");
var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
var begin = parseInt(matches[1], 10);
pendingRequest.onDone({
begin,
chunk,
});
} else if (pendingRequest.onProgressiveData) {
pendingRequest.onDone(null);
} else if (chunk) {
pendingRequest.onDone({
begin: 0,
chunk,
});
} else if (pendingRequest.onError) {
pendingRequest.onError(xhr.status);
}
}
hasPendingRequests() {
for (var xhrId in this.pendingRequests) {
return true;
}
return false;
}
getRequestXhr(xhrId) {
return this.pendingRequests[xhrId].xhr;
}
isStreamingRequest(xhrId) {
return !!(this.pendingRequests[xhrId].onProgressiveData);
}
isPendingRequest(xhrId) {
return xhrId in this.pendingRequests;
}
isLoadedRequest(xhrId) {
return xhrId in this.loadedRequests;
}
abortAllRequests() {
for (var xhrId in this.pendingRequests) {
this.abortRequest(xhrId | 0);
}
}
abortRequest(xhrId) {
var xhr = this.pendingRequests[xhrId].xhr;
delete this.pendingRequests[xhrId];
xhr.abort();
}
}
return NetworkManagerClass;
})();

View file

@ -0,0 +1,964 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals Components, Services, XPCOMUtils, NetUtil, PrivateBrowsingUtils,
dump, NetworkManager, PdfjsContentUtils */
"use strict";
var EXPORTED_SYMBOLS = ["PdfStreamConverter"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const PDFJS_EVENT_ID = "pdf.js.message";
const PDF_CONTENT_TYPE = "application/pdf";
const PREF_PREFIX = "pdfjs";
const PDF_VIEWER_WEB_PAGE = "resource://pdf.js/web/viewer.html";
const MAX_NUMBER_OF_PREFS = 50;
const MAX_STRING_PREF_LENGTH = 128;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetworkManager",
"resource://pdf.js/PdfJsNetwork.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PdfjsContentUtils",
"resource://pdf.js/PdfjsContentUtils.jsm");
var Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
"@mozilla.org/mime;1",
"nsIMIMEService");
function getContainingBrowser(domWindow) {
return domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
}
function getFindBar(domWindow) {
if (PdfjsContentUtils.isRemote) {
throw new Error("FindBar is not accessible from the content process.");
}
try {
var browser = getContainingBrowser(domWindow);
var tabbrowser = browser.getTabBrowser();
var tab = tabbrowser.getTabForBrowser(browser);
return tabbrowser.getFindBar(tab);
} catch (e) {
// Suppress errors for PDF files opened in the bookmark sidebar, see
// https://bugzilla.mozilla.org/show_bug.cgi?id=1248959.
return null;
}
}
function getBoolPref(pref, def) {
try {
return Services.prefs.getBoolPref(pref);
} catch (ex) {
return def;
}
}
function getIntPref(pref, def) {
try {
return Services.prefs.getIntPref(pref);
} catch (ex) {
return def;
}
}
function getStringPref(pref, def) {
try {
return Services.prefs.getComplexValue(pref, Ci.nsISupportsString).data;
} catch (ex) {
return def;
}
}
function log(aMsg) {
if (!getBoolPref(PREF_PREFIX + ".pdfBugEnabled", false)) {
return;
}
var msg = "PdfStreamConverter.js: " + (aMsg.join ? aMsg.join("") : aMsg);
Services.console.logStringMessage(msg);
dump(msg + "\n");
}
function getDOMWindow(aChannel) {
var requestor = aChannel.notificationCallbacks ?
aChannel.notificationCallbacks :
aChannel.loadGroup.notificationCallbacks;
var win = requestor.getInterface(Components.interfaces.nsIDOMWindow);
return win;
}
function getLocalizedStrings(path) {
var stringBundle = Cc["@mozilla.org/intl/stringbundle;1"].
getService(Ci.nsIStringBundleService).
createBundle("chrome://pdf.js/locale/" + path);
var map = {};
var enumerator = stringBundle.getSimpleEnumeration();
while (enumerator.hasMoreElements()) {
var string = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement);
var key = string.key, property = "textContent";
var i = key.lastIndexOf(".");
if (i >= 0) {
property = key.substring(i + 1);
key = key.substring(0, i);
}
if (!(key in map)) {
map[key] = {};
}
map[key][property] = string.value;
}
return map;
}
function getLocalizedString(strings, id, property) {
property = property || "textContent";
if (id in strings) {
return strings[id][property];
}
return id;
}
// PDF data storage
function PdfDataListener(length) {
this.length = length; // less than 0, if length is unknown
this.buffer = null;
this.loaded = 0;
}
PdfDataListener.prototype = {
append: function PdfDataListener_append(chunk) {
// In most of the cases we will pass data as we receive it, but at the
// beginning of the loading we may accumulate some data.
if (!this.buffer) {
this.buffer = new Uint8Array(chunk);
} else {
var buffer = this.buffer;
var newBuffer = new Uint8Array(buffer.length + chunk.length);
newBuffer.set(buffer);
newBuffer.set(chunk, buffer.length);
this.buffer = newBuffer;
}
this.loaded += chunk.length;
if (this.length >= 0 && this.length < this.loaded) {
this.length = -1; // reset the length, server is giving incorrect one
}
this.onprogress(this.loaded, this.length >= 0 ? this.length : void 0);
},
readData: function PdfDataListener_readData() {
var result = this.buffer;
this.buffer = null;
return result;
},
finish: function PdfDataListener_finish() {
this.isDataReady = true;
if (this.oncompleteCallback) {
this.oncompleteCallback(this.readData());
}
},
error: function PdfDataListener_error(errorCode) {
this.errorCode = errorCode;
if (this.oncompleteCallback) {
this.oncompleteCallback(null, errorCode);
}
},
onprogress() {},
get oncomplete() {
return this.oncompleteCallback;
},
set oncomplete(value) {
this.oncompleteCallback = value;
if (this.isDataReady) {
value(this.readData());
}
if (this.errorCode) {
value(null, this.errorCode);
}
}
};
/**
* All the privileged actions.
*/
class ChromeActions {
constructor(domWindow, contentDispositionFilename) {
this.domWindow = domWindow;
this.contentDispositionFilename = contentDispositionFilename;
}
isInPrivateBrowsing() {
return PrivateBrowsingUtils.isContentWindowPrivate(this.domWindow);
}
download(data, sendResponse) {
var self = this;
var originalUrl = data.originalUrl;
var blobUrl = data.blobUrl || originalUrl;
// The data may not be downloaded so we need just retry getting the pdf with
// the original url.
var originalUri = NetUtil.newURI(originalUrl);
var filename = data.filename;
if (typeof filename !== "string" ||
(!/\.pdf$/i.test(filename) && !data.isAttachment)) {
filename = "document.pdf";
}
var blobUri = NetUtil.newURI(blobUrl);
var extHelperAppSvc =
Cc["@mozilla.org/uriloader/external-helper-app-service;1"].
getService(Ci.nsIExternalHelperAppService);
var docIsPrivate = this.isInPrivateBrowsing();
var netChannel = NetUtil.newChannel({
uri: blobUri,
loadUsingSystemPrincipal: true,
});
if ("nsIPrivateBrowsingChannel" in Ci &&
netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
netChannel.setPrivate(docIsPrivate);
}
NetUtil.asyncFetch(netChannel, function(aInputStream, aResult) {
if (!Components.isSuccessCode(aResult)) {
if (sendResponse) {
sendResponse(true);
}
return;
}
// Create a nsIInputStreamChannel so we can set the url on the channel
// so the filename will be correct.
var channel = Cc["@mozilla.org/network/input-stream-channel;1"].
createInstance(Ci.nsIInputStreamChannel);
channel.QueryInterface(Ci.nsIChannel);
try {
// contentDisposition/contentDispositionFilename is readonly before FF18
channel.contentDisposition = Ci.nsIChannel.DISPOSITION_ATTACHMENT;
if (self.contentDispositionFilename && !data.isAttachment) {
channel.contentDispositionFilename = self.contentDispositionFilename;
} else {
channel.contentDispositionFilename = filename;
}
} catch (e) {}
channel.setURI(originalUri);
channel.loadInfo = netChannel.loadInfo;
channel.contentStream = aInputStream;
if ("nsIPrivateBrowsingChannel" in Ci &&
channel instanceof Ci.nsIPrivateBrowsingChannel) {
channel.setPrivate(docIsPrivate);
}
var listener = {
extListener: null,
onStartRequest(aRequest, aContext) {
var loadContext = self.domWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext);
this.extListener = extHelperAppSvc.doContent(
(data.isAttachment ? "application/octet-stream" :
"application/pdf"),
aRequest, loadContext, false);
this.extListener.onStartRequest(aRequest, aContext);
},
onStopRequest(aRequest, aContext, aStatusCode) {
if (this.extListener) {
this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
}
// Notify the content code we're done downloading.
if (sendResponse) {
sendResponse(false);
}
},
onDataAvailable(aRequest, aContext, aDataInputStream, aOffset, aCount) {
this.extListener.onDataAvailable(aRequest, aContext, aDataInputStream,
aOffset, aCount);
}
};
channel.asyncOpen2(listener);
});
}
getLocale() {
return getStringPref("general.useragent.locale", "en-US");
}
getStrings(data) {
try {
// Lazy initialization of localizedStrings
if (!("localizedStrings" in this)) {
this.localizedStrings = getLocalizedStrings("viewer.properties");
}
var result = this.localizedStrings[data];
return JSON.stringify(result || null);
} catch (e) {
log("Unable to retrieve localized strings: " + e);
return "null";
}
}
supportsIntegratedFind() {
// Integrated find is only supported when we're not in a frame
if (this.domWindow.frameElement !== null) {
return false;
}
// ... and we are in a child process
if (PdfjsContentUtils.isRemote) {
return true;
}
// ... or when the new find events code exists.
var findBar = getFindBar(this.domWindow);
return !!findBar && ("updateControlState" in findBar);
}
supportsDocumentFonts() {
var prefBrowser = getIntPref("browser.display.use_document_fonts", 1);
var prefGfx = getBoolPref("gfx.downloadable_fonts.enabled", true);
return (!!prefBrowser && prefGfx);
}
supportsDocumentColors() {
return getIntPref("browser.display.document_color_use", 0) !== 2;
}
supportedMouseWheelZoomModifierKeys() {
return {
ctrlKey: getIntPref("mousewheel.with_control.action", 3) === 3,
metaKey: getIntPref("mousewheel.with_meta.action", 1) === 3,
};
}
/**
* @param {Object} args - Object with `featureId` and `url` properties.
* @param {function} sendResponse - Callback function.
*/
fallback(args, sendResponse) {
var featureId = args.featureId;
var domWindow = this.domWindow;
var strings = getLocalizedStrings("chrome.properties");
var message;
if (featureId === "forms") {
message = getLocalizedString(strings, "unsupported_feature_forms");
} else {
message = getLocalizedString(strings, "unsupported_feature");
}
PdfjsContentUtils.displayWarning(domWindow, message,
getLocalizedString(strings, "open_with_different_viewer"),
getLocalizedString(strings, "open_with_different_viewer", "accessKey"));
let winmm = domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
winmm.addMessageListener("PDFJS:Child:fallbackDownload",
function fallbackDownload(msg) {
let data = msg.data;
sendResponse(data.download);
winmm.removeMessageListener("PDFJS:Child:fallbackDownload",
fallbackDownload);
});
}
updateFindControlState(data) {
if (!this.supportsIntegratedFind()) {
return;
}
// Verify what we're sending to the findbar.
var result = data.result;
var findPrevious = data.findPrevious;
var findPreviousType = typeof findPrevious;
if ((typeof result !== "number" || result < 0 || result > 3) ||
(findPreviousType !== "undefined" && findPreviousType !== "boolean")) {
return;
}
var winmm = this.domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
winmm.sendAsyncMessage("PDFJS:Parent:updateControlState", data);
}
setPreferences(prefs, sendResponse) {
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + ".");
var numberOfPrefs = 0;
var prefValue, prefName;
for (var key in prefs) {
if (++numberOfPrefs > MAX_NUMBER_OF_PREFS) {
log("setPreferences - Exceeded the maximum number of preferences " +
"that is allowed to be set at once.");
break;
} else if (!defaultBranch.getPrefType(key)) {
continue;
}
prefValue = prefs[key];
prefName = (PREF_PREFIX + "." + key);
switch (typeof prefValue) {
case "boolean":
PdfjsContentUtils.setBoolPref(prefName, prefValue);
break;
case "number":
PdfjsContentUtils.setIntPref(prefName, prefValue);
break;
case "string":
if (prefValue.length > MAX_STRING_PREF_LENGTH) {
log("setPreferences - Exceeded the maximum allowed length " +
"for a string preference.");
} else {
PdfjsContentUtils.setStringPref(prefName, prefValue);
}
break;
}
}
if (sendResponse) {
sendResponse(true);
}
}
getPreferences(prefs, sendResponse) {
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + ".");
var currentPrefs = {}, numberOfPrefs = 0;
var prefValue, prefName;
for (var key in prefs) {
if (++numberOfPrefs > MAX_NUMBER_OF_PREFS) {
log("getPreferences - Exceeded the maximum number of preferences " +
"that is allowed to be fetched at once.");
break;
} else if (!defaultBranch.getPrefType(key)) {
continue;
}
prefValue = prefs[key];
prefName = (PREF_PREFIX + "." + key);
switch (typeof prefValue) {
case "boolean":
currentPrefs[key] = getBoolPref(prefName, prefValue);
break;
case "number":
currentPrefs[key] = getIntPref(prefName, prefValue);
break;
case "string":
currentPrefs[key] = getStringPref(prefName, prefValue);
break;
}
}
let result = JSON.stringify(currentPrefs);
if (sendResponse) {
sendResponse(result);
}
return result;
}
}
/**
* This is for range requests.
*/
class RangedChromeActions extends ChromeActions {
constructor(domWindow, contentDispositionFilename, originalRequest,
rangeEnabled, streamingEnabled, dataListener) {
super(domWindow, contentDispositionFilename);
this.dataListener = dataListener;
this.originalRequest = originalRequest;
this.rangeEnabled = rangeEnabled;
this.streamingEnabled = streamingEnabled;
this.pdfUrl = originalRequest.URI.spec;
this.contentLength = originalRequest.contentLength;
// Pass all the headers from the original request through
var httpHeaderVisitor = {
headers: {},
visitHeader(aHeader, aValue) {
if (aHeader === "Range") {
// When loading the PDF from cache, firefox seems to set the Range
// request header to fetch only the unfetched portions of the file
// (e.g. 'Range: bytes=1024-'). However, we want to set this header
// manually to fetch the PDF in chunks.
return;
}
this.headers[aHeader] = aValue;
}
};
if (originalRequest.visitRequestHeaders) {
originalRequest.visitRequestHeaders(httpHeaderVisitor);
}
var self = this;
var xhr_onreadystatechange = function xhr_onreadystatechange() {
if (this.readyState === 1) { // LOADING
var netChannel = this.channel;
if ("nsIPrivateBrowsingChannel" in Ci &&
netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
var docIsPrivate = self.isInPrivateBrowsing();
netChannel.setPrivate(docIsPrivate);
}
}
};
var getXhr = function getXhr() {
const XMLHttpRequest = Components.Constructor(
"@mozilla.org/xmlextras/xmlhttprequest;1");
var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", xhr_onreadystatechange);
return xhr;
};
this.networkManager = new NetworkManager(this.pdfUrl, {
httpHeaders: httpHeaderVisitor.headers,
getXhr,
});
// If we are in range request mode, this means we manually issued xhr
// requests, which we need to abort when we leave the page
domWindow.addEventListener("unload", function unload(e) {
domWindow.removeEventListener(e.type, unload);
self.abortLoading();
});
}
initPassiveLoading() {
var data;
if (!this.streamingEnabled) {
this.originalRequest.cancel(Cr.NS_BINDING_ABORTED);
this.originalRequest = null;
data = this.dataListener.readData();
this.dataListener = null;
} else {
data = this.dataListener.readData();
this.dataListener.onprogress = (loaded, total) => {
this.domWindow.postMessage({
pdfjsLoadAction: "progressiveRead",
loaded,
total,
chunk: this.dataListener.readData(),
}, "*");
};
this.dataListener.oncomplete = () => {
this.dataListener = null;
};
}
this.domWindow.postMessage({
pdfjsLoadAction: "supportsRangedLoading",
rangeEnabled: this.rangeEnabled,
streamingEnabled: this.streamingEnabled,
pdfUrl: this.pdfUrl,
length: this.contentLength,
data,
}, "*");
return true;
}
requestDataRange(args) {
if (!this.rangeEnabled) {
return;
}
var begin = args.begin;
var end = args.end;
var domWindow = this.domWindow;
// TODO(mack): Support error handler. We're not currently not handling
// errors from chrome code for non-range requests, so this doesn't
// seem high-pri
this.networkManager.requestRange(begin, end, {
onDone: function RangedChromeActions_onDone(aArgs) {
domWindow.postMessage({
pdfjsLoadAction: "range",
begin: aArgs.begin,
chunk: aArgs.chunk,
}, "*");
},
onProgress: function RangedChromeActions_onProgress(evt) {
domWindow.postMessage({
pdfjsLoadAction: "rangeProgress",
loaded: evt.loaded,
}, "*");
}
});
}
abortLoading() {
this.networkManager.abortAllRequests();
if (this.originalRequest) {
this.originalRequest.cancel(Cr.NS_BINDING_ABORTED);
this.originalRequest = null;
}
this.dataListener = null;
}
}
/**
* This is for a single network stream.
*/
class StandardChromeActions extends ChromeActions {
constructor(domWindow, contentDispositionFilename, originalRequest,
dataListener) {
super(domWindow, contentDispositionFilename);
this.originalRequest = originalRequest;
this.dataListener = dataListener;
}
initPassiveLoading() {
if (!this.dataListener) {
return false;
}
this.dataListener.onprogress = (loaded, total) => {
this.domWindow.postMessage({
pdfjsLoadAction: "progress",
loaded,
total,
}, "*");
};
this.dataListener.oncomplete = (data, errorCode) => {
this.domWindow.postMessage({
pdfjsLoadAction: "complete",
data,
errorCode,
}, "*");
this.dataListener = null;
this.originalRequest = null;
};
return true;
}
abortLoading() {
if (this.originalRequest) {
this.originalRequest.cancel(Cr.NS_BINDING_ABORTED);
this.originalRequest = null;
}
this.dataListener = null;
}
}
/**
* Event listener to trigger chrome privileged code.
*/
class RequestListener {
constructor(actions) {
this.actions = actions;
}
// Receive an event and synchronously or asynchronously responds.
receive(event) {
var message = event.target;
var doc = message.ownerDocument;
var action = event.detail.action;
var data = event.detail.data;
var sync = event.detail.sync;
var actions = this.actions;
if (!(action in actions)) {
log("Unknown action: " + action);
return;
}
var response;
if (sync) {
response = actions[action].call(this.actions, data);
event.detail.response = Cu.cloneInto(response, doc.defaultView);
} else {
if (!event.detail.responseExpected) {
doc.documentElement.removeChild(message);
response = null;
} else {
response = function sendResponse(aResponse) {
try {
var listener = doc.createEvent("CustomEvent");
let detail = Cu.cloneInto({ response: aResponse }, doc.defaultView);
listener.initCustomEvent("pdf.js.response", true, false, detail);
return message.dispatchEvent(listener);
} catch (e) {
// doc is no longer accessible because the requestor is already
// gone. unloaded content cannot receive the response anyway.
return false;
}
};
}
actions[action].call(this.actions, data, response);
}
}
}
/**
* Forwards events from the eventElement to the contentWindow only if the
* content window matches the currently selected browser window.
*/
class FindEventManager {
constructor(contentWindow) {
this.contentWindow = contentWindow;
this.winmm = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
}
bind() {
var unload = function(e) {
this.unbind();
this.contentWindow.removeEventListener(e.type, unload);
}.bind(this);
this.contentWindow.addEventListener("unload", unload);
// We cannot directly attach listeners to for the find events
// since the FindBar is in the parent process. Instead we're
// asking the PdfjsChromeUtils to do it for us and forward
// all the find events to us.
this.winmm.sendAsyncMessage("PDFJS:Parent:addEventListener");
this.winmm.addMessageListener("PDFJS:Child:handleEvent", this);
}
receiveMessage(msg) {
var detail = msg.data.detail;
var type = msg.data.type;
var contentWindow = this.contentWindow;
detail = Cu.cloneInto(detail, contentWindow);
var forward = contentWindow.document.createEvent("CustomEvent");
forward.initCustomEvent(type, true, true, detail);
contentWindow.dispatchEvent(forward);
}
unbind() {
this.winmm.sendAsyncMessage("PDFJS:Parent:removeEventListener");
}
}
function PdfStreamConverter() {
}
PdfStreamConverter.prototype = {
// properties required for XPCOM registration:
classID: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2291}"),
classDescription: "pdf.js Component",
contractID: "@mozilla.org/streamconv;1?from=application/pdf&to=*/*",
classID2: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2292}"),
contractID2: "@mozilla.org/streamconv;1?from=application/pdf&to=text/html",
QueryInterface: XPCOMUtils.generateQI([
Ci.nsISupports,
Ci.nsIStreamConverter,
Ci.nsIStreamListener,
Ci.nsIRequestObserver
]),
/*
* This component works as such:
* 1. asyncConvertData stores the listener
* 2. onStartRequest creates a new channel, streams the viewer
* 3. If range requests are supported:
* 3.1. Leave the request open until the viewer is ready to switch to
* range requests.
*
* If range rquests are not supported:
* 3.1. Read the stream as it's loaded in onDataAvailable to send
* to the viewer
*
* The convert function just returns the stream, it's just the synchronous
* version of asyncConvertData.
*/
// nsIStreamConverter::convert
convert(aFromStream, aFromType, aToType, aCtxt) {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
// nsIStreamConverter::asyncConvertData
asyncConvertData(aFromType, aToType, aListener, aCtxt) {
// Store the listener passed to us
this.listener = aListener;
},
// nsIStreamListener::onDataAvailable
onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount) {
if (!this.dataListener) {
return;
}
var binaryStream = this.binaryStream;
binaryStream.setInputStream(aInputStream);
var chunk = binaryStream.readByteArray(aCount);
this.dataListener.append(chunk);
},
// nsIRequestObserver::onStartRequest
onStartRequest(aRequest, aContext) {
// Setup the request so we can use it below.
var isHttpRequest = false;
try {
aRequest.QueryInterface(Ci.nsIHttpChannel);
isHttpRequest = true;
} catch (e) {}
var rangeRequest = false;
var streamRequest = false;
if (isHttpRequest) {
var contentEncoding = "identity";
try {
contentEncoding = aRequest.getResponseHeader("Content-Encoding");
} catch (e) {}
var acceptRanges;
try {
acceptRanges = aRequest.getResponseHeader("Accept-Ranges");
} catch (e) {}
var hash = aRequest.URI.ref;
var isPDFBugEnabled = getBoolPref(PREF_PREFIX + ".pdfBugEnabled", false);
rangeRequest = contentEncoding === "identity" &&
acceptRanges === "bytes" &&
aRequest.contentLength >= 0 &&
!getBoolPref(PREF_PREFIX + ".disableRange", false) &&
(!isPDFBugEnabled ||
hash.toLowerCase().indexOf("disablerange=true") < 0);
streamRequest = contentEncoding === "identity" &&
aRequest.contentLength >= 0 &&
!getBoolPref(PREF_PREFIX + ".disableStream", false) &&
(!isPDFBugEnabled ||
hash.toLowerCase().indexOf("disablestream=true") < 0);
}
aRequest.QueryInterface(Ci.nsIChannel);
aRequest.QueryInterface(Ci.nsIWritablePropertyBag);
var contentDispositionFilename;
try {
contentDispositionFilename = aRequest.contentDispositionFilename;
} catch (e) {}
// Change the content type so we don't get stuck in a loop.
aRequest.setProperty("contentType", aRequest.contentType);
aRequest.contentType = "text/html";
if (isHttpRequest) {
// We trust PDF viewer, using no CSP
aRequest.setResponseHeader("Content-Security-Policy", "", false);
aRequest.setResponseHeader("Content-Security-Policy-Report-Only", "",
false);
// The viewer does not need to handle HTTP Refresh header.
aRequest.setResponseHeader("Refresh", "", false);
}
// Creating storage for PDF data
var contentLength = aRequest.contentLength;
this.dataListener = new PdfDataListener(contentLength);
this.binaryStream = Cc["@mozilla.org/binaryinputstream;1"]
.createInstance(Ci.nsIBinaryInputStream);
// Create a new channel that is viewer loaded as a resource.
var channel = NetUtil.newChannel({
uri: PDF_VIEWER_WEB_PAGE,
loadUsingSystemPrincipal: true,
});
var listener = this.listener;
var dataListener = this.dataListener;
// Proxy all the request observer calls, when it gets to onStopRequest
// we can get the dom window. We also intentionally pass on the original
// request(aRequest) below so we don't overwrite the original channel and
// trigger an assertion.
var proxy = {
onStartRequest(request, context) {
listener.onStartRequest(aRequest, aContext);
},
onDataAvailable(request, context, inputStream, offset, count) {
listener.onDataAvailable(aRequest, aContext, inputStream,
offset, count);
},
onStopRequest(request, context, statusCode) {
// We get the DOM window here instead of before the request since it
// may have changed during a redirect.
var domWindow = getDOMWindow(channel);
var actions;
if (rangeRequest || streamRequest) {
actions = new RangedChromeActions(
domWindow, contentDispositionFilename, aRequest,
rangeRequest, streamRequest, dataListener);
} else {
actions = new StandardChromeActions(
domWindow, contentDispositionFilename, aRequest, dataListener);
}
var requestListener = new RequestListener(actions);
domWindow.addEventListener(PDFJS_EVENT_ID, function(event) {
requestListener.receive(event);
}, false, true);
if (actions.supportsIntegratedFind()) {
var findEventManager = new FindEventManager(domWindow);
findEventManager.bind();
}
listener.onStopRequest(aRequest, aContext, statusCode);
if (domWindow.frameElement) {
var isObjectEmbed = domWindow.frameElement.tagName !== "IFRAME" ||
domWindow.frameElement.className === "previewPluginContentFrame";
}
}
};
// Keep the URL the same so the browser sees it as the same.
channel.originalURI = aRequest.URI;
channel.loadGroup = aRequest.loadGroup;
channel.loadInfo.originAttributes = aRequest.loadInfo.originAttributes;
// We can use the resource principal when data is fetched by the chrome,
// e.g. useful for NoScript. Make make sure we reuse the origin attributes
// from the request channel to keep isolation consistent.
var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
var uri = NetUtil.newURI(PDF_VIEWER_WEB_PAGE);
var resourcePrincipal =
ssm.createCodebasePrincipal(uri, aRequest.loadInfo.originAttributes);
aRequest.owner = resourcePrincipal;
channel.asyncOpen2(proxy);
},
// nsIRequestObserver::onStopRequest
onStopRequest(aRequest, aContext, aStatusCode) {
if (!this.dataListener) {
// Do nothing
return;
}
if (Components.isSuccessCode(aStatusCode)) {
this.dataListener.finish();
} else {
this.dataListener.error(aStatusCode);
}
delete this.dataListener;
delete this.binaryStream;
}
};

View file

@ -0,0 +1,355 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals Components, Services, XPCOMUtils */
"use strict";
var EXPORTED_SYMBOLS = ["PdfjsChromeUtils"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const PREF_PREFIX = "pdfjs";
const PDF_CONTENT_TYPE = "application/pdf";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
"@mozilla.org/mime;1",
"nsIMIMEService");
var DEFAULT_PREFERENCES =
{
"showPreviousViewOnLoad": true,
"defaultZoomValue": "",
"sidebarViewOnLoad": 0,
"enableHandToolOnLoad": false,
"enableWebGL": false,
"pdfBugEnabled": false,
"disableRange": false,
"disableStream": false,
"disableAutoFetch": false,
"disableFontFace": false,
"disableTextLayer": false,
"useOnlyCssZoom": false,
"externalLinkTarget": 0,
"enhanceTextSelection": false,
"renderer": "canvas",
"renderInteractiveForms": false,
"enablePrintAutoRotate": false,
"disablePageLabels": false
}
var PdfjsChromeUtils = {
// For security purposes when running remote, we restrict preferences
// content can access.
_allowedPrefNames: Object.keys(DEFAULT_PREFERENCES),
_ppmm: null,
_mmg: null,
/*
* Public API
*/
init() {
this._browsers = new WeakSet();
if (!this._ppmm) {
// global parent process message manager (PPMM)
this._ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"].
getService(Ci.nsIMessageBroadcaster);
this._ppmm.addMessageListener("PDFJS:Parent:clearUserPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:setIntPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:setBoolPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:setCharPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:setStringPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:isDefaultHandlerApp", this);
// global dom message manager (MMg)
this._mmg = Cc["@mozilla.org/globalmessagemanager;1"].
getService(Ci.nsIMessageListenerManager);
this._mmg.addMessageListener("PDFJS:Parent:displayWarning", this);
this._mmg.addMessageListener("PDFJS:Parent:addEventListener", this);
this._mmg.addMessageListener("PDFJS:Parent:removeEventListener", this);
this._mmg.addMessageListener("PDFJS:Parent:updateControlState", this);
// observer to handle shutdown
Services.obs.addObserver(this, "quit-application", false);
}
},
uninit() {
if (this._ppmm) {
this._ppmm.removeMessageListener("PDFJS:Parent:clearUserPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:setIntPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:setBoolPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:setCharPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:setStringPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:isDefaultHandlerApp",
this);
this._mmg.removeMessageListener("PDFJS:Parent:displayWarning", this);
this._mmg.removeMessageListener("PDFJS:Parent:addEventListener", this);
this._mmg.removeMessageListener("PDFJS:Parent:removeEventListener", this);
this._mmg.removeMessageListener("PDFJS:Parent:updateControlState", this);
Services.obs.removeObserver(this, "quit-application");
this._mmg = null;
this._ppmm = null;
}
},
/*
* Called by the main module when preference changes are picked up
* in the parent process. Observers don't propagate so we need to
* instruct the child to refresh its configuration and (possibly)
* the module's registration.
*/
notifyChildOfSettingsChange() {
if (Services.appinfo.processType ===
Services.appinfo.PROCESS_TYPE_DEFAULT && this._ppmm) {
// XXX kinda bad, we want to get the parent process mm associated
// with the content process. _ppmm is currently the global process
// manager, which means this is going to fire to every child process
// we have open. Unfortunately I can't find a way to get at that
// process specific mm from js.
this._ppmm.broadcastAsyncMessage("PDFJS:Child:refreshSettings", {});
}
},
/*
* Events
*/
observe(aSubject, aTopic, aData) {
if (aTopic === "quit-application") {
this.uninit();
}
},
receiveMessage(aMsg) {
switch (aMsg.name) {
case "PDFJS:Parent:clearUserPref":
this._clearUserPref(aMsg.data.name);
break;
case "PDFJS:Parent:setIntPref":
this._setIntPref(aMsg.data.name, aMsg.data.value);
break;
case "PDFJS:Parent:setBoolPref":
this._setBoolPref(aMsg.data.name, aMsg.data.value);
break;
case "PDFJS:Parent:setCharPref":
this._setCharPref(aMsg.data.name, aMsg.data.value);
break;
case "PDFJS:Parent:setStringPref":
this._setStringPref(aMsg.data.name, aMsg.data.value);
break;
case "PDFJS:Parent:isDefaultHandlerApp":
return this.isDefaultHandlerApp();
case "PDFJS:Parent:displayWarning":
this._displayWarning(aMsg);
break;
case "PDFJS:Parent:updateControlState":
return this._updateControlState(aMsg);
case "PDFJS:Parent:addEventListener":
return this._addEventListener(aMsg);
case "PDFJS:Parent:removeEventListener":
return this._removeEventListener(aMsg);
}
return undefined;
},
/*
* Internal
*/
_findbarFromMessage(aMsg) {
let browser = aMsg.target;
let tabbrowser = browser.getTabBrowser();
let tab = tabbrowser.getTabForBrowser(browser);
return tabbrowser.getFindBar(tab);
},
_updateControlState(aMsg) {
let data = aMsg.data;
this._findbarFromMessage(aMsg)
.updateControlState(data.result, data.findPrevious);
},
handleEvent(aEvent) {
// To avoid forwarding the message as a CPOW, create a structured cloneable
// version of the event for both performance, and ease of usage, reasons.
let type = aEvent.type;
let detail = {
query: aEvent.detail.query,
caseSensitive: aEvent.detail.caseSensitive,
highlightAll: aEvent.detail.highlightAll,
findPrevious: aEvent.detail.findPrevious
};
let browser = aEvent.currentTarget.browser;
if (!this._browsers.has(browser)) {
throw new Error("FindEventManager was not bound " +
"for the current browser.");
}
// Only forward the events if the current browser is a registered browser.
let mm = browser.messageManager;
mm.sendAsyncMessage("PDFJS:Child:handleEvent", { type, detail, });
aEvent.preventDefault();
},
_types: ["find",
"findagain",
"findhighlightallchange",
"findcasesensitivitychange"],
_addEventListener(aMsg) {
let browser = aMsg.target;
if (this._browsers.has(browser)) {
throw new Error("FindEventManager was bound 2nd time " +
"without unbinding it first.");
}
// Since this jsm is global, we need to store all the browsers
// we have to forward the messages for.
this._browsers.add(browser);
// And we need to start listening to find events.
for (var i = 0; i < this._types.length; i++) {
var type = this._types[i];
this._findbarFromMessage(aMsg)
.addEventListener(type, this, true);
}
},
_removeEventListener(aMsg) {
let browser = aMsg.target;
if (!this._browsers.has(browser)) {
throw new Error("FindEventManager was unbound without binding it first.");
}
this._browsers.delete(browser);
// No reason to listen to find events any longer.
for (var i = 0; i < this._types.length; i++) {
var type = this._types[i];
this._findbarFromMessage(aMsg)
.removeEventListener(type, this, true);
}
},
_ensurePreferenceAllowed(aPrefName) {
let unPrefixedName = aPrefName.split(PREF_PREFIX + ".");
if (unPrefixedName[0] !== "" ||
this._allowedPrefNames.indexOf(unPrefixedName[1]) === -1) {
let msg = "\"" + aPrefName + "\" " +
"can't be accessed from content. See PdfjsChromeUtils.";
throw new Error(msg);
}
},
_clearUserPref(aPrefName) {
this._ensurePreferenceAllowed(aPrefName);
Services.prefs.clearUserPref(aPrefName);
},
_setIntPref(aPrefName, aPrefValue) {
this._ensurePreferenceAllowed(aPrefName);
Services.prefs.setIntPref(aPrefName, aPrefValue);
},
_setBoolPref(aPrefName, aPrefValue) {
this._ensurePreferenceAllowed(aPrefName);
Services.prefs.setBoolPref(aPrefName, aPrefValue);
},
_setCharPref(aPrefName, aPrefValue) {
this._ensurePreferenceAllowed(aPrefName);
Services.prefs.setCharPref(aPrefName, aPrefValue);
},
_setStringPref(aPrefName, aPrefValue) {
this._ensurePreferenceAllowed(aPrefName);
let str = Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
str.data = aPrefValue;
Services.prefs.setComplexValue(aPrefName, Ci.nsISupportsString, str);
},
/*
* Svc.mime doesn't have profile information in the child, so
* we bounce this pdfjs enabled configuration check over to the
* parent.
*/
isDefaultHandlerApp() {
var handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, "pdf");
return (!handlerInfo.alwaysAskBeforeHandling &&
handlerInfo.preferredAction === Ci.nsIHandlerInfo.handleInternally);
},
/*
* Display a notification warning when the renderer isn't sure
* a pdf displayed correctly.
*/
_displayWarning(aMsg) {
let data = aMsg.data;
let browser = aMsg.target;
let tabbrowser = browser.getTabBrowser();
let notificationBox = tabbrowser.getNotificationBox(browser);
// Flag so we don't send the message twice, since if the user clicks
// "open with different viewer" both the button callback and
// eventCallback will be called.
let messageSent = false;
function sendMessage(download) {
let mm = browser.messageManager;
mm.sendAsyncMessage("PDFJS:Child:fallbackDownload", { download, });
}
let buttons = [{
label: data.label,
accessKey: data.accessKey,
callback() {
messageSent = true;
sendMessage(true);
}
}];
notificationBox.appendNotification(data.message, "pdfjs-fallback", null,
notificationBox.PRIORITY_INFO_LOW,
buttons,
function eventsCallback(eventType) {
// Currently there is only one event "removed" but if there are any other
// added in the future we still only care about removed at the moment.
if (eventType !== "removed") {
return;
}
// Don't send a response again if we already responded when the button was
// clicked.
if (messageSent) {
return;
}
sendMessage(false);
});
}
};

View file

@ -0,0 +1,149 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals Components, Services, XPCOMUtils */
"use strict";
var EXPORTED_SYMBOLS = ["PdfjsContentUtils"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var PdfjsContentUtils = {
_mm: null,
/*
* Public API
*/
get isRemote() {
return (Services.appinfo.processType ===
Services.appinfo.PROCESS_TYPE_CONTENT);
},
init() {
// child *process* mm, or when loaded into the parent for in-content
// support the psuedo child process mm 'child PPMM'.
if (!this._mm) {
this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].
getService(Ci.nsISyncMessageSender);
this._mm.addMessageListener("PDFJS:Child:refreshSettings", this);
Services.obs.addObserver(this, "quit-application", false);
}
},
uninit() {
if (this._mm) {
this._mm.removeMessageListener("PDFJS:Child:refreshSettings", this);
Services.obs.removeObserver(this, "quit-application");
}
this._mm = null;
},
/*
* prefs utilities - the child does not have write access to prefs.
* note, the pref names here are cross-checked against a list of
* approved pdfjs prefs in chrome utils.
*/
clearUserPref(aPrefName) {
this._mm.sendSyncMessage("PDFJS:Parent:clearUserPref", {
name: aPrefName
});
},
setIntPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setIntPref", {
name: aPrefName,
value: aPrefValue
});
},
setBoolPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setBoolPref", {
name: aPrefName,
value: aPrefValue
});
},
setCharPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setCharPref", {
name: aPrefName,
value: aPrefValue
});
},
setStringPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setStringPref", {
name: aPrefName,
value: aPrefValue
});
},
/*
* Forwards default app query to the parent where we check various
* handler app settings only available in the parent process.
*/
isDefaultHandlerApp() {
return this._mm.sendSyncMessage("PDFJS:Parent:isDefaultHandlerApp")[0];
},
/*
* Request the display of a notification warning in the associated window
* when the renderer isn't sure a pdf displayed correctly.
*/
displayWarning(aWindow, aMessage, aLabel, aAccessKey) {
// the child's dom frame mm associated with the window.
let winmm = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
winmm.sendAsyncMessage("PDFJS:Parent:displayWarning", {
message: aMessage,
label: aLabel,
accessKey: aAccessKey,
});
},
/*
* Events
*/
observe(aSubject, aTopic, aData) {
if (aTopic === "quit-application") {
this.uninit();
}
},
receiveMessage(aMsg) {
switch (aMsg.name) {
case "PDFJS:Child:refreshSettings":
// Only react to this if we are remote.
if (Services.appinfo.processType ===
Services.appinfo.PROCESS_TYPE_CONTENT) {
let jsm = "resource://pdf.js/PdfJs.jsm";
let pdfjs = Components.utils.import(jsm, {}).PdfJs;
pdfjs.updateRegistration();
}
break;
}
}
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
/* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals Components, PdfjsContentUtils, PdfJs, Services */
"use strict";
/*
* pdfjschildbootstrap.js loads into the content process to take care of
* initializing our built-in version of pdfjs when running remote.
*/
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://pdf.js/PdfJs.jsm");
Components.utils.import("resource://pdf.js/PdfjsContentUtils.jsm");
// init content utils shim pdfjs will use to access privileged apis.
PdfjsContentUtils.init();
if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
// register various pdfjs factories that hook us into content loading.
PdfJs.updateRegistration();
}

View file

@ -0,0 +1,3 @@
àRCopyright 1990-2009 Adobe Systems Incorporated.
All rights reserved.
See ./LICENSEáCNS2-H

View file

@ -0,0 +1,3 @@
àRCopyright 1990-2009 Adobe Systems Incorporated.
All rights reserved.
See ./LICENSEá ETen-B5-H` ^

View file

@ -0,0 +1,4 @@
àRCopyright 1990-2009 Adobe Systems Incorporated.
All rights reserved.
See ./LICENSE!!<21>º]aX!!]`<60>21<32>> <09>p <0B>z<EFBFBD>$]<06>"Rd<E2809A>-Uƒ7<C692>*4„%<25>+ „Z „{<7B>/%…<<3C>9K…b<E280A6>1]†.<2E>" ‰`]‡,<2C>"]ˆ
<EFBFBD>"]ˆh<CB86>"]‰F<E280B0>"]Š$<24>"]<02>"]`<60>"]Œ><3E>"]<5D><1C>"]<5D>z<EFBFBD>"]ŽX<C5BD>"]<5D>6<EFBFBD>"]<5D><14>"]<5D>r<EFBFBD>"]P<E28098>"].<2E>"]“ <0C>"]“j<E2809C>"]”H<E2809D>"]•&<26>"]<04>"]b<E28093>"]—@<40>"]˜<1E>"]˜|<7C>"]™Z<E284A2>"]š8<C5A1>"]<16>"]t<E280BA>"]œR<C593>"]<5D>0<EFBFBD>"]ž<0E>"]žl<C5BE>"]ŸJ<C5B8>"] (<28>"]¡<06>"]¡d<C2A1>"]¢B<C2A2>"]£ <20>"X£~<7E>']¤W<C2A4>"]¥5<C2A5>"]¦<13>"]¦q<C2A6>"]§O<C2A7>"]¨-<2D>"]© <0B>"]©i<C2A9>"]ªG<C2AA>"]«%<25>"]¬<03>"]¬a<C2AC>"]­?<3F>"]®<1D>"]®{<7B>"]¯Y<C2AF>"]°7<C2B0>"]±<15>"]±s<C2B1>"]²Q<C2B2>"]³/<2F>"]´ <0A>"]´k<C2B4>"]µI<C2B5>"]¶'<27>"]·<05>"]·c<C2B7>"]¸A<C2B8>"]¹<1F>"]¹}<7D>"]º[<5B>"]»9

Some files were not shown because too many files have changed in this diff Show more