Source code

Revision control

Copy as Markdown

Other Tools

/* 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
*
*
* 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.
*/
const PREF_DISABLED = "pdfjs.disabled";
const PREF_MIGRATION_VERSION = "pdfjs.migrationVersion";
const PREF_PREVIOUS_ACTION = "pdfjs.previousHandler.preferredAction";
const PREF_PREVIOUS_ASK = "pdfjs.previousHandler.alwaysAskBeforeHandling";
const PREF_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state";
const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged";
const PDF_CONTENT_TYPE = "application/pdf";
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
var Svc = {};
XPCOMUtils.defineLazyServiceGetter(
Svc,
"mime",
"@mozilla.org/mime;1",
"nsIMIMEService"
);
XPCOMUtils.defineLazyServiceGetter(
Svc,
"handlerService",
"@mozilla.org/uriloader/handler-service;1",
"nsIHandlerService"
);
// We're supposed to get this type of thing from the OS, and generally we do.
// But doing so is expensive, so on startup paths we can use this to make the
// handler service get and store the Right Thing (it just goes into a JSON
// file) and avoid the performance issues.
const gPdfFakeHandlerInfo = {
QueryInterface: ChromeUtils.generateQI(["nsIMIMEInfo"]),
getFileExtensions() {
return ["pdf"];
},
possibleApplicationHandlers: Cc["@mozilla.org/array;1"].createInstance(
Ci.nsIMutableArray
),
extensionExists(ext) {
return ext == "pdf";
},
alwaysAskBeforeHandling: false,
preferredAction: Ci.nsIHandlerInfo.handleInternally,
type: PDF_CONTENT_TYPE,
};
export var PdfJs = {
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
_initialized: false,
_cachedIsDefault: true,
init: function init(isNewProfile) {
if (
Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT
) {
throw new Error(
"PdfJs.init should only get called in the parent process."
);
}
this.initPrefs();
this.checkIsDefault(isNewProfile);
},
initPrefs: function initPrefs() {
if (this._initialized) {
return;
}
this._initialized = true;
if (this._prefDisabled) {
this._unbecomeHandler();
} else {
this._migrate();
}
// Listen for when a different pdf handler is chosen.
Services.obs.addObserver(this, TOPIC_PDFJS_HANDLER_CHANGED);
},
uninit: function uninit() {
if (this._initialized) {
Services.obs.removeObserver(this, TOPIC_PDFJS_HANDLER_CHANGED);
this._initialized = false;
}
},
_migrate: function migrate() {
const VERSION = 2;
var currentVersion = Services.prefs.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("pdfjs.database");
}
Services.prefs.setIntPref(PREF_MIGRATION_VERSION, VERSION);
},
_becomeHandler: function _becomeHandler() {
// Normally, this happens in the first run at some point, where the
// handler service doesn't have any info on user preferences yet.
// Don't bother storing old defaults in this case, as they're
// meaningless anyway.
if (!Svc.handlerService.exists(gPdfFakeHandlerInfo)) {
// Store the requisite info into the DB, and nothing else:
Svc.handlerService.store(gPdfFakeHandlerInfo);
} else {
let handlerInfo = Svc.mime.getFromTypeAndExtension(
PDF_CONTENT_TYPE,
"pdf"
);
let prefs = Services.prefs;
if (
handlerInfo.preferredAction !== Ci.nsIHandlerInfo.handleInternally &&
handlerInfo.alwaysAskBeforeHandling !== 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
);
}
// Change and save mime handler settings.
handlerInfo.alwaysAskBeforeHandling = false;
handlerInfo.preferredAction = Ci.nsIHandlerInfo.handleInternally;
Svc.handlerService.store(handlerInfo);
}
},
_unbecomeHandler: function _unbecomeHandler() {
let handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, "pdf");
if (handlerInfo.preferredAction === Ci.nsIHandlerInfo.handleInternally) {
// If PDFJS is disabled, but we're still marked to handleInternally,
// either put it back to what it was, or remove it.
if (Services.prefs.prefHasUserValue(PREF_PREVIOUS_ACTION)) {
handlerInfo.preferredAction =
Services.prefs.getIntPref(PREF_PREVIOUS_ACTION);
handlerInfo.alwaysAskBeforeHandling =
Services.prefs.getBoolPref(PREF_PREVIOUS_ASK);
Svc.handlerService.store(handlerInfo);
} else {
Svc.handlerService.remove(handlerInfo);
// Clear migration pref so the handler comes back if reenabled
Services.prefs.clearUserPref(PREF_MIGRATION_VERSION);
}
}
},
/**
* @param isNewProfile used to decide whether we need to check the
* handler service to see if the user configured
* pdfs differently. If we're on a new profile,
* there's no need to check.
*/
_isDefault(isNewProfile) {
let { processType, PROCESS_TYPE_DEFAULT } = Services.appinfo;
if (processType !== PROCESS_TYPE_DEFAULT) {
throw new Error(
"isDefault should only get called in the parent process."
);
}
if (this._prefDisabled) {
return false;
}
// Don't bother with the handler service on a new profile:
if (isNewProfile) {
return true;
}
// Check if the 'application/pdf' preview handler is configured properly.
let handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, "pdf");
return (
!handlerInfo.alwaysAskBeforeHandling &&
handlerInfo.preferredAction == Ci.nsIHandlerInfo.handleInternally
);
},
checkIsDefault(isNewProfile) {
this._cachedIsDefault = this._isDefault(isNewProfile);
Services.prefs.setBoolPref(
PREF_ISDEFAULT_CACHE_STATE,
this._cachedIsDefault
);
},
cachedIsDefault() {
return this._cachedIsDefault;
},
// nsIObserver
observe() {
this.checkIsDefault();
},
};
XPCOMUtils.defineLazyPreferenceGetter(
PdfJs,
"_prefDisabled",
PREF_DISABLED,
false,
() => PdfJs.checkIsDefault()
);