--- /dev/null
+REPO = git@github.com:andreasgal/pdf.js.git
+BUILD_DIR := build
+DEFAULT_BROWSERS := test/resources/browser_manifests/browser_manifest.json
+DEFAULT_TESTS := test/test_manifest.json
+
+# JS files needed for pdf.js.
+# This list doesn't account for the 'worker' directory.
+PDF_JS_FILES = \
+ pdf.js \
+ crypto.js \
+ fonts.js \
+ glyphlist.js \
+ $(NULL)
+
+# not sure what to do for all yet
+all: help
+
+test: shell-test browser-test
+
+# make browser-test
+#
+# This target runs in-browser tests using two primary arguments: a
+# test manifest file, and a browser manifest file. Both are simple
+# JSON formats, and examples can be found in the test/ directory. The
+# target will inspect the environment for the PDF_TESTS and
+# PDF_BROWSERS variables, and use those if found. Otherwise, the
+# defaults at the top of this file are used.
+ifeq ($(PDF_TESTS),)
+PDF_TESTS := $(DEFAULT_TESTS)
+endif
+ifeq ($(PDF_BROWSERS),)
+PDF_BROWSERS := $(DEFAULT_BROWSERS)
+endif
+
+
+browser-test:
+ @if [ ! "$(PDF_BROWSERS)" ]; then \
+ echo "Browser manifest file $(PDF_BROWSERS) does not exist."; \
+ echo "Try copying one of the examples" \
+ "in test/resources/browser_manifests/"; \
+ exit 1; \
+ fi;
+
+ cd test; \
+ python test.py --reftest \
+ --browserManifestFile=$(abspath $(PDF_BROWSERS)) \
+ --manifestFile=$(abspath $(PDF_TESTS))
+
+# make shell-test
+#
+# This target runs all of the tests that can be run in a JS shell.
+# The shell used is taken from the JS_SHELL environment variable. If
+# that veriable is not defined, the script will attempt to use the copy
+# of Rhino that comes with the Closure compiler used for producing the
+# website.
+SHELL_TARGET = $(NULL)
+ifeq ($(JS_SHELL),)
+JS_SHELL := "java -cp $(BUILD_DIR)/compiler.jar"
+JS_SHELL += "com.google.javascript.jscomp.mozilla.rhino.tools.shell.Main"
+SHELL_TARGET = compiler
+endif
+
+shell-test: shell-msg $(SHELL_TARGET) font-test
+shell-msg:
+ifeq ($(SHELL_TARGET), compiler)
+ @echo "No JS_SHELL env variable present."
+ @echo "The default is to find a copy of Rhino and try that."
+endif
+ @echo "JS shell command is: $(JS_SHELL)"
+
+font-test:
+ @echo "font test stub."
+
+# make lint
+#
+# This target runs the Closure Linter on most of our JS files.
+# To install gjslint, see:
+#
+# <http://code.google.com/closure/utilities/docs/linter_howto.html>
+SRC_DIRS := . utils worker web
+GJSLINT_FILES = $(foreach DIR,$(SRC_DIRS),$(wildcard $(DIR)/*.js))
+lint:
+ gjslint $(GJSLINT_FILES)
+
+# make web
+#
+# This target produces the website for the project, by checking out
+# the gh-pages branch underneath the build directory, and then move
+# the various viewer files into place.
+#
+# TODO: Use the Closure compiler to optimize the pdf.js files.
+#
+GH_PAGES = $(BUILD_DIR)/gh-pages
+web: | compiler pages-repo \
+ $(addprefix $(GH_PAGES)/, $(PDF_JS_FILES)) \
+ $(addprefix $(GH_PAGES)/, $(wildcard web/*.*)) \
+ $(addprefix $(GH_PAGES)/, $(wildcard web/images/*.*))
+
+ @cp $(GH_PAGES)/web/index.html.template $(GH_PAGES)/index.html;
+ @cd $(GH_PAGES); git add -A;
+ @echo "Website built in $(GH_PAGES)"
+
+# make pages-repo
+#
+# This target clones the gh-pages repo into the build directory. It
+# deletes the current contents of the repo, since we overwrite
+# everything with data from the master repo. The 'make web' target
+# then uses 'git add -A' to track additions, modifications, moves,
+# and deletions.
+pages-repo: | $(BUILD_DIR)
+ @if [ ! -d "$(GH_PAGES)" ]; then \
+ git clone -b gh-pages $(REPO) $(GH_PAGES); \
+ rm -rf $(GH_PAGES)/*; \
+ fi;
+ @mkdir -p $(GH_PAGES)/web;
+ @mkdir -p $(GH_PAGES)/web/images;
+
+$(GH_PAGES)/%.js: %.js
+ @cp $< $@
+
+$(GH_PAGES)/web/%: web/%
+ @cp $< $@
+
+$(GH_PAGES)/web/images/%: web/images/%
+ @cp $< $@
+
+# make compiler
+#
+# This target downloads the Closure compiler, and places it in the
+# build directory. This target is also useful when the user doesn't
+# have a JS shell available--we can have them use the Rhino shell that
+# comes with Closure.
+COMPILER_URL = http://closure-compiler.googlecode.com/files/compiler-latest.zip
+
+compiler: $(BUILD_DIR)/compiler.zip
+$(BUILD_DIR)/compiler.zip: | $(BUILD_DIR)
+ curl $(COMPILER_URL) > $(BUILD_DIR)/compiler.zip;
+ cd $(BUILD_DIR); unzip compiler.zip compiler.jar;
+
+# Make sure there's a build directory.
+$(BUILD_DIR):
+ mkdir -p $(BUILD_DIR)
+
+clean:
+ rm -rf $(BUILD_DIR)
+
+# make help
+#
+# This target just prints out a message to read these comments. :)
+help:
+ @echo "Read the comments in the Makefile for guidance.";
+
+.PHONY: all test browser-test font-test shell-test \
+ shell-msg lint clean web compiler help
\ No newline at end of file
+++ /dev/null
-/* -*- 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;
-}
-
-.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: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
- -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
- -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
-}
-
-.control > select {
- float: left;
- border: 1px solid #4d4d4d;
- height: 22px;
- padding: 2px 0px 0px;
- margin: 0px 0px 1px;
- border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
- -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
- -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
-}
-
-.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;
- 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;
-}
-
-#previousPageButton {
- background: url('images/buttons.png') no-repeat 0px -23px;
- cursor: default;
- display: inline-block;
- float: left;
- margin: 0px;
- width: 28px;
- height: 23px;
-}
-
-#previousPageButton.down {
- background: url('images/buttons.png') no-repeat 0px -46px;
-}
-
-#previousPageButton.disabled {
- background: url('images/buttons.png') no-repeat 0px 0px;
-}
-
-#nextPageButton {
- background: url('images/buttons.png') no-repeat -28px -23px;
- cursor: default;
- display: inline-block;
- float: left;
- margin: 0px;
- width: 28px;
- height: 23px;
-}
-
-#nextPageButton.down {
- background: url('images/buttons.png') no-repeat -28px -46px;
-}
-
-#nextPageButton.disabled {
- background: url('images/buttons.png') no-repeat -28px 0px;
-}
-
-#openFileButton {
- background: url('images/buttons.png') no-repeat -56px -23px;
- cursor: default;
- display: inline-block;
- float: left;
- margin: 0px 0px 0px 3px;
- width: 29px;
- height: 23px;
-}
-
-#openFileButton.down {
- background: url('images/buttons.png') no-repeat -56px -46px;
-}
-
-#openFileButton.disabled {
- background: url('images/buttons.png') no-repeat -56px 0px;
-}
-
-#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;
-}
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
-<title>pdf.js Multi-Page Viewer</title>
-<meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>
-<link rel="stylesheet" href="multi_page_viewer.css" type="text/css" media="screen"/>
-<script type="text/javascript" src="pdf.js"></script>
-<script type="text/javascript" src="fonts.js"></script>
-<script type="text/javascript" src="crypto.js"></script>
-<script type="text/javascript" src="glyphlist.js"></script>
-<script type="text/javascript" src="multi_page_viewer.js"></script>
-</head>
-<body>
- <div id="controls">
- <span class="control">
- <span id="previousPageButton" class="disabled"></span>
- <span id="nextPageButton" class="disabled"></span>
- <span class="label">Previous/Next</span>
- </span>
- <span class="control">
- <input type="text" id="pageNumber" value="1" size="2"/>
- <span>/</span>
- <span id="numPages">--</span>
- <span class="label">Page Number</span>
- </span>
- <span class="control">
- <select id="scaleSelect">
- <option value="50">50%</option>
- <option value="75">75%</option>
- <option value="100">100%</option>
- <option value="125">125%</option>
- <option value="150" selected="selected">150%</option>
- <option value="200">200%</option>
- </select>
- <span class="label">Zoom</span>
- </span>
- <span class="control">
- <span id="openFileButton"></span>
- <input type="file" id="fileInput"/>
- <span class="label">Open File</span>
- </span>
- </div>
-
- <!-- EXPERIMENTAL: Slide-out sidebar with page thumbnails (comment-out to disable) -->
- <div id="sidebar">
- <div id="sidebarBox">
- <div id="sidebarScrollView">
- <div id="sidebarContentView"></div>
- </div>
- </div>
- </div>
-
- <div id="viewer"></div>
-</body>
-</html>
+++ /dev/null
-/* -*- 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() {
- const 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();
-
- 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);
-
- FontLoader.bind(fonts, function() { page.display(gfx); });
- }
- },
-
- 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();
-
- 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);
-
- FontLoader.bind(fonts, function() { page.display(gfx); });
- }
- },
-
- 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.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;
-
- 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.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.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) {
- 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;
- }
- };
-};
+++ /dev/null
-/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
-/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
-
-body {
- margin: 6px;
- padding: 0px;
- background-color: #c0bdb7;
-}
-
-#controls {
- position:fixed;
- left: 0px;
- top: 0px;
- width: 100%;
- padding: 7px;
- border-bottom: 1px solid black;
- background-color: rgb(242, 240, 238);
-}
-
-span#info {
- float: right;
- font: 14px sans-serif;
- margin-right: 10px;
-}
-
-#viewer {
-}
-
-#canvas {
- margin: auto;
- display: block;
-}
-
-#pageNumber {
- text-align: right;
-}
+++ /dev/null
-<html>
- <head>
- <title>Simple pdf.js page viewer</title>
- <link rel="stylesheet" href="viewer.css"></link>
-
- <script type="text/javascript" src="viewer.js"></script>
- <script type="text/javascript" src="pdf.js"></script>
- <script type="text/javascript" src="utils/fonts_utils.js"></script>
- <script type="text/javascript" src="fonts.js"></script>
- <script type="text/javascript" src="crypto.js"></script>
- <script type="text/javascript" src="glyphlist.js"></script>
- </head>
-
- <body onload="load();">
- <div id="controls">
- <input type="file" style="float: right; margin: auto 32px;" onChange="load(this.value.toString());"></input>
- <!-- This only opens supported PDFs from the source path...
- -- Can we use JSONP to overcome the same-origin restrictions? -->
- <button onclick="prevPage();">Previous</button>
- <button onclick="nextPage();">Next</button>
- <input type="text" id="pageNumber" onchange="gotoPage(this.value);"
- value="1" size="4"></input>
- <span id="numPages">--</span>
- <span id="info"></span>
- </div>
-
- <div id="viewer">
- <canvas id="canvas"></canvas>
- </div>
- </body>
-</html>
-
+++ /dev/null
-/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
-/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
-
-"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);
-}
-
-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;
-}
-
-function open(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;
- pdfDocument = new PDFDoc(new Stream(data));
- numPages = pdfDocument.numPages;
- document.getElementById("numPages").innerHTML = numPages.toString();
- goToPage(pageNum);
- }
- };
- req.send(null);
-}
-
-function gotoPage(num) {
- if (0 <= num && num <= numPages)
- pageNum = num;
- displayPage(pageNum);
-}
-
-function displayPage(num) {
- document.getElementById("pageNumber").value = num;
-
- var t0 = Date.now();
-
- var page = pdfDocument.getPage(pageNum = num);
-
- 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;
-
- 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();
-
- 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 t2 = Date.now();
-
- function displayPage() {
- var t3 = Date.now();
-
- page.display(gfx);
-
- var t4 = Date.now();
-
- var infoDisplay = document.getElementById("info");
- infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms";
- }
-
- // Always defer call to displayPage() to work around bug in
- // Firefox error reporting from XHR callbacks.
- FontLoader.bind(fonts, function () { setTimeout(displayPage, 0); });
-}
-
-function nextPage() {
- if (pageNum < pdfDocument.numPages)
- displayPage(++pageNum);
-}
-
-function prevPage() {
- if (pageNum > 1)
- displayPage(--pageNum);
-}
-
-function goToPage(num) {
- if (0 <= num && num <= numPages)
- displayPage(pageNum = num);
-}
-
+++ /dev/null
-<html>
- <head>
- <title>Simple pdf.js page worker viewer</title>
- <script type="text/javascript" src="fonts.js"></script>
- <script type="text/javascript" src="glyphlist.js"></script>
- <script type="text/javascript" src="pdf.js"></script>
- <script type="text/javascript" src="worker/client.js"></script>
-<script>
-
-
-var pdfDoc;
-window.onload = function() {
- window.canvas = document.getElementById("canvas");
- window.ctx = canvas.getContext("2d");
-
- pdfDoc = new WorkerPDFDoc(window.canvas);
- pdfDoc.onChangePage = function(numPage) {
- document.getElementById("pageNumber").value = numPage;
- }
- // pdfDoc.open("canvas.pdf", function() {
- pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() {
- document.getElementById("numPages").innerHTML = "/" + pdfDoc.numPages;
- })
-}
-</script>
- <link rel="stylesheet" href="viewer.css"></link>
- </head>
- <body>
- <div id="controls">
- <input type="file" style="float: right; margin: auto 32px;" onChange="load(this.value.toString());"></input>
- <!-- This only opens supported PDFs from the source path...
- -- Can we use JSONP to overcome the same-origin restrictions? -->
- <button onclick="pdfDoc.prevPage();">Previous</button>
- <button onclick="pdfDoc.nextPage();">Next</button>
- <input type="text" id="pageNumber" onchange="pdfDoc.showPage(this.value);"
- value="1" size="4"></input>
- <span id="numPages">--</span>
- <span id="info"></span>
- </div>
-
- <div id="viewer">
- <canvas id="canvas"></canvas>
- </div>
- </body>
-</html>
-
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset='utf-8'>
+
+ <title>andreasgal/pdf.js @ GitHub</title>
+
+ <style type="text/css">
+ body {
+ margin-top: 1.0em;
+ background-color: #482a30;
+ font-family: Helvetica, Arial, FreeSans, san-serif;
+ color: #ffffff;
+ }
+ #container {
+ margin: 0 auto;
+ width: 700px;
+ }
+ h1 { font-size: 3.8em; color: #b7d5cf; margin-bottom: 3px; }
+ h1 .small { font-size: 0.4em; }
+ h1 a { text-decoration: none }
+ h2 { font-size: 1.5em; color: #b7d5cf; }
+ h3 { text-align: center; color: #b7d5cf; }
+ a { color: #b7d5cf; }
+ .description { font-size: 1.2em; margin-bottom: 30px; margin-top: 30px; font-style: italic;}
+ .download { float: right; }
+ pre { background: #000; color: #fff; padding: 15px;}
+ hr { border: 0; width: 80%; border-bottom: 1px solid #aaa}
+ .footer { text-align:center; padding-top:30px; font-style: italic; }
+ </style>
+</head>
+
+<body>
+ <a href="http://github.com/andreasgal/pdf.js"><img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" /></a>
+
+ <div id="container">
+
+ <div class="download">
+ <a href="http://github.com/andreasgal/pdf.js/zipball/master">
+ <img border="0" width="90" src="http://github.com/images/modules/download/zip.png"></a>
+ <a href="http://github.com/andreasgal/pdf.js/tarball/master">
+ <img border="0" width="90" src="http://github.com/images/modules/download/tar.png"></a>
+ </div>
+
+ <h1><a href="http://github.com/andreasgal/pdf.js">pdf.js</a>
+ <span class="small">by <a href="http://github.com/andreasgal">andreasgal</a></span></h1>
+
+ <div class="description">
+ PDF Reader in JavaScript
+ </div>
+
+ <h2>Try it out!</h2>
+ <p>Live <a href="web/multi_page_viewer.html">demo</a> lives here.</p>
+
+ <h2>Authors</h2>
+<p>Vivien Nicolas (21@vingtetun.org)
+<br/>Andreas Gal (andreas.gal@gmail.com)
+<br/>Soumya Deb (debloper@gmail.com)
+<br/>Chris Jones (jones.chris.g@gmail.com)
+<br/>Justin D'Arcangelo (justindarc@gmail.com)
+<br/>sbarman (sbarman@eecs.berkeley.edu)
+<br/>
+<br/> </p>
+<h2>Contact</h2>
+<p> (andreas.gal@gmail.com)
+<br/> </p>
+
+
+ <h2>Download</h2>
+ <p>
+ You can download this project in either
+ <a href="http://github.com/andreasgal/pdf.js/zipball/master">zip</a> or
+ <a href="http://github.com/andreasgal/pdf.js/tarball/master">tar</a> formats.
+ </p>
+ <p>You can also clone the project with <a href="http://git-scm.com">Git</a>
+ by running:
+ <pre>$ git clone git://github.com/andreasgal/pdf.js</pre>
+ </p>
+
+ <div class="footer">
+ get the source code on GitHub : <a href="http://github.com/andreasgal/pdf.js">andreasgal/pdf.js</a>
+ </div>
+
+ </div>
+
+
+</body>
+</html>
--- /dev/null
+/* -*- 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;
+}
+
+.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: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
+ -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
+ -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
+}
+
+.control > select {
+ float: left;
+ border: 1px solid #4d4d4d;
+ height: 22px;
+ padding: 2px 0px 0px;
+ margin: 0px 0px 1px;
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
+ -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
+ -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
+}
+
+.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;
+ 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;
+}
+
+#previousPageButton {
+ background: url('images/buttons.png') no-repeat 0px -23px;
+ cursor: default;
+ display: inline-block;
+ float: left;
+ margin: 0px;
+ width: 28px;
+ height: 23px;
+}
+
+#previousPageButton.down {
+ background: url('images/buttons.png') no-repeat 0px -46px;
+}
+
+#previousPageButton.disabled {
+ background: url('images/buttons.png') no-repeat 0px 0px;
+}
+
+#nextPageButton {
+ background: url('images/buttons.png') no-repeat -28px -23px;
+ cursor: default;
+ display: inline-block;
+ float: left;
+ margin: 0px;
+ width: 28px;
+ height: 23px;
+}
+
+#nextPageButton.down {
+ background: url('images/buttons.png') no-repeat -28px -46px;
+}
+
+#nextPageButton.disabled {
+ background: url('images/buttons.png') no-repeat -28px 0px;
+}
+
+#openFileButton {
+ background: url('images/buttons.png') no-repeat -56px -23px;
+ cursor: default;
+ display: inline-block;
+ float: left;
+ margin: 0px 0px 0px 3px;
+ width: 29px;
+ height: 23px;
+}
+
+#openFileButton.down {
+ background: url('images/buttons.png') no-repeat -56px -46px;
+}
+
+#openFileButton.disabled {
+ background: url('images/buttons.png') no-repeat -56px 0px;
+}
+
+#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;
+}
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>pdf.js Multi-Page Viewer</title>
+<meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>
+<link rel="stylesheet" href="multi_page_viewer.css" type="text/css" media="screen"/>
+<script type="text/javascript" src="pdf.js"></script>
+<script type="text/javascript" src="fonts.js"></script>
+<script type="text/javascript" src="crypto.js"></script>
+<script type="text/javascript" src="glyphlist.js"></script>
+<script type="text/javascript" src="multi_page_viewer.js"></script>
+</head>
+<body>
+ <div id="controls">
+ <span class="control">
+ <span id="previousPageButton" class="disabled"></span>
+ <span id="nextPageButton" class="disabled"></span>
+ <span class="label">Previous/Next</span>
+ </span>
+ <span class="control">
+ <input type="text" id="pageNumber" value="1" size="2"/>
+ <span>/</span>
+ <span id="numPages">--</span>
+ <span class="label">Page Number</span>
+ </span>
+ <span class="control">
+ <select id="scaleSelect">
+ <option value="50">50%</option>
+ <option value="75">75%</option>
+ <option value="100">100%</option>
+ <option value="125">125%</option>
+ <option value="150" selected="selected">150%</option>
+ <option value="200">200%</option>
+ </select>
+ <span class="label">Zoom</span>
+ </span>
+ <span class="control">
+ <span id="openFileButton"></span>
+ <input type="file" id="fileInput"/>
+ <span class="label">Open File</span>
+ </span>
+ </div>
+
+ <!-- EXPERIMENTAL: Slide-out sidebar with page thumbnails (comment-out to disable) -->
+ <div id="sidebar">
+ <div id="sidebarBox">
+ <div id="sidebarScrollView">
+ <div id="sidebarContentView"></div>
+ </div>
+ </div>
+ </div>
+
+ <div id="viewer"></div>
+</body>
+</html>
--- /dev/null
+/* -*- 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() {
+ const 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();
+
+ 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);
+
+ FontLoader.bind(fonts, function() { page.display(gfx); });
+ }
+ },
+
+ 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();
+
+ 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);
+
+ FontLoader.bind(fonts, function() { page.display(gfx); });
+ }
+ },
+
+ 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.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;
+
+ 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.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.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) {
+ 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;
+ }
+ };
+};
--- /dev/null
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
+/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
+
+body {
+ margin: 6px;
+ padding: 0px;
+ background-color: #c0bdb7;
+}
+
+#controls {
+ position:fixed;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ padding: 7px;
+ border-bottom: 1px solid black;
+ background-color: rgb(242, 240, 238);
+}
+
+span#info {
+ float: right;
+ font: 14px sans-serif;
+ margin-right: 10px;
+}
+
+#viewer {
+}
+
+#canvas {
+ margin: auto;
+ display: block;
+}
+
+#pageNumber {
+ text-align: right;
+}
--- /dev/null
+<html>
+ <head>
+ <title>Simple pdf.js page viewer</title>
+ <link rel="stylesheet" href="viewer.css"></link>
+
+ <script type="text/javascript" src="viewer.js"></script>
+ <script type="text/javascript" src="pdf.js"></script>
+ <script type="text/javascript" src="utils/fonts_utils.js"></script>
+ <script type="text/javascript" src="fonts.js"></script>
+ <script type="text/javascript" src="crypto.js"></script>
+ <script type="text/javascript" src="glyphlist.js"></script>
+ </head>
+
+ <body onload="load();">
+ <div id="controls">
+ <input type="file" style="float: right; margin: auto 32px;" onChange="load(this.value.toString());"></input>
+ <!-- This only opens supported PDFs from the source path...
+ -- Can we use JSONP to overcome the same-origin restrictions? -->
+ <button onclick="prevPage();">Previous</button>
+ <button onclick="nextPage();">Next</button>
+ <input type="text" id="pageNumber" onchange="gotoPage(this.value);"
+ value="1" size="4"></input>
+ <span id="numPages">--</span>
+ <span id="info"></span>
+ </div>
+
+ <div id="viewer">
+ <canvas id="canvas"></canvas>
+ </div>
+ </body>
+</html>
+
--- /dev/null
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
+/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
+
+"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);
+}
+
+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;
+}
+
+function open(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;
+ pdfDocument = new PDFDoc(new Stream(data));
+ numPages = pdfDocument.numPages;
+ document.getElementById("numPages").innerHTML = numPages.toString();
+ goToPage(pageNum);
+ }
+ };
+ req.send(null);
+}
+
+function gotoPage(num) {
+ if (0 <= num && num <= numPages)
+ pageNum = num;
+ displayPage(pageNum);
+}
+
+function displayPage(num) {
+ document.getElementById("pageNumber").value = num;
+
+ var t0 = Date.now();
+
+ var page = pdfDocument.getPage(pageNum = num);
+
+ 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;
+
+ 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();
+
+ 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 t2 = Date.now();
+
+ function displayPage() {
+ var t3 = Date.now();
+
+ page.display(gfx);
+
+ var t4 = Date.now();
+
+ var infoDisplay = document.getElementById("info");
+ infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms";
+ }
+
+ // Always defer call to displayPage() to work around bug in
+ // Firefox error reporting from XHR callbacks.
+ FontLoader.bind(fonts, function () { setTimeout(displayPage, 0); });
+}
+
+function nextPage() {
+ if (pageNum < pdfDocument.numPages)
+ displayPage(++pageNum);
+}
+
+function prevPage() {
+ if (pageNum > 1)
+ displayPage(--pageNum);
+}
+
+function goToPage(num) {
+ if (0 <= num && num <= numPages)
+ displayPage(pageNum = num);
+}
+
--- /dev/null
+<html>
+ <head>
+ <title>Simple pdf.js page worker viewer</title>
+ <script type="text/javascript" src="fonts.js"></script>
+ <script type="text/javascript" src="glyphlist.js"></script>
+ <script type="text/javascript" src="pdf.js"></script>
+ <script type="text/javascript" src="worker/client.js"></script>
+<script>
+
+
+var pdfDoc;
+window.onload = function() {
+ window.canvas = document.getElementById("canvas");
+ window.ctx = canvas.getContext("2d");
+
+ pdfDoc = new WorkerPDFDoc(window.canvas);
+ pdfDoc.onChangePage = function(numPage) {
+ document.getElementById("pageNumber").value = numPage;
+ }
+ // pdfDoc.open("canvas.pdf", function() {
+ pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() {
+ document.getElementById("numPages").innerHTML = "/" + pdfDoc.numPages;
+ })
+}
+</script>
+ <link rel="stylesheet" href="viewer.css"></link>
+ </head>
+ <body>
+ <div id="controls">
+ <input type="file" style="float: right; margin: auto 32px;" onChange="load(this.value.toString());"></input>
+ <!-- This only opens supported PDFs from the source path...
+ -- Can we use JSONP to overcome the same-origin restrictions? -->
+ <button onclick="pdfDoc.prevPage();">Previous</button>
+ <button onclick="pdfDoc.nextPage();">Next</button>
+ <input type="text" id="pageNumber" onchange="pdfDoc.showPage(this.value);"
+ value="1" size="4"></input>
+ <span id="numPages">--</span>
+ <span id="info"></span>
+ </div>
+
+ <div id="viewer">
+ <canvas id="canvas"></canvas>
+ </div>
+ </body>
+</html>
+