Merge pull request #990 from notmasteryet/concurload
Fixes concurrent pages loading (#974 and #626)
This commit is contained in:
commit
9fd41e11da
25
src/core.js
25
src/core.js
@ -527,6 +527,13 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
this.startXRef,
|
||||
this.mainXRefEntriesOffset);
|
||||
this.catalog = new Catalog(this.xref);
|
||||
if (this.xref.trailer && this.xref.trailer.has('ID')) {
|
||||
var fileID = '';
|
||||
this.xref.trailer.get('ID')[0].split('').forEach(function(el) {
|
||||
fileID += Number(el.charCodeAt(0)).toString(16);
|
||||
});
|
||||
this.fileID = fileID;
|
||||
}
|
||||
},
|
||||
get numPages() {
|
||||
var linearization = this.linearization;
|
||||
@ -534,6 +541,22 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
// shadow the prototype getter
|
||||
return shadow(this, 'numPages', num);
|
||||
},
|
||||
getFingerprint: function pdfDocGetFingerprint() {
|
||||
if (this.fileID) {
|
||||
return this.fileID;
|
||||
} else {
|
||||
// If we got no fileID, then we generate one,
|
||||
// from the first 100 bytes of PDF
|
||||
var data = this.stream.bytes.subarray(0, 100);
|
||||
var hash = calculateMD5(data, 0, data.length);
|
||||
var strHash = '';
|
||||
for (var i = 0, length = hash.length; i < length; i++) {
|
||||
strHash += Number(hash[i]).toString(16);
|
||||
}
|
||||
|
||||
return strHash;
|
||||
}
|
||||
},
|
||||
getPage: function pdfDocGetPage(n) {
|
||||
return this.catalog.getPage(n);
|
||||
}
|
||||
@ -560,7 +583,7 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
this.data = data;
|
||||
this.stream = stream;
|
||||
this.pdf = new PDFDocModel(stream);
|
||||
|
||||
this.fingerprint = this.pdf.getFingerprint();
|
||||
this.catalog = this.pdf.catalog;
|
||||
this.objs = new PDFObjects();
|
||||
|
||||
|
@ -269,7 +269,7 @@ var XRef = (function XRefClosure() {
|
||||
this.entries = [];
|
||||
this.xrefstms = {};
|
||||
var trailerDict = this.readXRef(startXRef);
|
||||
|
||||
this.trailer = trailerDict;
|
||||
// prepare the XRef cache
|
||||
this.cache = [];
|
||||
|
||||
|
171
web/viewer.js
171
web/viewer.js
@ -12,6 +12,7 @@ var kScrollbarPadding = 40;
|
||||
var kMinScale = 0.25;
|
||||
var kMaxScale = 4.0;
|
||||
var kImageDirectory = './images/';
|
||||
var kSettingsMemory = 20;
|
||||
|
||||
var Cache = function cacheCache(size) {
|
||||
var data = [];
|
||||
@ -25,13 +26,126 @@ var Cache = function cacheCache(size) {
|
||||
};
|
||||
};
|
||||
|
||||
var RenderingQueue = (function RenderingQueueClosure() {
|
||||
function RenderingQueue() {
|
||||
this.items = [];
|
||||
}
|
||||
|
||||
RenderingQueue.prototype = {
|
||||
enqueueDraw: function RenderingQueueEnqueueDraw(item) {
|
||||
if ('rendering' in item)
|
||||
return; // is already in the queue
|
||||
|
||||
item.rendering = true;
|
||||
this.items.push(item);
|
||||
if (this.items.length > 1)
|
||||
return; // not first item
|
||||
|
||||
item.draw(this.continueExecution.bind(this));
|
||||
},
|
||||
continueExecution: function RenderingQueueContinueExecution() {
|
||||
var item = this.items.shift();
|
||||
delete item.rendering;
|
||||
|
||||
if (this.items.length == 0)
|
||||
return; // queue is empty
|
||||
|
||||
item = this.items[0];
|
||||
item.draw(this.continueExecution.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
return RenderingQueue;
|
||||
})();
|
||||
|
||||
// Settings Manager - This is a utility for saving settings
|
||||
// First we see if localStorage is available, FF bug #495747
|
||||
// If not, we use FUEL in FF
|
||||
var Settings = (function SettingsClosure() {
|
||||
var isLocalStorageEnabled = (function localStorageEnabledTest() {
|
||||
try {
|
||||
localStorage;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
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;
|
||||
}
|
||||
|
||||
function Settings(fingerprint) {
|
||||
var database = null;
|
||||
var index;
|
||||
if (inPrivateBrowsing)
|
||||
return false;
|
||||
else if (isExtension)
|
||||
database = Application.prefs.getValue(extPrefix + '.database', '{}');
|
||||
else if (isLocalStorageEnabled)
|
||||
database = localStorage.getItem('database') || '{}';
|
||||
else
|
||||
return false;
|
||||
|
||||
database = JSON.parse(database);
|
||||
if (!('files' in database))
|
||||
database.files = [];
|
||||
if (database.files.length >= kSettingsMemory)
|
||||
database.files.shift();
|
||||
for (var i = 0, length = database.files.length; i < length; i++) {
|
||||
var branch = database.files[i];
|
||||
if (branch.fingerprint == fingerprint) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (typeof index != 'number')
|
||||
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)
|
||||
localStorage.setItem('database', JSON.stringify(database));
|
||||
}
|
||||
|
||||
Settings.prototype = {
|
||||
set: function settingsSet(name, val) {
|
||||
if (inPrivateBrowsing)
|
||||
return false;
|
||||
var file = this.file;
|
||||
file[name] = val;
|
||||
if (isExtension)
|
||||
Application.prefs.setValue(extPrefix + '.database',
|
||||
JSON.stringify(this.database));
|
||||
else if (isLocalStorageEnabled)
|
||||
localStorage.setItem('database', JSON.stringify(this.database));
|
||||
},
|
||||
|
||||
get: function settingsGet(name, defaultValue) {
|
||||
if (inPrivateBrowsing)
|
||||
return defaultValue;
|
||||
else
|
||||
return this.file[name] || defaultValue;
|
||||
}
|
||||
};
|
||||
|
||||
return Settings;
|
||||
})();
|
||||
|
||||
var cache = new Cache(kCacheSize);
|
||||
var renderingQueue = new RenderingQueue();
|
||||
var currentPageNumber = 1;
|
||||
|
||||
var PDFView = {
|
||||
pages: [],
|
||||
thumbnails: [],
|
||||
currentScale: kDefaultScale,
|
||||
currentScale: 0,
|
||||
initialBookmark: document.location.hash.substring(1),
|
||||
|
||||
setScale: function pdfViewSetScale(val, resetAutoSettings) {
|
||||
@ -272,8 +386,20 @@ var PDFView = {
|
||||
this.error('An error occurred while reading the PDF.', e);
|
||||
}
|
||||
var pagesCount = pdf.numPages;
|
||||
var id = pdf.fingerprint;
|
||||
var storedHash = null;
|
||||
document.getElementById('numPages').innerHTML = pagesCount;
|
||||
document.getElementById('pageNumber').max = pagesCount;
|
||||
PDFView.documentFingerprint = id;
|
||||
var store = PDFView.store = new Settings(id);
|
||||
if (store.get('exists', false)) {
|
||||
var page = store.get('page', '1');
|
||||
var zoom = store.get('zoom', PDFView.currentScale);
|
||||
var left = store.get('scrollLeft', '0');
|
||||
var top = store.get('scrollTop', '0');
|
||||
|
||||
storedHash = 'page=' + page + '&zoom=' + zoom + ',' + left + ',' + top;
|
||||
}
|
||||
|
||||
var pages = this.pages = [];
|
||||
var pagesRefMap = {};
|
||||
@ -294,7 +420,6 @@ var PDFView = {
|
||||
|
||||
this.pagesRefMap = pagesRefMap;
|
||||
this.destinations = pdf.catalog.destinations;
|
||||
this.setScale(scale || kDefaultScale, true);
|
||||
|
||||
if (pdf.catalog.documentOutline) {
|
||||
this.outline = new DocumentOutlineView(pdf.catalog.documentOutline);
|
||||
@ -307,8 +432,12 @@ var PDFView = {
|
||||
this.setHash(this.initialBookmark);
|
||||
this.initialBookmark = null;
|
||||
}
|
||||
else
|
||||
else if (storedHash)
|
||||
this.setHash(storedHash);
|
||||
else {
|
||||
this.setScale(scale || kDefaultScale, true);
|
||||
this.page = 1;
|
||||
}
|
||||
},
|
||||
|
||||
setHash: function pdfViewSetHash(hash) {
|
||||
@ -334,7 +463,7 @@ var PDFView = {
|
||||
if ('zoom' in params) {
|
||||
var zoomArgs = params.zoom.split(','); // scale,left,top
|
||||
// building destination array
|
||||
var dest = [null, new Name('XYZ'), (zoomArgs[1] | 0),
|
||||
var dest = [null, {name: 'XYZ'}, (zoomArgs[1] | 0),
|
||||
(zoomArgs[2] | 0), (zoomArgs[0] | 0) / 100];
|
||||
var currentPage = this.pages[pageNumber - 1];
|
||||
currentPage.scrollIntoView(dest);
|
||||
@ -609,10 +738,11 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
}, 0);
|
||||
};
|
||||
|
||||
this.draw = function pageviewDraw() {
|
||||
this.draw = function pageviewDraw(callback) {
|
||||
if (div.hasChildNodes()) {
|
||||
this.updateStats();
|
||||
return false;
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
@ -644,13 +774,14 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
this.updateStats();
|
||||
if (this.onAfterDraw)
|
||||
this.onAfterDraw();
|
||||
|
||||
cache.push(this);
|
||||
callback();
|
||||
}).bind(this), textLayer
|
||||
);
|
||||
|
||||
setupAnnotations(this.content, this.scale);
|
||||
div.setAttribute('data-loaded', true);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
this.updateStats = function pageViewUpdateStats() {
|
||||
@ -717,12 +848,16 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
this.draw = function thumbnailViewDraw() {
|
||||
if (this.hasImage)
|
||||
this.draw = function thumbnailViewDraw(callback) {
|
||||
if (this.hasImage) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var ctx = getPageDrawContext();
|
||||
page.startRendering(ctx, function thumbnailViewDrawStartRendering() {});
|
||||
page.startRendering(ctx, function thumbnailViewDrawStartRendering() {
|
||||
callback();
|
||||
});
|
||||
|
||||
this.hasImage = true;
|
||||
};
|
||||
@ -805,8 +940,7 @@ function updateViewarea() {
|
||||
var visiblePages = PDFView.getVisiblePages();
|
||||
for (var i = 0; i < visiblePages.length; i++) {
|
||||
var page = visiblePages[i];
|
||||
if (PDFView.pages[page.id - 1].draw())
|
||||
cache.push(page.view);
|
||||
renderingQueue.enqueueDraw(PDFView.pages[page.id - 1]);
|
||||
}
|
||||
|
||||
if (!visiblePages.length)
|
||||
@ -826,6 +960,14 @@ function updateViewarea() {
|
||||
var topLeft = currentPage.getPagePoint(window.pageXOffset,
|
||||
window.pageYOffset - firstPage.y - kViewerTopMargin);
|
||||
pdfOpenParams += ',' + Math.round(topLeft.x) + ',' + Math.round(topLeft.y);
|
||||
|
||||
var store = PDFView.store;
|
||||
store.set('exists', true);
|
||||
store.set('page', pageNumber);
|
||||
store.set('zoom', Math.round(PDFView.currentScale * 100));
|
||||
store.set('scrollLeft', Math.round(topLeft.x));
|
||||
store.set('scrollTop', Math.round(topLeft.y));
|
||||
|
||||
document.getElementById('viewBookmark').href = pdfOpenParams;
|
||||
}
|
||||
|
||||
@ -848,7 +990,7 @@ function updateThumbViewArea() {
|
||||
var visibleThumbs = PDFView.getVisibleThumbs();
|
||||
for (var i = 0; i < visibleThumbs.length; i++) {
|
||||
var thumb = visibleThumbs[i];
|
||||
PDFView.thumbnails[thumb.id - 1].draw();
|
||||
renderingQueue.enqueueDraw(PDFView.thumbnails[thumb.id - 1]);
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
@ -888,7 +1030,6 @@ window.addEventListener('change', function webViewerChange(evt) {
|
||||
// implemented in Firefox.
|
||||
var file = files[0];
|
||||
fileReader.readAsBinaryString(file);
|
||||
|
||||
document.title = file.name;
|
||||
|
||||
// URL does not reflect proper document location - hiding some icons.
|
||||
|
Loading…
Reference in New Issue
Block a user