diff --git a/web/images/buttons.png b/web/images/buttons.png deleted file mode 100644 index b96b9e141..000000000 Binary files a/web/images/buttons.png and /dev/null differ diff --git a/web/images/go-down.svg b/web/images/go-down.svg new file mode 100644 index 000000000..18dadc498 --- /dev/null +++ b/web/images/go-down.svg @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Down + + + go + lower + down + arrow + pointer + > + + + + + Andreas Nilsson + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/images/go-up.svg b/web/images/go-up.svg new file mode 100644 index 000000000..0e3d01d17 --- /dev/null +++ b/web/images/go-up.svg @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Go Up + + + go + higher + up + arrow + pointer + > + + + + + Andreas Nilsson + + + + + + + + + + + + + + + + + + + + diff --git a/web/images/source/Buttons.psd.zip b/web/images/source/Buttons.psd.zip deleted file mode 100644 index 39745f540..000000000 Binary files a/web/images/source/Buttons.psd.zip and /dev/null differ diff --git a/web/multi_page_viewer.css b/web/multi_page_viewer.css deleted file mode 100644 index 76bf8cd1e..000000000 --- a/web/multi_page_viewer.css +++ /dev/null @@ -1,296 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -body { - background-color: #929292; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; - margin: 0px; - padding: 0px; -} - -canvas { - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; -} - -span { - font-size: 0.8em; - text-shadow: 0px 1px 0px #fff; -} - -.control { - display: inline-block; - float: left; - margin: 0px 20px 0px 0px; - padding: 0px 4px 0px 0px; -} - -.control > input { - float: left; - border: 1px solid #4d4d4d; - height: 20px; - padding: 0px; - margin: 0px 2px 0px 0px; - border-radius: 3px; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3); - -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3); -} - -.control > select { - float: left; - border: 1px solid #4d4d4d; - height: 22px; - padding: 2px 0px 0px; - margin: 0px 0px 1px; - border-radius: 3px; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3); - -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3); -} - -.control > span { - cursor: default; - float: left; - height: 18px; - margin: 5px 2px 0px; - padding: 0px; - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; -} - -.control .label { - clear: both; - float: left; - font-size: 0.65em; - margin: 2px 0px 0px; - position: relative; - text-align: center; - width: 100%; -} - -.thumbnailPageNumber { - color: #fff; - font-size: 0.55em; - text-align: right; - margin: -6px 2px 6px 0px; - width: 102px; -} - -.thumbnail { - width: 104px; - height: 134px; - margin: 0px auto 10px; -} - -.page { - width: 816px; - height: 1056px; - margin: 10px auto; -} - -#controls { - background-color: #eee; - background: -moz-linear-gradient(center bottom, #ddd 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; - padding: 4px 0px 0px 8px; - position: fixed; - left: 0px; - top: 0px; - height: 40px; - width: 100%; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; -} - -#controls input { - user-select: text; - -moz-user-select: text; - -webkit-user-select: text; -} - -button { - background-color: #ddd; - background: -moz-linear-gradient(center bottom, #c3c3c3 0%, #f3f3f3 100%); - background: -webkit-gradient(linear, left bottom, left top, color-stop(0.0, #c3c3c3), color-stop(1.0, #f3f3f3)); - border: 1px solid #4d4d4d; - cursor: default; - float: left; - margin: 0px 0px 1px; - width: 29px; - height: 22px; - border-radius: 3px; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; -} - -button:disabled { - background-color: #eee; - background: -moz-linear-gradient(center bottom, #ddd 0%, #fff 100%); - background: -webkit-gradient(linear, left bottom, left top, color-stop(0.0, #ddd), color-stop(1.0, #fff)); -} - -button:disabled > span { - opacity: 0.3; - -moz-opacity: 0.3; - -webkit-opacity: 0.3; -} - -button.down { - background-color: #777; - background: -moz-linear-gradient(center bottom, #888 0%, #555 100%); - background: -webkit-gradient(linear, left bottom, left top, color-stop(0.0, #888), color-stop(1.0, #555)); - box-shadow: inset 0px 0px 2px rgba(0, 0, 0, 0.8); - -moz-box-shadow: inset 0px 0px 2px rgba(0, 0, 0, 0.8); - -webkit-box-shadow: inset 0px 0px 2px rgba(0, 0, 0, 0.8); -} - -#previousPageButton { - width: 28px; - border-right: 0px; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; - -moz-border-radius-topright: 0px; - -moz-border-radius-bottomright: 0px; - -webkit-border-top-right-radius: 0px; - -webkit-border-bottom-right-radius: 0px; -} - -#previousPageButton > span { - background: url('images/buttons.png') no-repeat 0px 0px; - display: inline-block; - width: 19px; - height: 19px; -} - -#nextPageButton { - width: 28px; - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - -moz-border-radius-topleft: 0px; - -moz-border-radius-bottomleft: 0px; - -webkit-border-top-left-radius: 0px; - -webkit-border-bottom-left-radius: 0px; -} - -#nextPageButton > span { - background: url('images/buttons.png') no-repeat -19px 0px; - display: inline-block; - width: 19px; - height: 19px; -} - -#singleLayoutButton { - width: 28px; - border-right: 0px; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; - -moz-border-radius-topright: 0px; - -moz-border-radius-bottomright: 0px; - -webkit-border-top-right-radius: 0px; - -webkit-border-bottom-right-radius: 0px; -} - -#singleLayoutButton > span { - background: url('images/buttons.png') no-repeat -57px 0px; - display: inline-block; - width: 19px; - height: 19px; -} - -#splitLayoutButton { - width: 28px; - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - -moz-border-radius-topleft: 0px; - -moz-border-radius-bottomleft: 0px; - -webkit-border-top-left-radius: 0px; - -webkit-border-bottom-left-radius: 0px; -} - -#splitLayoutButton > span { - background: url('images/buttons.png') no-repeat -76px 0px; - display: inline-block; - width: 19px; - height: 19px; -} - -#openFileButton { - margin-left: 3px; -} - -#openFileButton > span { - background: url('images/buttons.png') no-repeat -38px 0px; - display: inline-block; - width: 19px; - height: 19px; -} - -#fileInput { - display: none; -} - -#pageNumber { - text-align: right; -} - -#sidebar { - position: fixed; - width: 200px; - top: 62px; - bottom: 18px; - left: -140px; - 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; -} - -#sidebar:hover { - left: 0px; - 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; -} - -#sidebarBox { - background-color: rgba(0, 0, 0, 0.7); - width: 150px; - height: 100%; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; -} - -#sidebarScrollView { - position: absolute; - overflow: hidden; - overflow-y: auto; - top: 10px; - bottom: 10px; - left: 10px; - width: 130px; -} - -#sidebarContentView { - height: auto; - width: 100px; -} - -#viewer { - margin: 44px 0px 0px; - padding: 8px 0px; -} diff --git a/web/multi_page_viewer.html b/web/multi_page_viewer.html deleted file mode 100644 index 00dac6484..000000000 --- a/web/multi_page_viewer.html +++ /dev/null @@ -1,66 +0,0 @@ - - - -pdf.js Multi-Page Viewer - - - - - - - - - - -
- - - - Previous/Next - - - - / - -- - Page Number - - - - Zoom - - - - - - - - - Open File - -
- - - - -
- - diff --git a/web/multi_page_viewer.js b/web/multi_page_viewer.js deleted file mode 100644 index 3e7e122e0..000000000 --- a/web/multi_page_viewer.js +++ /dev/null @@ -1,513 +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'; - -var pageTimeout; - -var PDFViewer = { - queryParams: {}, - - element: null, - - sidebarContentView: 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) { - var pdfToCssUnitsCoef = 96.0 / 72.0; - var width = (page.mediaBox[2] - page.mediaBox[0]); - return width * PDFViewer.scale * pdfToCssUnitsCoef; - }, - - pageHeight: function(page) { - var pdfToCssUnitsCoef = 96.0 / 72.0; - var height = (page.mediaBox[3] - page.mediaBox[1]); - return height * PDFViewer.scale * pdfToCssUnitsCoef; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - var pageBottomMargin = 10; - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - - var pageHeight, page; - var i, n = PDFViewer.numberOfPages, currentHeight = pageBottomMargin; - 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; - }, - - createThumbnail: function(num) { - if (PDFViewer.sidebarContentView) { - var anchor = document.createElement('a'); - anchor.href = '#' + num; - - var containerDiv = document.createElement('div'); - containerDiv.id = 'thumbnailContainer' + num; - containerDiv.className = 'thumbnail'; - - var pageNumberDiv = document.createElement('div'); - pageNumberDiv.className = 'thumbnailPageNumber'; - pageNumberDiv.innerHTML = '' + num; - - anchor.appendChild(containerDiv); - PDFViewer.sidebarContentView.appendChild(anchor); - PDFViewer.sidebarContentView.appendChild(pageNumberDiv); - } - }, - - removeThumbnail: function(num) { - var div = document.getElementById('thumbnailContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawThumbnail: function(num) { - if (!PDFViewer.pdf) - return; - - var div = document.getElementById('thumbnailContainer' + num); - - if (div && !div.hasChildNodes()) { - var page = PDFViewer.pdf.getPage(num); - var canvas = document.createElement('canvas'); - - canvas.id = 'thumbnail' + num; - canvas.mozOpaque = true; - - var pageWidth = PDFViewer.pageWidth(page); - var pageHeight = PDFViewer.pageHeight(page); - var thumbScale = Math.min(104 / pageWidth, 134 / pageHeight); - canvas.width = pageWidth * thumbScale; - canvas.height = pageHeight * thumbScale; - 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(); - - page.startRendering(ctx, function() { }); - } - }, - - 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); - - if (div && !div.hasChildNodes()) { - var page = PDFViewer.pdf.getPage(num); - var canvas = document.createElement('canvas'); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - 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(); - - page.startRendering(ctx, function() { }); - } - }, - - 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); - } - } - - 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) + '%'; - - // Clear the array of the last pages drawn to force a redraw. - PDFViewer.lastPagesDrawn = []; - - // Jump the scroll position to the correct page. - PDFViewer.goToPage(PDFViewer.pageNumber); - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - if (document.location.hash.substr(1) == PDFViewer.pageNumber) - // Force a "scroll event" to redraw - setTimeout(window.onscroll, 0); - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.disabled = (PDFViewer.pageNumber === 1); - PDFViewer.nextPageButton.disabled = (PDFViewer.pageNumber === PDFViewer.numberOfPages); - } - }, - - 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; - - if (this.thumbsLoadingInterval) { - // cancel thumbs loading operations - clearInterval(this.thumbsLoadingInterval); - this.thumbsLoadingInterval = null; - } - - 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); - }, - - thumbsLoadingInterval: null, - - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - while (PDFViewer.sidebarContentView.hasChildNodes()) { - PDFViewer.sidebarContentView.removeChild( - PDFViewer.sidebarContentView.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; - - // slowly loading the thumbs (few per second) - // first time we are loading more images than subsequent - var currentPageIndex = 1, imagesToLoad = 15; - this.thumbsLoadingInterval = setInterval((function() { - while (imagesToLoad-- > 0) { - if (currentPageIndex > PDFViewer.numberOfPages) { - clearInterval(this.thumbsLoadingInterval); - this.thumbsLoadingInterval = null; - return; - } - PDFViewer.createThumbnail(currentPageIndex); - PDFViewer.drawThumbnail(currentPageIndex); - ++currentPageIndex; - } - imagesToLoad = 3; // next time loading less images - }).bind(this), 500); - } - - PDFViewer.previousPageButton.disabled = (PDFViewer.pageNumber === 1); - PDFViewer.nextPageButton.disabled = (PDFViewer.pageNumber === PDFViewer.numberOfPages); - } -}; - -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.sidebarContentView = document.getElementById('sidebarContentView'); - - 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) { - PDFViewer.goToPreviousPage(); - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - this.className = 'down'; - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = ''; - }; - - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - PDFViewer.goToNextPage(); - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - this.className = 'down'; - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = ''; - }; - - 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) { - PDFViewer.fileInput.click(); - }; - openFileButton.onmousedown = function(evt) { - this.className = 'down'; - }; - openFileButton.onmouseup = function(evt) { - this.className = ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = ''; - }; - - 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.disabled = (PDFViewer.pageNumber === 1); - PDFViewer.nextPageButton.disabled = (PDFViewer.pageNumber === PDFViewer.numberOfPages); - } else { - PDFViewer.willJumpToPage = false; - } - }; -}; diff --git a/web/viewer.css b/web/viewer.css index 9987492dc..54f648adb 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -2,35 +2,129 @@ /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ body { - margin: 6px; - padding: 0px; - background-color: #c0bdb7; + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; } +/* === Toolbar === */ #controls { - position:fixed; - left: 0px; - top: 0px; - width: 100%; - padding: 7px; - border-bottom: 1px solid black; - background-color: rgb(242, 240, 238); + background-color: #eee; + 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; + padding: 4px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; } -span#info { - float: right; - font: 14px sans-serif; - margin-right: 10px; +.separator { + display: inline; + border-left: 1px solid #d3d3d3; + border-right: 1px solid #fff; + height: 32px; + width:0px; + margin: 4px; } -#viewer { +#controls > button { + line-height: 32px; } -#canvas { - margin: auto; - display: block; +#controls > button[disabled] > img { + opacity: 0.5; } #pageNumber { - text-align: right; + text-align: right; } + +#fileInput { + line-height: 32px; +} + +span#info { + display: none; +} + +@-moz-document regexp("http:.*debug=1.*") { + span#info { + display: inline-block; + } +} + +/* === Sidebar === */ +#sidebar { + position: fixed; + width: 200px; + top: 62px; + bottom: 18px; + left: -140px; + 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; +} + +#sidebar:hover { + left: 0px; + 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; +} + +#sidebarBox { + background-color: rgba(0, 0, 0, 0.7); + width: 150px; + height: 100%; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; +} + +#sidebarScrollView { + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 10px; + bottom: 10px; + left: 10px; + width: 130px; +} + +.thumbnail { + width: 104px; + height: 134px; + background-color: white; + margin: 5px; +} + +/* === Content view === */ +canvas { + margin: auto; + display: block; + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; +} + +.page { + width: 816px; + height: 1056px; + margin: 10px auto; +} + +#viewer { + margin: 44px 0px 0px; + padding: 8px 0px; +} + diff --git a/web/viewer.html b/web/viewer.html index df9604db4..285dadb01 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -12,22 +12,54 @@ - +
- - - - - + + + + +
+ + + + / -- - + +
+ + + +
+ + + +
+ + --
-
- + + +
diff --git a/web/viewer.js b/web/viewer.js index 12a42006f..328388396 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -3,108 +3,316 @@ 'use strict'; -var pdfDocument, canvas, pageScale, pageDisplay, pageNum, numPages; -function load(userInput) { - canvas = document.getElementById('canvas'); - canvas.mozOpaque = true; - pageNum = ('page' in queryParams()) ? parseInt(queryParams().page) : 1; - pageScale = ('scale' in queryParams()) ? parseInt(queryParams().scale) : 1.5; - var fileName = userInput; - if (!userInput) { - fileName = queryParams().file || 'compressed.tracemonkey-pldi-09.pdf'; - } - open(fileName); -} +var kDefaultURL = 'compressed.tracemonkey-pldi-09.pdf'; +var kDefaultScale = 150; -function queryParams() { - 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; -} +var kCacheSize = 20; -function open(url) { - document.title = url; - if (url.indexOf("http") == 0) - return; - - 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); - loadDocument(data); - } +var Cache = function(size) { + var data = []; + this.push = function(view) { + data.push(view); + if (data.length > size) + data.shift().update(); }; - req.send(null); -} +}; -window.addEventListener("pdfloaded", function(aEvent) { - loadDocument(aEvent.detail); +var cache = new Cache(kCacheSize); + +var PDFView = { + pages: [], + thumbnails: [], + + set scale(val) { + var options = document.getElementById('scaleSelect').options; + for (var i = 0; i < options.length; i++) { + var option = options[i]; + option.selected = (option.value == val); + } + + var pages = this.pages; + var cssUnits = 96.0 / 72.0; + for (var i = 0; i < pages.length; i++) + pages[i].update(val / 100 * cssUnits); + + // Jump the scroll position to the correct page. + this.page = this.page; + }, + + set page(val) { + var pages = this.pages; + var input = document.getElementById("pageNumber"); + if (val <= 0 || val > pages.length) { + input.value = this.page; + return; + } + + document.location.hash = val; + document.getElementById("previous").disabled = (val == 1); + document.getElementById("next").disabled = (val == pages.length); + if (input.value == val) + return; + + input.value = val; + pages[val - 1].draw(); + }, + + get page() { + return parseInt(document.location.hash.substring(1)) || 1; + }, + + open: function(url, scale) { + if (url.indexOf("http") == 0) + return; + + document.title = url; + + var xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.mozResponseType = xhr.responseType = 'arraybuffer'; + xhr.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === xhr.expected) { + var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse || + xhr.responseArrayBuffer || xhr.response); + + PDFView.load(data, scale); + } + }; + + xhr.send(null); + }, + + load: function(data, scale) { + var sidebar = document.getElementById('sidebarView'); + sidebar.parentNode.scrollTop = 0; + + while (sidebar.hasChildNodes()) + sidebar.removeChild(sidebar.lastChild); + clearInterval(sidebar._loadingInterval); + + var container = document.getElementById('viewer'); + while (container.hasChildNodes()) + container.removeChild(container.lastChild); + + var pdf = new PDFDoc(new Stream(data)); + var pagesCount = pdf.numPages; + document.getElementById('numPages').innerHTML = pagesCount; + + var pages = this.pages = []; + var thumbnails = this.thumbnails = []; + for (var i = 1; i <= pagesCount; i++) { + var page = pdf.getPage(i); + var mediaBox = page.mediaBox; + var width = (mediaBox[2] - mediaBox[0]); + var height = (mediaBox[3] - mediaBox[1]); + pages.push(new PageView(container, page, i, width, height, page.stats)); + thumbnails.push(new ThumbnailView(sidebar, pages[i - 1])); + }; + + this.scale = (scale || kDefaultScale); + this.page = parseInt(document.location.hash.substring(1)) || 1; + }, + + getVisiblePages: function() { + var pages = this.pages; + var kBottomMargin = 10; + var visiblePages = []; + + var currentHeight = kBottomMargin; + var windowTop = window.pageYOffset; + for (var i = 1; i <= pages.length; i++) { + var page = pages[i - 1]; + var pageHeight = page.height * page.scale + kBottomMargin; + if (currentHeight + pageHeight > windowTop) + break; + + currentHeight += pageHeight; + } + + var windowBottom = window.pageYOffset + window.innerHeight; + for (; i <= pages.length && currentHeight < windowBottom; i++) { + var page = pages[i - 1]; + visiblePages.push({ id: page.id, y: currentHeight, view: page }); + currentHeight += page.height * page.scale + kBottomMargin; + } + + return visiblePages; + }, +}; + +var PageView = function(container, content, id, width, height, stats) { + this.width = width; + this.height = height; + this.id = id; + this.content = content; + + var anchor = document.createElement('a'); + anchor.name = '' + this.id; + + var div = document.createElement('div'); + div.id = 'pageContainer' + this.id; + div.className = 'page'; + + container.appendChild(anchor); + container.appendChild(div); + + this.update = function(scale) { + this.scale = scale || this.scale; + div.style.width = (this.width * this.scale)+ 'px'; + div.style.height = (this.height * this.scale) + 'px'; + + while (div.hasChildNodes()) + div.removeChild(div.lastChild); + }; + + this.draw = function() { + if (div.hasChildNodes()) { + this.updateStats(); + return false; + } + + var canvas = document.createElement('canvas'); + canvas.id = 'page' + this.id; + canvas.mozOpaque = true; + + canvas.width = this.width * this.scale; + canvas.height = this.height * this.scale; + 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(); + + stats.begin = Date.now(); + this.content.startRendering(ctx, this.updateStats); + + return true; + }; + + this.updateStats = function() { + 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; + }; +}; + +var ThumbnailView = function(container, page) { + var anchor = document.createElement('a'); + anchor.href = '#' + page.id; + + var div = document.createElement('div'); + div.id = 'thumbnailContainer' + page.id; + div.className = 'thumbnail'; + + anchor.appendChild(div); + container.appendChild(anchor); + + this.draw = function() { + if (div.hasChildNodes()) + return; + + var canvas = document.createElement('canvas'); + canvas.id = 'thumbnail' + page.id; + canvas.mozOpaque = true; + + canvas.width = 104; + canvas.height = 134; + 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(); + + page.content.startRendering(ctx, function() { }); + }; +}; + +window.addEventListener('load', function(evt) { + var params = document.location.search.substring(1).split('&'); + for (var i = 0; i < params.length; i++) { + var param = params[i].split('='); + params[unescape(param[0])] = unescape(param[1]); + } + + PDFView.open(params.file || kDefaultURL, parseInt(params.scale)); + + if (!window.File || !window.FileReader || !window.FileList || !window.Blob) + document.getElementById('fileInput').style.display = 'none'; + else + document.getElementById('fileInput').value = null; }, true); -function loadDocument(data) { - pdfDocument = new PDFDoc(new Stream(data)); - numPages = pdfDocument.numPages; - document.getElementById('numPages').innerHTML = numPages.toString(); - goToPage(pageNum); -} +window.addEventListener('pdfloaded', function(evt) { + PDFView.load(evt.detail); +}, true); -function gotoPage(num) { - if (0 <= num && num <= numPages) - pageNum = num; - displayPage(pageNum); -} +window.addEventListener('scroll', function(evt) { + 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); + } -function displayPage(num) { - document.getElementById('pageNumber').value = num; + if (!visiblePages.length) + return; - var t0 = Date.now(); + var currentId = PDFView.page; + var firstPage = visiblePages[0]; + var lastPage = visiblePages[visiblePages.length - 1]; + if (currentId > lastPage.id && lastPage.y > window.pageYOffset) + PDFView.page = lastPage.id; + else if (currentId < firstPage.id) + PDFView.page = firstPage.id; +}, true); - var page = pdfDocument.getPage(pageNum = num); +window.addEventListener("hashchange", function(evt) { + PDFView.page = PDFView.page; +}); - var pdfToCssUnitsCoef = 96.0 / 72.0; - var pageWidth = (page.mediaBox[2] - page.mediaBox[0]); - var pageHeight = (page.mediaBox[3] - page.mediaBox[1]); - canvas.width = pageScale * pageWidth * pdfToCssUnitsCoef; - canvas.height = pageScale * pageHeight * pdfToCssUnitsCoef; +window.addEventListener("change", function(evt) { + var files = evt.target.files; + if (!files || files.length == 0) + return; - var t1 = Date.now(); - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); + // Read the local file into a Uint8Array. + var fileReader = new FileReader(); + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); - page.startRendering( - ctx, - function() { - var infoDisplay = document.getElementById('info'); - var stats = page.stats; - var t2 = stats.compile, t3 = stats.fonts, t4 = stats.render; - infoDisplay.innerHTML = 'Time to load/compile/fonts/render: ' + - (t1 - t0) + '/' + (t2 - t1) + '/' + (t3 - t2) + '/' + (t4 - t3) + ' ms'; - }); -} + for (var i = 0; i < data.length; i++) + uint8Array[i] = data.charCodeAt(i); + PDFView.load(uint8Array); + }; -function nextPage() { - if (pageNum < pdfDocument.numPages) - displayPage(++pageNum); -} + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + var file = files[0]; + fileReader.readAsBinaryString(file); -function prevPage() { - if (pageNum > 1) - displayPage(--pageNum); -} + document.title = file.name; + document.location.hash = 1; +}, true); + +window.addEventListener("transitionend", function(evt) { + var pageIndex = 0; + var pagesCount = PDFView.pages.length; + + var container = document.getElementById('sidebarView'); + container._interval = window.setInterval(function() { + if (pageIndex >= pagesCount) + return window.clearInterval(container._interval); + + PDFView.thumbnails[pageIndex++].draw(); + }, 500); +}, true); -function goToPage(num) { - if (0 <= num && num <= numPages) - displayPage(pageNum = num); -}