mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-20 15:18:08 +02:00
Merge remote-tracking branch 'mozilla/master' into textsearch-1
Conflicts: src/core.js src/fonts.js
This commit is contained in:
commit
1ac24dbc01
53 changed files with 6051 additions and 1127 deletions
|
@ -5,11 +5,16 @@
|
|||
|
||||
// Checking if the typed arrays are supported
|
||||
(function checkTypedArrayCompatibility() {
|
||||
if (typeof Uint8Array !== 'undefined')
|
||||
if (typeof Uint8Array !== 'undefined') {
|
||||
// some mobile version might not support Float64Array
|
||||
if (typeof Float64Array === 'undefined')
|
||||
window.Float64Array = Float32Array;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function subarray(start, end) {
|
||||
return this.slice(start, end);
|
||||
return new TypedArray(this.slice(start, end));
|
||||
}
|
||||
|
||||
function setArrayOffset(array, offset) {
|
||||
|
@ -46,6 +51,8 @@
|
|||
window.Uint32Array = TypedArray;
|
||||
window.Int32Array = TypedArray;
|
||||
window.Uint16Array = TypedArray;
|
||||
window.Float32Array = TypedArray;
|
||||
window.Float64Array = TypedArray;
|
||||
})();
|
||||
|
||||
// Object.create() ?
|
||||
|
|
|
@ -15,6 +15,7 @@ body {
|
|||
/* === Toolbar === */
|
||||
#controls {
|
||||
background-color: #eee;
|
||||
background: -o-linear-gradient(bottom,#eee 0%,#fff 100%);
|
||||
background: -moz-linear-gradient(center bottom, #eee 0%, #fff 100%);
|
||||
background: -webkit-gradient(linear, left bottom, left top, color-stop(0.0, #ddd), color-stop(1.0, #fff));
|
||||
border-bottom: 1px solid #666;
|
||||
|
@ -82,6 +83,7 @@ span#info {
|
|||
bottom: 18px;
|
||||
left: -290px;
|
||||
transition: left 0.25s ease-in-out 1s;
|
||||
-o-transition: left 0.25s ease-in-out 1s;
|
||||
-moz-transition: left 0.25s ease-in-out 1s;
|
||||
-webkit-transition: left 0.25s ease-in-out 1s;
|
||||
z-index: 1;
|
||||
|
@ -90,6 +92,7 @@ span#info {
|
|||
#sidebar:hover {
|
||||
left: 0px;
|
||||
transition: left 0.25s ease-in-out 0s;
|
||||
-o-transition: left 0.25s ease-in-out 0s;
|
||||
-moz-transition: left 0.25s ease-in-out 0s;
|
||||
-webkit-transition: left 0.25s ease-in-out 0s;
|
||||
}
|
||||
|
@ -365,7 +368,7 @@ canvas {
|
|||
color: black;
|
||||
padding: 3px;
|
||||
margin: 3px;
|
||||
white-space: pre;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
.clearBoth {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<script type="text/javascript" src="../src/stream.js"></script> <!-- PDFJSSCRIPT_REMOVE -->
|
||||
<script type="text/javascript" src="../src/worker.js"></script> <!-- PDFJSSCRIPT_REMOVE -->
|
||||
<script type="text/javascript" src="../external/jpgjs/jpg.js"></script> <!-- PDFJSSCRIPT_REMOVE -->
|
||||
<script type="text/javascript" src="../src/jpx.js"></script> <!-- PDFJSSCRIPT_REMOVE -->
|
||||
<script type="text/javascript">PDFJS.workerSrc = '../src/worker_loader.js';</script> <!-- PDFJSSCRIPT_REMOVE -->
|
||||
<script type="text/javascript" src="viewer.js"></script>
|
||||
|
||||
|
@ -67,10 +68,11 @@
|
|||
<option value="0.75">75%</option>
|
||||
<option value="1">100%</option>
|
||||
<option value="1.25">125%</option>
|
||||
<option value="1.5" selected="selected">150%</option>
|
||||
<option value="1.5">150%</option>
|
||||
<option value="2">200%</option>
|
||||
<option id="pageWidthOption" value="page-width">Page Width</option>
|
||||
<option id="pageFitOption" value="page-fit">Page Fit</option>
|
||||
<option id="pageAutoOption" value="auto" selected="selected">Auto</option>
|
||||
</select>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
@ -113,7 +115,7 @@
|
|||
</button>
|
||||
</div>
|
||||
<div class="clearBoth"></div>
|
||||
<div id="errorMoreInfo" hidden='true'></div>
|
||||
<textarea id="errorMoreInfo" hidden='true' readonly="readonly"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="sidebar">
|
||||
|
|
220
web/viewer.js
220
web/viewer.js
|
@ -4,7 +4,7 @@
|
|||
'use strict';
|
||||
|
||||
var kDefaultURL = 'compressed.tracemonkey-pldi-09.pdf';
|
||||
var kDefaultScale = 1.5;
|
||||
var kDefaultScale = 'auto';
|
||||
var kDefaultScaleDelta = 1.1;
|
||||
var kCacheSize = 20;
|
||||
var kCssUnits = 96.0 / 72.0;
|
||||
|
@ -33,6 +33,9 @@ var RenderingQueue = (function RenderingQueueClosure() {
|
|||
|
||||
RenderingQueue.prototype = {
|
||||
enqueueDraw: function RenderingQueueEnqueueDraw(item) {
|
||||
if (!item.drawingRequired())
|
||||
return; // as no redraw required, no need for queueing.
|
||||
|
||||
if ('rendering' in item)
|
||||
return; // is already in the queue
|
||||
|
||||
|
@ -146,9 +149,13 @@ var PDFView = {
|
|||
pages: [],
|
||||
thumbnails: [],
|
||||
currentScale: 0,
|
||||
currentScaleValue: null,
|
||||
initialBookmark: document.location.hash.substring(1),
|
||||
|
||||
setScale: function pdfViewSetScale(val, resetAutoSettings) {
|
||||
if (val == this.currentScale)
|
||||
return;
|
||||
|
||||
var pages = this.pages;
|
||||
for (var i = 0; i < pages.length; i++)
|
||||
pages[i].update(val * kCssUnits);
|
||||
|
@ -169,6 +176,7 @@ var PDFView = {
|
|||
return;
|
||||
|
||||
var scale = parseFloat(value);
|
||||
this.currentScaleValue = value;
|
||||
if (scale) {
|
||||
this.setScale(scale, true);
|
||||
return;
|
||||
|
@ -187,6 +195,10 @@ var PDFView = {
|
|||
this.setScale(
|
||||
Math.min(pageWidthScale, pageHeightScale), resetAutoSettings);
|
||||
}
|
||||
if ('auto' == value)
|
||||
this.setScale(Math.min(1.0, pageWidthScale), resetAutoSettings);
|
||||
|
||||
selectScaleOption(value);
|
||||
},
|
||||
|
||||
zoomIn: function pdfViewZoomIn() {
|
||||
|
@ -337,13 +349,14 @@ var PDFView = {
|
|||
};
|
||||
moreInfoButton.removeAttribute('hidden');
|
||||
lessInfoButton.setAttribute('hidden', 'true');
|
||||
errorMoreInfo.innerHTML = 'PDF.JS Build: ' + PDFJS.build + '\n';
|
||||
errorMoreInfo.value = 'PDF.JS Build: ' + PDFJS.build + '\n';
|
||||
|
||||
if (moreInfo) {
|
||||
errorMoreInfo.innerHTML += 'Message: ' + moreInfo.message;
|
||||
errorMoreInfo.value += 'Message: ' + moreInfo.message;
|
||||
if (moreInfo.stack)
|
||||
errorMoreInfo.innerHTML += '\n' + 'Stack: ' + moreInfo.stack;
|
||||
errorMoreInfo.value += '\n' + 'Stack: ' + moreInfo.stack;
|
||||
}
|
||||
errorMoreInfo.rows = errorMoreInfo.value.split('\n').length - 1;
|
||||
},
|
||||
|
||||
progress: function pdfViewProgress(level) {
|
||||
|
@ -357,6 +370,7 @@ var PDFView = {
|
|||
// when page is painted, using the image as thumbnail base
|
||||
pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() {
|
||||
thumbnailView.setImage(pageView.canvas);
|
||||
preDraw();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -428,6 +442,10 @@ var PDFView = {
|
|||
this.switchSidebarView('outline');
|
||||
}
|
||||
|
||||
// Reset the current scale, as otherwise the page's scale might not get
|
||||
// updated if the zoom level stayed the same.
|
||||
this.currentScale = 0;
|
||||
this.currentScaleValue = null;
|
||||
if (this.initialBookmark) {
|
||||
this.setHash(this.initialBookmark);
|
||||
this.initialBookmark = null;
|
||||
|
@ -435,7 +453,7 @@ var PDFView = {
|
|||
else if (storedHash)
|
||||
this.setHash(storedHash);
|
||||
else {
|
||||
this.setScale(scale || kDefaultScale, true);
|
||||
this.parseScale(scale || kDefaultScale, true);
|
||||
this.page = 1;
|
||||
}
|
||||
|
||||
|
@ -525,8 +543,16 @@ var PDFView = {
|
|||
if ('zoom' in params) {
|
||||
var zoomArgs = params.zoom.split(','); // scale,left,top
|
||||
// building destination array
|
||||
|
||||
// If the zoom value, it has to get divided by 100. If it is a string,
|
||||
// it should stay as it is.
|
||||
var zoomArg = zoomArgs[0];
|
||||
var zoomArgNumber = parseFloat(zoomArg);
|
||||
if (zoomArgNumber)
|
||||
zoomArg = zoomArgNumber / 100;
|
||||
|
||||
var dest = [null, {name: 'XYZ'}, (zoomArgs[1] | 0),
|
||||
(zoomArgs[2] | 0), (zoomArgs[0] | 0) / 100];
|
||||
(zoomArgs[2] | 0), zoomArg];
|
||||
var currentPage = this.pages[pageNumber - 1];
|
||||
currentPage.scrollIntoView(dest);
|
||||
} else
|
||||
|
@ -813,8 +839,12 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||
}, 0);
|
||||
};
|
||||
|
||||
this.drawingRequired = function() {
|
||||
return !div.hasChildNodes();
|
||||
};
|
||||
|
||||
this.draw = function pageviewDraw(callback) {
|
||||
if (div.hasChildNodes()) {
|
||||
if (!this.drawingRequired()) {
|
||||
this.updateStats();
|
||||
callback();
|
||||
return;
|
||||
|
@ -826,9 +856,13 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||
div.appendChild(canvas);
|
||||
this.canvas = canvas;
|
||||
|
||||
var textLayer = document.createElement('div');
|
||||
textLayer.className = 'textLayer';
|
||||
div.appendChild(textLayer);
|
||||
var textLayerDiv = null;
|
||||
if (!PDFJS.disableTextLayer) {
|
||||
textLayerDiv = document.createElement('div');
|
||||
textLayerDiv.className = 'textLayer';
|
||||
div.appendChild(textLayerDiv);
|
||||
}
|
||||
var textLayer = textLayerDiv ? new TextLayerBuilder(textLayerDiv) : null;
|
||||
|
||||
var scale = this.scale;
|
||||
canvas.width = pageWidth * scale;
|
||||
|
@ -923,6 +957,10 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
|
|||
return ctx;
|
||||
}
|
||||
|
||||
this.drawingRequired = function thumbnailViewDrawingRequired() {
|
||||
return !this.hasImage;
|
||||
};
|
||||
|
||||
this.draw = function thumbnailViewDraw(callback) {
|
||||
if (this.hasImage) {
|
||||
callback();
|
||||
|
@ -985,6 +1023,86 @@ var DocumentOutlineView = function documentOutlineView(outline) {
|
|||
}
|
||||
};
|
||||
|
||||
var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
||||
this.textLayerDiv = textLayerDiv;
|
||||
|
||||
this.beginLayout = function textLayerBuilderBeginLayout() {
|
||||
this.textDivs = [];
|
||||
this.textLayerQueue = [];
|
||||
};
|
||||
|
||||
this.endLayout = function textLayerBuilderEndLayout() {
|
||||
var self = this;
|
||||
var textDivs = this.textDivs;
|
||||
var textLayerDiv = this.textLayerDiv;
|
||||
var renderTimer = null;
|
||||
var renderingDone = false;
|
||||
var renderInterval = 0;
|
||||
var resumeInterval = 500; // in ms
|
||||
|
||||
// Render the text layer, one div at a time
|
||||
function renderTextLayer() {
|
||||
if (textDivs.length === 0) {
|
||||
clearInterval(renderTimer);
|
||||
renderingDone = true;
|
||||
return;
|
||||
}
|
||||
var textDiv = textDivs.shift();
|
||||
if (textDiv.dataset.textLength > 0) {
|
||||
textLayerDiv.appendChild(textDiv);
|
||||
|
||||
if (textDiv.dataset.textLength > 1) { // avoid div by zero
|
||||
// Adjust div width (via letterSpacing) to match canvas text
|
||||
// Due to the .offsetWidth calls, this is slow
|
||||
// This needs to come after appending to the DOM
|
||||
textDiv.style.letterSpacing =
|
||||
((textDiv.dataset.canvasWidth - textDiv.offsetWidth) /
|
||||
(textDiv.dataset.textLength - 1)) + 'px';
|
||||
}
|
||||
} // textLength > 0
|
||||
}
|
||||
renderTimer = setInterval(renderTextLayer, renderInterval);
|
||||
|
||||
// Stop rendering when user scrolls. Resume after XXX milliseconds
|
||||
// of no scroll events
|
||||
var scrollTimer = null;
|
||||
function textLayerOnScroll() {
|
||||
if (renderingDone) {
|
||||
window.removeEventListener('scroll', textLayerOnScroll, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Immediately pause rendering
|
||||
clearInterval(renderTimer);
|
||||
|
||||
clearTimeout(scrollTimer);
|
||||
scrollTimer = setTimeout(function textLayerScrollTimer() {
|
||||
// Resume rendering
|
||||
renderTimer = setInterval(renderTextLayer, renderInterval);
|
||||
}, resumeInterval);
|
||||
}; // textLayerOnScroll
|
||||
|
||||
window.addEventListener('scroll', textLayerOnScroll, false);
|
||||
}; // endLayout
|
||||
|
||||
this.appendText = function textLayerBuilderAppendText(text,
|
||||
fontName, fontSize) {
|
||||
var textDiv = document.createElement('div');
|
||||
|
||||
// vScale and hScale already contain the scaling to pixel units
|
||||
var fontHeight = fontSize * text.geom.vScale;
|
||||
textDiv.dataset.canvasWidth = text.canvasWidth * text.geom.hScale;
|
||||
|
||||
textDiv.style.fontSize = fontHeight + 'px';
|
||||
textDiv.style.fontFamily = fontName || 'sans-serif';
|
||||
textDiv.style.left = text.geom.x + 'px';
|
||||
textDiv.style.top = (text.geom.y - fontHeight) + 'px';
|
||||
textDiv.textContent = text.str;
|
||||
textDiv.dataset.textLength = text.length;
|
||||
this.textDivs.push(textDiv);
|
||||
};
|
||||
};
|
||||
|
||||
window.addEventListener('load', function webViewerLoad(evt) {
|
||||
var params = document.location.search.substring(1).split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
|
@ -992,7 +1110,7 @@ window.addEventListener('load', function webViewerLoad(evt) {
|
|||
params[unescape(param[0])] = unescape(param[1]);
|
||||
}
|
||||
|
||||
var scale = ('scale' in params) ? params.scale : kDefaultScale;
|
||||
var scale = ('scale' in params) ? params.scale : 0;
|
||||
PDFView.open(params.file || kDefaultURL, parseFloat(scale));
|
||||
|
||||
if (!window.File || !window.FileReader || !window.FileList || !window.Blob)
|
||||
|
@ -1001,7 +1119,10 @@ window.addEventListener('load', function webViewerLoad(evt) {
|
|||
document.getElementById('fileInput').value = null;
|
||||
|
||||
if ('disableWorker' in params)
|
||||
PDFJS.disableWorker = params['disableWorker'] === 'true' ? true : false;
|
||||
PDFJS.disableWorker = (params['disableWorker'] === 'true');
|
||||
|
||||
if ('disableTextLayer' in params)
|
||||
PDFJS.disableTextLayer = (params['disableTextLayer'] === 'true');
|
||||
|
||||
var sidebarScrollView = document.getElementById('sidebarScrollView');
|
||||
sidebarScrollView.addEventListener('scroll', updateThumbViewArea, true);
|
||||
|
@ -1011,26 +1132,64 @@ window.addEventListener('unload', function webViewerUnload(evt) {
|
|||
window.scrollTo(0, 0);
|
||||
}, true);
|
||||
|
||||
/**
|
||||
* Render the next not yet visible page already such that it is
|
||||
* hopefully ready once the user scrolls to it.
|
||||
*/
|
||||
function preDraw() {
|
||||
var pages = PDFView.pages;
|
||||
var visible = PDFView.getVisiblePages();
|
||||
var last = visible[visible.length - 1];
|
||||
// PageView.id is the actual page number, which is + 1 compared
|
||||
// to the index in `pages`. That means, pages[last.id] is the next
|
||||
// PageView instance.
|
||||
if (pages[last.id] && pages[last.id].drawingRequired()) {
|
||||
renderingQueue.enqueueDraw(pages[last.id]);
|
||||
return;
|
||||
}
|
||||
// If there is nothing to draw on the next page, maybe the user
|
||||
// is scrolling up, so, let's try to render the next page *before*
|
||||
// the first visible page
|
||||
if (pages[visible[0].id - 2]) {
|
||||
renderingQueue.enqueueDraw(pages[visible[0].id - 2]);
|
||||
}
|
||||
}
|
||||
|
||||
function updateViewarea() {
|
||||
var visiblePages = PDFView.getVisiblePages();
|
||||
var pageToDraw;
|
||||
for (var i = 0; i < visiblePages.length; i++) {
|
||||
var page = visiblePages[i];
|
||||
renderingQueue.enqueueDraw(PDFView.pages[page.id - 1]);
|
||||
var pageObj = PDFView.pages[page.id - 1];
|
||||
|
||||
pageToDraw |= pageObj.drawingRequired();
|
||||
renderingQueue.enqueueDraw(pageObj);
|
||||
}
|
||||
|
||||
if (!visiblePages.length)
|
||||
return;
|
||||
|
||||
// If there is no need to draw a page that is currenlty visible, preDraw the
|
||||
// next page the user might scroll to.
|
||||
if (!pageToDraw) {
|
||||
preDraw();
|
||||
}
|
||||
|
||||
updateViewarea.inProgress = true; // used in "set page"
|
||||
var currentId = PDFView.page;
|
||||
var firstPage = visiblePages[0];
|
||||
PDFView.page = firstPage.id;
|
||||
updateViewarea.inProgress = false;
|
||||
|
||||
var currentScale = PDFView.currentScale;
|
||||
var currentScaleValue = PDFView.currentScaleValue;
|
||||
var normalizedScaleValue = currentScaleValue == currentScale ?
|
||||
currentScale * 100 : currentScaleValue;
|
||||
|
||||
var kViewerTopMargin = 52;
|
||||
var pageNumber = firstPage.id;
|
||||
var pdfOpenParams = '#page=' + pageNumber;
|
||||
pdfOpenParams += '&zoom=' + Math.round(PDFView.currentScale * 100);
|
||||
pdfOpenParams += '&zoom=' + normalizedScaleValue;
|
||||
var currentPage = PDFView.pages[pageNumber - 1];
|
||||
var topLeft = currentPage.getPagePoint(window.pageXOffset,
|
||||
window.pageYOffset - firstPage.y - kViewerTopMargin);
|
||||
|
@ -1039,7 +1198,7 @@ function updateViewarea() {
|
|||
var store = PDFView.store;
|
||||
store.set('exists', true);
|
||||
store.set('page', pageNumber);
|
||||
store.set('zoom', Math.round(PDFView.currentScale * 100));
|
||||
store.set('zoom', normalizedScaleValue);
|
||||
store.set('scrollLeft', Math.round(topLeft.x));
|
||||
store.set('scrollTop', Math.round(topLeft.y));
|
||||
|
||||
|
@ -1075,7 +1234,8 @@ window.addEventListener('webkitTransitionEnd', updateThumbViewArea, true);
|
|||
|
||||
window.addEventListener('resize', function webViewerResize(evt) {
|
||||
if (document.getElementById('pageWidthOption').selected ||
|
||||
document.getElementById('pageFitOption').selected)
|
||||
document.getElementById('pageFitOption').selected ||
|
||||
document.getElementById('pageAutoOption').selected)
|
||||
PDFView.parseScale(document.getElementById('scaleSelect').value);
|
||||
updateViewarea();
|
||||
});
|
||||
|
@ -1112,20 +1272,9 @@ window.addEventListener('change', function webViewerChange(evt) {
|
|||
document.getElementById('download').setAttribute('hidden', 'true');
|
||||
}, true);
|
||||
|
||||
window.addEventListener('scalechange', function scalechange(evt) {
|
||||
var customScaleOption = document.getElementById('customScaleOption');
|
||||
customScaleOption.selected = false;
|
||||
|
||||
if (!evt.resetAutoSettings &&
|
||||
(document.getElementById('pageWidthOption').selected ||
|
||||
document.getElementById('pageFitOption').selected)) {
|
||||
updateViewarea();
|
||||
return;
|
||||
}
|
||||
|
||||
function selectScaleOption(value) {
|
||||
var options = document.getElementById('scaleSelect').options;
|
||||
var predefinedValueFound = false;
|
||||
var value = '' + evt.scale;
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var option = options[i];
|
||||
if (option.value != value) {
|
||||
|
@ -1135,7 +1284,22 @@ window.addEventListener('scalechange', function scalechange(evt) {
|
|||
option.selected = true;
|
||||
predefinedValueFound = true;
|
||||
}
|
||||
return predefinedValueFound;
|
||||
}
|
||||
|
||||
window.addEventListener('scalechange', function scalechange(evt) {
|
||||
var customScaleOption = document.getElementById('customScaleOption');
|
||||
customScaleOption.selected = false;
|
||||
|
||||
if (!evt.resetAutoSettings &&
|
||||
(document.getElementById('pageWidthOption').selected ||
|
||||
document.getElementById('pageFitOption').selected ||
|
||||
document.getElementById('pageAutoOption').selected)) {
|
||||
updateViewarea();
|
||||
return;
|
||||
}
|
||||
|
||||
var predefinedValueFound = selectScaleOption('' + evt.scale);
|
||||
if (!predefinedValueFound) {
|
||||
customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%';
|
||||
customScaleOption.selected = true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue