From 39d3ea862beaf4142f164fa79ae99f58e832cbf9 Mon Sep 17 00:00:00 2001
From: Saebekassebil <saebekassebil@gmail.com>
Date: Mon, 30 Jul 2012 17:12:49 +0200
Subject: [PATCH] Initial support for Presentation Mode

---
 web/viewer.css  |  48 +++++++++++++++++++++
 web/viewer.html |   4 ++
 web/viewer.js   | 109 ++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 153 insertions(+), 8 deletions(-)

diff --git a/web/viewer.css b/web/viewer.css
index 80a8c5a40..09f649419 100644
--- a/web/viewer.css
+++ b/web/viewer.css
@@ -27,6 +27,50 @@ select {
   display: none !important;
 }
 
+:-webkit-full-screen #viewerContainer {
+  top: 0px;
+  padding-top: 6px;
+  padding-bottom: 24px;
+  background-color: #404040;
+  background-image: url(images/texture.png);
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+}
+
+:-webkit-full-screen #viewer {
+  margin: 0pt;
+  padding: 0pt;
+  height: 100%;
+  width: 100%;
+  overflow: hidden;
+}
+
+:-webkit-full-screen .page {
+  margin: 0px auto;
+  margin-bottom: 10px;
+}
+
+:-moz-full-screen .page {
+  margin: 10px auto;
+}
+
+:-moz-full-screen #viewerContainer {
+  background-color: #404040;
+  background-image: url(images/texture.png);
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+
+#viewerContainer:full-screen {
+  top: 0px;
+  background-color: #404040;
+  background-image: url(images/texture.png);
+  width: 100%;
+  height: 100%;
+}
+
 /* outer/inner center provides horizontal center */
 html[dir='ltr'] .outerCenter {
   float: right;
@@ -609,6 +653,10 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
   content: url(images/toolbarButton-zoomIn.png);
 }
 
