]> git.parisson.com Git - pdf.js.git/commitdiff
Add Makefile. Move some files around to make building the website easier.
authorRob Sayre <sayrer@gmail.com>
Tue, 5 Jul 2011 17:53:57 +0000 (10:53 -0700)
committerRob Sayre <sayrer@gmail.com>
Tue, 5 Jul 2011 17:53:57 +0000 (10:53 -0700)
24 files changed:
Makefile [new file with mode: 0644]
compressed.tracemonkey-pldi-09.pdf [deleted file]
images/buttons.png [deleted file]
images/source/Buttons.psd.zip [deleted file]
images/source/FileButton.psd.zip [deleted file]
multi_page_viewer.css [deleted file]
multi_page_viewer.html [deleted file]
multi_page_viewer.js [deleted file]
viewer.css [deleted file]
viewer.html [deleted file]
viewer.js [deleted file]
viewer_worker.html [deleted file]
web/compressed.tracemonkey-pldi-09.pdf [new file with mode: 0644]
web/images/buttons.png [new file with mode: 0644]
web/images/source/Buttons.psd.zip [new file with mode: 0644]
web/images/source/FileButton.psd.zip [new file with mode: 0644]
web/index.html.template [new file with mode: 0644]
web/multi_page_viewer.css [new file with mode: 0644]
web/multi_page_viewer.html [new file with mode: 0644]
web/multi_page_viewer.js [new file with mode: 0644]
web/viewer.css [new file with mode: 0644]
web/viewer.html [new file with mode: 0644]
web/viewer.js [new file with mode: 0644]
web/viewer_worker.html [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..da18e5b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,154 @@
+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
diff --git a/compressed.tracemonkey-pldi-09.pdf b/compressed.tracemonkey-pldi-09.pdf
deleted file mode 100644 (file)
index 6557018..0000000
Binary files a/compressed.tracemonkey-pldi-09.pdf and /dev/null differ
diff --git a/images/buttons.png b/images/buttons.png
deleted file mode 100644 (file)
index 3357b47..0000000
Binary files a/images/buttons.png and /dev/null differ
diff --git a/images/source/Buttons.psd.zip b/images/source/Buttons.psd.zip
deleted file mode 100644 (file)
index 528e6ee..0000000
Binary files a/images/source/Buttons.psd.zip and /dev/null differ
diff --git a/images/source/FileButton.psd.zip b/images/source/FileButton.psd.zip
deleted file mode 100644 (file)
index 1f2b51c..0000000
Binary files a/images/source/FileButton.psd.zip and /dev/null differ
diff --git a/multi_page_viewer.css b/multi_page_viewer.css
deleted file mode 100644 (file)
index 17b2537..0000000
+++ /dev/null
@@ -1,230 +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;
-}
-
-.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;
-}
diff --git a/multi_page_viewer.html b/multi_page_viewer.html
deleted file mode 100644 (file)
index df71d66..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<!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>
diff --git a/multi_page_viewer.js b/multi_page_viewer.js
deleted file mode 100644 (file)
index 01d7b4f..0000000
+++ /dev/null
@@ -1,534 +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() {
-    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;
-    }
-  };
-};
diff --git a/viewer.css b/viewer.css
deleted file mode 100644 (file)
index 9987492..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- 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;
-}
diff --git a/viewer.html b/viewer.html
deleted file mode 100644 (file)
index c600547..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<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>
-
diff --git a/viewer.js b/viewer.js
deleted file mode 100644 (file)
index 6702a67..0000000
--- a/viewer.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/* -*- 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);
-}
-
diff --git a/viewer_worker.html b/viewer_worker.html
deleted file mode 100644 (file)
index 89fb8a0..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<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>
-
diff --git a/web/compressed.tracemonkey-pldi-09.pdf b/web/compressed.tracemonkey-pldi-09.pdf
new file mode 100644 (file)
index 0000000..6557018
Binary files /dev/null and b/web/compressed.tracemonkey-pldi-09.pdf differ
diff --git a/web/images/buttons.png b/web/images/buttons.png
new file mode 100644 (file)
index 0000000..3357b47
Binary files /dev/null and b/web/images/buttons.png differ
diff --git a/web/images/source/Buttons.psd.zip b/web/images/source/Buttons.psd.zip
new file mode 100644 (file)
index 0000000..528e6ee
Binary files /dev/null and b/web/images/source/Buttons.psd.zip differ
diff --git a/web/images/source/FileButton.psd.zip b/web/images/source/FileButton.psd.zip
new file mode 100644 (file)
index 0000000..1f2b51c
Binary files /dev/null and b/web/images/source/FileButton.psd.zip differ
diff --git a/web/index.html.template b/web/index.html.template
new file mode 100644 (file)
index 0000000..c3086f0
--- /dev/null
@@ -0,0 +1,88 @@
+<!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>
diff --git a/web/multi_page_viewer.css b/web/multi_page_viewer.css
new file mode 100644 (file)
index 0000000..17b2537
--- /dev/null
@@ -0,0 +1,230 @@
+/* -*- 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;
+}
diff --git a/web/multi_page_viewer.html b/web/multi_page_viewer.html
new file mode 100644 (file)
index 0000000..df71d66
--- /dev/null
@@ -0,0 +1,55 @@
+<!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>
diff --git a/web/multi_page_viewer.js b/web/multi_page_viewer.js
new file mode 100644 (file)
index 0000000..01d7b4f
--- /dev/null
@@ -0,0 +1,534 @@
+/* -*- 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;
+    }
+  };
+};
diff --git a/web/viewer.css b/web/viewer.css
new file mode 100644 (file)
index 0000000..9987492
--- /dev/null
@@ -0,0 +1,36 @@
+/* -*- 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;
+}
diff --git a/web/viewer.html b/web/viewer.html
new file mode 100644 (file)
index 0000000..c600547
--- /dev/null
@@ -0,0 +1,32 @@
+<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>
+
diff --git a/web/viewer.js b/web/viewer.js
new file mode 100644 (file)
index 0000000..6702a67
--- /dev/null
@@ -0,0 +1,113 @@
+/* -*- 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);
+}
+
diff --git a/web/viewer_worker.html b/web/viewer_worker.html
new file mode 100644 (file)
index 0000000..89fb8a0
--- /dev/null
@@ -0,0 +1,46 @@
+<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>
+