diff --git a/extensions/chrome/hide-xhtml-error.css b/extensions/chrome/hide-xhtml-error.css
new file mode 100644
index 000000000..b917c6b8c
--- /dev/null
+++ b/extensions/chrome/hide-xhtml-error.css
@@ -0,0 +1,3 @@
+parsererror {
+ display: none;
+}
diff --git a/extensions/chrome/insertviewer.js b/extensions/chrome/insertviewer.js
new file mode 100644
index 000000000..3538c94f2
--- /dev/null
+++ b/extensions/chrome/insertviewer.js
@@ -0,0 +1,128 @@
+/* -*- 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.
+*/
+/* globals chrome */
+
+'use strict';
+
+var VIEWER_URL = chrome.extension.getURL('content/web/viewer.html');
+var BASE_URL = VIEWER_URL.replace(/[^\/]+$/, '');
+
+function getViewerURL(pdf_url) {
+ return VIEWER_URL + '?file=' + encodeURIComponent(pdf_url);
+}
+
+function showViewer(url) {
+ // Cancel page load and empty document.
+ window.stop();
+ document.body.textContent = '';
+
+ replaceDocumentWithViewer(url);
+}
+function makeLinksAbsolute(doc) {
+ normalize('href', 'link[href]');
+ normalize('src', 'style[src],script[src]');
+
+ function normalize(attribute, selector) {
+ var nodes = doc.querySelectorAll(selector);
+ for (var i=0; i elements (added back later).
+ // I assumed that no inline script tags exist.
+ var scripts = [];
+ while (x.response.scripts.length) {
+ var script = x.response.scripts[0];
+ var newScript = document.createElement('script');
+ newScript.onload = loadNextScript;
+ newScript.src = script.src;
+ script.parentNode.removeChild(script);
+ scripts.push(newScript);
+ }
+
+ // Replace document with viewer
+ var docEl = document.adoptNode(x.response.documentElement);
+ document.replaceChild(docEl, document.documentElement);
+ // Force Chrome to render content
+ // (without this line, the layout is broken and querySelector
+ // fails to find elements, even when they appear in the doc)
+ document.body.innerHTML += '';
+
+ // Load all scripts
+ loadNextScript();
+
+ function loadNextScript() {
+ if (scripts.length > 0)
+ document.head.appendChild(scripts.shift());
+ else
+ renderPDF(url);
+ }
+ };
+ x.send();
+}
+function renderPDF(url) {
+ var args = {
+ BASE_URL: BASE_URL,
+ pdf_url: url
+ };
+ // The following technique is explained at
+ // http://stackoverflow.com/a/9517879/938089
+ var script = document.createElement('script');
+ script.textContent =
+ '(function(args) {' +
+ ' PDFJS.workerSrc = args.BASE_URL + PDFJS.workerSrc;' +
+ ' window.DEFAULT_URL = args.pdf_url;' +
+ ' window.IMAGE_DIR = args.BASE_URL + window.IMAGE_DIR;' +
+ '})(' + JSON.stringify(args) + ');';
+ document.head.appendChild(script);
+
+ // Trigger domready
+ if (document.readyState === 'complete') {
+ var event = document.createEvent('Event');
+ event.initEvent('DOMContentLoaded', true, true);
+ document.dispatchEvent(event);
+ }
+}
+
+
+// Activate the content script only once per frame (until reload)
+if (!window.hasRun) {
+ window.hasRun = true;
+ chrome.extension.onMessage.addListener(function listener(message) {
+ if (message && message.type === 'showPDFViewer' &&
+ message.url === location.href) {
+ chrome.extension.onMessage.removeListener(listener);
+ showViewer(message.url);
+ }
+ });
+}
diff --git a/extensions/chrome/manifest.json b/extensions/chrome/manifest.json
index b66f8d41f..37c3385f4 100644
--- a/extensions/chrome/manifest.json
+++ b/extensions/chrome/manifest.json
@@ -10,14 +10,20 @@
},
"permissions": [
"webRequest", "webRequestBlocking",
- "http://*/*.pdf",
- "https://*/*.pdf",
- "file:///*/*.pdf",
- "http://*/*.PDF",
- "https://*/*.PDF",
- "file://*/*.PDF"
+ "",
+ "tabs"
],
+ "content_scripts": [{
+ "matches": [
+ "*://*/*.pdf*",
+ "*://*/*.PDF*"
+ ],
+ "css": ["hide-xhtml-error.css"]
+ }],
"background": {
"page": "pdfHandler.html"
- }
+ },
+ "web_accessible_resources": [
+ "content/*"
+ ]
}
diff --git a/extensions/chrome/pdfHandler-local.js b/extensions/chrome/pdfHandler-local.js
new file mode 100644
index 000000000..8fe33bf00
--- /dev/null
+++ b/extensions/chrome/pdfHandler-local.js
@@ -0,0 +1,69 @@
+/* -*- 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.
+*/
+/* globals chrome, isPdfDownloadable */
+
+'use strict';
+
+// The onHeadersReceived event is not generated for local resources.
+// Fortunately, local PDF files will have the .pdf extension, so there's
+// no need to detect the Content-Type
+// Unfortunately, the omnibox won't show the URL.
+// Unfortunately, this method will not work for pages in incognito mode,
+// unless "incognito":"split" is used AND http:/crbug.com/224094 is fixed.
+
+// Keeping track of incognito tab IDs will become obsolete when
+// "incognito":"split" can be used.
+var incognitoTabIds = [];
+chrome.windows.getAll({ populate: true }, function(windows) {
+ windows.forEach(function(win) {
+ if (win.incognito) {
+ win.tabs.forEach(function(tab) {
+ incognitoTabIds.push(tab.id);
+ });
+ }
+ });
+});
+chrome.tabs.onCreated.addListener(function(tab) {
+ if (tab.incognito) incognitoTabIds.push(tab.id);
+});
+chrome.tabs.onRemoved.addListener(function(tabId) {
+ var index = incognitoTabIds.indexOf(tabId);
+ if (index !== -1) incognitoTabIds.splice(index, 1);
+});
+
+chrome.webRequest.onBeforeRequest.addListener(
+ function(details) {
+ if (isPdfDownloadable(details)) // Defined in pdfHandler.js
+ return;
+
+ if (incognitoTabIds.indexOf(details.tabId) !== -1)
+ return; // Doesn't work in incognito mode, so don't redirect.
+
+ var viewerPage = 'content/web/viewer.html';
+ var url = chrome.extension.getURL(viewerPage) +
+ '?file=' + encodeURIComponent(details.url);
+ return { redirectUrl: url };
+ },
+ {
+ urls: [
+ 'file://*/*.pdf',
+ 'file://*/*.PDF'
+ ],
+ types: ['main_frame', 'sub_frame']
+ },
+ ['blocking']);
diff --git a/extensions/chrome/pdfHandler.html b/extensions/chrome/pdfHandler.html
index 7a64ecd16..821f4c884 100644
--- a/extensions/chrome/pdfHandler.html
+++ b/extensions/chrome/pdfHandler.html
@@ -15,3 +15,4 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
+
diff --git a/extensions/chrome/pdfHandler.js b/extensions/chrome/pdfHandler.js
index 87d7bb439..76811f0aa 100644
--- a/extensions/chrome/pdfHandler.js
+++ b/extensions/chrome/pdfHandler.js
@@ -23,25 +23,94 @@ function isPdfDownloadable(details) {
return details.url.indexOf('pdfjs.action=download') >= 0;
}
-chrome.webRequest.onBeforeRequest.addListener(
+function insertPDFJSForTab(tabId, url) {
+ chrome.tabs.executeScript(tabId, {
+ file: 'insertviewer.js',
+ allFrames: true,
+ runAt: 'document_start'
+ }, function() {
+ chrome.tabs.sendMessage(tabId, {
+ type: 'showPDFViewer',
+ url: url
+ });
+ });
+}
+function activatePDFJSForTab(tabId, url) {
+ chrome.tabs.onUpdated.addListener(function listener(_tabId) {
+ if (tabId === _tabId) {
+ insertPDFJSForTab(tabId, url);
+ chrome.tabs.onUpdated.removeListener(listener);
+ }
+ });
+}
+
+chrome.webRequest.onHeadersReceived.addListener(
function(details) {
- if (isPdfDownloadable(details))
+ // Check if the response is a PDF file
+ var isPDF = false;
+ var headers = details.responseHeaders;
+ var header, i;
+ var cdHeader;
+ if (!headers)
+ return;
+ for (i=0; i 0;
+ break;
+ }
+ }
+ if (!isPDF)
return;
- var viewerPage = 'content/web/viewer.html';
- var url = chrome.extension.getURL(viewerPage) +
- '?file=' + encodeURIComponent(details.url);
- return { redirectUrl: url };
+ if (isPdfDownloadable(details)) {
+ // Force download by ensuring that Content-Disposition: attachment is set
+ if (!cdHeader) {
+ for (; i'
],
- types: ['main_frame']
+ types: ['main_frame', 'sub_frame']
},
- ['blocking']);
+ ['blocking','responseHeaders']);
diff --git a/make.js b/make.js
index b2a76a90d..78d07538a 100644
--- a/make.js
+++ b/make.js
@@ -591,6 +591,7 @@ target.chrome = function() {
[['extensions/chrome/*.json',
'extensions/chrome/*.html',
'extensions/chrome/*.js',
+ 'extensions/chrome/*.css',
'extensions/chrome/icon*.png',],
CHROME_BUILD_DIR],
['external/webL10n/l10n.js', CHROME_BUILD_CONTENT_DIR + '/web'],
@@ -607,6 +608,22 @@ target.chrome = function() {
sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION,
CHROME_BUILD_DIR + '/manifest.json');
+ // Allow PDF.js resources to be loaded by adding the files to
+ // the "web_accessible_resources" section.
+ var file_list = ls('-RA', CHROME_BUILD_CONTENT_DIR);
+ var public_chrome_files = file_list.reduce(function(war, file) {
+ // Exclude directories (naive: Exclude paths without dot)
+ if (file.indexOf('.') !== -1) {
+ // Only add a comma after the first file
+ if (war)
+ war += ',\n';
+ war += JSON.stringify('content/' + file);
+ }
+ return war;
+ }, '');
+ sed('-i', /"content\/\*"/, public_chrome_files,
+ CHROME_BUILD_DIR + '/manifest.json');
+
// Bundle the files to a Chrome extension file .crx if path to key is set
var pem = env['PDFJS_CHROME_KEY'];
if (!pem) {