Merge branch 'refs/heads/master' into localStorage-fix
Conflicts: web/viewer.js
This commit is contained in:
commit
6aa02d286e
21
Makefile
21
Makefile
@ -209,11 +209,11 @@ pages-repo: | $(BUILD_DIR)
|
||||
# copy of the pdf.js source.
|
||||
CONTENT_DIR := content
|
||||
BUILD_NUMBER := `git log --format=oneline $(EXTENSION_BASE_VERSION).. | wc -l | awk '{print $$1}'`
|
||||
PDF_WEB_FILES = \
|
||||
EXTENSION_WEB_FILES = \
|
||||
web/images \
|
||||
web/compatibility.js \
|
||||
web/viewer.css \
|
||||
web/viewer.js \
|
||||
web/viewer.html \
|
||||
web/viewer-production.html \
|
||||
$(NULL)
|
||||
|
||||
@ -251,8 +251,19 @@ extension: | production
|
||||
@cd extensions/firefox; cp -r $(FIREFOX_EXTENSION_FILES_TO_COPY) ../../$(FIREFOX_BUILD_DIR)/
|
||||
# Copy a standalone version of pdf.js inside the content directory
|
||||
@cp $(BUILD_TARGET) $(FIREFOX_BUILD_CONTENT)/$(BUILD_DIR)/
|
||||
@cp -r $(PDF_WEB_FILES) $(FIREFOX_BUILD_CONTENT)/web/
|
||||
@mv -f $(FIREFOX_BUILD_CONTENT)/web/viewer-production.html $(FIREFOX_BUILD_CONTENT)/web/viewer.html
|
||||
@cp -r $(EXTENSION_WEB_FILES) $(FIREFOX_BUILD_CONTENT)/web/
|
||||
@rm $(FIREFOX_BUILD_CONTENT)/web/viewer-production.html
|
||||
# Copy over the firefox extension snippet so we can inline pdf.js in it
|
||||
@cp web/viewer-snippet-firefox-extension.html $(FIREFOX_BUILD_CONTENT)/web/
|
||||
# Modify the viewer so it does all the extension only stuff.
|
||||
@cd $(FIREFOX_BUILD_CONTENT)/web; \
|
||||
sed -i.bak '/PDFJSSCRIPT_INCLUDE_BUNDLE/ r ../build/pdf.js' viewer-snippet-firefox-extension.html; \
|
||||
sed -i.bak '/PDFJSSCRIPT_REMOVE/d' viewer.html; \
|
||||
sed -i.bak '/PDFJSSCRIPT_REMOVE_FIREFOX_EXTENSION/d' viewer.html; \
|
||||
sed -i.bak '/PDFJSSCRIPT_INCLUDE_FIREFOX_EXTENSION/ r viewer-snippet-firefox-extension.html' viewer.html; \
|
||||
rm -f *.bak;
|
||||
# We don't need pdf.js anymore since its inlined
|
||||
@rm -Rf $(FIREFOX_BUILD_CONTENT)/$(BUILD_DIR)/;
|
||||
# Update the build version number
|
||||
@sed -i.bak "s/PDFJSSCRIPT_BUILD/$(BUILD_NUMBER)/" $(FIREFOX_BUILD_DIR)/install.rdf
|
||||
@sed -i.bak "s/PDFJSSCRIPT_BUILD/$(BUILD_NUMBER)/" $(FIREFOX_BUILD_DIR)/update.rdf
|
||||
@ -274,7 +285,7 @@ extension: | production
|
||||
@cp -R $(CHROME_EXTENSION_FILES) $(CHROME_BUILD_DIR)/
|
||||
# Copy a standalone version of pdf.js inside the content directory
|
||||
@cp $(BUILD_TARGET) $(CHROME_BUILD_CONTENT)/$(BUILD_DIR)/
|
||||
@cp -r $(PDF_WEB_FILES) $(CHROME_BUILD_CONTENT)/web/
|
||||
@cp -r $(EXTENSION_WEB_FILES) $(CHROME_BUILD_CONTENT)/web/
|
||||
@mv -f $(CHROME_BUILD_CONTENT)/web/viewer-production.html $(CHROME_BUILD_CONTENT)/web/viewer.html
|
||||
|
||||
# Create the crx
|
||||
|
@ -11,7 +11,7 @@ rendering PDFs, and eventually release a PDF reader extension powered by
|
||||
pdf.js. Integration with Firefox is a possibility if the experiment proves
|
||||
successful.
|
||||
|
||||
|
||||
|
||||
|
||||
# Getting started
|
||||
|
||||
|
7
extensions/firefox/bootstrap.js
vendored
7
extensions/firefox/bootstrap.js
vendored
@ -3,6 +3,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const EXT_PREFIX = 'extensions.uriloader@pdf.js';
|
||||
const PDFJS_EVENT_ID = 'pdf.js.message';
|
||||
let Cc = Components.classes;
|
||||
let Ci = Components.interfaces;
|
||||
let Cm = Components.manager;
|
||||
@ -14,6 +16,7 @@ function log(str) {
|
||||
dump(str + '\n');
|
||||
}
|
||||
|
||||
|
||||
function startup(aData, aReason) {
|
||||
let manifestPath = 'chrome.manifest';
|
||||
let manifest = Cc['@mozilla.org/file/local;1']
|
||||
@ -34,13 +37,11 @@ function shutdown(aData, aReason) {
|
||||
}
|
||||
|
||||
function install(aData, aReason) {
|
||||
let url = 'chrome://pdf.js/content/web/viewer.html?file=%s';
|
||||
Services.prefs.setCharPref('extensions.pdf.js.url', url);
|
||||
Services.prefs.setBoolPref('extensions.pdf.js.active', false);
|
||||
}
|
||||
|
||||
function uninstall(aData, aReason) {
|
||||
Services.prefs.clearUserPref('extensions.pdf.js.url');
|
||||
Services.prefs.clearUserPref('extensions.pdf.js.active');
|
||||
application.prefs.setValue(EXT_PREFIX + '.database', '{}');
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
content pdf.js content/
|
||||
resource pdf.js content/
|
||||
|
||||
component {2278dfd0-b75c-11e0-8257-1ba3d93c9f1a} components/pdfContentHandler.js
|
||||
contract @mozilla.org/uriloader/content-handler;1?type=application/pdf {2278dfd0-b75c-11e0-8257-1ba3d93c9f1a}
|
||||
component {6457a96b-2d68-439a-bcfa-44465fbcdbb1} components/PdfStreamConverter.js
|
||||
contract @mozilla.org/streamconv;1?from=application/pdf&to=*/* {6457a96b-2d68-439a-bcfa-44465fbcdbb1}
|
||||
|
||||
|
159
extensions/firefox/components/PdfStreamConverter.js
Normal file
159
extensions/firefox/components/PdfStreamConverter.js
Normal file
@ -0,0 +1,159 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
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 NS_ERROR_NOT_IMPLEMENTED = 0x80004001;
|
||||
const EXT_PREFIX = 'extensions.uriloader@pdf.js';
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
function log(aMsg) {
|
||||
let msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
|
||||
Cc['@mozilla.org/consoleservice;1'].getService(Ci.nsIConsoleService)
|
||||
.logStringMessage(msg);
|
||||
dump(msg + '\n');
|
||||
}
|
||||
let application = Cc['@mozilla.org/fuel/application;1']
|
||||
.getService(Ci.fuelIApplication);
|
||||
let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
|
||||
.getService(Ci.nsIPrivateBrowsingService);
|
||||
let inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
|
||||
|
||||
// All the priviledged actions.
|
||||
function ChromeActions() {
|
||||
this.inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
|
||||
}
|
||||
ChromeActions.prototype = {
|
||||
download: function(data) {
|
||||
Services.wm.getMostRecentWindow('navigator:browser').saveURL(data);
|
||||
},
|
||||
setDatabase: function(data) {
|
||||
if (this.inPrivateBrowswing)
|
||||
return;
|
||||
application.prefs.setValue(EXT_PREFIX + '.database', data);
|
||||
},
|
||||
getDatabase: function() {
|
||||
if (this.inPrivateBrowswing)
|
||||
return '{}';
|
||||
return application.prefs.getValue(EXT_PREFIX + '.database', '{}');
|
||||
}
|
||||
};
|
||||
|
||||
// Event listener to trigger chrome privedged code.
|
||||
function RequestListener(actions) {
|
||||
this.actions = actions;
|
||||
}
|
||||
// Receive an event and synchronously responds.
|
||||
RequestListener.prototype.receive = function(event) {
|
||||
var message = event.target;
|
||||
var action = message.getUserData('action');
|
||||
var data = message.getUserData('data');
|
||||
var actions = this.actions;
|
||||
if (!(action in actions)) {
|
||||
log('Unknown action: ' + action);
|
||||
return;
|
||||
}
|
||||
var response = actions[action].call(this.actions, data);
|
||||
message.setUserData('response', response, null);
|
||||
};
|
||||
|
||||
|
||||
function PdfStreamConverter() {
|
||||
}
|
||||
|
||||
PdfStreamConverter.prototype = {
|
||||
|
||||
// properties required for XPCOM registration:
|
||||
classID: Components.ID('{6457a96b-2d68-439a-bcfa-44465fbcdbb1}'),
|
||||
classDescription: 'pdf.js Component',
|
||||
contractID: '@mozilla.org/streamconv;1?from=application/pdf&to=*/*',
|
||||
|
||||
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 and cancels
|
||||
* the request so pdf.js can do the request
|
||||
* Since the request is cancelled onDataAvailable should not be called. The
|
||||
* onStopRequest does nothing. The convert function just returns the stream,
|
||||
* it's just the synchronous version of asyncConvertData.
|
||||
*/
|
||||
|
||||
// nsIStreamConverter::convert
|
||||
convert: function(aFromStream, aFromType, aToType, aCtxt) {
|
||||
return aFromStream;
|
||||
},
|
||||
|
||||
// nsIStreamConverter::asyncConvertData
|
||||
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
|
||||
if (!Services.prefs.getBoolPref('extensions.pdf.js.active'))
|
||||
throw NS_ERROR_NOT_IMPLEMENTED;
|
||||
// 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.
|
||||
log('SANITY CHECK: onDataAvailable SHOULD NOT BE CALLED!');
|
||||
},
|
||||
|
||||
// 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);
|
||||
|
||||
// Create a new channel that is viewer loaded as a resource.
|
||||
var ioService = Cc['@mozilla.org/network/io-service;1']
|
||||
.getService(Ci.nsIIOService);
|
||||
var channel = ioService.newChannel(
|
||||
'resource://pdf.js/web/viewer.html', null, null);
|
||||
|
||||
// Keep the URL the same so the browser sees it as the same.
|
||||
channel.originalURI = aRequest.originalURI;
|
||||
channel.asyncOpen(this.listener, aContext);
|
||||
|
||||
// Setup a global listener waiting for the next DOM to be created and verfiy
|
||||
// that its the one we want by its URL. When the correct DOM is found create
|
||||
// an event listener on that window for the pdf.js events that require
|
||||
// chrome priviledges.
|
||||
var url = aRequest.originalURI.spec;
|
||||
var gb = Services.wm.getMostRecentWindow('navigator:browser');
|
||||
var domListener = function domListener(event) {
|
||||
var doc = event.originalTarget;
|
||||
var win = doc.defaultView;
|
||||
if (doc.location.href === url) {
|
||||
gb.removeEventListener('DOMContentLoaded', domListener);
|
||||
var requestListener = new RequestListener(new ChromeActions());
|
||||
win.addEventListener(PDFJS_EVENT_ID, function(event) {
|
||||
requestListener.receive(event);
|
||||
}, false, true);
|
||||
}
|
||||
};
|
||||
gb.addEventListener('DOMContentLoaded', domListener, false);
|
||||
},
|
||||
|
||||
// nsIRequestObserver::onStopRequest
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
// Do nothing.
|
||||
}
|
||||
};
|
||||
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([PdfStreamConverter]);
|
@ -1,67 +0,0 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const PDF_CONTENT_TYPE = 'application/pdf';
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
function log(aMsg) {
|
||||
let msg = 'pdfContentHandler.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
|
||||
Cc['@mozilla.org/consoleservice;1'].getService(Ci.nsIConsoleService)
|
||||
.logStringMessage(msg);
|
||||
dump(msg + '\n');
|
||||
}
|
||||
|
||||
const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
|
||||
function pdfContentHandler() {
|
||||
}
|
||||
|
||||
pdfContentHandler.prototype = {
|
||||
handleContent: function handleContent(aMimetype, aContext, aRequest) {
|
||||
if (aMimetype != PDF_CONTENT_TYPE)
|
||||
throw NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
|
||||
if (!(aRequest instanceof Ci.nsIChannel))
|
||||
throw NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
|
||||
if (!Services.prefs.getBoolPref('extensions.pdf.js.active'))
|
||||
throw NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
|
||||
let window = null;
|
||||
let callbacks = aRequest.notificationCallbacks ||
|
||||
aRequest.loadGroup.notificationCallbacks;
|
||||
if (!callbacks)
|
||||
return;
|
||||
|
||||
window = callbacks.getInterface(Ci.nsIDOMWindow);
|
||||
|
||||
let url = null;
|
||||
try {
|
||||
url = Services.prefs.getCharPref('extensions.pdf.js.url');
|
||||
} catch (e) {
|
||||
log('Error retrieving the pdf.js base url - ' + e);
|
||||
throw NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
}
|
||||
|
||||
let targetUrl = aRequest.URI.spec;
|
||||
if (targetUrl.indexOf('#pdfjs.action=download') >= 0)
|
||||
throw NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
|
||||
aRequest.cancel(Cr.NS_BINDING_ABORTED);
|
||||
window.location = url.replace('%s', encodeURIComponent(targetUrl));
|
||||
},
|
||||
|
||||
classID: Components.ID('{2278dfd0-b75c-11e0-8257-1ba3d93c9f1a}'),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler])
|
||||
};
|
||||
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([pdfContentHandler]);
|
||||
|
@ -548,7 +548,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
var fontObj = this.objs.get(fontRefName).fontObj;
|
||||
|
||||
if (!fontObj) {
|
||||
throw 'Can\'t find font for ' + fontRefName;
|
||||
error('Can\'t find font for ' + fontRefName);
|
||||
}
|
||||
|
||||
var name = fontObj.loadedName || 'sans-serif';
|
||||
@ -866,7 +866,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
} else if (IR[0] == 'RadialAxial' || IR[0] == 'Dummy') {
|
||||
var pattern = Pattern.shadingFromIR(this.ctx, IR);
|
||||
} else {
|
||||
throw 'Unkown IR type';
|
||||
error('Unkown IR type ' + IR[0]);
|
||||
}
|
||||
return pattern;
|
||||
},
|
||||
|
@ -369,55 +369,16 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
|
||||
DeviceCmykCS.prototype = {
|
||||
getRgb: function cmykcs_getRgb(color) {
|
||||
var c = color[0], m = color[1], y = color[2], k = color[3];
|
||||
var c1 = 1 - c, m1 = 1 - m, y1 = 1 - y, k1 = 1 - k;
|
||||
|
||||
var x, r, g, b;
|
||||
// this is a matrix multiplication, unrolled for performance
|
||||
// code is taken from the poppler implementation
|
||||
x = c1 * m1 * y1 * k1; // 0 0 0 0
|
||||
r = g = b = x;
|
||||
x = c1 * m1 * y1 * k; // 0 0 0 1
|
||||
r += 0.1373 * x;
|
||||
g += 0.1216 * x;
|
||||
b += 0.1255 * x;
|
||||
x = c1 * m1 * y * k1; // 0 0 1 0
|
||||
r += x;
|
||||
g += 0.9490 * x;
|
||||
x = c1 * m1 * y * k; // 0 0 1 1
|
||||
r += 0.1098 * x;
|
||||
g += 0.1020 * x;
|
||||
x = c1 * m * y1 * k1; // 0 1 0 0
|
||||
r += 0.9255 * x;
|
||||
b += 0.5490 * x;
|
||||
x = c1 * m * y1 * k; // 0 1 0 1
|
||||
r += 0.1412 * x;
|
||||
x = c1 * m * y * k1; // 0 1 1 0
|
||||
r += 0.9294 * x;
|
||||
g += 0.1098 * x;
|
||||
b += 0.1412 * x;
|
||||
x = c1 * m * y * k; // 0 1 1 1
|
||||
r += 0.1333 * x;
|
||||
x = c * m1 * y1 * k1; // 1 0 0 0
|
||||
g += 0.6784 * x;
|
||||
b += 0.9373 * x;
|
||||
x = c * m1 * y1 * k; // 1 0 0 1
|
||||
g += 0.0588 * x;
|
||||
b += 0.1412 * x;
|
||||
x = c * m1 * y * k1; // 1 0 1 0
|
||||
g += 0.6510 * x;
|
||||
b += 0.3137 * x;
|
||||
x = c * m1 * y * k; // 1 0 1 1
|
||||
g += 0.0745 * x;
|
||||
x = c * m * y1 * k1; // 1 1 0 0
|
||||
r += 0.1804 * x;
|
||||
g += 0.1922 * x;
|
||||
b += 0.5725 * x;
|
||||
x = c * m * y1 * k; // 1 1 0 1
|
||||
b += 0.0078 * x;
|
||||
x = c * m * y * k1; // 1 1 1 0
|
||||
r += 0.2118 * x;
|
||||
g += 0.2119 * x;
|
||||
b += 0.2235 * x;
|
||||
// CMYK -> CMY: http://www.easyrgb.com/index.php?X=MATH&H=14#text14
|
||||
c = (c * (1 - k) + k);
|
||||
m = (m * (1 - k) + k);
|
||||
y = (y * (1 - k) + k);
|
||||
|
||||
// CMY -> RGB: http://www.easyrgb.com/index.php?X=MATH&H=12#text12
|
||||
var r = (1 - c);
|
||||
var g = (1 - m);
|
||||
var b = (1 - y);
|
||||
|
||||
return [r, g, b];
|
||||
},
|
||||
|
30
src/core.js
30
src/core.js
@ -410,14 +410,14 @@ var Page = (function PageClosure() {
|
||||
if (callback)
|
||||
callback(e);
|
||||
else
|
||||
throw e;
|
||||
error(e);
|
||||
}
|
||||
}.bind(this),
|
||||
function pageDisplayReadPromiseError(reason) {
|
||||
if (callback)
|
||||
callback(reason);
|
||||
else
|
||||
throw reason;
|
||||
error(reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -620,13 +620,23 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
|
||||
var workerSrc = PDFJS.workerSrc;
|
||||
if (typeof workerSrc === 'undefined') {
|
||||
throw 'No PDFJS.workerSrc specified';
|
||||
error('No PDFJS.workerSrc specified');
|
||||
}
|
||||
|
||||
try {
|
||||
// Some versions of FF can't create a worker on localhost, see:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||
var worker = new Worker(workerSrc);
|
||||
var worker;
|
||||
if (PDFJS.isFirefoxExtension) {
|
||||
// The firefox extension can't load the worker from the resource://
|
||||
// url so we have to inline the script and then use the blob loader.
|
||||
var bb = new MozBlobBuilder();
|
||||
bb.append(document.querySelector('#PDFJS_SCRIPT_TAG').textContent);
|
||||
var blobUrl = window.URL.createObjectURL(bb.getBlob());
|
||||
worker = new Worker(blobUrl);
|
||||
} else {
|
||||
// Some versions of FF can't create a worker on localhost, see:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||
worker = new Worker(workerSrc);
|
||||
}
|
||||
|
||||
var messageHandler = new MessageHandler('main', worker);
|
||||
|
||||
@ -645,7 +655,9 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
// serializing the typed array.
|
||||
messageHandler.send('test', testObj);
|
||||
return;
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
warn('The worker has been disabled.');
|
||||
}
|
||||
}
|
||||
// Either workers are disabled, not supported or have thrown an exception.
|
||||
// Thus, we fallback to a faked worker.
|
||||
@ -716,7 +728,7 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw 'Got unkown object type ' + type;
|
||||
error('Got unkown object type ' + type);
|
||||
}
|
||||
}, this);
|
||||
|
||||
@ -737,7 +749,7 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
if (page.displayReadyPromise)
|
||||
page.displayReadyPromise.reject(data.error);
|
||||
else
|
||||
throw data.error;
|
||||
error(data.error);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('jpeg_decode', function(data, promise) {
|
||||
|
@ -481,8 +481,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
|
||||
}
|
||||
|
||||
var flags = properties.flags;
|
||||
var differences = [];
|
||||
var baseEncoding = Encodings.StandardEncoding;
|
||||
var baseEncoding = !!(flags & FontFlags.Symbolic) ?
|
||||
Encodings.symbolsEncoding : Encodings.StandardEncoding;
|
||||
var hasEncoding = dict.has('Encoding');
|
||||
if (hasEncoding) {
|
||||
var encoding = xref.fetchIfRef(dict.get('Encoding'));
|
||||
@ -761,8 +763,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
// Simulating descriptor flags attribute
|
||||
var fontNameWoStyle = baseFontName.split('-')[0];
|
||||
var flags = (serifFonts[fontNameWoStyle] ||
|
||||
(fontNameWoStyle.search(/serif/gi) != -1) ? 2 : 0) |
|
||||
(symbolsFonts[fontNameWoStyle] ? 4 : 32);
|
||||
(fontNameWoStyle.search(/serif/gi) != -1) ? FontFlags.Serif : 0) |
|
||||
(symbolsFonts[fontNameWoStyle] ? FontFlags.Symbolic :
|
||||
FontFlags.Nonsymbolic);
|
||||
|
||||
var properties = {
|
||||
type: type.name,
|
||||
|
67
src/fonts.js
67
src/fonts.js
@ -19,6 +19,18 @@ var kPDFGlyphSpaceUnits = 1000;
|
||||
// Until hinting is fully supported this constant can be used
|
||||
var kHintingEnabled = false;
|
||||
|
||||
var FontFlags = {
|
||||
FixedPitch: 1,
|
||||
Serif: 2,
|
||||
Symbolic: 4,
|
||||
Script: 8,
|
||||
Nonsymbolic: 32,
|
||||
Italic: 64,
|
||||
AllCap: 65536,
|
||||
SmallCap: 131072,
|
||||
ForceBold: 262144
|
||||
};
|
||||
|
||||
var Encodings = {
|
||||
get ExpertEncoding() {
|
||||
return shadow(this, 'ExpertEncoding', ['', '', '', '', '', '', '', '', '',
|
||||
@ -160,19 +172,20 @@ var Encodings = {
|
||||
'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
|
||||
'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'braceleft', 'bar', 'braceright', 'asciitilde', '', '', 'exclamdown',
|
||||
'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
|
||||
'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
|
||||
'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl',
|
||||
'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase',
|
||||
'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
|
||||
'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex',
|
||||
'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring',
|
||||
'cedilla', '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '',
|
||||
'ordfeminine', '', '', '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine',
|
||||
'', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '', 'lslash',
|
||||
'oslash', 'oe', 'germandbls'
|
||||
'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', 'exclamdown', 'cent', 'sterling',
|
||||
'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle',
|
||||
'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi',
|
||||
'fl', '', 'endash', 'dagger', 'daggerdbl', 'periodcentered', '',
|
||||
'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright',
|
||||
'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '',
|
||||
'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent',
|
||||
'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron',
|
||||
'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'AE', '', 'ordfeminine', '', '', '', '', 'Lslash', 'Oslash', 'OE',
|
||||
'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '',
|
||||
'lslash', 'oslash', 'oe', 'germandbls'
|
||||
]);
|
||||
},
|
||||
get WinAnsiEncoding() {
|
||||
@ -405,6 +418,19 @@ var symbolsFonts = {
|
||||
'Dingbats': true, 'Symbol': true, 'ZapfDingbats': true
|
||||
};
|
||||
|
||||
// Some characters, e.g. copyrightserif, mapped to the private use area and
|
||||
// might not be displayed using standard fonts. Mapping/hacking well-known chars
|
||||
// to the similar equivalents in the normal characters range.
|
||||
function mapPrivateUseChars(code) {
|
||||
switch (code) {
|
||||
case 0xF8E9: // copyrightsans
|
||||
case 0xF6D9: // copyrightserif
|
||||
return 0x00A9; // copyright
|
||||
default:
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
var FontLoader = {
|
||||
listeningForFontLoad: false,
|
||||
|
||||
@ -761,8 +787,8 @@ var Font = (function FontClosure() {
|
||||
var names = name.split('+');
|
||||
names = names.length > 1 ? names[1] : names[0];
|
||||
names = names.split(/[-,_]/g)[0];
|
||||
this.isSerifFont = !!(properties.flags & 2);
|
||||
this.isSymbolicFont = !!(properties.flags & 4);
|
||||
this.isSerifFont = !!(properties.flags & FontFlags.Serif);
|
||||
this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
|
||||
|
||||
var type = properties.type;
|
||||
this.type = type;
|
||||
@ -2186,7 +2212,7 @@ var Font = (function FontClosure() {
|
||||
case 'CIDFontType0':
|
||||
if (this.noUnicodeAdaptation) {
|
||||
width = this.widths[this.unicodeToCID[charcode] || charcode];
|
||||
unicode = charcode;
|
||||
unicode = mapPrivateUseChars(charcode);
|
||||
break;
|
||||
}
|
||||
unicode = this.toUnicode[charcode] || charcode;
|
||||
@ -2194,7 +2220,7 @@ var Font = (function FontClosure() {
|
||||
case 'CIDFontType2':
|
||||
if (this.noUnicodeAdaptation) {
|
||||
width = this.widths[this.unicodeToCID[charcode] || charcode];
|
||||
unicode = charcode;
|
||||
unicode = mapPrivateUseChars(charcode);
|
||||
break;
|
||||
}
|
||||
unicode = this.toUnicode[charcode] || charcode;
|
||||
@ -2204,7 +2230,7 @@ var Font = (function FontClosure() {
|
||||
if (!isNum(width))
|
||||
width = this.widths[glyphName];
|
||||
if (this.noUnicodeAdaptation) {
|
||||
unicode = GlyphsUnicode[glyphName] || charcode;
|
||||
unicode = mapPrivateUseChars(GlyphsUnicode[glyphName] || charcode);
|
||||
break;
|
||||
}
|
||||
unicode = this.glyphNameMap[glyphName] ||
|
||||
@ -2235,9 +2261,8 @@ var Font = (function FontClosure() {
|
||||
}
|
||||
|
||||
// MacRoman encoding address by re-encoding the cmap table
|
||||
unicode = glyphName in GlyphsUnicode ?
|
||||
GlyphsUnicode[glyphName] :
|
||||
this.glyphNameMap[glyphName];
|
||||
unicode = glyphName in this.glyphNameMap ?
|
||||
this.glyphNameMap[glyphName] : GlyphsUnicode[glyphName];
|
||||
break;
|
||||
default:
|
||||
warn('Unsupported font type: ' + this.type);
|
||||
|
156
src/function.js
156
src/function.js
@ -125,109 +125,99 @@ var PDFFunction = (function PDFFunctionClosure() {
|
||||
else
|
||||
decode = toMultiArray(decode);
|
||||
|
||||
// Precalc the multipliers
|
||||
var inputMul = new Float64Array(inputSize);
|
||||
for (var i = 0; i < inputSize; ++i) {
|
||||
inputMul[i] = (encode[i][1] - encode[i][0]) /
|
||||
(domain[i][1] - domain[i][0]);
|
||||
}
|
||||
|
||||
var idxMul = new Int32Array(inputSize);
|
||||
idxMul[0] = outputSize;
|
||||
for (i = 1; i < inputSize; ++i) {
|
||||
idxMul[i] = idxMul[i - 1] * size[i - 1];
|
||||
}
|
||||
|
||||
var nSamples = outputSize;
|
||||
for (i = 0; i < inputSize; ++i)
|
||||
nSamples *= size[i];
|
||||
|
||||
var samples = this.getSampleArray(size, outputSize, bps, str);
|
||||
|
||||
return [
|
||||
CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
|
||||
outputSize, bps, range, inputMul, idxMul, nSamples
|
||||
outputSize, Math.pow(2, bps) - 1, range
|
||||
];
|
||||
},
|
||||
|
||||
constructSampledFromIR: function pdfFunctionConstructSampledFromIR(IR) {
|
||||
var inputSize = IR[1];
|
||||
var domain = IR[2];
|
||||
var encode = IR[3];
|
||||
var decode = IR[4];
|
||||
var samples = IR[5];
|
||||
var size = IR[6];
|
||||
var outputSize = IR[7];
|
||||
var bps = IR[8];
|
||||
var range = IR[9];
|
||||
var inputMul = IR[10];
|
||||
var idxMul = IR[11];
|
||||
var nSamples = IR[12];
|
||||
// See chapter 3, page 109 of the PDF reference
|
||||
function interpolate(x, xmin, xmax, ymin, ymax) {
|
||||
return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin)));
|
||||
}
|
||||
|
||||
return function constructSampledFromIRResult(args) {
|
||||
if (inputSize != args.length)
|
||||
// See chapter 3, page 110 of the PDF reference.
|
||||
var m = IR[1];
|
||||
var domain = IR[2];
|
||||
var encode = IR[3];
|
||||
var decode = IR[4];
|
||||
var samples = IR[5];
|
||||
var size = IR[6];
|
||||
var n = IR[7];
|
||||
var mask = IR[8];
|
||||
var range = IR[9];
|
||||
|
||||
if (m != args.length)
|
||||
error('Incorrect number of arguments: ' + inputSize + ' != ' +
|
||||
args.length);
|
||||
// Most of the below is a port of Poppler's implementation.
|
||||
// TODO: There's a few other ways to do multilinear interpolation such
|
||||
// as piecewise, which is much faster but an approximation.
|
||||
var out = new Float64Array(outputSize);
|
||||
var x;
|
||||
var e = new Array(inputSize);
|
||||
var efrac0 = new Float64Array(inputSize);
|
||||
var efrac1 = new Float64Array(inputSize);
|
||||
var sBuf = new Float64Array(1 << inputSize);
|
||||
var i, j, k, idx, t;
|
||||
|
||||
// map input values into sample array
|
||||
for (i = 0; i < inputSize; ++i) {
|
||||
x = (args[i] - domain[i][0]) * inputMul[i] + encode[i][0];
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
} else if (x > size[i] - 1) {
|
||||
x = size[i] - 1;
|
||||
}
|
||||
e[i] = [Math.floor(x), 0];
|
||||
if ((e[i][1] = e[i][0] + 1) >= size[i]) {
|
||||
// this happens if in[i] = domain[i][1]
|
||||
e[i][1] = e[i][0];
|
||||
}
|
||||
efrac1[i] = x - e[i][0];
|
||||
efrac0[i] = 1 - efrac1[i];
|
||||
}
|
||||
var x = args;
|
||||
|
||||
// for each output, do m-linear interpolation
|
||||
for (i = 0; i < outputSize; ++i) {
|
||||
// Building the cube vertices: its part and sample index
|
||||
// http://rjwagner49.com/Mathematics/Interpolation.pdf
|
||||
var cubeVertices = 1 << m;
|
||||
var cubeN = new Float64Array(cubeVertices);
|
||||
var cubeVertex = new Uint32Array(cubeVertices);
|
||||
for (var j = 0; j < cubeVertices; j++)
|
||||
cubeN[j] = 1;
|
||||
|
||||
// pull 2^m values out of the sample array
|
||||
for (j = 0; j < (1 << inputSize); ++j) {
|
||||
idx = i;
|
||||
for (k = 0, t = j; k < inputSize; ++k, t >>= 1) {
|
||||
idx += idxMul[k] * (e[k][t & 1]);
|
||||
}
|
||||
if (idx >= 0 && idx < nSamples) {
|
||||
sBuf[j] = samples[idx];
|
||||
var k = n, pos = 1;
|
||||
// Map x_i to y_j for 0 <= i < m using the sampled function.
|
||||
for (var i = 0; i < m; ++i) {
|
||||
// x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
|
||||
var domain_2i = domain[i][0];
|
||||
var domain_2i_1 = domain[i][1];
|
||||
var xi = Math.min(Math.max(x[i], domain_2i), domain_2i_1);
|
||||
|
||||
// e_i = Interpolate(x_i', Domain_2i, Domain_2i+1,
|
||||
// Encode_2i, Encode_2i+1)
|
||||
var e = interpolate(xi, domain_2i, domain_2i_1,
|
||||
encode[i][0], encode[i][1]);
|
||||
|
||||
// e_i' = min(max(e_i, 0), Size_i - 1)
|
||||
var size_i = size[i];
|
||||
e = Math.min(Math.max(e, 0), size_i - 1);
|
||||
|
||||
// Adjusting the cube: N and vertex sample index
|
||||
var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1;
|
||||
var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
|
||||
var n1 = e - e0; // (e - e0) / (e1 - e0);
|
||||
var offset0 = e0 * k;
|
||||
var offset1 = offset0 + k; // e1 * k
|
||||
for (var j = 0; j < cubeVertices; j++) {
|
||||
if (j & pos) {
|
||||
cubeN[j] *= n1;
|
||||
cubeVertex[j] += offset1;
|
||||
} else {
|
||||
sBuf[j] = 0; // TODO Investigate if this is what Adobe does
|
||||
cubeN[j] *= n0;
|
||||
cubeVertex[j] += offset0;
|
||||
}
|
||||
}
|
||||
|
||||
// do m sets of interpolations
|
||||
for (j = 0, t = (1 << inputSize); j < inputSize; ++j, t >>= 1) {
|
||||
for (k = 0; k < t; k += 2) {
|
||||
sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// map output value to range
|
||||
out[i] = (sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0]);
|
||||
if (out[i] < range[i][0]) {
|
||||
out[i] = range[i][0];
|
||||
} else if (out[i] > range[i][1]) {
|
||||
out[i] = range[i][1];
|
||||
}
|
||||
k *= size_i;
|
||||
pos <<= 1;
|
||||
}
|
||||
return out;
|
||||
|
||||
var y = new Float64Array(n);
|
||||
for (var j = 0; j < n; ++j) {
|
||||
// Sum all cube vertices' samples portions
|
||||
var rj = 0;
|
||||
for (var i = 0; i < cubeVertices; i++)
|
||||
rj += samples[cubeVertex[i] + j] * cubeN[i];
|
||||
|
||||
// r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1,
|
||||
// Decode_2j, Decode_2j+1)
|
||||
rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
|
||||
|
||||
// y_j = min(max(r_j, range_2j), range_2j+1)
|
||||
y[j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
},
|
||||
|
||||
|
16
src/jpx.js
16
src/jpx.js
@ -1052,7 +1052,7 @@ var JpxImage = (function JpxImageClosure() {
|
||||
}
|
||||
r = 0;
|
||||
}
|
||||
throw 'Out of packets';
|
||||
error('JPX error: Out of packets');
|
||||
};
|
||||
}
|
||||
function ResolutionLayerComponentPositionIterator(context) {
|
||||
@ -1091,7 +1091,7 @@ var JpxImage = (function JpxImageClosure() {
|
||||
}
|
||||
l = 0;
|
||||
}
|
||||
throw 'Out of packets';
|
||||
error('JPX error: Out of packets');
|
||||
};
|
||||
}
|
||||
function buildPackets(context) {
|
||||
@ -1187,7 +1187,7 @@ var JpxImage = (function JpxImageClosure() {
|
||||
new ResolutionLayerComponentPositionIterator(context);
|
||||
break;
|
||||
default:
|
||||
throw 'Unsupported progression order';
|
||||
error('JPX error: Unsupported progression order ' + progressionOrder);
|
||||
}
|
||||
}
|
||||
function parseTilePackets(context, data, offset, dataLength) {
|
||||
@ -1589,7 +1589,7 @@ var JpxImage = (function JpxImageClosure() {
|
||||
if (lbox == 0)
|
||||
lbox = length - position + headerSize;
|
||||
if (lbox < headerSize)
|
||||
throw 'Invalid box field size';
|
||||
error('JPX error: Invalid box field size');
|
||||
var dataLength = lbox - headerSize;
|
||||
var jumpDataLength = true;
|
||||
switch (tbox) {
|
||||
@ -1675,7 +1675,7 @@ var JpxImage = (function JpxImageClosure() {
|
||||
scalarExpounded = true;
|
||||
break;
|
||||
default:
|
||||
throw 'Invalid SQcd value';
|
||||
error('JPX error: Invalid SQcd value ' + sqcd);
|
||||
}
|
||||
qcd.noQuantization = spqcdSize == 8;
|
||||
qcd.scalarExpounded = scalarExpounded;
|
||||
@ -1728,7 +1728,7 @@ var JpxImage = (function JpxImageClosure() {
|
||||
scalarExpounded = true;
|
||||
break;
|
||||
default:
|
||||
throw 'Invalid SQcd value';
|
||||
error('JPX error: Invalid SQcd value ' + sqcd);
|
||||
}
|
||||
qcc.noQuantization = spqcdSize == 8;
|
||||
qcc.scalarExpounded = scalarExpounded;
|
||||
@ -1795,7 +1795,7 @@ var JpxImage = (function JpxImageClosure() {
|
||||
cod.terminationOnEachCodingPass ||
|
||||
cod.verticalyStripe || cod.predictableTermination ||
|
||||
cod.segmentationSymbolUsed)
|
||||
throw 'Unsupported COD options: ' + uneval(cod);
|
||||
error('JPX error: Unsupported COD options: ' + uneval(cod));
|
||||
|
||||
if (context.mainHeader)
|
||||
context.COD = cod;
|
||||
@ -1840,7 +1840,7 @@ var JpxImage = (function JpxImageClosure() {
|
||||
// skipping content
|
||||
break;
|
||||
default:
|
||||
throw 'Unknown codestream code: ' + code.toString(16);
|
||||
error('JPX error: Unknown codestream code: ' + code.toString(16));
|
||||
}
|
||||
position += length;
|
||||
}
|
||||
|
159
src/obj.js
159
src/obj.js
@ -287,74 +287,69 @@ var XRef = (function XRefClosure() {
|
||||
|
||||
XRef.prototype = {
|
||||
readXRefTable: function readXRefTable(parser) {
|
||||
// Example of cross-reference table:
|
||||
// xref
|
||||
// 0 1 <-- subsection header (first obj #, obj count)
|
||||
// 0000000000 65535 f <-- actual object (offset, generation #, f/n)
|
||||
// 23 2 <-- subsection header ... and so on ...
|
||||
// 0000025518 00002 n
|
||||
// 0000025635 00000 n
|
||||
// trailer
|
||||
// ...
|
||||
|
||||
// Outer loop is over subsection headers
|
||||
var obj;
|
||||
while (true) {
|
||||
if (isCmd(obj = parser.getObj(), 'trailer'))
|
||||
break;
|
||||
if (!isInt(obj))
|
||||
error('Invalid XRef table');
|
||||
var first = obj;
|
||||
if (!isInt(obj = parser.getObj()))
|
||||
error('Invalid XRef table');
|
||||
var n = obj;
|
||||
if (first < 0 || n < 0 || (first + n) != ((first + n) | 0))
|
||||
error('Invalid XRef table: ' + first + ', ' + n);
|
||||
for (var i = first; i < first + n; ++i) {
|
||||
while (!isCmd(obj = parser.getObj(), 'trailer')) {
|
||||
var first = obj,
|
||||
count = parser.getObj();
|
||||
|
||||
if (!isInt(first) || !isInt(count))
|
||||
error('Invalid XRef table: wrong types in subsection header');
|
||||
|
||||
// Inner loop is over objects themselves
|
||||
for (var i = 0; i < count; i++) {
|
||||
var entry = {};
|
||||
if (!isInt(obj = parser.getObj()))
|
||||
error('Invalid XRef table: ' + first + ', ' + n);
|
||||
entry.offset = obj;
|
||||
if (!isInt(obj = parser.getObj()))
|
||||
error('Invalid XRef table: ' + first + ', ' + n);
|
||||
entry.gen = obj;
|
||||
obj = parser.getObj();
|
||||
if (isCmd(obj, 'n')) {
|
||||
entry.uncompressed = true;
|
||||
} else if (isCmd(obj, 'f')) {
|
||||
entry.offset = parser.getObj();
|
||||
entry.gen = parser.getObj();
|
||||
var type = parser.getObj();
|
||||
|
||||
if (isCmd(type, 'f'))
|
||||
entry.free = true;
|
||||
} else {
|
||||
error('Invalid XRef table: ' + first + ', ' + n);
|
||||
}
|
||||
if (!this.entries[i]) {
|
||||
// In some buggy PDF files the xref table claims to start at 1
|
||||
// instead of 0.
|
||||
if (i == 1 && first == 1 &&
|
||||
entry.offset == 0 && entry.gen == 65535 && entry.free) {
|
||||
i = first = 0;
|
||||
}
|
||||
this.entries[i] = entry;
|
||||
else if (isCmd(type, 'n'))
|
||||
entry.uncompressed = true;
|
||||
|
||||
// Validate entry obj
|
||||
if (!isInt(entry.offset) || !isInt(entry.gen) ||
|
||||
!(entry.free || entry.uncompressed)) {
|
||||
error('Invalid entry in XRef subsection: ' + first + ', ' + count);
|
||||
}
|
||||
|
||||
if (!this.entries[i + first])
|
||||
this.entries[i + first] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
// read the trailer dictionary
|
||||
var dict;
|
||||
if (!isDict(dict = parser.getObj()))
|
||||
error('Invalid XRef table');
|
||||
// Sanity check: as per spec, first object must have these properties
|
||||
if (this.entries[0] &&
|
||||
!(this.entries[0].gen === 65535 && this.entries[0].free))
|
||||
error('Invalid XRef table: unexpected first object');
|
||||
|
||||
// get the 'Prev' pointer
|
||||
var prev;
|
||||
obj = dict.get('Prev');
|
||||
if (isInt(obj)) {
|
||||
prev = obj;
|
||||
} else if (isRef(obj)) {
|
||||
// certain buggy PDF generators generate "/Prev NNN 0 R" instead
|
||||
// of "/Prev NNN"
|
||||
prev = obj.num;
|
||||
}
|
||||
if (prev) {
|
||||
this.readXRef(prev);
|
||||
}
|
||||
// Sanity check
|
||||
if (!isCmd(obj, 'trailer'))
|
||||
error('Invalid XRef table: could not find trailer dictionary');
|
||||
|
||||
// check for 'XRefStm' key
|
||||
if (isInt(obj = dict.get('XRefStm'))) {
|
||||
var pos = obj;
|
||||
// ignore previously loaded xref streams (possible infinite recursion)
|
||||
if (!(pos in this.xrefstms)) {
|
||||
this.xrefstms[pos] = 1;
|
||||
this.readXRef(pos);
|
||||
}
|
||||
}
|
||||
// Read trailer dictionary, e.g.
|
||||
// trailer
|
||||
// << /Size 22
|
||||
// /Root 20R
|
||||
// /Info 10R
|
||||
// /ID [ <81b14aafa313db63dbd6f981e49f94f4> ]
|
||||
// >>
|
||||
// The parser goes through the entire stream << ... >> and provides
|
||||
// a getter interface for the key-value table
|
||||
var dict = parser.getObj();
|
||||
if (!isDict(dict))
|
||||
error('Invalid XRef table: could not parse trailer dictionary');
|
||||
|
||||
return dict;
|
||||
},
|
||||
@ -407,9 +402,6 @@ var XRef = (function XRefClosure() {
|
||||
}
|
||||
range.splice(0, 2);
|
||||
}
|
||||
var prev = streamParameters.get('Prev');
|
||||
if (isInt(prev))
|
||||
this.readXRef(prev);
|
||||
return streamParameters;
|
||||
},
|
||||
indexObjects: function indexObjects() {
|
||||
@ -529,22 +521,47 @@ var XRef = (function XRefClosure() {
|
||||
try {
|
||||
var parser = new Parser(new Lexer(stream), true);
|
||||
var obj = parser.getObj();
|
||||
var dict;
|
||||
|
||||
// parse an old-style xref table
|
||||
if (isCmd(obj, 'xref'))
|
||||
return this.readXRefTable(parser);
|
||||
// Get dictionary
|
||||
if (isCmd(obj, 'xref')) {
|
||||
// Parse end-of-file XRef
|
||||
dict = this.readXRefTable(parser);
|
||||
|
||||
// parse an xref stream
|
||||
if (isInt(obj)) {
|
||||
// Recursively get other XRefs 'XRefStm', if any
|
||||
obj = dict.get('XRefStm');
|
||||
if (isInt(obj)) {
|
||||
var pos = obj;
|
||||
// ignore previously loaded xref streams
|
||||
// (possible infinite recursion)
|
||||
if (!(pos in this.xrefstms)) {
|
||||
this.xrefstms[pos] = 1;
|
||||
this.readXRef(pos);
|
||||
}
|
||||
}
|
||||
} else if (isInt(obj)) {
|
||||
// Parse in-stream XRef
|
||||
if (!isInt(parser.getObj()) ||
|
||||
!isCmd(parser.getObj(), 'obj') ||
|
||||
!isStream(obj = parser.getObj())) {
|
||||
error('Invalid XRef stream');
|
||||
}
|
||||
return this.readXRefStream(obj);
|
||||
dict = this.readXRefStream(obj);
|
||||
}
|
||||
|
||||
// Recursively get previous dictionary, if any
|
||||
obj = dict.get('Prev');
|
||||
if (isInt(obj))
|
||||
this.readXRef(obj);
|
||||
else if (isRef(obj)) {
|
||||
// The spec says Prev must not be a reference, i.e. "/Prev NNN"
|
||||
// This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R"
|
||||
this.readXRef(obj.num);
|
||||
}
|
||||
|
||||
return dict;
|
||||
} catch (e) {
|
||||
log('Reading of the xref table/stream failed: ' + e);
|
||||
log('(while reading XRef): ' + e);
|
||||
}
|
||||
|
||||
warn('Indexing all PDF objects');
|
||||
@ -574,7 +591,7 @@ var XRef = (function XRefClosure() {
|
||||
var stream, parser;
|
||||
if (e.uncompressed) {
|
||||
if (e.gen != gen)
|
||||
throw ('inconsistent generation in XRef');
|
||||
error('inconsistent generation in XRef');
|
||||
stream = this.stream.makeSubStream(e.offset);
|
||||
parser = new Parser(new Lexer(stream), true, this);
|
||||
var obj1 = parser.getObj();
|
||||
@ -703,7 +720,7 @@ var PDFObjects = (function PDFObjectsClosure() {
|
||||
// If there isn't an object yet or the object isn't resolved, then the
|
||||
// data isn't ready yet!
|
||||
if (!obj || !obj.isResolved) {
|
||||
throw 'Requesting object that isn\'t resolved yet ' + objId;
|
||||
error('Requesting object that isn\'t resolved yet ' + objId);
|
||||
return null;
|
||||
} else {
|
||||
return obj.data;
|
||||
|
@ -821,15 +821,19 @@ var JpegStream = (function JpegStreamClosure() {
|
||||
JpegStream.prototype.ensureBuffer = function jpegStreamEnsureBuffer(req) {
|
||||
if (this.bufferLength)
|
||||
return;
|
||||
var jpegImage = new JpegImage();
|
||||
if (this.colorTransform != -1)
|
||||
jpegImage.colorTransform = this.colorTransform;
|
||||
jpegImage.parse(this.bytes);
|
||||
var width = jpegImage.width;
|
||||
var height = jpegImage.height;
|
||||
var data = jpegImage.getData(width, height);
|
||||
this.buffer = data;
|
||||
this.bufferLength = data.length;
|
||||
try {
|
||||
var jpegImage = new JpegImage();
|
||||
if (this.colorTransform != -1)
|
||||
jpegImage.colorTransform = this.colorTransform;
|
||||
jpegImage.parse(this.bytes);
|
||||
var width = jpegImage.width;
|
||||
var height = jpegImage.height;
|
||||
var data = jpegImage.getData(width, height);
|
||||
this.buffer = data;
|
||||
this.bufferLength = data.length;
|
||||
} catch (e) {
|
||||
error('JPEG error: ' + e);
|
||||
}
|
||||
};
|
||||
JpegStream.prototype.getIR = function jpegStreamGetIR() {
|
||||
return bytesToString(this.bytes);
|
||||
|
16
src/util.js
16
src/util.js
@ -255,8 +255,8 @@ var Promise = (function PromiseClosure() {
|
||||
return;
|
||||
}
|
||||
if (this._data !== EMPTY_PROMISE) {
|
||||
throw 'Promise ' + this.name +
|
||||
': Cannot set the data of a promise twice';
|
||||
error('Promise ' + this.name +
|
||||
': Cannot set the data of a promise twice');
|
||||
}
|
||||
this._data = value;
|
||||
this.hasData = true;
|
||||
@ -268,7 +268,7 @@ var Promise = (function PromiseClosure() {
|
||||
|
||||
get data() {
|
||||
if (this._data === EMPTY_PROMISE) {
|
||||
throw 'Promise ' + this.name + ': Cannot get data that isn\'t set';
|
||||
error('Promise ' + this.name + ': Cannot get data that isn\'t set');
|
||||
}
|
||||
return this._data;
|
||||
},
|
||||
@ -283,10 +283,10 @@ var Promise = (function PromiseClosure() {
|
||||
|
||||
resolve: function promiseResolve(data) {
|
||||
if (this.isResolved) {
|
||||
throw 'A Promise can be resolved only once ' + this.name;
|
||||
error('A Promise can be resolved only once ' + this.name);
|
||||
}
|
||||
if (this.isRejected) {
|
||||
throw 'The Promise was already rejected ' + this.name;
|
||||
error('The Promise was already rejected ' + this.name);
|
||||
}
|
||||
|
||||
this.isResolved = true;
|
||||
@ -300,10 +300,10 @@ var Promise = (function PromiseClosure() {
|
||||
|
||||
reject: function proimseReject(reason) {
|
||||
if (this.isRejected) {
|
||||
throw 'A Promise can be rejected only once ' + this.name;
|
||||
error('A Promise can be rejected only once ' + this.name);
|
||||
}
|
||||
if (this.isResolved) {
|
||||
throw 'The Promise was already resolved ' + this.name;
|
||||
error('The Promise was already resolved ' + this.name);
|
||||
}
|
||||
|
||||
this.isRejected = true;
|
||||
@ -317,7 +317,7 @@ var Promise = (function PromiseClosure() {
|
||||
|
||||
then: function promiseThen(callback, errback) {
|
||||
if (!callback) {
|
||||
throw 'Requiring callback' + this.name;
|
||||
error('Requiring callback' + this.name);
|
||||
}
|
||||
|
||||
// If the promise is already resolved, call the callback directly.
|
||||
|
@ -26,7 +26,7 @@ function MessageHandler(name, comObj) {
|
||||
delete callbacks[callbackId];
|
||||
callback(data.data);
|
||||
} else {
|
||||
throw 'Cannot resolve callback ' + callbackId;
|
||||
error('Cannot resolve callback ' + callbackId);
|
||||
}
|
||||
} else if (data.action in ah) {
|
||||
var action = ah[data.action];
|
||||
@ -44,7 +44,7 @@ function MessageHandler(name, comObj) {
|
||||
action[0].call(action[1], data.data);
|
||||
}
|
||||
} else {
|
||||
throw 'Unkown action from worker: ' + data.action;
|
||||
error('Unkown action from worker: ' + data.action);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -53,7 +53,7 @@ MessageHandler.prototype = {
|
||||
on: function messageHandlerOn(actionName, handler, scope) {
|
||||
var ah = this.actionHandler;
|
||||
if (ah[actionName]) {
|
||||
throw 'There is already an actionName called "' + actionName + '"';
|
||||
error('There is already an actionName called "' + actionName + '"');
|
||||
}
|
||||
ah[actionName] = [handler, scope];
|
||||
},
|
||||
@ -208,6 +208,7 @@ var workerConsole = {
|
||||
action: 'console_error',
|
||||
data: args
|
||||
});
|
||||
throw 'pdf.js execution error';
|
||||
},
|
||||
|
||||
time: function time(name) {
|
||||
@ -217,7 +218,7 @@ var workerConsole = {
|
||||
timeEnd: function timeEnd(name) {
|
||||
var time = consoleTimer[name];
|
||||
if (time == null) {
|
||||
throw 'Unkown timer name ' + name;
|
||||
error('Unkown timer name ' + name);
|
||||
}
|
||||
this.log('Timer:', name, Date.now() - time);
|
||||
}
|
||||
|
1
test/pdfs/issue1096.pdf.link
Normal file
1
test/pdfs/issue1096.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
http://www.faithaliveresources.org/Content/Site135/FilesSamples/105315400440pdf_00000009843.pdf
|
1
test/pdfs/issue1127.pdf.link
Normal file
1
test/pdfs/issue1127.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
https://vmp.ethz.ch/pdfs/diplome/vordiplome/Block%201/Algorithmen_%26_Komplexitaet/AlgoKo_f08_Aufg.pdf
|
@ -402,6 +402,21 @@
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue1096",
|
||||
"file": "pdfs/issue1096.pdf",
|
||||
"md5": "7f75d2b4b93c78d401ff39e8c1b00612",
|
||||
"rounds": 1,
|
||||
"pageLimit": 10,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue1127",
|
||||
"file": "pdfs/issue1127.pdf",
|
||||
"md5": "4fb2be5ffefeafda4ba977de2a1bb4d8",
|
||||
"rounds": 1,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "liveprogramming",
|
||||
"file": "pdfs/liveprogramming.pdf",
|
||||
"md5": "7bd4dad1188232ef597d36fd72c33e52",
|
||||
|
@ -224,3 +224,10 @@
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// Check console compatability
|
||||
(function checkConsoleCompatibility() {
|
||||
if (typeof console == 'undefined') {
|
||||
console = {log: function() {}};
|
||||
}
|
||||
})();
|
||||
|
14
web/viewer-snippet-firefox-extension.html
Normal file
14
web/viewer-snippet-firefox-extension.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!-- This snippet is used in firefox extension, see Makefile -->
|
||||
<base href="resource://pdf.js/web/" />
|
||||
<script type="text/javascript" id="PDFJS_SCRIPT_TAG">
|
||||
<!--
|
||||
// pdf.js is inlined here because resource:// urls won't work
|
||||
// for loading workers.
|
||||
/* PDFJSSCRIPT_INCLUDE_BUNDLE */
|
||||
-->
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
// This specifies the location of the pdf.js file.
|
||||
PDFJS.isFirefoxExtension = true;
|
||||
PDFJS.workerSrc = 'none';
|
||||
</script>
|
@ -9,7 +9,7 @@ body {
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* === Toolbar === */
|
||||
|
@ -2,9 +2,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Simple pdf.js page viewer</title>
|
||||
<!-- PDFJSSCRIPT_INCLUDE_FIREFOX_EXTENSION -->
|
||||
|
||||
<link rel="stylesheet" href="viewer.css"/>
|
||||
|
||||
<script type="text/javascript" src="compatibility.js"></script>
|
||||
<script type="text/javascript" src="compatibility.js"></script> <!-- PDFJSSCRIPT_REMOVE_FIREFOX_EXTENSION -->
|
||||
|
||||
<!-- PDFJSSCRIPT_INCLUDE_BUILD -->
|
||||
<script type="text/javascript" src="../src/core.js"></script> <!-- PDFJSSCRIPT_REMOVE -->
|
||||
@ -91,7 +93,7 @@
|
||||
|
||||
<input id="fileInput" type="file" oncontextmenu="return false;"/>
|
||||
|
||||
<div class="separator"></div>
|
||||
<div id="fileInputSeperator" class="separator"></div>
|
||||
|
||||
<a href="#" id="viewBookmark" title="Bookmark (or copy) current location">
|
||||
<img src="images/bookmark.svg" alt="Bookmark" align="top" height="16"/>
|
||||
|
140
web/viewer.js
140
web/viewer.js
@ -6,6 +6,7 @@
|
||||
var kDefaultURL = 'compressed.tracemonkey-pldi-09.pdf';
|
||||
var kDefaultScale = 'auto';
|
||||
var kDefaultScaleDelta = 1.1;
|
||||
var kUnknownScale = 0;
|
||||
var kCacheSize = 20;
|
||||
var kCssUnits = 96.0 / 72.0;
|
||||
var kScrollbarPadding = 40;
|
||||
@ -61,6 +62,31 @@ var RenderingQueue = (function RenderingQueueClosure() {
|
||||
return RenderingQueue;
|
||||
})();
|
||||
|
||||
var FirefoxCom = (function FirefoxComClosure() {
|
||||
return {
|
||||
/**
|
||||
* Creates an event that hopefully the extension is listening for and will
|
||||
* synchronously respond to.
|
||||
* @param {String} action The action to trigger.
|
||||
* @param {String} data Optional data to send.
|
||||
* @return {*} The response.
|
||||
*/
|
||||
request: function(action, data) {
|
||||
var request = document.createTextNode('');
|
||||
request.setUserData('action', action, null);
|
||||
request.setUserData('data', data, null);
|
||||
document.documentElement.appendChild(request);
|
||||
|
||||
var sender = document.createEvent('Events');
|
||||
sender.initEvent('pdf.js.message', true, false);
|
||||
request.dispatchEvent(sender);
|
||||
var response = request.getUserData('response');
|
||||
document.documentElement.removeChild(request);
|
||||
return response;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
// Settings Manager - This is a utility for saving settings
|
||||
// First we see if localStorage is available
|
||||
// If not, we use FUEL in FF
|
||||
@ -76,22 +102,14 @@ var Settings = (function SettingsClosure() {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
var extPrefix = 'extensions.uriloader@pdf.js';
|
||||
var isExtension = location.protocol == 'chrome:' && !isLocalStorageEnabled;
|
||||
var inPrivateBrowsing = false;
|
||||
if (isExtension) {
|
||||
var pbs = Components.classes['@mozilla.org/privatebrowsing;1']
|
||||
.getService(Components.interfaces.nsIPrivateBrowsingService);
|
||||
inPrivateBrowsing = pbs.privateBrowsingEnabled;
|
||||
}
|
||||
|
||||
var isFirefoxExtension = PDFJS.isFirefoxExtension;
|
||||
|
||||
function Settings(fingerprint) {
|
||||
var database = null;
|
||||
var index;
|
||||
if (inPrivateBrowsing)
|
||||
return false;
|
||||
else if (isExtension)
|
||||
database = Application.prefs.getValue(extPrefix + '.database', '{}');
|
||||
if (isFirefoxExtension)
|
||||
database = FirefoxCom.request('getDatabase', null);
|
||||
else if (isLocalStorageEnabled)
|
||||
database = localStorage.getItem('database') || '{}';
|
||||
else
|
||||
@ -113,29 +131,26 @@ var Settings = (function SettingsClosure() {
|
||||
index = database.files.push({fingerprint: fingerprint}) - 1;
|
||||
this.file = database.files[index];
|
||||
this.database = database;
|
||||
if (isExtension)
|
||||
Application.prefs.setValue(extPrefix + '.database',
|
||||
JSON.stringify(database));
|
||||
else if (isLocalStorageEnabled)
|
||||
if (isLocalStorageEnabled)
|
||||
localStorage.setItem('database', JSON.stringify(database));
|
||||
}
|
||||
|
||||
Settings.prototype = {
|
||||
set: function settingsSet(name, val) {
|
||||
if (inPrivateBrowsing || !('file' in this))
|
||||
if (!('file' in this))
|
||||
return false;
|
||||
|
||||
var file = this.file;
|
||||
file[name] = val;
|
||||
if (isExtension)
|
||||
Application.prefs.setValue(extPrefix + '.database',
|
||||
JSON.stringify(this.database));
|
||||
var database = JSON.stringify(this.database);
|
||||
if (isFirefoxExtension)
|
||||
FirefoxCom.request('setDatabase', database);
|
||||
else if (isLocalStorageEnabled)
|
||||
localStorage.setItem('database', JSON.stringify(this.database));
|
||||
localStorage.setItem('database', database);
|
||||
},
|
||||
|
||||
get: function settingsGet(name, defaultValue) {
|
||||
if (inPrivateBrowsing || !('file' in this))
|
||||
if (!('file' in this))
|
||||
return defaultValue;
|
||||
|
||||
return this.file[name] || defaultValue;
|
||||
@ -152,7 +167,7 @@ var currentPageNumber = 1;
|
||||
var PDFView = {
|
||||
pages: [],
|
||||
thumbnails: [],
|
||||
currentScale: 0,
|
||||
currentScale: kUnknownScale,
|
||||
currentScaleValue: null,
|
||||
initialBookmark: document.location.hash.substring(1),
|
||||
|
||||
@ -207,12 +222,12 @@ var PDFView = {
|
||||
|
||||
zoomIn: function pdfViewZoomIn() {
|
||||
var newScale = Math.min(kMaxScale, this.currentScale * kDefaultScaleDelta);
|
||||
this.setScale(newScale, true);
|
||||
this.parseScale(newScale, true);
|
||||
},
|
||||
|
||||
zoomOut: function pdfViewZoomOut() {
|
||||
var newScale = Math.max(kMinScale, this.currentScale / kDefaultScaleDelta);
|
||||
this.setScale(newScale, true);
|
||||
this.parseScale(newScale, true);
|
||||
},
|
||||
|
||||
set page(val) {
|
||||
@ -261,7 +276,7 @@ var PDFView = {
|
||||
},
|
||||
error: function getPdfError(e) {
|
||||
var loadingIndicator = document.getElementById('loading');
|
||||
loadingIndicator.innerHTML = 'Error';
|
||||
loadingIndicator.textContent = 'Error';
|
||||
var moreInfo = {
|
||||
message: 'Unexpected server response of ' + e.target.status + '.'
|
||||
};
|
||||
@ -276,7 +291,13 @@ var PDFView = {
|
||||
},
|
||||
|
||||
download: function pdfViewDownload() {
|
||||
window.open(this.url + '#pdfjs.action=download', '_parent');
|
||||
var url = this.url.split('#')[0];
|
||||
if (PDFJS.isFirefoxExtension) {
|
||||
FirefoxCom.request('download', url);
|
||||
} else {
|
||||
url += '#pdfjs.action=download', '_parent';
|
||||
window.open(url, '_parent');
|
||||
}
|
||||
},
|
||||
|
||||
navigateTo: function pdfViewNavigateTo(dest) {
|
||||
@ -297,14 +318,14 @@ var PDFView = {
|
||||
|
||||
getDestinationHash: function pdfViewGetDestinationHash(dest) {
|
||||
if (typeof dest === 'string')
|
||||
return '#' + escape(dest);
|
||||
return PDFView.getAnchorUrl('#' + escape(dest));
|
||||
if (dest instanceof Array) {
|
||||
var destRef = dest[0]; // see navigateTo method for dest format
|
||||
var pageNumber = destRef instanceof Object ?
|
||||
this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] :
|
||||
(destRef + 1);
|
||||
if (pageNumber) {
|
||||
var pdfOpenParams = '#page=' + pageNumber;
|
||||
var pdfOpenParams = PDFView.getAnchorUrl('#page=' + pageNumber);
|
||||
var destKind = dest[1];
|
||||
if ('name' in destKind && destKind.name == 'XYZ') {
|
||||
var scale = (dest[4] || this.currentScale);
|
||||
@ -319,6 +340,17 @@ var PDFView = {
|
||||
return '';
|
||||
},
|
||||
|
||||
/**
|
||||
* For the firefox extension we prefix the full url on anchor links so they
|
||||
* don't come up as resource:// urls and so open in new tab/window works.
|
||||
* @param {String} anchor The anchor hash include the #.
|
||||
*/
|
||||
getAnchorUrl: function getAnchorUrl(anchor) {
|
||||
if (PDFJS.isFirefoxExtension)
|
||||
return this.url.split('#')[0] + anchor;
|
||||
return anchor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the error box.
|
||||
* @param {String} message A message that is human readable.
|
||||
@ -331,7 +363,7 @@ var PDFView = {
|
||||
errorWrapper.removeAttribute('hidden');
|
||||
|
||||
var errorMessage = document.getElementById('errorMessage');
|
||||
errorMessage.innerHTML = message;
|
||||
errorMessage.textContent = message;
|
||||
|
||||
var closeButton = document.getElementById('errorClose');
|
||||
closeButton.onclick = function() {
|
||||
@ -366,7 +398,7 @@ var PDFView = {
|
||||
progress: function pdfViewProgress(level) {
|
||||
var percent = Math.round(level * 100);
|
||||
var loadingIndicator = document.getElementById('loading');
|
||||
loadingIndicator.innerHTML = 'Loading... ' + percent + '%';
|
||||
loadingIndicator.textContent = 'Loading... ' + percent + '%';
|
||||
},
|
||||
|
||||
load: function pdfViewLoad(data, scale) {
|
||||
@ -406,7 +438,7 @@ var PDFView = {
|
||||
var pagesCount = pdf.numPages;
|
||||
var id = pdf.fingerprint;
|
||||
var storedHash = null;
|
||||
document.getElementById('numPages').innerHTML = pagesCount;
|
||||
document.getElementById('numPages').textContent = pagesCount;
|
||||
document.getElementById('pageNumber').max = pagesCount;
|
||||
PDFView.documentFingerprint = id;
|
||||
var store = PDFView.store = new Settings(id);
|
||||
@ -456,10 +488,16 @@ var PDFView = {
|
||||
}
|
||||
else if (storedHash)
|
||||
this.setHash(storedHash);
|
||||
else {
|
||||
this.parseScale(scale || kDefaultScale, true);
|
||||
else if (scale) {
|
||||
this.parseScale(scale, true);
|
||||
this.page = 1;
|
||||
}
|
||||
|
||||
if (PDFView.currentScale === kUnknownScale) {
|
||||
// Scale was not initialized: invalid bookmark or scale was not specified.
|
||||
// Setting the default one.
|
||||
this.parseScale(kDefaultScale, true);
|
||||
}
|
||||
},
|
||||
|
||||
setHash: function pdfViewSetHash(hash) {
|
||||
@ -652,7 +690,15 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
if (!item.content) {
|
||||
content.setAttribute('hidden', true);
|
||||
} else {
|
||||
text.innerHTML = item.content.replace('\n', '<br />');
|
||||
var e = document.createElement('span');
|
||||
var lines = item.content.split('\n');
|
||||
for (var i = 0, ii = lines.length; i < ii; ++i) {
|
||||
var line = lines[i];
|
||||
e.appendChild(document.createTextNode(line));
|
||||
if (i < (ii - 1))
|
||||
e.appendChild(document.createElement('br'));
|
||||
}
|
||||
text.appendChild(e);
|
||||
image.addEventListener('mouseover', function annotationImageOver() {
|
||||
this.nextSibling.removeAttribute('hidden');
|
||||
}, false);
|
||||
@ -746,6 +792,8 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
|
||||
if (scale && scale !== PDFView.currentScale)
|
||||
PDFView.parseScale(scale, true);
|
||||
else if (PDFView.currentScale === kUnknownScale)
|
||||
PDFView.parseScale(kDefaultScale, true);
|
||||
|
||||
setTimeout(function pageViewScrollIntoViewRelayout() {
|
||||
// letting page to re-layout before scrolling
|
||||
@ -826,13 +874,13 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
var t1 = stats.compile, t2 = stats.fonts, t3 = stats.render;
|
||||
var str = 'Time to compile/fonts/render: ' +
|
||||
(t1 - stats.begin) + '/' + (t2 - t1) + '/' + (t3 - t2) + ' ms';
|
||||
document.getElementById('info').innerHTML = str;
|
||||
document.getElementById('info').textContent = str;
|
||||
};
|
||||
};
|
||||
|
||||
var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
|
||||
var anchor = document.createElement('a');
|
||||
anchor.href = '#' + id;
|
||||
anchor.href = PDFView.getAnchorUrl('#page=' + id);
|
||||
anchor.onclick = function stopNivigation() {
|
||||
PDFView.page = id;
|
||||
return false;
|
||||
@ -1040,12 +1088,18 @@ window.addEventListener('load', function webViewerLoad(evt) {
|
||||
}
|
||||
|
||||
var scale = ('scale' in params) ? params.scale : 0;
|
||||
PDFView.open(params.file || kDefaultURL, parseFloat(scale));
|
||||
var file = PDFJS.isFirefoxExtension ?
|
||||
window.location.toString() : params.file || kDefaultURL;
|
||||
PDFView.open(file, parseFloat(scale));
|
||||
|
||||
if (!window.File || !window.FileReader || !window.FileList || !window.Blob)
|
||||
if (PDFJS.isFirefoxExtension || !window.File || !window.FileReader ||
|
||||
!window.FileList || !window.Blob) {
|
||||
document.getElementById('fileInput').setAttribute('hidden', 'true');
|
||||
else
|
||||
document.getElementById('fileInputSeperator')
|
||||
.setAttribute('hidden', 'true');
|
||||
} else {
|
||||
document.getElementById('fileInput').value = null;
|
||||
}
|
||||
|
||||
if ('disableWorker' in params)
|
||||
PDFJS.disableWorker = (params['disableWorker'] === 'true');
|
||||
@ -1130,8 +1184,8 @@ function updateViewarea() {
|
||||
store.set('zoom', normalizedScaleValue);
|
||||
store.set('scrollLeft', Math.round(topLeft.x));
|
||||
store.set('scrollTop', Math.round(topLeft.y));
|
||||
|
||||
document.getElementById('viewBookmark').href = pdfOpenParams;
|
||||
var href = PDFView.getAnchorUrl(pdfOpenParams);
|
||||
document.getElementById('viewBookmark').href = href;
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', function webViewerScroll(evt) {
|
||||
@ -1271,7 +1325,7 @@ window.addEventListener('keydown', function keydown(evt) {
|
||||
handled = true;
|
||||
break;
|
||||
case 48: // '0'
|
||||
PDFView.setScale(kDefaultScale, true);
|
||||
PDFView.parseScale(kDefaultScale, true);
|
||||
handled = true;
|
||||
break;
|
||||
case 37: // left arrow
|
||||
|
Loading…
Reference in New Issue
Block a user