Skip to content

Instantly share code, notes, and snippets.

@rexboy7
Created March 7, 2017 12:08
Show Gist options
  • Save rexboy7/e529856f08dbcbac3f79124e8f1cb978 to your computer and use it in GitHub Desktop.
Save rexboy7/e529856f08dbcbac3f79124e8f1cb978 to your computer and use it in GitHub Desktop.
diff --git a/browser/extensions/mortar/host/common/ppapi-runtime.jsm b/browser/extensions/mortar/host/common/ppapi-runtime.jsm
index d680fe0..f59c6e3 100644
--- a/browser/extensions/mortar/host/common/ppapi-runtime.jsm
+++ b/browser/extensions/mortar/host/common/ppapi-runtime.jsm
@@ -11,6 +11,7 @@ const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://ppapi.js/opengles2-utils.jsm");
+Cu.importGlobalProperties(['URL']);
const PP_OK = 0;
const PP_OK_COMPLETIONPENDING = -1;
@@ -1538,12 +1539,29 @@ class PPAPIInstance {
this.viewport = new PPAPIViewport(this);
this.selectedText = "";
+ this.notifyHashChange(info.url);
+
this.mm.addMessageListener("ppapi.js:fullscreenchange", (evt) => {
this.viewport.notify({
type: "fullscreenChange",
fullscreen: evt.data.fullscreen
});
});
+
+ this.mm.addMessageListener("ppapipdf.js:hashchange", (evt) => {
+ this.notifyHashChange(evt.data.url);
+ });
+ }
+
+ notifyHashChange(url) {
+ let location = new URL(url);
+ if (location.hash) {
+ this.viewport.notify({
+ type: "hashChange",
+ // substring(1) for getting rid of the first '#' character
+ hash: location.hash.substring(1)
+ });
+ }
}
bindGraphics(graphicsDevice) {
@@ -1673,6 +1691,9 @@ class PPAPIInstance {
case 'save':
this.mm.sendAsyncMessage("ppapipdf.js:save");
break;
+ case 'setHash':
+ this.mm.sendAsyncMessage("ppapipdf.js:setHash", message.hash);
+ break;
case 'viewport':
case 'rotateClockwise':
case 'rotateCounterclockwise':
diff --git a/browser/extensions/mortar/host/pdf/chrome/js/toolbar.js b/browser/extensions/mortar/host/pdf/chrome/js/toolbar.js
index 9c040cc..2185ebf 100644
--- a/browser/extensions/mortar/host/pdf/chrome/js/toolbar.js
+++ b/browser/extensions/mortar/host/pdf/chrome/js/toolbar.js
@@ -210,6 +210,10 @@ class Toolbar {
case 'secondaryToolbarToggle':
this._secondaryToolbar.toggle();
break;
+ case 'viewBookmark':
+ case 'secondaryViewBookmark':
+ this._viewport.createBookmarkHash();
+ break;
}
}
diff --git a/browser/extensions/mortar/host/pdf/chrome/js/viewport.js b/browser/extensions/mortar/host/pdf/chrome/js/viewport.js
index 4a80fa5..6bd4a83 100644
--- a/browser/extensions/mortar/host/pdf/chrome/js/viewport.js
+++ b/browser/extensions/mortar/host/pdf/chrome/js/viewport.js
@@ -34,6 +34,10 @@ class Viewport {
this._runtimeSize = this.getBoundingClientRect();
this._runtimeOnResizedListener = [];
+ // If the document is opened with a bookmarkView hash, we save it until
+ // we know document dimension to move the view.
+ this._initPosition = null;
+
this.onProgressChanged = null;
this.onZoomChanged = null;
this.onDimensionChanged = null;
@@ -64,8 +68,7 @@ class Viewport {
}
set fitting(newFitting) {
- let VALID_VALUE = ['none', 'auto', 'page-actual', 'page-width', 'page-fit'];
- if (!VALID_VALUE.includes(newFitting)) {
+ if (!this._isValidFitting(newFitting)) {
return;
}
@@ -126,6 +129,11 @@ class Viewport {
});
}
+ _isValidFitting(fitting) {
+ let VALID_VALUE = ['none', 'auto', 'page-actual', 'page-width', 'page-fit'];
+ return VALID_VALUE.includes(fitting);
+ }
+
_getScrollbarWidth() {
let div = document.createElement('div');
div.style.visibility = 'hidden';
@@ -175,7 +183,13 @@ class Viewport {
if (typeof this.onDimensionChanged === 'function') {
this.onDimensionChanged();
}
- this._refresh();
+
+ if (this._initPosition) {
+ this._jumpToBookmark(this._initPosition);
+ this._initPosition = null;
+ } else {
+ this._refresh();
+ }
}
_computeFittingZoom(pageIndex) {
@@ -487,6 +501,100 @@ class Viewport {
gClipboardHelper.copyString(text);
}
+ _getPageCoordinate() {
+ let currentPos = this._nextPosition || this.getScrollOffset();
+ let pageDimension = this._pageDimensions[this._page];
+ // Page coordinate uses Cartesian coordinate system which locates its origin
+ // at bottom-left of a page.
+ // The coordinate used in PDF.js is scaled by 0.75 with respect to PDFium so
+ // we keep it here for backward compability.
+ let pageOrigin = {
+ x: pageDimension.x,
+ y: pageDimension.y + pageDimension.height
+ };
+ currentPos.x /= this._zoom;
+ currentPos.y /= this._zoom;
+
+ let pageCoordinate = {
+ x: Math.round((currentPos.x - pageOrigin.x) * 0.75),
+ y: Math.round((pageOrigin.y - currentPos.y) * 0.75)
+ };
+ return pageCoordinate;
+ }
+
+ _getScreenCooridnate(pageNo, pageX, pageY) {
+ let pageDimension = this._pageDimensions[pageNo];
+
+ // Page coordinate uses Cartesian coordinate system which locates its origin
+ // at bottom-left of a page.
+ // The coordinate used in PDF.js is scaled by 0.75 with respect to PDFium so
+ // we keep it here for backward compability.
+
+ // Both pageX and pageY are omittable and we assume top or left side of the
+ // page as their default.
+ pageX = Number.isInteger(pageX) ? pageX : 0;
+ pageY = Number.isInteger(pageY) ? pageY : pageDimension.height * 0.75;
+ pageX /= 0.75;
+ pageY /= 0.75;
+
+ let pageOrigin = {
+ x: pageDimension.x,
+ y: pageDimension.y + pageDimension.height
+ };
+
+ return {
+ x: Math.round((pageX - pageOrigin.x) * this._zoom),
+ y: Math.round((pageOrigin.y - pageY) * this._zoom)
+ };
+ }
+
+ /**
+ * @param hash
+ * contains page and zoom parameters which should be in the following
+ * format: page={page}&zoom={scale},{x},{y}
+ * for example the following hashes are valid:
+ * page=1&zoom=auto,100,100
+ * page=3&zoom=300,10,-50
+ */
+ _jumpToBookmark(hash) {
+ let params = {};
+ hash.split('&').forEach(param => {
+ let [name, value] = param.split('=');
+ params[name.toLowerCase()] = value.toLowerCase();
+ });
+
+ let pageNo = parseInt(params.page, 10);
+ pageNo = Math.max(0, Math.min(this.pageCount - 1, pageNo - 1));
+ pageNo = Number.isNaN(pageNo) ? this._page : pageNo;
+
+ params.zoom = (typeof(params.zoom) == 'string') ? params.zoom : "";
+ let [scale, pageX, pageY] = params.zoom.split(',');
+ pageX = parseInt(pageX, 10);
+ pageY = parseInt(pageY, 10);
+
+ if (this._isValidFitting(scale)) {
+ this._fitting = scale;
+ } else {
+ this._fitting = 'none';
+ let zoom = parseFloat(scale);
+ zoom = (Number.isNaN(zoom) || zoom <= 0) ? 100 : zoom;
+ this._zoom = zoom / 100;
+ }
+
+ let screenPos = this._getScreenCooridnate(pageNo, pageX, pageY);
+ this._setPosition(screenPos.x, screenPos.y);
+ this._setZoom(this._computeFittingZoom());
+ this._refresh();
+ }
+
+ _handleHashChange(hash) {
+ if (!this._documentDimensions) {
+ this._initPosition = hash;
+ } else {
+ this._jumpToBookmark(hash);
+ }
+ }
+
verifyPassword(password) {
this._doAction({
type: 'getPasswordComplete',
@@ -550,6 +658,21 @@ class Viewport {
}
}
+ createBookmarkHash() {
+ let pagePosition = this._getPageCoordinate();
+ let scale = this._fitting == 'none' ?
+ Math.round(this._zoom * 100) :
+ this._fitting;
+ let hash = "page=" + (this._page + 1) +
+ "&zoom=" + scale +
+ "," + pagePosition.x +
+ "," + pagePosition.y;
+ this._doAction({
+ type: 'setHash',
+ hash: hash
+ })
+ }
+
/***************************/
/* PPAPIViewport Interface */
/***************************/
@@ -631,6 +754,9 @@ class Viewport {
// that case.
this._copyToClipboard(message.selectedText);
break;
+ case 'hashChange':
+ this._handleHashChange(message.hash);
+ break;
}
}
}
diff --git a/browser/extensions/mortar/host/pdf/chrome/style/viewer.css b/browser/extensions/mortar/host/pdf/chrome/style/viewer.css
index c052273..a1f879a 100644
--- a/browser/extensions/mortar/host/pdf/chrome/style/viewer.css
+++ b/browser/extensions/mortar/host/pdf/chrome/style/viewer.css
@@ -889,11 +889,6 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
padding-top: 5px;
}
-.bookmark[href='#'] {
- opacity: .5;
- pointer-events: none;
-}
-
.toolbarButton.bookmark::before,
.secondaryToolbarButton.bookmark::before {
content: url(images/toolbarButton-bookmark.png);
diff --git a/browser/extensions/mortar/host/pdf/chrome/viewer.html b/browser/extensions/mortar/host/pdf/chrome/viewer.html
index 50ca81a..efc212c 100644
--- a/browser/extensions/mortar/host/pdf/chrome/viewer.html
+++ b/browser/extensions/mortar/host/pdf/chrome/viewer.html
@@ -74,9 +74,9 @@
<span data-l10n-id="download_label">Download</span>
</button>
- <a href="#" id="secondaryViewBookmark" class="secondaryToolbarButton bookmark visibleSmallView" title="Current view (copy or open in new window)" tabindex="55" data-l10n-id="bookmark">
+ <button href="#" id="secondaryViewBookmark" class="secondaryToolbarButton bookmark visibleSmallView" title="Current view (copy or open in new window)" tabindex="55" data-l10n-id="bookmark">
<span data-l10n-id="bookmark_label">Current View</span>
- </a>
+ </button>
<div class="horizontalToolbarSeparator visibleLargeView"></div>
@@ -135,9 +135,9 @@
<button id="download" class="toolbarButton download hiddenMediumView" title="Download" tabindex="34" data-l10n-id="download">
<span data-l10n-id="download_label">Download</span>
</button>
- <a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView" title="Current view (copy or open in new window)" tabindex="35" data-l10n-id="bookmark">
+ <button target="_blank" id="viewBookmark" class="toolbarButton bookmark hiddenMediumView" title="Current view (copy or open in new window)" tabindex="35" data-l10n-id="bookmark">
<span data-l10n-id="bookmark_label">Current View</span>
- </a>
+ </button>
<div class="verticalToolbarSeparator hiddenSmallView"></div>
diff --git a/browser/extensions/mortar/host/pdf/ppapi-content-sandbox.js b/browser/extensions/mortar/host/pdf/ppapi-content-sandbox.js
index 44aded8..75f5177 100644
--- a/browser/extensions/mortar/host/pdf/ppapi-content-sandbox.js
+++ b/browser/extensions/mortar/host/pdf/ppapi-content-sandbox.js
@@ -89,6 +89,11 @@ mm.addMessageListener("ppapi.js:frameLoaded", ({ target }) => {
let fullscreen = (containerWindow.document.fullscreenElement == pluginElement);
mm.sendAsyncMessage("ppapi.js:fullscreenchange", { fullscreen });
});
+
+ containerWindow.addEventListener("hashchange", () => {
+ let url = containerWindow.location.href;
+ mm.sendAsyncMessage("ppapipdf.js:hashchange", { url });
+ })
});
mm.addMessageListener("ppapi.js:setFullscreen", ({ data }) => {
@@ -99,6 +104,12 @@ mm.addMessageListener("ppapi.js:setFullscreen", ({ data }) => {
}
});
+mm.addMessageListener("ppapipdf.js:setHash", ({ data }) => {
+ if (data) {
+ containerWindow.location.hash = data;
+ }
+});
+
mm.addMessageListener("ppapipdf.js:save", () => {
let url = containerWindow.document.location;
let filename = "document.pdf";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment