Handles embed tags via PlayPreview API

This commit is contained in:
Yury Delendik 2013-02-14 14:44:46 -06:00
parent 4247339d28
commit 61a3b3d035
2 changed files with 186 additions and 5 deletions

View File

@ -16,7 +16,7 @@
*/
/* jshint esnext:true */
/* globals Components, Services, dump, XPCOMUtils, PdfStreamConverter,
APP_SHUTDOWN */
PdfRedirector, APP_SHUTDOWN */
'use strict';
@ -32,6 +32,9 @@ const Cr = Components.results;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
var Ph = Cc['@mozilla.org/plugin/host;1'].getService(Ci.nsIPluginHost);
var registerOverlayPreview = 'getPlayPreviewInfo' in Ph;
function getBoolPref(pref, def) {
try {
return Services.prefs.getBoolPref(pref);
@ -53,8 +56,10 @@ function log(str) {
dump(str + '\n');
}
// Register/unregister a constructor as a component.
var Factory = {
// Factory that registers/unregisters a constructor as a component.
function Factory() {}
Factory.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]),
_targetConstructor: null,
@ -88,6 +93,9 @@ var Factory = {
};
var pdfStreamConverterUrl = null;
var pdfStreamConverterFactory = new Factory();
var pdfRedirectorUrl = null;
var pdfRedirectorFactory = new Factory();
// As of Firefox 13 bootstrapped add-ons don't support automatic registering and
// unregistering of resource urls and components/contracts. Until then we do
@ -105,7 +113,17 @@ function startup(aData, aReason) {
pdfStreamConverterUrl = aData.resourceURI.spec +
'components/PdfStreamConverter.js';
Cu.import(pdfStreamConverterUrl);
Factory.register(PdfStreamConverter);
pdfStreamConverterFactory.register(PdfStreamConverter);
if (registerOverlayPreview) {
pdfRedirectorUrl = aData.resourceURI.spec +
'components/PdfRedirector.js';
Cu.import(pdfRedirectorUrl);
pdfRedirectorFactory.register(PdfRedirector);
Ph.registerPlayPreviewMimeType('application/pdf', true,
'data:application/x-moz-playpreview-pdfjs;,');
}
}
function shutdown(aData, aReason) {
@ -117,10 +135,18 @@ function shutdown(aData, aReason) {
// Remove the resource url.
resProt.setSubstitution(RESOURCE_NAME, null);
// Remove the contract/component.
Factory.unregister();
pdfStreamConverterFactory.unregister();
// Unload the converter
Cu.unload(pdfStreamConverterUrl);
pdfStreamConverterUrl = null;
if (registerOverlayPreview) {
pdfRedirectorFactory.unregister();
Cu.unload(pdfRedirectorUrl);
pdfRedirectorUrl = null;
Ph.unregisterPlayPreviewMimeType('application/pdf');
}
}
function install(aData, aReason) {

View File

@ -0,0 +1,155 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* 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.
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils, NetUtil, dump */
'use strict';
var EXPORTED_SYMBOLS = ['PdfRedirector'];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const PDF_CONTENT_TYPE = 'application/pdf';
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/NetUtil.jsm');
function getDOMWindow(aChannel) {
var requestor = aChannel.notificationCallbacks ?
aChannel.notificationCallbacks :
aChannel.loadGroup.notificationCallbacks;
var win = requestor.getInterface(Components.interfaces.nsIDOMWindow);
return win;
}
function getObjectUrl(window) {
var url;
var element = window.frameElement;
var isOverlay = false;
var params = {};
if (element) {
var tagName = element.nodeName;
while (tagName != 'EMBED' && tagName != 'OBJECT') {
// plugin overlay skipping until the target plugin is found
isOverlay = true;
element = element.parentNode;
if (!element)
throw 'Plugin element is not found';
tagName = element.nodeName;
}
if (tagName == 'EMBED') {
for (var i = 0; i < element.attributes.length; ++i) {
params[element.attributes[i].localName] = element.attributes[i].value;
}
url = params.src;
} else {
for (var i = 0; i < element.childNodes.length; ++i) {
var paramElement = element.childNodes[i];
if (paramElement.nodeType != Ci.nsIDOMNode.ELEMENT_NODE ||
paramElement.nodeName != 'PARAM') {
continue;
}
params[paramElement.getAttribute('name')] =
paramElement.getAttribute('value');
}
var dataAttribute = element.getAttribute('data');
url = dataAttribute || params.movie || params.src;
}
}
if (!url) {
return url; // src is not specified
}
var element = window.frameElement;
// XXX base uri?
var baseUri = !element ? null :
Services.io.newURI(element.ownerDocument.location.href, null, null);
return Services.io.newURI(url, null, baseUri).spec;
}
function PdfRedirector() {
}
PdfRedirector.prototype = {
// properties required for XPCOM registration:
classID: Components.ID('{8cbfd8d0-2042-4976-b3ef-d9dee1efb975}'),
classDescription: 'pdf.js Redirector',
contractID:
'@mozilla.org/streamconv;1?from=application/x-moz-playpreview-pdfjs&to=*/*',
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIStreamConverter,
Ci.nsIStreamListener,
Ci.nsIRequestObserver
]),
// nsIStreamConverter::convert
convert: function(aFromStream, aFromType, aToType, aCtxt) {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
// nsIStreamConverter::asyncConvertData
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
// Store the listener passed to us
this.listener = aListener;
},
// nsIStreamListener::onDataAvailable
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
// Do nothing since all the data loading is handled by the viewer.
},
// nsIRequestObserver::onStartRequest
onStartRequest: function(aRequest, aContext) {
// Setup the request so we can use it below.
aRequest.QueryInterface(Ci.nsIChannel);
// Cancel the request so the viewer can handle it.
aRequest.cancel(Cr.NS_BINDING_ABORTED);
var domWindow = getDOMWindow(aRequest);
var pdfUrl = getObjectUrl(domWindow);
if (!pdfUrl) {
Services.console.logStringMessage(
'PdfRedirector.js: PDF location is not specified for OBJECT/EMBED tag');
return;
}
// Create a new channel that is viewer loaded as a resource.
var ioService = Services.io;
var channel = ioService.newChannel(pdfUrl, null, null);
channel.loadGroup = aRequest.loadGroup;
channel.asyncOpen(this.listener, aContext);
},
// nsIRequestObserver::onStopRequest
onStopRequest: function(aRequest, aContext, aStatusCode) {
// Do nothing
}
};
var NSGetFactory = XPCOMUtils.generateNSGetFactory([PdfRedirector]);