/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ "use strict"; var pageTimeout; var PDFViewer = { queryParams: {}, element: null, previousPageButton: null, nextPageButton: null, pageNumberInput: null, scaleSelect: null, fileInput: null, willJumpToPage: false, pdf: null, url: 'compressed.tracemonkey-pldi-09.pdf', pageNumber: 1, numberOfPages: 1, scale: 1.0, pageWidth: function(page) { return page.mediaBox[2] * PDFViewer.scale; }, pageHeight: function(page) { return page.mediaBox[3] * PDFViewer.scale; }, lastPagesDrawn: [], visiblePages: function() { const pageBottomMargin = 20; var windowTop = window.pageYOffset; var windowBottom = window.pageYOffset + window.innerHeight; var pageHeight, page; var i, n = PDFViewer.numberOfPages, currentHeight = 0; for (i = 1; i <= n; i++) { var page = PDFViewer.pdf.getPage(i); pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; if (currentHeight + pageHeight > windowTop) break; currentHeight += pageHeight; } var pages = []; for (; i <= n && currentHeight < windowBottom; i++) { var page = PDFViewer.pdf.getPage(i); pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; currentHeight += pageHeight; pages.push(i); } return pages; }, createPage: function(num) { var page = PDFViewer.pdf.getPage(num); var anchor = document.createElement('a'); anchor.name = '' + num; var div = document.createElement('div'); div.id = 'pageContainer' + num; div.className = 'page'; div.style.width = PDFViewer.pageWidth(page) + 'px'; div.style.height = PDFViewer.pageHeight(page) + 'px'; PDFViewer.element.appendChild(anchor); PDFViewer.element.appendChild(div); }, removePage: function(num) { var div = document.getElementById('pageContainer' + num); if (div) { while (div.hasChildNodes()) { div.removeChild(div.firstChild); } } }, drawPage: function(num) { if (!PDFViewer.pdf) return; var div = document.getElementById('pageContainer' + num); var canvas = document.createElement('canvas'); if (div && !div.hasChildNodes()) { var page = PDFViewer.pdf.getPage(num); canvas.id = 'page' + num; canvas.mozOpaque = true; // Canvas dimensions must be specified in CSS pixels. CSS pixels // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. canvas.width = PDFViewer.pageWidth(page); canvas.height = PDFViewer.pageHeight(page); div.appendChild(canvas); var ctx = canvas.getContext('2d'); ctx.save(); ctx.fillStyle = 'rgb(255, 255, 255)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore(); var gfx = new CanvasGraphics(ctx); // page.compile will collect all fonts for us, once we have loaded them // we can trigger the actual page rendering with page.display var fonts = []; page.compile(gfx, fonts); var loadFont = function() { if (!FontLoader.bind(fonts)) { pageTimeout = window.setTimeout(loadFont, 10); return; } page.display(gfx); } loadFont(); } }, changeScale: function(num) { while (PDFViewer.element.hasChildNodes()) { PDFViewer.element.removeChild(PDFViewer.element.firstChild); } PDFViewer.scale = num / 100; var i; if (PDFViewer.pdf) { for (i = 1; i <= PDFViewer.numberOfPages; i++) { PDFViewer.createPage(i); } if (PDFViewer.numberOfPages > 0) { PDFViewer.drawPage(1); } } for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { var option = PDFViewer.scaleSelect.childNodes[i]; if (option.value == num) { if (!option.selected) { option.selected = 'selected'; } } else { if (option.selected) { option.removeAttribute('selected'); } } } PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; }, goToPage: function(num) { if (1 <= num && num <= PDFViewer.numberOfPages) { PDFViewer.pageNumber = num; PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; PDFViewer.willJumpToPage = true; document.location.hash = PDFViewer.pageNumber; PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; } }, goToPreviousPage: function() { if (PDFViewer.pageNumber > 1) { PDFViewer.goToPage(--PDFViewer.pageNumber); } }, goToNextPage: function() { if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { PDFViewer.goToPage(++PDFViewer.pageNumber); } }, openURL: function(url) { PDFViewer.url = url; document.title = url; var req = new XMLHttpRequest(); req.open('GET', url); req.mozResponseType = req.responseType = 'arraybuffer'; req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; req.onreadystatechange = function() { if (req.readyState === 4 && req.status === req.expected) { var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response; PDFViewer.readPDF(data); } }; req.send(null); }, readPDF: function(data) { while (PDFViewer.element.hasChildNodes()) { PDFViewer.element.removeChild(PDFViewer.element.firstChild); } PDFViewer.pdf = new PDFDoc(new Stream(data)); PDFViewer.numberOfPages = PDFViewer.pdf.numPages; document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); for (var i = 1; i <= PDFViewer.numberOfPages; i++) { PDFViewer.createPage(i); } if (PDFViewer.numberOfPages > 0) { PDFViewer.drawPage(1); document.location.hash = 1; } PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; } }; window.onload = function() { // Parse the URL query parameters into a cached object. PDFViewer.queryParams = function() { var qs = window.location.search.substring(1); var kvs = qs.split('&'); var params = {}; for (var i = 0; i < kvs.length; ++i) { var kv = kvs[i].split('='); params[unescape(kv[0])] = unescape(kv[1]); } return params; }(); PDFViewer.element = document.getElementById('viewer'); PDFViewer.pageNumberInput = document.getElementById('pageNumber'); PDFViewer.pageNumberInput.onkeydown = function(evt) { var charCode = evt.charCode || evt.keyCode; // Up arrow key. if (charCode === 38) { PDFViewer.goToNextPage(); this.select(); } // Down arrow key. else if (charCode === 40) { PDFViewer.goToPreviousPage(); this.select(); } // All other non-numeric keys (excluding Left arrow, Right arrow, // Backspace, and Delete keys). else if ((charCode < 48 || charCode > 57) && charCode !== 8 && // Backspace charCode !== 46 && // Delete charCode !== 37 && // Left arrow charCode !== 39 // Right arrow ) { return false; } return true; }; PDFViewer.pageNumberInput.onkeyup = function(evt) { var charCode = evt.charCode || evt.keyCode; // All numeric keys, Backspace, and Delete. if ((charCode >= 48 && charCode <= 57) || charCode === 8 || // Backspace charCode === 46 // Delete ) { PDFViewer.goToPage(this.value); } this.focus(); }; PDFViewer.previousPageButton = document.getElementById('previousPageButton'); PDFViewer.previousPageButton.onclick = function(evt) { if (this.className.indexOf('disabled') === -1) { PDFViewer.goToPreviousPage(); } }; PDFViewer.previousPageButton.onmousedown = function(evt) { if (this.className.indexOf('disabled') === -1) { this.className = 'down'; } }; PDFViewer.previousPageButton.onmouseup = function(evt) { this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; PDFViewer.previousPageButton.onmouseout = function(evt) { this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; PDFViewer.nextPageButton = document.getElementById('nextPageButton'); PDFViewer.nextPageButton.onclick = function(evt) { if (this.className.indexOf('disabled') === -1) { PDFViewer.goToNextPage(); } }; PDFViewer.nextPageButton.onmousedown = function(evt) { if (this.className.indexOf('disabled') === -1) { this.className = 'down'; } }; PDFViewer.nextPageButton.onmouseup = function(evt) { this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; PDFViewer.nextPageButton.onmouseout = function(evt) { this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; PDFViewer.scaleSelect = document.getElementById('scaleSelect'); PDFViewer.scaleSelect.onchange = function(evt) { PDFViewer.changeScale(parseInt(this.value)); }; if (window.File && window.FileReader && window.FileList && window.Blob) { var openFileButton = document.getElementById('openFileButton'); openFileButton.onclick = function(evt) { if (this.className.indexOf('disabled') === -1) { PDFViewer.fileInput.click(); } }; openFileButton.onmousedown = function(evt) { if (this.className.indexOf('disabled') === -1) { this.className = 'down'; } }; openFileButton.onmouseup = function(evt) { this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; openFileButton.onmouseout = function(evt) { this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; PDFViewer.fileInput = document.getElementById('fileInput'); PDFViewer.fileInput.onchange = function(evt) { var files = evt.target.files; if (files.length > 0) { var file = files[0]; var fileReader = new FileReader(); document.title = file.name; // Read the local file into a Uint8Array. fileReader.onload = function(evt) { var data = evt.target.result; var buffer = new ArrayBuffer(data.length); var uint8Array = new Uint8Array(buffer); for (var i = 0; i < data.length; i++) { uint8Array[i] = data.charCodeAt(i); } PDFViewer.readPDF(uint8Array); }; // Read as a binary string since "readAsArrayBuffer" is not yet // implemented in Firefox. fileReader.readAsBinaryString(file); } }; PDFViewer.fileInput.value = null; } else { document.getElementById('fileWrapper').style.display = 'none'; } PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); window.onscroll = function(evt) { var lastPagesDrawn = PDFViewer.lastPagesDrawn; var visiblePages = PDFViewer.visiblePages(); var pagesToDraw = []; var pagesToKeep = []; var pagesToRemove = []; var i; // Determine which visible pages were not previously drawn. for (i = 0; i < visiblePages.length; i++) { if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { pagesToDraw.push(visiblePages[i]); PDFViewer.drawPage(visiblePages[i]); } else { pagesToKeep.push(visiblePages[i]); } } // Determine which previously drawn pages are no longer visible. for (i = 0; i < lastPagesDrawn.length; i++) { if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { pagesToRemove.push(lastPagesDrawn[i]); PDFViewer.removePage(lastPagesDrawn[i]); } } PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); // Update the page number input with the current page number. if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; } else { PDFViewer.willJumpToPage = false; } }; };