+.toolbarButton.fullscreen::before {
+  display: inline-block;
+}
+
 .toolbarButton.print::before {
   display: inline-block;
   content: url(images/toolbarButton-print.png);
diff --git a/web/viewer.html b/web/viewer.html
index 28e57f700..f4f0ebca5 100644
--- a/web/viewer.html
+++ b/web/viewer.html
@@ -98,6 +98,10 @@
               </div>
               <div id="toolbarViewerRight">
                 <input id="fileInput" class="fileInput" type="file" oncontextmenu="return false;" style="visibility: hidden; position: fixed; right: 0; top: 0" />
+
+
+                <button id="fullscreen" class="toolbarButton fullscreen" title="Fullscreen" tabindex="11" data-l10n-id="fullscreen" onclick="PDFView.fullscreen();">Fullscreen</button>
+
                 <button id="openFile" class="toolbarButton openFile" title="Open File" tabindex="11" data-l10n-id="open_file" onclick="document.getElementById('fileInput').click()">
                    <span data-l10n-id="open_file_label">Open</span>
                 </button>
diff --git a/web/viewer.js b/web/viewer.js
index e24e694f2..4de66b5af 100644
--- a/web/viewer.js
+++ b/web/viewer.js
@@ -241,6 +241,8 @@ var PDFView = {
   sidebarOpen: false,
   pageViewScroll: null,
   thumbnailViewScroll: null,
+  isFullscreen: false,
+  previousScale: null,
 
   // called once when the document is loaded
   initialize: function pdfViewInitialize() {
@@ -307,6 +309,7 @@ var PDFView = {
 
     var container = this.container;
     var currentPage = this.pages[this.page - 1];
+
     var pageWidthScale = (container.clientWidth - kScrollbarPadding) /
                           currentPage.width * currentPage.scale / kCssUnits;
     var pageHeightScale = (container.clientHeight - kScrollbarPadding) /
@@ -390,6 +393,17 @@ var PDFView = {
     return value;
   },
 
+  get supportsFullscreen() {
+    var doc = document.documentElement;
+    var support = doc.requestFullScreen || doc.mozRequestFullScreen ||
+                  doc.webkitRequestFullScreen;
+    Object.defineProperty(this, 'supportsFullScreen', { value: support,
+                                                        enumerable: true,
+                                                        configurable: true,
+                                                        writable: false });
+    return support;
+  },
+
   open: function pdfViewOpen(url, scale, password) {
     var parameters = {password: password};
     if (typeof url === 'string') { // URL
@@ -786,7 +800,7 @@ var PDFView = {
     }
     for (var i = 0; i < numVisible; ++i) {
       var view = visibleViews[i].view;
-      if (!this.isViewFinshed(view))
+      if (!this.isViewFinished(view))
         return view;
     }
 
@@ -795,19 +809,19 @@ var PDFView = {
       var lastVisible = visibleViews[visibleViews.length - 1];
       var nextPageIndex = lastVisible.id;
       // ID's start at 1 so no need to add 1.
-      if (views[nextPageIndex] && !this.isViewFinshed(views[nextPageIndex]))
+      if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex]))
         return views[nextPageIndex];
     } else {
       var previousPageIndex = visibleViews[0].id - 2;
       if (views[previousPageIndex] &&
-          !this.isViewFinshed(views[previousPageIndex]))
+          !this.isViewFinished(views[previousPageIndex]))
         return views[previousPageIndex];
     }
     // Everything that needs to be rendered has been.
     return false;
   },
 
-  isViewFinshed: function pdfViewNeedsRendering(view) {
+  isViewFinished: function pdfViewNeedsRendering(view) {
     return view.renderingState === RenderingStates.FINISHED;
   },
 
@@ -1029,6 +1043,18 @@ var PDFView = {
     }
 
     var visible = [];
+
+    // Algorithm broken in fullscreen mode
+    if (this.isFullscreen) {
+      var currentPage = this.pages[this.page - 1];
+      visible.push({
+        id: currentPage.id,
+        view: currentPage
+      });
+
+      return visible;
+    }
+
     var bottom = top + scrollEl.clientHeight;
     for (; i <= views.length && currentHeight < bottom; ++i) {
       view = views[i - 1];
@@ -1072,6 +1098,44 @@ var PDFView = {
     var div = document.getElementById('printContainer');
     while (div.hasChildNodes())
       div.removeChild(div.lastChild);
+  },
+
+  fullscreen: function pdfViewFullscreen() {
+    var isFullscreen = document.fullscreen || document.mozFullScreen ||
+        document.webkitIsFullScreen;
+
+    if (isFullscreen) {
+      return false;
+    }
+
+    var wrapper = document.getElementById('viewerContainer');
+    if (document.documentElement.requestFullScreen) {
+      wrapper.requestFullScreen();
+    } else if (document.documentElement.mozRequestFullScreen) {
+      wrapper.mozRequestFullScreen();
+    } else if (document.documentElement.webkitRequestFullScreen) {
+      wrapper.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
+    } else {
+      return false;
+    }
+
+    this.isFullscreen = true;
+    var currentPage = this.pages[this.page - 1];
+    this.previousScale = this.currentScaleValue;
+    this.parseScale('page-fit', true);
+
+    // Wait for fullscreen to take effect
+    setTimeout(function() {
+      currentPage.scrollIntoView();
+    }, 0);
+
+    return true;
+  },
+
+  exitFullscreen: function pdfViewExitFullscreen() {
+    this.isFullscreen = false;
+    this.parseScale(this.previousScale);
+    this.page = this.page;
   }
 };
 
@@ -1785,6 +1849,10 @@ window.addEventListener('load', function webViewerLoad(evt) {
     document.getElementById('print').classList.add('hidden');
   }
 
+  if (!PDFView.supportsFullscreen) {
+    document.getElementById('fullscreen').classList.add('hidden');
+  }
+
   // Listen for warnings to trigger the fallback UI.  Errors should be caught
   // and call PDFView.error() so we don't need to listen for those.
   PDFJS.LogManager.addLogger({
@@ -1823,11 +1891,14 @@ function updateViewarea() {
 
   PDFView.renderHighestPriority();
 
-  updateViewarea.inProgress = true; // used in "set page"
   var currentId = PDFView.page;
   var firstPage = visiblePages[0];
-  PDFView.page = firstPage.id;
-  updateViewarea.inProgress = false;
+
+  if (!PDFView.isFullscreen) {
+    updateViewarea.inProgress = true; // used in "set page"
+    PDFView.page = firstPage.id;
+    updateViewarea.inProgress = false;
+  }
 
   var currentScale = PDFView.currentScale;
   var currentScaleValue = PDFView.currentScaleValue;
@@ -2013,7 +2084,7 @@ window.addEventListener('keydown', function keydown(evt) {
     return;
   var controlsElement = document.getElementById('controls');
   while (curElement) {
-    if (curElement === controlsElement)
+    if (curElement === controlsElement && !PDFView.isFullscreen)
       return; // ignoring if the 'controls' element is focused
     curElement = curElement.parentNode;
   }
@@ -2032,6 +2103,13 @@ window.addEventListener('keydown', function keydown(evt) {
         PDFView.page++;
         handled = true;
         break;
+
+      case 32: // spacebar
+        if (PDFView.isFullscreen) {
+          PDFView.page++;
+          handled = true;
+        }
+        break;
     }
   }
 
@@ -2047,3 +2125,18 @@ window.addEventListener('beforeprint', function beforePrint(evt) {
 window.addEventListener('afterprint', function afterPrint(evt) {
   PDFView.afterPrint();
 });
+
+(function fullscreenClosure() {
+  function fullscreenChange(e) {
+    var isFullscreen = document.fullscreen || document.mozFullScreen ||
+        document.webkitIsFullScreen;
+
+    if (!isFullscreen) {
+      PDFView.exitFullscreen();
+    }
+  }
+
+  window.addEventListener('fullscreenchange', fullscreenChange, false);
+  window.addEventListener('mozfullscreenchange', fullscreenChange, false);
+  window.addEventListener('webkitfullscreenchange', fullscreenChange, false);
+})();