Created
March 7, 2017 12:08
-
-
Save rexboy7/e529856f08dbcbac3f79124e8f1cb978 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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