From 334b3d9808b7b6f6cdae1b6187eb59c98c08b49b Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 27 Apr 2015 18:06:55 -0400 Subject: [PATCH] Bug 1157827 - Update pdf.js to version 1.1.82. r=bdahl, r=Mossop --- browser/extensions/pdfjs/README.mozilla | 2 +- .../pdfjs/content/PdfStreamConverter.jsm | 4 - .../pdfjs/content/PdfjsChromeUtils.jsm | 23 +- browser/extensions/pdfjs/content/build/pdf.js | 15 +- .../pdfjs/content/build/pdf.worker.js | 84 +- .../pdfjs/content/pdfjschildbootstrap.js | 3 +- .../extensions/pdfjs/content/web/viewer.css | 20 +- .../extensions/pdfjs/content/web/viewer.html | 1 - .../extensions/pdfjs/content/web/viewer.js | 875 ++++++++++-------- 9 files changed, 564 insertions(+), 463 deletions(-) diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla index be7a4066618..bd5d5b3c37a 100644 --- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,3 +1,3 @@ This is the pdf.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 1.1.24 +Current extension version is: 1.1.82 diff --git a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm index 11109f5005e..dc3e1c0ca3f 100644 --- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm +++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm @@ -459,8 +459,6 @@ ChromeActions.prototype = { var winmm = this.domWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDocShell) - .sameTypeRootTreeItem - .QueryInterface(Ci.nsIDocShell) .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIContentFrameMessageManager); @@ -773,8 +771,6 @@ function FindEventManager(contentWindow) { this.contentWindow = contentWindow; this.winmm = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDocShell) - .sameTypeRootTreeItem - .QueryInterface(Ci.nsIDocShell) .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIContentFrameMessageManager); } diff --git a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm index 13ea294e519..2e0c4db56cf 100644 --- a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm +++ b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm @@ -194,9 +194,8 @@ let PdfjsChromeUtils = { }, handleEvent: function(aEvent) { - // We cannot just forward the message as a CPOW without setting up - // __exposedProps__ on it. Instead, let's just create a structured - // cloneable version of the event for performance and for the ease of usage. + // To avoid forwarding the message as a CPOW, create a structured cloneable + // version of the event for both performance, and ease of usage, reasons. let type = aEvent.type; let detail = { query: aEvent.detail.query, @@ -205,16 +204,16 @@ let PdfjsChromeUtils = { findPrevious: aEvent.detail.findPrevious }; - let chromeWindow = aEvent.target.ownerDocument.defaultView; - let browser = chromeWindow.gBrowser.selectedBrowser; - if (this._browsers.has(browser)) { - // Only forward the events if the selected browser is a registered - // browser. - let mm = browser.messageManager; - mm.sendAsyncMessage('PDFJS:Child:handleEvent', - { type: type, detail: detail }); - aEvent.preventDefault(); + let browser = aEvent.currentTarget.browser; + if (!this._browsers.has(browser)) { + throw new Error('FindEventManager was not bound ' + + 'for the current browser.'); } + // Only forward the events if the current browser is a registered browser. + let mm = browser.messageManager; + mm.sendAsyncMessage('PDFJS:Child:handleEvent', + { type: type, detail: detail }); + aEvent.preventDefault(); }, _types: ['find', diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js index acdecab72ad..a0d00c0c260 100644 --- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -22,8 +22,8 @@ if (typeof PDFJS === 'undefined') { (typeof window !== 'undefined' ? window : this).PDFJS = {}; } -PDFJS.version = '1.1.24'; -PDFJS.build = 'f6a8110'; +PDFJS.version = '1.1.82'; +PDFJS.build = '71ab5e5'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it @@ -239,17 +239,10 @@ function warn(msg) { // Fatal errors that should trigger the fallback UI and halt execution by // throwing an exception. function error(msg) { - // If multiple arguments were passed, pass them all to the log function. - if (arguments.length > 1) { - var logArguments = ['Error:']; - logArguments.push.apply(logArguments, arguments); - console.log.apply(console, logArguments); - // Join the arguments into a single string for the lines below. - msg = [].join.call(arguments, ' '); - } else { + if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.errors) { console.log('Error: ' + msg); + console.log(backtrace()); } - console.log(backtrace()); UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown); throw new Error(msg); } diff --git a/browser/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js index 943fcc6aaeb..4e497e9a85f 100644 --- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -22,8 +22,8 @@ if (typeof PDFJS === 'undefined') { (typeof window !== 'undefined' ? window : this).PDFJS = {}; } -PDFJS.version = '1.1.24'; -PDFJS.build = 'f6a8110'; +PDFJS.version = '1.1.82'; +PDFJS.build = '71ab5e5'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it @@ -239,17 +239,10 @@ function warn(msg) { // Fatal errors that should trigger the fallback UI and halt execution by // throwing an exception. function error(msg) { - // If multiple arguments were passed, pass them all to the log function. - if (arguments.length > 1) { - var logArguments = ['Error:']; - logArguments.push.apply(logArguments, arguments); - console.log.apply(console, logArguments); - // Join the arguments into a single string for the lines below. - msg = [].join.call(arguments, ' '); - } else { + if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.errors) { console.log('Error: ' + msg); + console.log(backtrace()); } - console.log(backtrace()); UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown); throw new Error(msg); } @@ -3126,6 +3119,7 @@ var Catalog = (function CatalogClosure() { var nodesToVisit = [this.catDict.getRaw('Pages')]; var currentPageIndex = 0; var xref = this.xref; + var checkAllKids = false; function next() { while (nodesToVisit.length) { @@ -3133,7 +3127,7 @@ var Catalog = (function CatalogClosure() { if (isRef(currentNode)) { xref.fetchAsync(currentNode).then(function (obj) { - if ((isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids')))) { + if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) { if (pageIndex === currentPageIndex) { capability.resolve([obj, currentNode]); } else { @@ -3148,12 +3142,17 @@ var Catalog = (function CatalogClosure() { return; } - // must be a child page dictionary + // Must be a child page dictionary. assert( isDict(currentNode), 'page dictionary kid reference points to wrong type of object' ); var count = currentNode.get('Count'); + // If the current node doesn't have any children, avoid getting stuck + // in an empty node further down in the tree (see issue5644.pdf). + if (count === 0) { + checkAllKids = true; + } // Skip nodes where the page can't be. if (currentPageIndex + count <= pageIndex) { currentPageIndex += count; @@ -3162,7 +3161,7 @@ var Catalog = (function CatalogClosure() { var kids = currentNode.get('Kids'); assert(isArray(kids), 'page dictionary kids object is not an array'); - if (count === kids.length) { + if (!checkAllKids && count === kids.length) { // Nodes that don't have the page have been skipped and this is the // bottom of the tree which means the page requested must be a // descendant of this pages node. Ideally we would just resolve the @@ -9140,7 +9139,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { this.cf = dict.get('CF'); this.stmf = dict.get('StmF') || identityName; this.strf = dict.get('StrF') || identityName; - this.eff = dict.get('EFF') || this.strf; + this.eff = dict.get('EFF') || this.stmf; } } @@ -9215,6 +9214,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { return CipherTransformFactory; })(); + var PatternType = { FUNCTION_BASED: 1, AXIAL: 2, @@ -16191,6 +16191,38 @@ var Font = (function FontClosure() { return readUint32(header, 0) === 0x00010000; } + /** + * Helper function for |adjustMapping|. + * @return {boolean} + */ + function isProblematicUnicodeLocation(code) { + if (code <= 0x1F) { // Control chars + return true; + } + if (code >= 0x80 && code <= 0x9F) { // Control chars + return true; + } + if ((code >= 0x2000 && code <= 0x200F) || // General punctuation chars + (code >= 0x2028 && code <= 0x202F) || + (code >= 0x2060 && code <= 0x206F)) { + return true; + } + if (code >= 0xFFF0 && code <= 0xFFFF) { // Specials Unicode block + return true; + } + switch (code) { + case 0x7F: // Control char + case 0xA0: // Non breaking space + case 0xAD: // Soft hyphen + case 0x0E33: // Thai character SARA AM + case 0x2011: // Non breaking hyphen + case 0x205F: // Medium mathematical space + case 0x25CC: // Dotted circle (combining mark) + return true; + } + return false; + } + /** * Rebuilds the char code to glyph ID map by trying to replace the char codes * with their unicode value. It also moves char codes that are in known @@ -16230,15 +16262,7 @@ var Font = (function FontClosure() { // characters probably aren't in the correct position (fixes an issue // with firefox and thuluthfont). if ((usedFontCharCodes[fontCharCode] !== undefined || - fontCharCode <= 0x1f || // Control chars - fontCharCode === 0x7F || // Control char - fontCharCode === 0xAD || // Soft hyphen - fontCharCode === 0xA0 || // Non breaking space - fontCharCode === 0x0E33 || // Thai character SARA AM - fontCharCode === 0x25CC || // Dotted circle (combining mark) - (fontCharCode >= 0x80 && fontCharCode <= 0x9F) || // Control chars - // Prevent drawing characters in the specials unicode block. - (fontCharCode >= 0xFFF0 && fontCharCode <= 0xFFFF) || + isProblematicUnicodeLocation(fontCharCode) || (isSymbolic && isIdentityUnicode)) && nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END) { // Room left. // Loop to try and find a free spot in the private use area. @@ -30995,25 +31019,25 @@ var StreamsSequenceStream = (function StreamsSequenceStreamClosure() { })(); var FlateStream = (function FlateStreamClosure() { - var codeLenCodeMap = new Uint32Array([ + var codeLenCodeMap = new Int32Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]); - var lengthDecode = new Uint32Array([ + var lengthDecode = new Int32Array([ 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102 ]); - var distDecode = new Uint32Array([ + var distDecode = new Int32Array([ 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001 ]); - var fixedLitCodeTab = [new Uint32Array([ + var fixedLitCodeTab = [new Int32Array([ 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, @@ -31080,7 +31104,7 @@ var FlateStream = (function FlateStreamClosure() { 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff ]), 9]; - var fixedDistCodeTab = [new Uint32Array([ + var fixedDistCodeTab = [new Int32Array([ 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, @@ -31177,7 +31201,7 @@ var FlateStream = (function FlateStreamClosure() { // build the table var size = 1 << maxLen; - var codes = new Uint32Array(size); + var codes = new Int32Array(size); for (var len = 1, code = 0, skip = 2; len <= maxLen; ++len, code <<= 1, skip <<= 1) { diff --git a/browser/extensions/pdfjs/content/pdfjschildbootstrap.js b/browser/extensions/pdfjs/content/pdfjschildbootstrap.js index 68e7c28b9fa..788ec68b1a8 100644 --- a/browser/extensions/pdfjs/content/pdfjschildbootstrap.js +++ b/browser/extensions/pdfjs/content/pdfjschildbootstrap.js @@ -31,7 +31,8 @@ Components.utils.import('resource://pdf.js/PdfjsContentUtils.jsm'); // init content utils shim pdfjs will use to access privileged apis. PdfjsContentUtils.init(); -if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) { +if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) { // register various pdfjs factories that hook us into content loading. PdfJs.updateRegistration(); } + diff --git a/browser/extensions/pdfjs/content/web/viewer.css b/browser/extensions/pdfjs/content/web/viewer.css index d87ba44f80a..bf57df85343 100644 --- a/browser/extensions/pdfjs/content/web/viewer.css +++ b/browser/extensions/pdfjs/content/web/viewer.css @@ -102,12 +102,12 @@ box-shadow: 0px 2px 10px #ff0; } -:-moz-full-screen .pdfViewer .page { +.pdfPresentationMode:-moz-full-screen .pdfViewer .page { margin-bottom: 100%; border: 0; } -:fullscreen .pdfViewer .page { +.pdfPresentationMode:fullscreen .pdfViewer .page { margin-bottom: 100%; border: 0; } @@ -184,7 +184,7 @@ select { display: none !important; } -#viewerContainer:-moz-full-screen { +#viewerContainer.pdfPresentationMode:-moz-full-screen { top: 0px; border-top: 2px solid transparent; background-color: #000; @@ -195,7 +195,7 @@ select { -moz-user-select: none; } -#viewerContainer:fullscreen { +#viewerContainer.pdfPresentationMode:fullscreen { top: 0px; border-top: 2px solid transparent; background-color: #000; @@ -206,24 +206,24 @@ select { -moz-user-select: none; } -:-moz-full-screen a:not(.internalLink) { +.pdfPresentationMode:-moz-full-screen a:not(.internalLink) { display: none; } -:fullscreen a:not(.internalLink) { +.pdfPresentationMode:fullscreen a:not(.internalLink) { display: none; } -:-moz-full-screen .textLayer > div { +.pdfPresentationMode:-moz-full-screen .textLayer > div { cursor: none; } -:fullscreen .textLayer > div { +.pdfPresentationMode:fullscreen .textLayer > div { cursor: none; } -#viewerContainer.presentationControls, -#viewerContainer.presentationControls .textLayer > div { +.pdfPresentationMode.pdfPresentationModeControls > *, +.pdfPresentationMode.pdfPresentationModeControls .textLayer > div { cursor: default; } diff --git a/browser/extensions/pdfjs/content/web/viewer.html b/browser/extensions/pdfjs/content/web/viewer.html index 74809570a87..056bfc9fb67 100644 --- a/browser/extensions/pdfjs/content/web/viewer.html +++ b/browser/extensions/pdfjs/content/web/viewer.html @@ -182,7 +182,6 @@ http://sourceforge.net/adobe/cmap/wiki/License/ - Current View diff --git a/browser/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js index 15bd5dc7036..0be41038b28 100644 --- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -15,10 +15,10 @@ * limitations under the License. */ /* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, ProgressBar, - DownloadManager, getFileName, scrollIntoView, getPDFFileNameFromURL, + DownloadManager, getFileName, getPDFFileNameFromURL, PDFHistory, Preferences, SidebarView, ViewHistory, Stats, PDFThumbnailViewer, URL, noContextMenuHandler, SecondaryToolbar, - PasswordPrompt, PresentationMode, HandTool, Promise, + PasswordPrompt, PDFPresentationMode, HandTool, Promise, DocumentProperties, PDFOutlineView, PDFAttachmentView, OverlayManager, PDFFindController, PDFFindBar, getVisibleElements, watchScroll, PDFViewer, PDFRenderingQueue, PresentationModeState, @@ -1343,6 +1343,7 @@ var PDFHistory = { this.reInitialized = false; this.allowHashChange = true; this.historyUnlocked = true; + this.isViewerInPresentationMode = false; this.previousHash = window.location.hash.substring(1); this.currentBookmark = ''; @@ -1434,6 +1435,10 @@ var PDFHistory = { // the 'DOMContentLoaded' event is not fired on 'pageshow'. window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false); }, false); + + window.addEventListener('presentationmodechanged', function(e) { + self.isViewerInPresentationMode = !!e.detail.active; + }); }, _isStateObjectDefined: function pdfHistory_isStateObjectDefined(state) { @@ -1585,7 +1590,7 @@ var PDFHistory = { return null; } var params = { hash: this.currentBookmark, page: this.currentPage }; - if (PresentationMode.active) { + if (this.isViewerInPresentationMode) { params.hash = null; } return params; @@ -1684,7 +1689,6 @@ var SecondaryToolbar = { initialize: function secondaryToolbarInitialize(options) { this.toolbar = options.toolbar; - this.presentationMode = options.presentationMode; this.documentProperties = options.documentProperties; this.buttonContainer = this.toolbar.firstElementChild; @@ -1731,7 +1735,7 @@ var SecondaryToolbar = { // Event handling functions. presentationModeClick: function secondaryToolbarPresentationModeClick(evt) { - this.presentationMode.request(); + PDFViewerApplication.requestPresentationMode(); this.close(); }, @@ -1823,237 +1827,373 @@ var SecondaryToolbar = { }; +var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500; // in ms var DELAY_BEFORE_HIDING_CONTROLS = 3000; // in ms -var SELECTOR = 'presentationControls'; -var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1000; // in ms +var ACTIVE_SELECTOR = 'pdfPresentationMode'; +var CONTROLS_SELECTOR = 'pdfPresentationModeControls'; -var PresentationMode = { - active: false, - args: null, - contextMenuOpen: false, - - initialize: function presentationModeInitialize(options) { - this.container = options.container; - this.secondaryToolbar = options.secondaryToolbar; - - this.viewer = this.container.firstElementChild; - - this.firstPage = options.firstPage; - this.lastPage = options.lastPage; - this.pageRotateCw = options.pageRotateCw; - this.pageRotateCcw = options.pageRotateCcw; - - this.firstPage.addEventListener('click', function() { - this.contextMenuOpen = false; - this.secondaryToolbar.firstPageClick(); - }.bind(this)); - this.lastPage.addEventListener('click', function() { - this.contextMenuOpen = false; - this.secondaryToolbar.lastPageClick(); - }.bind(this)); - - this.pageRotateCw.addEventListener('click', function() { - this.contextMenuOpen = false; - this.secondaryToolbar.pageRotateCwClick(); - }.bind(this)); - this.pageRotateCcw.addEventListener('click', function() { - this.contextMenuOpen = false; - this.secondaryToolbar.pageRotateCcwClick(); - }.bind(this)); - }, - - get isFullscreen() { - return (document.fullscreenElement || - document.mozFullScreen || - document.webkitIsFullScreen || - document.msFullscreenElement); - }, +/** + * @typedef {Object} PDFPresentationModeOptions + * @property {HTMLDivElement} container - The container for the viewer element. + * @property {HTMLDivElement} viewer - (optional) The viewer element. + * @property {PDFThumbnailViewer} pdfThumbnailViewer - (optional) The thumbnail + * viewer. + * @property {Array} contextMenuItems - (optional) The menuitems that are added + * to the context menu in Presentation Mode. + */ +/** + * @class + */ +var PDFPresentationMode = (function PDFPresentationModeClosure() { /** - * Initialize a timeout that is used to specify switchInProgress when the - * browser transitions to fullscreen mode. Since resize events are triggered - * multiple times during the switch to fullscreen mode, this is necessary in - * order to prevent the page from being scrolled partially, or completely, - * out of view when Presentation Mode is enabled. - * Note: This is only an issue at certain zoom levels, e.g. 'page-width'. + * @constructs PDFPresentationMode + * @param {PDFPresentationModeOptions} options */ - _setSwitchInProgress: function presentationMode_setSwitchInProgress() { - if (this.switchInProgress) { - clearTimeout(this.switchInProgress); - } - this.switchInProgress = setTimeout(function switchInProgressTimeout() { - delete this.switchInProgress; - this._notifyStateChange(); - }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); - }, + function PDFPresentationMode(options) { + this.container = options.container; + this.viewer = options.viewer || options.container.firstElementChild; + this.pdfThumbnailViewer = options.pdfThumbnailViewer || null; + var contextMenuItems = options.contextMenuItems || null; - _resetSwitchInProgress: function presentationMode_resetSwitchInProgress() { - if (this.switchInProgress) { - clearTimeout(this.switchInProgress); - delete this.switchInProgress; - } - }, - - request: function presentationModeRequest() { - if (!PDFViewerApplication.supportsFullscreen || this.isFullscreen || - !this.viewer.hasChildNodes()) { - return false; - } - this._setSwitchInProgress(); - this._notifyStateChange(); - - if (this.container.requestFullscreen) { - this.container.requestFullscreen(); - } else if (this.container.mozRequestFullScreen) { - this.container.mozRequestFullScreen(); - } else if (this.container.webkitRequestFullscreen) { - this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } else if (this.container.msRequestFullscreen) { - this.container.msRequestFullscreen(); - } else { - return false; - } - - this.args = { - page: PDFViewerApplication.page, - previousScale: PDFViewerApplication.currentScaleValue - }; - - return true; - }, - - _notifyStateChange: function presentationModeNotifyStateChange() { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('presentationmodechanged', true, true, { - active: PresentationMode.active, - switchInProgress: !!PresentationMode.switchInProgress - }); - window.dispatchEvent(event); - }, - - enter: function presentationModeEnter() { - this.active = true; - this._resetSwitchInProgress(); - this._notifyStateChange(); - - // Ensure that the correct page is scrolled into view when entering - // Presentation Mode, by waiting until fullscreen mode in enabled. - // Note: This is only necessary in non-Mozilla browsers. - setTimeout(function enterPresentationModeTimeout() { - PDFViewerApplication.page = this.args.page; - PDFViewerApplication.setScale('page-fit', true); - }.bind(this), 0); - - window.addEventListener('mousemove', this.mouseMove, false); - window.addEventListener('mousedown', this.mouseDown, false); - window.addEventListener('contextmenu', this.contextMenu, false); - - this.showControls(); - HandTool.enterPresentationMode(); + this.active = false; + this.args = null; this.contextMenuOpen = false; - this.container.setAttribute('contextmenu', 'viewerContextMenu'); + this.mouseScrollTimeStamp = 0; + this.mouseScrollDelta = 0; - // Text selection is disabled in Presentation Mode, thus it's not possible - // for the user to deselect text that is selected (e.g. with "Select all") - // when entering Presentation Mode, hence we remove any active selection. - window.getSelection().removeAllRanges(); - }, - - exit: function presentationModeExit() { - var page = PDFViewerApplication.page; - - // Ensure that the correct page is scrolled into view when exiting - // Presentation Mode, by waiting until fullscreen mode is disabled. - // Note: This is only necessary in non-Mozilla browsers. - setTimeout(function exitPresentationModeTimeout() { - this.active = false; - this._notifyStateChange(); - - PDFViewerApplication.setScale(this.args.previousScale, true); - PDFViewerApplication.page = page; - this.args = null; - }.bind(this), 0); - - window.removeEventListener('mousemove', this.mouseMove, false); - window.removeEventListener('mousedown', this.mouseDown, false); - window.removeEventListener('contextmenu', this.contextMenu, false); - - this.hideControls(); - PDFViewerApplication.clearMouseScrollState(); - HandTool.exitPresentationMode(); - this.container.removeAttribute('contextmenu'); - this.contextMenuOpen = false; - - // Ensure that the thumbnail of the current page is visible - // when exiting presentation mode. - scrollIntoView(document.getElementById('thumbnailContainer' + page)); - }, - - showControls: function presentationModeShowControls() { - if (this.controlsTimeout) { - clearTimeout(this.controlsTimeout); - } else { - this.container.classList.add(SELECTOR); - } - this.controlsTimeout = setTimeout(function hideControlsTimeout() { - this.container.classList.remove(SELECTOR); - delete this.controlsTimeout; - }.bind(this), DELAY_BEFORE_HIDING_CONTROLS); - }, - - hideControls: function presentationModeHideControls() { - if (!this.controlsTimeout) { - return; - } - this.container.classList.remove(SELECTOR); - clearTimeout(this.controlsTimeout); - delete this.controlsTimeout; - }, - - mouseMove: function presentationModeMouseMove(evt) { - PresentationMode.showControls(); - }, - - mouseDown: function presentationModeMouseDown(evt) { - var self = PresentationMode; - if (self.contextMenuOpen) { - self.contextMenuOpen = false; - evt.preventDefault(); - return; - } - - if (evt.button === 0) { - // Enable clicking of links in presentation mode. Please note: - // Only links pointing to destinations in the current PDF document work. - var isInternalLink = (evt.target.href && - evt.target.classList.contains('internalLink')); - if (!isInternalLink) { - // Unless an internal link was clicked, advance one page. - evt.preventDefault(); - PDFViewerApplication.page += (evt.shiftKey ? -1 : 1); + if (contextMenuItems) { + for (var i = 0, ii = contextMenuItems.length; i < ii; i++) { + var item = contextMenuItems[i]; + item.element.addEventListener('click', function (handler) { + this.contextMenuOpen = false; + handler(); + }.bind(this, item.handler)); } } - }, - - contextMenu: function presentationModeContextMenu(evt) { - PresentationMode.contextMenuOpen = true; } -}; -(function presentationModeClosure() { - function presentationModeChange(e) { - if (PresentationMode.isFullscreen) { - PresentationMode.enter(); - } else { - PresentationMode.exit(); + PDFPresentationMode.prototype = { + /** + * Request the browser to enter fullscreen mode. + * @returns {boolean} Indicating if the request was successful. + */ + request: function PDFPresentationMode_request() { + if (this.switchInProgress || this.active || + !this.viewer.hasChildNodes()) { + return false; + } + this._addFullscreenChangeListeners(); + this._setSwitchInProgress(); + this._notifyStateChange(); + + if (this.container.requestFullscreen) { + this.container.requestFullscreen(); + } else if (this.container.mozRequestFullScreen) { + this.container.mozRequestFullScreen(); + } else if (this.container.webkitRequestFullscreen) { + this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); + } else if (this.container.msRequestFullscreen) { + this.container.msRequestFullscreen(); + } else { + return false; + } + + this.args = { + page: PDFViewerApplication.page, + previousScale: PDFViewerApplication.currentScaleValue + }; + + return true; + }, + + /** + * Switches page when the user scrolls (using a scroll wheel or a touchpad) + * with large enough motion, to prevent accidental page switches. + * @param {number} delta - The delta value from the mouse event. + */ + mouseScroll: function PDFPresentationMode_mouseScroll(delta) { + if (!this.active) { + return; + } + var MOUSE_SCROLL_COOLDOWN_TIME = 50; + var PAGE_SWITCH_THRESHOLD = 120; + var PageSwitchDirection = { + UP: -1, + DOWN: 1 + }; + + var currentTime = (new Date()).getTime(); + var storedTime = this.mouseScrollTimeStamp; + + // If we've already switched page, avoid accidentally switching again. + if (currentTime > storedTime && + currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) { + return; + } + // If the scroll direction changed, reset the accumulated scroll delta. + if ((this.mouseScrollDelta > 0 && delta < 0) || + (this.mouseScrollDelta < 0 && delta > 0)) { + this._resetMouseScrollState(); + } + this.mouseScrollDelta += delta; + + if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) { + var pageSwitchDirection = (this.mouseScrollDelta > 0) ? + PageSwitchDirection.UP : PageSwitchDirection.DOWN; + var page = PDFViewerApplication.page; + this._resetMouseScrollState(); + + // If we're at the first/last page, we don't need to do anything. + if ((page === 1 && pageSwitchDirection === PageSwitchDirection.UP) || + (page === PDFViewerApplication.pagesCount && + pageSwitchDirection === PageSwitchDirection.DOWN)) { + return; + } + PDFViewerApplication.page = (page + pageSwitchDirection); + this.mouseScrollTimeStamp = currentTime; + } + }, + + get isFullscreen() { + return !!(document.fullscreenElement || + document.mozFullScreen || + document.webkitIsFullScreen || + document.msFullscreenElement); + }, + + /** + * @private + */ + _notifyStateChange: function PDFPresentationMode_notifyStateChange() { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('presentationmodechanged', true, true, { + active: this.active, + switchInProgress: !!this.switchInProgress + }); + window.dispatchEvent(event); + }, + + /** + * Used to initialize a timeout when requesting Presentation Mode, + * i.e. when the browser is requested to enter fullscreen mode. + * This timeout is used to prevent the current page from being scrolled + * partially, or completely, out of view when entering Presentation Mode. + * NOTE: This issue seems limited to certain zoom levels (e.g. page-width). + * @private + */ + _setSwitchInProgress: function PDFPresentationMode_setSwitchInProgress() { + if (this.switchInProgress) { + clearTimeout(this.switchInProgress); + } + this.switchInProgress = setTimeout(function switchInProgressTimeout() { + this._removeFullscreenChangeListeners(); + delete this.switchInProgress; + this._notifyStateChange(); + }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); + }, + + /** + * @private + */ + _resetSwitchInProgress: + function PDFPresentationMode_resetSwitchInProgress() { + if (this.switchInProgress) { + clearTimeout(this.switchInProgress); + delete this.switchInProgress; + } + }, + + /** + * @private + */ + _enter: function PDFPresentationMode_enter() { + this.active = true; + this._resetSwitchInProgress(); + this._notifyStateChange(); + this.container.classList.add(ACTIVE_SELECTOR); + + // Ensure that the correct page is scrolled into view when entering + // Presentation Mode, by waiting until fullscreen mode in enabled. + setTimeout(function enterPresentationModeTimeout() { + PDFViewerApplication.page = this.args.page; + PDFViewerApplication.setScale('page-fit', true); + }.bind(this), 0); + + this._addWindowListeners(); + this._showControls(); + this.contextMenuOpen = false; + this.container.setAttribute('contextmenu', 'viewerContextMenu'); + + // Text selection is disabled in Presentation Mode, thus it's not possible + // for the user to deselect text that is selected (e.g. with "Select all") + // when entering Presentation Mode, hence we remove any active selection. + window.getSelection().removeAllRanges(); + }, + + /** + * @private + */ + _exit: function PDFPresentationMode_exit() { + var page = PDFViewerApplication.page; + this.container.classList.remove(ACTIVE_SELECTOR); + + // Ensure that the correct page is scrolled into view when exiting + // Presentation Mode, by waiting until fullscreen mode is disabled. + setTimeout(function exitPresentationModeTimeout() { + this.active = false; + this._removeFullscreenChangeListeners(); + this._notifyStateChange(); + + PDFViewerApplication.setScale(this.args.previousScale, true); + PDFViewerApplication.page = page; + this.args = null; + }.bind(this), 0); + + this._removeWindowListeners(); + this._hideControls(); + this._resetMouseScrollState(); + this.container.removeAttribute('contextmenu'); + this.contextMenuOpen = false; + + if (this.pdfThumbnailViewer) { + this.pdfThumbnailViewer.ensureThumbnailVisible(page); + } + }, + + /** + * @private + */ + _mouseDown: function PDFPresentationMode_mouseDown(evt) { + if (this.contextMenuOpen) { + this.contextMenuOpen = false; + evt.preventDefault(); + return; + } + if (evt.button === 0) { + // Enable clicking of links in presentation mode. Please note: + // Only links pointing to destinations in the current PDF document work. + var isInternalLink = (evt.target.href && + evt.target.classList.contains('internalLink')); + if (!isInternalLink) { + // Unless an internal link was clicked, advance one page. + evt.preventDefault(); + PDFViewerApplication.page += (evt.shiftKey ? -1 : 1); + } + } + }, + + /** + * @private + */ + _contextMenu: function PDFPresentationMode_contextMenu() { + this.contextMenuOpen = true; + }, + + /** + * @private + */ + _showControls: function PDFPresentationMode_showControls() { + if (this.controlsTimeout) { + clearTimeout(this.controlsTimeout); + } else { + this.container.classList.add(CONTROLS_SELECTOR); + } + this.controlsTimeout = setTimeout(function showControlsTimeout() { + this.container.classList.remove(CONTROLS_SELECTOR); + delete this.controlsTimeout; + }.bind(this), DELAY_BEFORE_HIDING_CONTROLS); + }, + + /** + * @private + */ + _hideControls: function PDFPresentationMode_hideControls() { + if (!this.controlsTimeout) { + return; + } + clearTimeout(this.controlsTimeout); + this.container.classList.remove(CONTROLS_SELECTOR); + delete this.controlsTimeout; + }, + + /** + * Resets the properties used for tracking mouse scrolling events. + * @private + */ + _resetMouseScrollState: + function PDFPresentationMode_resetMouseScrollState() { + this.mouseScrollTimeStamp = 0; + this.mouseScrollDelta = 0; + }, + + /** + * @private + */ + _addWindowListeners: function PDFPresentationMode_addWindowListeners() { + this.showControlsBind = this._showControls.bind(this); + this.mouseDownBind = this._mouseDown.bind(this); + this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this); + this.contextMenuBind = this._contextMenu.bind(this); + + window.addEventListener('mousemove', this.showControlsBind); + window.addEventListener('mousedown', this.mouseDownBind); + window.addEventListener('keydown', this.resetMouseScrollStateBind); + window.addEventListener('contextmenu', this.contextMenuBind); + }, + + /** + * @private + */ + _removeWindowListeners: + function PDFPresentationMode_removeWindowListeners() { + window.removeEventListener('mousemove', this.showControlsBind); + window.removeEventListener('mousedown', this.mouseDownBind); + window.removeEventListener('keydown', this.resetMouseScrollStateBind); + window.removeEventListener('contextmenu', this.contextMenuBind); + + delete this.showControlsBind; + delete this.mouseDownBind; + delete this.resetMouseScrollStateBind; + delete this.contextMenuBind; + }, + + /** + * @private + */ + _fullscreenChange: function PDFPresentationMode_fullscreenChange() { + if (this.isFullscreen) { + this._enter(); + } else { + this._exit(); + } + }, + + /** + * @private + */ + _addFullscreenChangeListeners: + function PDFPresentationMode_addFullscreenChangeListeners() { + this.fullscreenChangeBind = this._fullscreenChange.bind(this); + + window.addEventListener('fullscreenchange', this.fullscreenChangeBind); + window.addEventListener('mozfullscreenchange', this.fullscreenChangeBind); + }, + + /** + * @private + */ + _removeFullscreenChangeListeners: + function PDFPresentationMode_removeFullscreenChangeListeners() { + window.removeEventListener('fullscreenchange', this.fullscreenChangeBind); + window.removeEventListener('mozfullscreenchange', + this.fullscreenChangeBind); + + delete this.fullscreenChangeBind; } - } + }; - window.addEventListener('fullscreenchange', presentationModeChange, false); - window.addEventListener('mozfullscreenchange', presentationModeChange, false); - window.addEventListener('webkitfullscreenchange', presentationModeChange, - false); - window.addEventListener('MSFullscreenChange', presentationModeChange, false); + return PDFPresentationMode; })(); @@ -2311,6 +2451,17 @@ var HandTool = { } }.bind(this), function rejected(reason) {}); }.bind(this)); + + window.addEventListener('presentationmodechanged', function (evt) { + if (evt.detail.switchInProgress) { + return; + } + if (evt.detail.active) { + this.enterPresentationMode(); + } else { + this.exitPresentationMode(); + } + }.bind(this)); } }, @@ -2659,8 +2810,7 @@ var DocumentProperties = { }, parseDate: function documentPropertiesParseDate(inputDate) { - // This is implemented according to the PDF specification (see - // http://www.gnupdf.org/Date for an overview), but note that + // This is implemented according to the PDF specification, but note that // Adobe Reader doesn't handle changing the date to universal time // and doesn't use the user's time zone (they're effectively ignoring // the HH' and mm' parts of the date string). @@ -2942,6 +3092,7 @@ var PDFPageView = (function PDFPageViewClosure() { div.className = 'page'; div.style.width = Math.floor(this.viewport.width) + 'px'; div.style.height = Math.floor(this.viewport.height) + 'px'; + div.setAttribute('data-page-number', this.id); this.div = div; container.appendChild(div); @@ -4296,11 +4447,8 @@ var PDFViewer = (function pdfViewer() { if (!noScroll) { var page = this._currentPageNumber, dest; - var inPresentationMode = - this.presentationModeState === PresentationModeState.CHANGING || - this.presentationModeState === PresentationModeState.FULLSCREEN; - if (this.location && !inPresentationMode && - !IGNORE_CURRENT_POSITION_ON_ZOOM) { + if (this.location && !IGNORE_CURRENT_POSITION_ON_ZOOM && + !(this.isInPresentationMode || this.isChangingPresentationMode)) { page = this.location.pageNumber; dest = [null, { name: 'XYZ' }, this.location.left, this.location.top, null]; @@ -4324,11 +4472,9 @@ var PDFViewer = (function pdfViewer() { if (!currentPage) { return; } - var inPresentationMode = - this.presentationModeState === PresentationModeState.FULLSCREEN; - var hPadding = (inPresentationMode || this.removePageBorders) ? + var hPadding = (this.isInPresentationMode || this.removePageBorders) ? 0 : SCROLLBAR_PADDING; - var vPadding = (inPresentationMode || this.removePageBorders) ? + var vPadding = (this.isInPresentationMode || this.removePageBorders) ? 0 : VERTICAL_PADDING; var pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale; @@ -4374,8 +4520,7 @@ var PDFViewer = (function pdfViewer() { dest) { var pageView = this.pages[pageNumber - 1]; - if (this.presentationModeState === - PresentationModeState.FULLSCREEN) { + if (this.isInPresentationMode) { if (this.linkService.page !== pageView.id) { // Avoid breaking getVisiblePages in presentation mode. this.linkService.page = pageView.id; @@ -4529,7 +4674,7 @@ var PDFViewer = (function pdfViewer() { currentId = visiblePages[0].id; } - if (this.presentationModeState !== PresentationModeState.FULLSCREEN) { + if (!this.isInPresentationMode) { this.currentPageNumber = currentId; } @@ -4554,13 +4699,21 @@ var PDFViewer = (function pdfViewer() { this.container.blur(); }, + get isInPresentationMode() { + return this.presentationModeState === PresentationModeState.FULLSCREEN; + }, + + get isChangingPresentationMode() { + return this.PresentationModeState === PresentationModeState.CHANGING; + }, + get isHorizontalScrollbarEnabled() { - return (this.presentationModeState === PresentationModeState.FULLSCREEN ? + return (this.isInPresentationMode ? false : (this.container.scrollWidth > this.container.clientWidth)); }, _getVisiblePages: function () { - if (this.presentationModeState !== PresentationModeState.FULLSCREEN) { + if (!this.isInPresentationMode) { return getVisibleElements(this.container, this.pages, true); } else { // The algorithm in getVisibleElements doesn't work in all browsers and @@ -4631,13 +4784,11 @@ var PDFViewer = (function pdfViewer() { * @returns {TextLayerBuilder} */ createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) { - var isViewerInPresentationMode = - this.presentationModeState === PresentationModeState.FULLSCREEN; return new TextLayerBuilder({ textLayerDiv: textLayerDiv, pageIndex: pageIndex, viewport: viewport, - findController: isViewerInPresentationMode ? null : this.findController + findController: this.isInPresentationMode ? null : this.findController }); }, @@ -5385,15 +5536,16 @@ var PDFViewerApplication = { pdfThumbnailViewer: null, /** @type {PDFRenderingQueue} */ pdfRenderingQueue: null, + /** @type {PDFPresentationMode} */ + pdfPresentationMode: null, pageRotation: 0, updateScaleControls: true, isInitialViewSet: false, animationStartedPromise: null, - mouseScrollTimeStamp: 0, - mouseScrollDelta: 0, preferenceSidebarViewOnLoad: SidebarView.NONE, preferencePdfBugEnabled: false, preferenceShowPreviousViewOnLoad: true, + preferenceDefaultZoomValue: '', isViewerEmbedded: (window.parent !== window), url: '', @@ -5451,7 +5603,6 @@ var PDFViewerApplication = { SecondaryToolbar.initialize({ toolbar: document.getElementById('secondaryToolbar'), - presentationMode: PresentationMode, toggleButton: document.getElementById('secondaryToolbarToggle'), presentationModeButton: document.getElementById('secondaryPresentationMode'), @@ -5467,14 +5618,24 @@ var PDFViewerApplication = { documentPropertiesButton: document.getElementById('documentProperties') }); - PresentationMode.initialize({ - container: container, - secondaryToolbar: SecondaryToolbar, - firstPage: document.getElementById('contextFirstPage'), - lastPage: document.getElementById('contextLastPage'), - pageRotateCw: document.getElementById('contextPageRotateCw'), - pageRotateCcw: document.getElementById('contextPageRotateCcw') - }); + if (this.supportsFullscreen) { + var toolbar = SecondaryToolbar; + this.pdfPresentationMode = new PDFPresentationMode({ + container: container, + viewer: viewer, + pdfThumbnailViewer: this.pdfThumbnailViewer, + contextMenuItems: [ + { element: document.getElementById('contextFirstPage'), + handler: toolbar.firstPageClick.bind(toolbar) }, + { element: document.getElementById('contextLastPage'), + handler: toolbar.lastPageClick.bind(toolbar) }, + { element: document.getElementById('contextPageRotateCw'), + handler: toolbar.pageRotateCwClick.bind(toolbar) }, + { element: document.getElementById('contextPageRotateCcw'), + handler: toolbar.pageRotateCcwClick.bind(toolbar) } + ] + }); + } PasswordPrompt.initialize({ overlayName: 'passwordOverlay', @@ -5514,9 +5675,9 @@ var PDFViewerApplication = { }), Preferences.get('showPreviousViewOnLoad').then(function resolved(value) { self.preferenceShowPreviousViewOnLoad = value; - if (!value && window.history.state) { - window.history.replaceState(null, ''); - } + }), + Preferences.get('defaultZoomValue').then(function resolved(value) { + self.preferenceDefaultZoomValue = value; }), Preferences.get('disableTextLayer').then(function resolved(value) { if (PDFJS.disableTextLayer === true) { @@ -5542,7 +5703,6 @@ var PDFViewerApplication = { Preferences.get('useOnlyCssZoom').then(function resolved(value) { PDFJS.useOnlyCssZoom = value; }) - // TODO move more preferences and other async stuff here ]).catch(function (reason) { }); @@ -5596,8 +5756,8 @@ var PDFViewerApplication = { get supportsFullscreen() { var doc = document.documentElement; - var support = doc.requestFullscreen || doc.mozRequestFullScreen || - doc.webkitRequestFullScreen || doc.msRequestFullscreen; + var support = !!(doc.requestFullscreen || doc.mozRequestFullScreen || + doc.webkitRequestFullScreen || doc.msRequestFullscreen); if (document.fullscreenEnabled === false || document.mozFullScreenEnabled === false || @@ -6103,46 +6263,37 @@ var PDFViewerApplication = { if (!PDFJS.disableHistory && !self.isViewerEmbedded) { // The browsing history is only enabled when the viewer is standalone, // i.e. not when it is embedded in a web page. + if (!self.preferenceShowPreviousViewOnLoad && window.history.state) { + window.history.replaceState(null, ''); + } PDFHistory.initialize(self.documentFingerprint, self); } - }); - // Fetch the necessary preference values. - var defaultZoomValue; - var defaultZoomValuePromise = - Preferences.get('defaultZoomValue').then(function (prefValue) { - defaultZoomValue = prefValue; - }); + store.initializedPromise.then(function resolved() { + var storedHash = null; + if (self.preferenceShowPreviousViewOnLoad && + store.get('exists', false)) { + var pageNum = store.get('page', '1'); + var zoom = self.preferenceDefaultZoomValue || + store.get('zoom', self.pdfViewer.currentScale); + var left = store.get('scrollLeft', '0'); + var top = store.get('scrollTop', '0'); - var storePromise = store.initializedPromise; - Promise.all([firstPagePromise, storePromise, defaultZoomValuePromise]).then( - function resolved() { - var storedHash = null; - if (PDFViewerApplication.preferenceShowPreviousViewOnLoad && - store.get('exists', false)) { - var pageNum = store.get('page', '1'); - var zoom = defaultZoomValue || - store.get('zoom', self.pdfViewer.currentScale); - var left = store.get('scrollLeft', '0'); - var top = store.get('scrollTop', '0'); + storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' + + left + ',' + top; + } else if (self.preferenceDefaultZoomValue) { + storedHash = 'page=1&zoom=' + self.preferenceDefaultZoomValue; + } + self.setInitialView(storedHash, scale); - storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' + - left + ',' + top; - } else if (defaultZoomValue) { - storedHash = 'page=1&zoom=' + defaultZoomValue; - } - self.setInitialView(storedHash, scale); - - // Make all navigation keys work on document load, - // unless the viewer is embedded in a web page. - if (!self.isViewerEmbedded) { - self.pdfViewer.focus(); - self.pdfViewer.blur(); - } - }, function rejected(reason) { - console.error(reason); - - firstPagePromise.then(function () { + // Make all navigation keys work on document load, + // unless the viewer is embedded in a web page. + if (!self.isViewerEmbedded) { + self.pdfViewer.focus(); + self.pdfViewer.blur(); + } + }, function rejected(reason) { + console.error(reason); self.setInitialView(null, scale); }); }); @@ -6554,72 +6705,21 @@ var PDFViewerApplication = { this.pdfViewer.scrollPageIntoView(pageNumber); }, - /** - * This function flips the page in presentation mode if the user scrolls up - * or down with large enough motion and prevents page flipping too often. - * - * @this {PDFView} - * @param {number} mouseScrollDelta The delta value from the mouse event. - */ - mouseScroll: function pdfViewMouseScroll(mouseScrollDelta) { - var MOUSE_SCROLL_COOLDOWN_TIME = 50; - - var currentTime = (new Date()).getTime(); - var storedTime = this.mouseScrollTimeStamp; - - // In case one page has already been flipped there is a cooldown time - // which has to expire before next page can be scrolled on to. - if (currentTime > storedTime && - currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) { + requestPresentationMode: function pdfViewRequestPresentationMode() { + if (!this.pdfPresentationMode) { return; } - - // In case the user decides to scroll to the opposite direction than before - // clear the accumulated delta. - if ((this.mouseScrollDelta > 0 && mouseScrollDelta < 0) || - (this.mouseScrollDelta < 0 && mouseScrollDelta > 0)) { - this.clearMouseScrollState(); - } - - this.mouseScrollDelta += mouseScrollDelta; - - var PAGE_FLIP_THRESHOLD = 120; - if (Math.abs(this.mouseScrollDelta) >= PAGE_FLIP_THRESHOLD) { - - var PageFlipDirection = { - UP: -1, - DOWN: 1 - }; - - // In presentation mode scroll one page at a time. - var pageFlipDirection = (this.mouseScrollDelta > 0) ? - PageFlipDirection.UP : - PageFlipDirection.DOWN; - this.clearMouseScrollState(); - var currentPage = this.page; - - // In case we are already on the first or the last page there is no need - // to do anything. - if ((currentPage === 1 && pageFlipDirection === PageFlipDirection.UP) || - (currentPage === this.pagesCount && - pageFlipDirection === PageFlipDirection.DOWN)) { - return; - } - - this.page += pageFlipDirection; - this.mouseScrollTimeStamp = currentTime; - } + this.pdfPresentationMode.request(); }, /** - * This function clears the member attributes used with mouse scrolling in - * presentation mode. - * - * @this {PDFView} + * @param {number} delta - The delta value from the mouse event. */ - clearMouseScrollState: function pdfViewClearMouseScrollState() { - this.mouseScrollTimeStamp = 0; - this.mouseScrollDelta = 0; + scrollPresentationMode: function pdfViewScrollPresentationMode(delta) { + if (!this.pdfPresentationMode) { + return; + } + this.pdfPresentationMode.mouseScroll(delta); } }; @@ -6814,10 +6914,6 @@ function webViewerInitialized() { PDFViewerApplication.initPassiveLoading(); return; - - if (file) { - PDFViewerApplication.open(file, 0); - } } document.addEventListener('DOMContentLoaded', webViewerLoad, true); @@ -7064,10 +7160,12 @@ function handleMouseWheel(evt) { evt.wheelDelta / MOUSE_WHEEL_DELTA_FACTOR; var direction = (ticks < 0) ? 'zoomOut' : 'zoomIn'; - if (PresentationMode.active) { + if (PDFViewerApplication.pdfViewer.isInPresentationMode) { evt.preventDefault(); - PDFViewerApplication.mouseScroll(ticks * MOUSE_WHEEL_DELTA_FACTOR); - } else if (evt.ctrlKey) { // Only zoom the pages, not the entire viewer + PDFViewerApplication.scrollPresentationMode(ticks * + MOUSE_WHEEL_DELTA_FACTOR); + } else if (evt.ctrlKey || evt.metaKey) { + // Only zoom the pages, not the entire viewer. evt.preventDefault(); PDFViewerApplication[direction](Math.abs(ticks)); } @@ -7077,15 +7175,9 @@ window.addEventListener('DOMMouseScroll', handleMouseWheel); window.addEventListener('mousewheel', handleMouseWheel); window.addEventListener('click', function click(evt) { - if (!PresentationMode.active) { - if (SecondaryToolbar.opened && + if (SecondaryToolbar.opened && PDFViewerApplication.pdfViewer.containsElement(evt.target)) { - SecondaryToolbar.close(); - } - } else if (evt.button === 0) { - // Necessary since preventDefault() in 'mousedown' won't stop - // the event propagation in all circumstances in presentation mode. - evt.preventDefault(); + SecondaryToolbar.close(); } }, false); @@ -7100,15 +7192,13 @@ window.addEventListener('keydown', function keydown(evt) { (evt.shiftKey ? 4 : 0) | (evt.metaKey ? 8 : 0); + var pdfViewer = PDFViewerApplication.pdfViewer; + var isViewerInPresentationMode = pdfViewer && pdfViewer.isInPresentationMode; + // First, handle the key bindings that are independent whether an input // control is selected or not. if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) { // either CTRL or META key with optional SHIFT. - var pdfViewer = PDFViewerApplication.pdfViewer; - var inPresentationMode = pdfViewer && - (pdfViewer.presentationModeState === PresentationModeState.CHANGING || - pdfViewer.presentationModeState === PresentationModeState.FULLSCREEN); - switch (evt.keyCode) { case 70: // f if (!PDFViewerApplication.supportsIntegratedFind) { @@ -7127,7 +7217,7 @@ window.addEventListener('keydown', function keydown(evt) { case 107: // FF '+' and '=' case 187: // Chrome '+' case 171: // FF with German keyboard - if (!inPresentationMode) { + if (!isViewerInPresentationMode) { PDFViewerApplication.zoomIn(); } handled = true; @@ -7135,14 +7225,14 @@ window.addEventListener('keydown', function keydown(evt) { case 173: // FF/Mac '-' case 109: // FF '-' case 189: // Chrome '-' - if (!inPresentationMode) { + if (!isViewerInPresentationMode) { PDFViewerApplication.zoomOut(); } handled = true; break; case 48: // '0' case 96: // '0' on Numpad of Swedish keyboard - if (!inPresentationMode) { + if (!isViewerInPresentationMode) { // keeping it unhandled (to restore page zoom to 100%) setTimeout(function () { // ... and resetting the scale after browser adjusts its scale @@ -7159,7 +7249,7 @@ window.addEventListener('keydown', function keydown(evt) { if (cmd === 3 || cmd === 10) { switch (evt.keyCode) { case 80: // p - SecondaryToolbar.presentationModeClick(); + PDFViewerApplication.requestPresentationMode(); handled = true; break; case 71: // g @@ -7193,15 +7283,15 @@ window.addEventListener('keydown', function keydown(evt) { case 38: // up arrow case 33: // pg up case 8: // backspace - if (!PresentationMode.active && - PDFViewerApplication.currentScaleValue !== 'page-fit') { + if (!isViewerInPresentationMode && + PDFViewerApplication.currentScaleValue !== 'page-fit') { break; } /* in presentation mode */ /* falls through */ case 37: // left arrow // horizontal scrolling using arrow keys - if (PDFViewerApplication.pdfViewer.isHorizontalScrollbarEnabled) { + if (pdfViewer.isHorizontalScrollbarEnabled) { break; } /* falls through */ @@ -7224,14 +7314,14 @@ window.addEventListener('keydown', function keydown(evt) { case 40: // down arrow case 34: // pg down case 32: // spacebar - if (!PresentationMode.active && + if (!isViewerInPresentationMode && PDFViewerApplication.currentScaleValue !== 'page-fit') { break; } /* falls through */ case 39: // right arrow // horizontal scrolling using arrow keys - if (PDFViewerApplication.pdfViewer.isHorizontalScrollbarEnabled) { + if (pdfViewer.isHorizontalScrollbarEnabled) { break; } /* falls through */ @@ -7242,13 +7332,13 @@ window.addEventListener('keydown', function keydown(evt) { break; case 36: // home - if (PresentationMode.active || PDFViewerApplication.page > 1) { + if (isViewerInPresentationMode || PDFViewerApplication.page > 1) { PDFViewerApplication.page = 1; handled = true; } break; case 35: // end - if (PresentationMode.active || (PDFViewerApplication.pdfDocument && + if (isViewerInPresentationMode || (PDFViewerApplication.pdfDocument && PDFViewerApplication.page < PDFViewerApplication.pagesCount)) { PDFViewerApplication.page = PDFViewerApplication.pagesCount; handled = true; @@ -7256,7 +7346,7 @@ window.addEventListener('keydown', function keydown(evt) { break; case 72: // 'h' - if (!PresentationMode.active) { + if (!isViewerInPresentationMode) { HandTool.toggle(); } break; @@ -7269,7 +7359,7 @@ window.addEventListener('keydown', function keydown(evt) { if (cmd === 4) { // shift-key switch (evt.keyCode) { case 32: // spacebar - if (!PresentationMode.active && + if (!isViewerInPresentationMode && PDFViewerApplication.currentScaleValue !== 'page-fit') { break; } @@ -7283,34 +7373,34 @@ window.addEventListener('keydown', function keydown(evt) { } } - if (!handled && !PresentationMode.active) { + if (!handled && !isViewerInPresentationMode) { // 33=Page Up 34=Page Down 35=End 36=Home // 37=Left 38=Up 39=Right 40=Down if (evt.keyCode >= 33 && evt.keyCode <= 40 && - !PDFViewerApplication.pdfViewer.containsElement(curElement)) { + !pdfViewer.containsElement(curElement)) { // The page container is not focused, but a page navigation key has been // pressed. Change the focus to the viewer container to make sure that // navigation by keyboard works as expected. - PDFViewerApplication.pdfViewer.focus(); + pdfViewer.focus(); } // 32=Spacebar if (evt.keyCode === 32 && curElementTagName !== 'BUTTON') { // Workaround for issue in Firefox, that prevents scroll keys from // working when elements with 'tabindex' are focused. (#3498) - PDFViewerApplication.pdfViewer.blur(); + pdfViewer.blur(); } } if (cmd === 2) { // alt-key switch (evt.keyCode) { case 37: // left arrow - if (PresentationMode.active) { + if (isViewerInPresentationMode) { PDFHistory.back(); handled = true; } break; case 39: // right arrow - if (PresentationMode.active) { + if (isViewerInPresentationMode) { PDFHistory.forward(); handled = true; } @@ -7320,7 +7410,6 @@ window.addEventListener('keydown', function keydown(evt) { if (handled) { evt.preventDefault(); - PDFViewerApplication.clearMouseScrollState(); } });