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.startXRef,
|
||||||
this.mainXRefEntriesOffset);
|
this.mainXRefEntriesOffset);
|
||||||
this.catalog = new Catalog(this.xref);
|
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() {
|
get numPages() {
|
||||||
var linearization = this.linearization;
|
var linearization = this.linearization;
|
||||||
@ -534,6 +541,22 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
|||||||
// shadow the prototype getter
|
// shadow the prototype getter
|
||||||
return shadow(this, 'numPages', num);
|
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) {
|
getPage: function pdfDocGetPage(n) {
|
||||||
return this.catalog.getPage(n);
|
return this.catalog.getPage(n);
|
||||||
}
|
}
|
||||||
@ -560,7 +583,7 @@ var PDFDoc = (function PDFDocClosure() {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.pdf = new PDFDocModel(stream);
|
this.pdf = new PDFDocModel(stream);
|
||||||
|
this.fingerprint = this.pdf.getFingerprint();
|
||||||
this.catalog = this.pdf.catalog;
|
this.catalog = this.pdf.catalog;
|
||||||
this.objs = new PDFObjects();
|
this.objs = new PDFObjects();
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ var XRef = (function XRefClosure() {
|
|||||||
this.entries = [];
|
this.entries = [];
|
||||||
this.xrefstms = {};
|
this.xrefstms = {};
|
||||||
var trailerDict = this.readXRef(startXRef);
|
var trailerDict = this.readXRef(startXRef);
|
||||||
|
this.trailer = trailerDict;
|
||||||
// prepare the XRef cache
|
// prepare the XRef cache
|
||||||
this.cache = [];
|
this.cache = [];
|
||||||
|
|
||||||
|
171
web/viewer.js
171
web/viewer.js
@ -12,6 +12,7 @@ var kScrollbarPadding = 40;
|
|||||||
var kMinScale = 0.25;
|
var kMinScale = 0.25;
|
||||||
var kMaxScale = 4.0;
|
var kMaxScale = 4.0;
|
||||||
var kImageDirectory = './images/';
|
var kImageDirectory = './images/';
|
||||||
|
var kSettingsMemory = 20;
|
||||||
|
|
||||||
var Cache = function cacheCache(size) {
|
var Cache = function cacheCache(size) {
|
||||||
var data = [];
|
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 cache = new Cache(kCacheSize);
|
||||||
|
var renderingQueue = new RenderingQueue();
|
||||||
var currentPageNumber = 1;
|
var currentPageNumber = 1;
|
||||||
|
|
||||||
var PDFView = {
|
var PDFView = {
|
||||||
pages: [],
|
pages: [],
|
||||||
thumbnails: [],
|
thumbnails: [],
|
||||||
currentScale: kDefaultScale,
|
currentScale: 0,
|
||||||
initialBookmark: document.location.hash.substring(1),
|
initialBookmark: document.location.hash.substring(1),
|
||||||
|
|
||||||
setScale: function pdfViewSetScale(val, resetAutoSettings) {
|
setScale: function pdfViewSetScale(val, resetAutoSettings) {
|
||||||
@ -272,8 +386,20 @@ var PDFView = {
|
|||||||
this.error('An error occurred while reading the PDF.', e);
|
this.error('An error occurred while reading the PDF.', e);
|
||||||
}
|
}
|
||||||
var pagesCount = pdf.numPages;
|
var pagesCount = pdf.numPages;
|
||||||
|
var id = pdf.fingerprint;
|
||||||
|
var storedHash = null;
|
||||||
document.getElementById('numPages').innerHTML = pagesCount;
|
document.getElementById('numPages').innerHTML = pagesCount;
|
||||||
document.getElementById('pageNumber').max = 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 pages = this.pages = [];
|
||||||
var pagesRefMap = {};
|
var pagesRefMap = {};
|
||||||
@ -294,7 +420,6 @@ var PDFView = {
|
|||||||
|
|
||||||
this.pagesRefMap = pagesRefMap;
|
this.pagesRefMap = pagesRefMap;
|
||||||
this.destinations = pdf.catalog.destinations;
|
this.destinations = pdf.catalog.destinations;
|
||||||
this.setScale(scale || kDefaultScale, true);
|
|
||||||
|
|
||||||
if (pdf.catalog.documentOutline) {
|
if (pdf.catalog.documentOutline) {
|
||||||
this.outline = new DocumentOutlineView(pdf.catalog.documentOutline);
|
this.outline = new DocumentOutlineView(pdf.catalog.documentOutline);
|
||||||
@ -307,8 +432,12 @@ var PDFView = {
|
|||||||
this.setHash(this.initialBookmark);
|
this.setHash(this.initialBookmark);
|
||||||
this.initialBookmark = null;
|
this.initialBookmark = null;
|
||||||
}
|
}
|
||||||
else
|
else if (storedHash)
|
||||||
|
this.setHash(storedHash);
|
||||||
|
else {
|
||||||
|
this.setScale(scale || kDefaultScale, true);
|
||||||
this.page = 1;
|
this.page = 1;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setHash: function pdfViewSetHash(hash) {
|
setHash: function pdfViewSetHash(hash) {
|
||||||
@ -334,7 +463,7 @@ var PDFView = {
|
|||||||
if ('zoom' in params) {
|
if ('zoom' in params) {
|
||||||
var zoomArgs = params.zoom.split(','); // scale,left,top
|
var zoomArgs = params.zoom.split(','); // scale,left,top
|
||||||
// building destination array
|
// 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];
|
(zoomArgs[2] | 0), (zoomArgs[0] | 0) / 100];
|
||||||
var currentPage = this.pages[pageNumber - 1];
|
var currentPage = this.pages[pageNumber - 1];
|
||||||
currentPage.scrollIntoView(dest);
|
currentPage.scrollIntoView(dest);
|
||||||
@ -609,10 +738,11 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.draw = function pageviewDraw() {
|
this.draw = function pageviewDraw(callback) {
|
||||||
if (div.hasChildNodes()) {
|
if (div.hasChildNodes()) {
|
||||||
this.updateStats();
|
this.updateStats();
|
||||||
return false;
|
callback();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var canvas = document.createElement('canvas');
|
var canvas = document.createElement('canvas');
|
||||||
@ -644,13 +774,14 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||||||
this.updateStats();
|
this.updateStats();
|
||||||
if (this.onAfterDraw)
|
if (this.onAfterDraw)
|
||||||
this.onAfterDraw();
|
this.onAfterDraw();
|
||||||
|
|
||||||
|
cache.push(this);
|
||||||
|
callback();
|
||||||
}).bind(this), textLayer
|
}).bind(this), textLayer
|
||||||
);
|
);
|
||||||
|
|
||||||
setupAnnotations(this.content, this.scale);
|
setupAnnotations(this.content, this.scale);
|
||||||
div.setAttribute('data-loaded', true);
|
div.setAttribute('data-loaded', true);
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateStats = function pageViewUpdateStats() {
|
this.updateStats = function pageViewUpdateStats() {
|
||||||
@ -717,12 +848,16 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.draw = function thumbnailViewDraw() {
|
this.draw = function thumbnailViewDraw(callback) {
|
||||||
if (this.hasImage)
|
if (this.hasImage) {
|
||||||
|
callback();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var ctx = getPageDrawContext();
|
var ctx = getPageDrawContext();
|
||||||
page.startRendering(ctx, function thumbnailViewDrawStartRendering() {});
|
page.startRendering(ctx, function thumbnailViewDrawStartRendering() {
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
this.hasImage = true;
|
this.hasImage = true;
|
||||||
};
|
};
|
||||||
@ -805,8 +940,7 @@ function updateViewarea() {
|
|||||||
var visiblePages = PDFView.getVisiblePages();
|
var visiblePages = PDFView.getVisiblePages();
|
||||||
for (var i = 0; i < visiblePages.length; i++) {
|
for (var i = 0; i < visiblePages.length; i++) {
|
||||||
var page = visiblePages[i];
|
var page = visiblePages[i];
|
||||||
if (PDFView.pages[page.id - 1].draw())
|
renderingQueue.enqueueDraw(PDFView.pages[page.id - 1]);
|
||||||
cache.push(page.view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!visiblePages.length)
|
if (!visiblePages.length)
|
||||||
@ -826,6 +960,14 @@ function updateViewarea() {
|
|||||||
var topLeft = currentPage.getPagePoint(window.pageXOffset,
|
var topLeft = currentPage.getPagePoint(window.pageXOffset,
|
||||||
window.pageYOffset - firstPage.y - kViewerTopMargin);
|
window.pageYOffset - firstPage.y - kViewerTopMargin);
|
||||||
pdfOpenParams += ',' + Math.round(topLeft.x) + ',' + Math.round(topLeft.y);
|
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;
|
document.getElementById('viewBookmark').href = pdfOpenParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,7 +990,7 @@ function updateThumbViewArea() {
|
|||||||
var visibleThumbs = PDFView.getVisibleThumbs();
|
var visibleThumbs = PDFView.getVisibleThumbs();
|
||||||
for (var i = 0; i < visibleThumbs.length; i++) {
|
for (var i = 0; i < visibleThumbs.length; i++) {
|
||||||
var thumb = visibleThumbs[i];
|
var thumb = visibleThumbs[i];
|
||||||
PDFView.thumbnails[thumb.id - 1].draw();
|
renderingQueue.enqueueDraw(PDFView.thumbnails[thumb.id - 1]);
|
||||||
}
|
}
|
||||||
}, delay);
|
}, delay);
|
||||||
}
|
}
|
||||||
@ -888,7 +1030,6 @@ window.addEventListener('change', function webViewerChange(evt) {
|
|||||||
// implemented in Firefox.
|
// implemented in Firefox.
|
||||||
var file = files[0];
|
var file = files[0];
|
||||||
fileReader.readAsBinaryString(file);
|
fileReader.readAsBinaryString(file);
|
||||||
|
|
||||||
document.title = file.name;
|
document.title = file.name;
|
||||||
|
|
||||||
// URL does not reflect proper document location - hiding some icons.
|
// URL does not reflect proper document location - hiding some icons.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user