1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/extensions/pdfjs/content/PdfJs.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,289 @@ 1.4 +/* Copyright 2012 Mozilla Foundation 1.5 + * 1.6 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.7 + * you may not use this file except in compliance with the License. 1.8 + * You may obtain a copy of the License at 1.9 + * 1.10 + * http://www.apache.org/licenses/LICENSE-2.0 1.11 + * 1.12 + * Unless required by applicable law or agreed to in writing, software 1.13 + * distributed under the License is distributed on an "AS IS" BASIS, 1.14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.15 + * See the License for the specific language governing permissions and 1.16 + * limitations under the License. 1.17 + */ 1.18 + 1.19 +var EXPORTED_SYMBOLS = ["PdfJs"]; 1.20 + 1.21 +const Cc = Components.classes; 1.22 +const Ci = Components.interfaces; 1.23 +const Cr = Components.results; 1.24 +const Cm = Components.manager; 1.25 +const Cu = Components.utils; 1.26 + 1.27 +const PREF_PREFIX = 'pdfjs'; 1.28 +const PREF_DISABLED = PREF_PREFIX + '.disabled'; 1.29 +const PREF_MIGRATION_VERSION = PREF_PREFIX + '.migrationVersion'; 1.30 +const PREF_PREVIOUS_ACTION = PREF_PREFIX + '.previousHandler.preferredAction'; 1.31 +const PREF_PREVIOUS_ASK = PREF_PREFIX + '.previousHandler.alwaysAskBeforeHandling'; 1.32 +const PREF_DISABLED_PLUGIN_TYPES = 'plugin.disable_full_page_plugin_for_types'; 1.33 +const TOPIC_PDFJS_HANDLER_CHANGED = 'pdfjs:handlerChanged'; 1.34 +const TOPIC_PLUGINS_LIST_UPDATED = "plugins-list-updated"; 1.35 +const TOPIC_PLUGIN_INFO_UPDATED = "plugin-info-updated"; 1.36 +const PDF_CONTENT_TYPE = 'application/pdf'; 1.37 + 1.38 +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); 1.39 +Cu.import('resource://gre/modules/Services.jsm'); 1.40 + 1.41 +let Svc = {}; 1.42 +XPCOMUtils.defineLazyServiceGetter(Svc, 'mime', 1.43 + '@mozilla.org/mime;1', 1.44 + 'nsIMIMEService'); 1.45 +XPCOMUtils.defineLazyServiceGetter(Svc, 'pluginHost', 1.46 + '@mozilla.org/plugin/host;1', 1.47 + 'nsIPluginHost'); 1.48 + 1.49 +function getBoolPref(aPref, aDefaultValue) { 1.50 + try { 1.51 + return Services.prefs.getBoolPref(aPref); 1.52 + } catch (ex) { 1.53 + return aDefaultValue; 1.54 + } 1.55 +} 1.56 + 1.57 +function getIntPref(aPref, aDefaultValue) { 1.58 + try { 1.59 + return Services.prefs.getIntPref(aPref); 1.60 + } catch (ex) { 1.61 + return aDefaultValue; 1.62 + } 1.63 +} 1.64 + 1.65 +function initializeDefaultPreferences() { 1.66 + 1.67 +var DEFAULT_PREFERENCES = { 1.68 + showPreviousViewOnLoad: true, 1.69 + defaultZoomValue: '', 1.70 + ifAvailableShowOutlineOnLoad: false, 1.71 + enableHandToolOnLoad: false, 1.72 + enableWebGL: false 1.73 +}; 1.74 + 1.75 + 1.76 + var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.'); 1.77 + var defaultValue; 1.78 + for (var key in DEFAULT_PREFERENCES) { 1.79 + defaultValue = DEFAULT_PREFERENCES[key]; 1.80 + switch (typeof defaultValue) { 1.81 + case 'boolean': 1.82 + defaultBranch.setBoolPref(key, defaultValue); 1.83 + break; 1.84 + case 'number': 1.85 + defaultBranch.setIntPref(key, defaultValue); 1.86 + break; 1.87 + case 'string': 1.88 + defaultBranch.setCharPref(key, defaultValue); 1.89 + break; 1.90 + } 1.91 + } 1.92 +} 1.93 + 1.94 +// Register/unregister a constructor as a factory. 1.95 +function Factory() {} 1.96 +Factory.prototype = { 1.97 + register: function register(targetConstructor) { 1.98 + var proto = targetConstructor.prototype; 1.99 + this._classID = proto.classID; 1.100 + 1.101 + var factory = XPCOMUtils._getFactory(targetConstructor); 1.102 + this._factory = factory; 1.103 + 1.104 + var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); 1.105 + registrar.registerFactory(proto.classID, proto.classDescription, 1.106 + proto.contractID, factory); 1.107 + }, 1.108 + 1.109 + unregister: function unregister() { 1.110 + var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); 1.111 + registrar.unregisterFactory(this._classID, this._factory); 1.112 + this._factory = null; 1.113 + } 1.114 +}; 1.115 + 1.116 +let PdfJs = { 1.117 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), 1.118 + _registered: false, 1.119 + 1.120 + init: function init() { 1.121 + if (!getBoolPref(PREF_DISABLED, true)) { 1.122 + this._migrate(); 1.123 + } 1.124 + 1.125 + if (this.enabled) 1.126 + this._ensureRegistered(); 1.127 + else 1.128 + this._ensureUnregistered(); 1.129 + 1.130 + // Listen for when pdf.js is completely disabled or a different pdf handler 1.131 + // is chosen. 1.132 + Services.prefs.addObserver(PREF_DISABLED, this, false); 1.133 + Services.prefs.addObserver(PREF_DISABLED_PLUGIN_TYPES, this, false); 1.134 + Services.obs.addObserver(this, TOPIC_PDFJS_HANDLER_CHANGED, false); 1.135 + Services.obs.addObserver(this, TOPIC_PLUGINS_LIST_UPDATED, false); 1.136 + Services.obs.addObserver(this, TOPIC_PLUGIN_INFO_UPDATED, false); 1.137 + 1.138 + initializeDefaultPreferences(); 1.139 + }, 1.140 + 1.141 + _migrate: function migrate() { 1.142 + const VERSION = 2; 1.143 + var currentVersion = getIntPref(PREF_MIGRATION_VERSION, 0); 1.144 + if (currentVersion >= VERSION) { 1.145 + return; 1.146 + } 1.147 + // Make pdf.js the default pdf viewer on the first migration. 1.148 + if (currentVersion < 1) { 1.149 + this._becomeHandler(); 1.150 + } 1.151 + if (currentVersion < 2) { 1.152 + // cleaning up of unused database preference (see #3994) 1.153 + Services.prefs.clearUserPref(PREF_PREFIX + '.database'); 1.154 + } 1.155 + Services.prefs.setIntPref(PREF_MIGRATION_VERSION, VERSION); 1.156 + }, 1.157 + 1.158 + _becomeHandler: function _becomeHandler() { 1.159 + let handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, 'pdf'); 1.160 + let prefs = Services.prefs; 1.161 + if (handlerInfo.preferredAction !== Ci.nsIHandlerInfo.handleInternally && 1.162 + handlerInfo.preferredAction !== false) { 1.163 + // Store the previous settings of preferredAction and 1.164 + // alwaysAskBeforeHandling in case we need to revert them in a hotfix that 1.165 + // would turn pdf.js off. 1.166 + prefs.setIntPref(PREF_PREVIOUS_ACTION, handlerInfo.preferredAction); 1.167 + prefs.setBoolPref(PREF_PREVIOUS_ASK, handlerInfo.alwaysAskBeforeHandling); 1.168 + } 1.169 + 1.170 + let handlerService = Cc['@mozilla.org/uriloader/handler-service;1']. 1.171 + getService(Ci.nsIHandlerService); 1.172 + 1.173 + // Change and save mime handler settings. 1.174 + handlerInfo.alwaysAskBeforeHandling = false; 1.175 + handlerInfo.preferredAction = Ci.nsIHandlerInfo.handleInternally; 1.176 + handlerService.store(handlerInfo); 1.177 + 1.178 + // Also disable any plugins for pdfs. 1.179 + var stringTypes = ''; 1.180 + var types = []; 1.181 + if (prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES)) { 1.182 + stringTypes = prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES); 1.183 + } 1.184 + if (stringTypes !== '') { 1.185 + types = stringTypes.split(','); 1.186 + } 1.187 + 1.188 + if (types.indexOf(PDF_CONTENT_TYPE) === -1) { 1.189 + types.push(PDF_CONTENT_TYPE); 1.190 + } 1.191 + prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES, types.join(',')); 1.192 + 1.193 + // Update the category manager in case the plugins are already loaded. 1.194 + let categoryManager = Cc["@mozilla.org/categorymanager;1"]; 1.195 + categoryManager.getService(Ci.nsICategoryManager). 1.196 + deleteCategoryEntry("Gecko-Content-Viewers", 1.197 + PDF_CONTENT_TYPE, 1.198 + false); 1.199 + }, 1.200 + 1.201 + // nsIObserver 1.202 + observe: function observe(aSubject, aTopic, aData) { 1.203 + if (this.enabled) 1.204 + this._ensureRegistered(); 1.205 + else 1.206 + this._ensureUnregistered(); 1.207 + }, 1.208 + 1.209 + /** 1.210 + * pdf.js is only enabled if it is both selected as the pdf viewer and if the 1.211 + * global switch enabling it is true. 1.212 + * @return {boolean} Wether or not it's enabled. 1.213 + */ 1.214 + get enabled() { 1.215 + var disabled = getBoolPref(PREF_DISABLED, true); 1.216 + if (disabled) { 1.217 + return false; 1.218 + } 1.219 + 1.220 + // the 'application/pdf' handler is selected as internal? 1.221 + var handlerInfo = Svc.mime 1.222 + .getFromTypeAndExtension(PDF_CONTENT_TYPE, 'pdf'); 1.223 + if (handlerInfo.alwaysAskBeforeHandling || 1.224 + handlerInfo.preferredAction !== Ci.nsIHandlerInfo.handleInternally) { 1.225 + return false; 1.226 + } 1.227 + 1.228 + // Check if we have disabled plugin handling of 'application/pdf' in prefs 1.229 + if (Services.prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES)) { 1.230 + let disabledPluginTypes = 1.231 + Services.prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES).split(','); 1.232 + if (disabledPluginTypes.indexOf(PDF_CONTENT_TYPE) >= 0) { 1.233 + return true; 1.234 + } 1.235 + } 1.236 + 1.237 + // Check if there is an enabled pdf plugin. 1.238 + // Note: this check is performed last because getPluginTags() triggers costly 1.239 + // plugin list initialization (bug 881575) 1.240 + let tags = Cc["@mozilla.org/plugin/host;1"]. 1.241 + getService(Ci.nsIPluginHost). 1.242 + getPluginTags(); 1.243 + let enabledPluginFound = tags.some(function(tag) { 1.244 + if (tag.disabled) { 1.245 + return false; 1.246 + } 1.247 + let mimeTypes = tag.getMimeTypes(); 1.248 + return mimeTypes.some(function(mimeType) { 1.249 + return mimeType === PDF_CONTENT_TYPE; 1.250 + }); 1.251 + }); 1.252 + 1.253 + // Use pdf.js if pdf plugin is not present or disabled 1.254 + return !enabledPluginFound; 1.255 + }, 1.256 + 1.257 + _ensureRegistered: function _ensureRegistered() { 1.258 + if (this._registered) 1.259 + return; 1.260 + 1.261 + this._pdfStreamConverterFactory = new Factory(); 1.262 + Cu.import('resource://pdf.js/PdfStreamConverter.jsm'); 1.263 + this._pdfStreamConverterFactory.register(PdfStreamConverter); 1.264 + 1.265 + this._pdfRedirectorFactory = new Factory(); 1.266 + Cu.import('resource://pdf.js/PdfRedirector.jsm'); 1.267 + this._pdfRedirectorFactory.register(PdfRedirector); 1.268 + 1.269 + Svc.pluginHost.registerPlayPreviewMimeType(PDF_CONTENT_TYPE, true, 1.270 + 'data:application/x-moz-playpreview-pdfjs;,'); 1.271 + 1.272 + this._registered = true; 1.273 + }, 1.274 + 1.275 + _ensureUnregistered: function _ensureUnregistered() { 1.276 + if (!this._registered) 1.277 + return; 1.278 + 1.279 + this._pdfStreamConverterFactory.unregister(); 1.280 + Cu.unload('resource://pdf.js/PdfStreamConverter.jsm'); 1.281 + delete this._pdfStreamConverterFactory; 1.282 + 1.283 + this._pdfRedirectorFactory.unregister(); 1.284 + Cu.unload('resource://pdf.js/PdfRedirector.jsm'); 1.285 + delete this._pdfRedirectorFactory; 1.286 + 1.287 + Svc.pluginHost.unregisterPlayPreviewMimeType(PDF_CONTENT_TYPE); 1.288 + 1.289 + this._registered = false; 1.290 + } 1.291 +}; 1.292 +