Merge pull request #5295 from yurydelendik/pdfviewer
Refactoring to move page display code into separate class
This commit is contained in:
		
						commit
						1145eb8c09
					
				| @ -14,7 +14,7 @@ | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| /* globals chrome, PDFJS, PDFView */ | ||||
| /* globals chrome, PDFJS, PDFViewerApplication */ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var ChromeCom = (function ChromeComClosure() { | ||||
| @ -64,10 +64,10 @@ var ChromeCom = (function ChromeComClosure() { | ||||
|         var streamUrl = response.streamUrl; | ||||
|         if (streamUrl) { | ||||
|           console.log('Found data stream for ' + file); | ||||
|           PDFView.open(streamUrl, 0, undefined, undefined, { | ||||
|           PDFViewerApplication.open(streamUrl, 0, undefined, undefined, { | ||||
|             length: response.contentLength | ||||
|           }); | ||||
|           PDFView.setTitleUsingUrl(file); | ||||
|           PDFViewerApplication.setTitleUsingUrl(file); | ||||
|           return; | ||||
|         } | ||||
|         if (isFTPFile && !response.extensionSupportsFTP) { | ||||
| @ -91,7 +91,7 @@ var ChromeCom = (function ChromeComClosure() { | ||||
|         resolveLocalFileSystemURL(file, function onResolvedFSURL(fileEntry) { | ||||
|           fileEntry.file(function(fileObject) { | ||||
|             var blobUrl = URL.createObjectURL(fileObject); | ||||
|             PDFView.open(blobUrl, 0, undefined, undefined, { | ||||
|             PDFViewerApplication.open(blobUrl, 0, undefined, undefined, { | ||||
|               length: fileObject.size | ||||
|             }); | ||||
|           }); | ||||
| @ -100,11 +100,11 @@ var ChromeCom = (function ChromeComClosure() { | ||||
|           // usual way of getting the File's data (via the Web worker).
 | ||||
|           console.warn('Cannot resolve file ' + file + ', ' + error.name + ' ' + | ||||
|                        error.message); | ||||
|           PDFView.open(file, 0); | ||||
|           PDFViewerApplication.open(file, 0); | ||||
|         }); | ||||
|         return; | ||||
|       } | ||||
|       PDFView.open(file, 0); | ||||
|       PDFViewerApplication.open(file, 0); | ||||
|     }); | ||||
|   }; | ||||
|   return ChromeCom; | ||||
|  | ||||
| @ -14,20 +14,18 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* globals PDFView, DownloadManager, getFileName */ | ||||
| /* globals DownloadManager, getFileName */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var DocumentAttachmentsView = function documentAttachmentsView(attachments) { | ||||
|   var attachmentsView = document.getElementById('attachmentsView'); | ||||
| var DocumentAttachmentsView = function documentAttachmentsView(options) { | ||||
|   var attachments = options.attachments; | ||||
|   var attachmentsView = options.attachmentsView; | ||||
|   while (attachmentsView.firstChild) { | ||||
|     attachmentsView.removeChild(attachmentsView.firstChild); | ||||
|   } | ||||
| 
 | ||||
|   if (!attachments) { | ||||
|     if (!attachmentsView.classList.contains('hidden')) { | ||||
|       PDFView.switchSidebarView('thumbs'); | ||||
|     } | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -14,27 +14,26 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* globals PDFView */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var DocumentOutlineView = function documentOutlineView(outline) { | ||||
|   var outlineView = document.getElementById('outlineView'); | ||||
| var DocumentOutlineView = function documentOutlineView(options) { | ||||
|   var outline = options.outline; | ||||
|   var outlineView = options.outlineView; | ||||
|   while (outlineView.firstChild) { | ||||
|     outlineView.removeChild(outlineView.firstChild); | ||||
|   } | ||||
| 
 | ||||
|   if (!outline) { | ||||
|     if (!outlineView.classList.contains('hidden')) { | ||||
|       PDFView.switchSidebarView('thumbs'); | ||||
|     } | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   var linkService = options.linkService; | ||||
| 
 | ||||
|   function bindItemLink(domObj, item) { | ||||
|     domObj.href = PDFView.getDestinationHash(item.dest); | ||||
|     domObj.href = linkService.getDestinationHash(item.dest); | ||||
|     domObj.onclick = function documentOutlineViewOnclick(e) { | ||||
|       PDFView.navigateTo(item.dest); | ||||
|       linkService.navigateTo(item.dest); | ||||
|       return false; | ||||
|     }; | ||||
|   } | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* globals PDFView, Promise, mozL10n, getPDFFileNameFromURL, OverlayManager */ | ||||
| /* globals Promise, mozL10n, getPDFFileNameFromURL, OverlayManager */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| @ -35,6 +35,8 @@ var DocumentProperties = { | ||||
|   producerField: null, | ||||
|   versionField: null, | ||||
|   pageCountField: null, | ||||
|   url: null, | ||||
|   pdfDocument: null, | ||||
| 
 | ||||
|   initialize: function documentPropertiesInitialize(options) { | ||||
|     this.overlayName = options.overlayName; | ||||
| @ -72,7 +74,7 @@ var DocumentProperties = { | ||||
|       return; | ||||
|     } | ||||
|     // Get the file size (if it hasn't already been set).
 | ||||
|     PDFView.pdfDocument.getDownloadInfo().then(function(data) { | ||||
|     this.pdfDocument.getDownloadInfo().then(function(data) { | ||||
|       if (data.length === this.rawFileSize) { | ||||
|         return; | ||||
|       } | ||||
| @ -81,10 +83,10 @@ var DocumentProperties = { | ||||
|     }.bind(this)); | ||||
| 
 | ||||
|     // Get the document properties.
 | ||||
|     PDFView.pdfDocument.getMetadata().then(function(data) { | ||||
|     this.pdfDocument.getMetadata().then(function(data) { | ||||
|       var fields = [ | ||||
|         { field: this.fileNameField, | ||||
|           content: getPDFFileNameFromURL(PDFView.url) }, | ||||
|           content: getPDFFileNameFromURL(this.url) }, | ||||
|         { field: this.fileSizeField, content: this.parseFileSize() }, | ||||
|         { field: this.titleField, content: data.info.Title }, | ||||
|         { field: this.authorField, content: data.info.Author }, | ||||
| @ -97,7 +99,7 @@ var DocumentProperties = { | ||||
|         { field: this.creatorField, content: data.info.Creator }, | ||||
|         { field: this.producerField, content: data.info.Producer }, | ||||
|         { field: this.versionField, content: data.info.PDFFormatVersion }, | ||||
|         { field: this.pageCountField, content: PDFView.pdfDocument.numPages } | ||||
|         { field: this.pageCountField, content: this.pdfDocument.numPages } | ||||
|       ]; | ||||
| 
 | ||||
|       // Show the properties in the dialog.
 | ||||
|  | ||||
							
								
								
									
										81
									
								
								web/interfaces.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								web/interfaces.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | ||||
| /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||||
| /* Copyright 2012 Mozilla Foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| /** | ||||
|  * @interface | ||||
|  */ | ||||
| function IPDFLinkService() {} | ||||
| IPDFLinkService.prototype = { | ||||
|   /** | ||||
|    * @returns {number} | ||||
|    */ | ||||
|   get page() {}, | ||||
|   /** | ||||
|    * @param {number} value | ||||
|    */ | ||||
|   set page(value) {}, | ||||
|   /** | ||||
|    * @param dest - The PDF destination object. | ||||
|    */ | ||||
|   navigateTo: function (dest) {}, | ||||
|   /** | ||||
|    * @param dest - The PDF destination object. | ||||
|    * @returns {string} The hyperlink to the PDF object. | ||||
|    */ | ||||
|   getDestinationHash: function (dest) {}, | ||||
|   /** | ||||
|    * @param hash - The PDF parameters/hash. | ||||
|    * @returns {string} The hyperlink to the PDF object. | ||||
|    */ | ||||
|   getAnchorUrl: function (hash) {}, | ||||
|   /** | ||||
|    * @param {string} hash | ||||
|    */ | ||||
|   setHash: function (hash) {}, | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * @interface | ||||
|  */ | ||||
| function IRenderableView() {} | ||||
| IRenderableView.prototype = { | ||||
|   /** | ||||
|    * @returns {string} - Unique ID for rendering queue. | ||||
|    */ | ||||
|   get renderingId() {}, | ||||
|   /** | ||||
|    * @returns {RenderingStates} | ||||
|    */ | ||||
|   get renderingState() {}, | ||||
|   /** | ||||
|    * @param {function} callback - The draw completion callback. | ||||
|    */ | ||||
|   draw: function (callback) {}, | ||||
|   resume: function () {}, | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * @interface | ||||
|  */ | ||||
| function ILastScrollSource() {} | ||||
| ILastScrollSource.prototype = { | ||||
|   /** | ||||
|    * @returns {number} | ||||
|    */ | ||||
|   get lastScroll() {}, | ||||
| }; | ||||
							
								
								
									
										160
									
								
								web/page_view.js
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								web/page_view.js
									
									
									
									
									
								
							| @ -14,16 +14,31 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* globals RenderingStates, PDFView, PDFHistory, PDFJS, mozL10n, CustomStyle, | ||||
|            PresentationMode, scrollIntoView, SCROLLBAR_PADDING, CSS_UNITS, | ||||
|            UNKNOWN_SCALE, DEFAULT_SCALE, getOutputScale, TextLayerBuilder, | ||||
|            cache, Stats */ | ||||
| /* globals RenderingStates, PDFJS, mozL10n, CustomStyle, | ||||
|            SCROLLBAR_PADDING, CSS_UNITS, UNKNOWN_SCALE, DEFAULT_SCALE, | ||||
|            getOutputScale, scrollIntoView, Stats, PresentationModeState */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var PageView = function pageView(container, id, scale, | ||||
|                                  navigateTo, defaultViewport) { | ||||
| /** | ||||
|  * @constructor | ||||
|  * @param {HTMLDivElement} container - The viewer element. | ||||
|  * @param {number} id - The page unique ID (normally its number). | ||||
|  * @param {number} scale - The page scale display. | ||||
|  * @param {PageViewport} defaultViewport - The page viewport. | ||||
|  * @param {IPDFLinkService} linkService - The navigation/linking service. | ||||
|  * @param {PDFRenderingQueue} renderingQueue - The rendering queue object. | ||||
|  * @param {Cache} cache - The page cache. | ||||
|  * @param {PDFPageSource} pageSource | ||||
|  * @param {PDFViewer} viewer | ||||
|  * | ||||
|  * @implements {IRenderableView} | ||||
|  */ | ||||
| var PageView = function pageView(container, id, scale, defaultViewport, | ||||
|                                  linkService, renderingQueue, cache, | ||||
|                                  pageSource, viewer) { | ||||
|   this.id = id; | ||||
|   this.renderingId = 'page' + id; | ||||
| 
 | ||||
|   this.rotation = 0; | ||||
|   this.scale = scale || 1.0; | ||||
| @ -31,6 +46,12 @@ var PageView = function pageView(container, id, scale, | ||||
|   this.pdfPageRotate = defaultViewport.rotation; | ||||
|   this.hasRestrictedScaling = false; | ||||
| 
 | ||||
|   this.linkService = linkService; | ||||
|   this.renderingQueue = renderingQueue; | ||||
|   this.cache = cache; | ||||
|   this.pageSource = pageSource; | ||||
|   this.viewer = viewer; | ||||
| 
 | ||||
|   this.renderingState = RenderingStates.INITIAL; | ||||
|   this.resume = null; | ||||
| 
 | ||||
| @ -241,10 +262,10 @@ var PageView = function pageView(container, id, scale, | ||||
|   function setupAnnotations(pageDiv, pdfPage, viewport) { | ||||
| 
 | ||||
|     function bindLink(link, dest) { | ||||
|       link.href = PDFView.getDestinationHash(dest); | ||||
|       link.href = linkService.getDestinationHash(dest); | ||||
|       link.onclick = function pageViewSetupLinksOnclick() { | ||||
|         if (dest) { | ||||
|           PDFView.navigateTo(dest); | ||||
|           linkService.navigateTo(dest); | ||||
|         } | ||||
|         return false; | ||||
|       }; | ||||
| @ -254,47 +275,9 @@ var PageView = function pageView(container, id, scale, | ||||
|     } | ||||
| 
 | ||||
|     function bindNamedAction(link, action) { | ||||
|       link.href = PDFView.getAnchorUrl(''); | ||||
|       link.href = linkService.getAnchorUrl(''); | ||||
|       link.onclick = function pageViewSetupNamedActionOnClick() { | ||||
|         // See PDF reference, table 8.45 - Named action
 | ||||
|         switch (action) { | ||||
|           case 'GoToPage': | ||||
|             document.getElementById('pageNumber').focus(); | ||||
|             break; | ||||
| 
 | ||||
|           case 'GoBack': | ||||
|             PDFHistory.back(); | ||||
|             break; | ||||
| 
 | ||||
|           case 'GoForward': | ||||
|             PDFHistory.forward(); | ||||
|             break; | ||||
| 
 | ||||
|           case 'Find': | ||||
|             if (!PDFView.supportsIntegratedFind) { | ||||
|               PDFView.findBar.toggle(); | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|           case 'NextPage': | ||||
|             PDFView.page++; | ||||
|             break; | ||||
| 
 | ||||
|           case 'PrevPage': | ||||
|             PDFView.page--; | ||||
|             break; | ||||
| 
 | ||||
|           case 'LastPage': | ||||
|             PDFView.page = PDFView.pages.length; | ||||
|             break; | ||||
| 
 | ||||
|           case 'FirstPage': | ||||
|             PDFView.page = 1; | ||||
|             break; | ||||
| 
 | ||||
|           default: | ||||
|             break; // No action according to spec
 | ||||
|         } | ||||
|         linkService.executeNamedAction(action); | ||||
|         return false; | ||||
|       }; | ||||
|       link.className = 'internalLink'; | ||||
| @ -376,14 +359,16 @@ var PageView = function pageView(container, id, scale, | ||||
|   }; | ||||
| 
 | ||||
|   this.scrollIntoView = function pageViewScrollIntoView(dest) { | ||||
|     if (PresentationMode.active) { | ||||
|       if (PDFView.page !== this.id) { | ||||
|         // Avoid breaking PDFView.getVisiblePages in presentation mode.
 | ||||
|         PDFView.page = this.id; | ||||
|     if (this.viewer.presentationModeState === | ||||
|         PresentationModeState.FULLSCREEN) { | ||||
|       if (this.linkService.page !== this.id) { | ||||
|         // Avoid breaking getVisiblePages in presentation mode.
 | ||||
|         this.linkService.page = this.id; | ||||
|         return; | ||||
|       } | ||||
|       dest = null; | ||||
|       PDFView.setScale(PDFView.currentScaleValue, true, true); | ||||
|       // Fixes the case when PDF has different page sizes.
 | ||||
|       this.viewer.currentScaleValue = this.viewer.currentScaleValue; | ||||
|     } | ||||
|     if (!dest) { | ||||
|       scrollIntoView(div); | ||||
| @ -431,9 +416,10 @@ var PageView = function pageView(container, id, scale, | ||||
|         y = dest[3]; | ||||
|         width = dest[4] - x; | ||||
|         height = dest[5] - y; | ||||
|         widthScale = (PDFView.container.clientWidth - SCROLLBAR_PADDING) / | ||||
|         var viewerContainer = this.viewer.container; | ||||
|         widthScale = (viewerContainer.clientWidth - SCROLLBAR_PADDING) / | ||||
|           width / CSS_UNITS; | ||||
|         heightScale = (PDFView.container.clientHeight - SCROLLBAR_PADDING) / | ||||
|         heightScale = (viewerContainer.clientHeight - SCROLLBAR_PADDING) / | ||||
|           height / CSS_UNITS; | ||||
|         scale = Math.min(Math.abs(widthScale), Math.abs(heightScale)); | ||||
|         break; | ||||
| @ -441,10 +427,10 @@ var PageView = function pageView(container, id, scale, | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (scale && scale !== PDFView.currentScale) { | ||||
|       PDFView.setScale(scale, true, true); | ||||
|     } else if (PDFView.currentScale === UNKNOWN_SCALE) { | ||||
|       PDFView.setScale(DEFAULT_SCALE, true, true); | ||||
|     if (scale && scale !== this.viewer.currentScale) { | ||||
|       this.viewer.currentScaleValue = scale; | ||||
|     } else if (this.viewer.currentScale === UNKNOWN_SCALE) { | ||||
|       this.viewer.currentScaleValue = DEFAULT_SCALE; | ||||
|     } | ||||
| 
 | ||||
|     if (scale === 'page-fit' && !dest[4]) { | ||||
| @ -462,12 +448,6 @@ var PageView = function pageView(container, id, scale, | ||||
|     scrollIntoView(div, { left: left, top: top }); | ||||
|   }; | ||||
| 
 | ||||
|   this.getTextContent = function pageviewGetTextContent() { | ||||
|     return PDFView.getPage(this.id).then(function(pdfPage) { | ||||
|       return pdfPage.getTextContent(); | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   this.draw = function pageviewDraw(callback) { | ||||
|     var pdfPage = this.pdfPage; | ||||
| 
 | ||||
| @ -475,7 +455,7 @@ var PageView = function pageView(container, id, scale, | ||||
|       return; | ||||
|     } | ||||
|     if (!pdfPage) { | ||||
|       var promise = PDFView.getPage(this.id); | ||||
|       var promise = this.pageSource.getPage(); | ||||
|       promise.then(function(pdfPage) { | ||||
|         delete this.pagePdfPromise; | ||||
|         this.setPdfPage(pdfPage); | ||||
| @ -543,6 +523,7 @@ var PageView = function pageView(container, id, scale, | ||||
|     canvas._viewport = viewport; | ||||
| 
 | ||||
|     var textLayerDiv = null; | ||||
|     var textLayer = null; | ||||
|     if (!PDFJS.disableTextLayer) { | ||||
|       textLayerDiv = document.createElement('div'); | ||||
|       textLayerDiv.className = 'textLayer'; | ||||
| @ -554,16 +535,12 @@ var PageView = function pageView(container, id, scale, | ||||
|       } else { | ||||
|         div.appendChild(textLayerDiv); | ||||
|       } | ||||
| 
 | ||||
|       textLayer = this.viewer.createTextLayerBuilder(textLayerDiv, this.id - 1, | ||||
|                                                      this.viewport); | ||||
|     } | ||||
|     var textLayer = this.textLayer = | ||||
|       textLayerDiv ? new TextLayerBuilder({ | ||||
|         textLayerDiv: textLayerDiv, | ||||
|         pageIndex: this.id - 1, | ||||
|         lastScrollSource: PDFView, | ||||
|         viewport: this.viewport, | ||||
|         isViewerInPresentationMode: PresentationMode.active, | ||||
|         findController: PDFView.findController | ||||
|       }) : null; | ||||
|     this.textLayer = textLayer; | ||||
| 
 | ||||
|     // TODO(mack): use data attributes to store these
 | ||||
|     ctx._scaleX = outputScale.sx; | ||||
|     ctx._scaleY = outputScale.sy; | ||||
| @ -598,22 +575,7 @@ var PageView = function pageView(container, id, scale, | ||||
|         self.zoomLayer = null; | ||||
|       } | ||||
| 
 | ||||
| //#if (FIREFOX || MOZCENTRAL)
 | ||||
| //    if (self.textLayer && self.textLayer.textDivs &&
 | ||||
| //        self.textLayer.textDivs.length > 0 &&
 | ||||
| //        !PDFView.supportsDocumentColors) {
 | ||||
| //      console.error(mozL10n.get('document_colors_disabled', null,
 | ||||
| //        'PDF documents are not allowed to use their own colors: ' +
 | ||||
| //        '\'Allow pages to choose their own colors\' ' +
 | ||||
| //        'is deactivated in the browser.'));
 | ||||
| //      PDFView.fallback();
 | ||||
| //    }
 | ||||
| //#endif
 | ||||
|       if (error) { | ||||
|         PDFView.error(mozL10n.get('rendering_error', null, | ||||
|           'An error occurred while rendering the page.'), error); | ||||
|       } | ||||
| 
 | ||||
|       self.error = error; | ||||
|       self.stats = pdfPage.stats; | ||||
|       self.updateStats(); | ||||
|       if (self.onAfterDraw) { | ||||
| @ -626,18 +588,6 @@ var PageView = function pageView(container, id, scale, | ||||
|       }); | ||||
|       div.dispatchEvent(event); | ||||
| 
 | ||||
| //#if (FIREFOX || MOZCENTRAL)
 | ||||
| //    FirefoxCom.request('reportTelemetry', JSON.stringify({
 | ||||
| //      type: 'pageInfo'
 | ||||
| //    }));
 | ||||
| //    // It is a good time to report stream and font types
 | ||||
| //    PDFView.pdfDocument.getStats().then(function (stats) {
 | ||||
| //      FirefoxCom.request('reportTelemetry', JSON.stringify({
 | ||||
| //        type: 'documentStats',
 | ||||
| //        stats: stats
 | ||||
| //      }));
 | ||||
| //    });
 | ||||
| //#endif
 | ||||
|       callback(); | ||||
|     } | ||||
| 
 | ||||
| @ -646,7 +596,7 @@ var PageView = function pageView(container, id, scale, | ||||
|       viewport: this.viewport, | ||||
|       // intent: 'default', // === 'display'
 | ||||
|       continueCallback: function pdfViewcContinueCallback(cont) { | ||||
|         if (PDFView.highestPriorityPage !== 'page' + self.id) { | ||||
|         if (!self.renderingQueue.isHighestPriority(self)) { | ||||
|           self.renderingState = RenderingStates.PAUSED; | ||||
|           self.resume = function resumeCallback() { | ||||
|             self.renderingState = RenderingStates.RUNNING; | ||||
| @ -663,7 +613,7 @@ var PageView = function pageView(container, id, scale, | ||||
|       function pdfPageRenderCallback() { | ||||
|         pageViewDrawCallback(null); | ||||
|         if (textLayer) { | ||||
|           self.getTextContent().then( | ||||
|           self.pdfPage.getTextContent().then( | ||||
|             function textContentResolved(textContent) { | ||||
|               textLayer.setTextContent(textContent); | ||||
|             } | ||||
|  | ||||
| @ -13,10 +13,17 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* globals PDFJS, FindStates, FirefoxCom, Promise */ | ||||
| /* globals PDFJS, FirefoxCom, Promise */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var FindStates = { | ||||
|   FIND_FOUND: 0, | ||||
|   FIND_NOTFOUND: 1, | ||||
|   FIND_WRAPPED: 2, | ||||
|   FIND_PENDING: 3 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Provides "search" or "find" functionality for the PDF. | ||||
|  * This object actually performs the search for a given string. | ||||
| @ -41,7 +48,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | ||||
|     this.state = null; | ||||
|     this.dirtyMatch = false; | ||||
|     this.findTimeout = null; | ||||
|     this.pdfPageSource = options.pdfPageSource || null; | ||||
|     this.pdfViewer = options.pdfViewer || null; | ||||
|     this.integratedFind = options.integratedFind || false; | ||||
|     this.charactersToNormalize = { | ||||
|       '\u2018': '\'', // Left single quotation mark
 | ||||
| @ -137,7 +144,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | ||||
| 
 | ||||
|       this.pageContents = []; | ||||
|       var extractTextPromisesResolves = []; | ||||
|       var numPages = this.pdfPageSource.pdfDocument.numPages; | ||||
|       var numPages = this.pdfViewer.pagesCount; | ||||
|       for (var i = 0; i < numPages; i++) { | ||||
|         this.extractTextPromises.push(new Promise(function (resolve) { | ||||
|           extractTextPromisesResolves.push(resolve); | ||||
| @ -146,7 +153,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | ||||
| 
 | ||||
|       var self = this; | ||||
|       function extractPageText(pageIndex) { | ||||
|         self.pdfPageSource.pages[pageIndex].getTextContent().then( | ||||
|         self.pdfViewer.getPageTextContent(pageIndex).then( | ||||
|           function textContentResolved(textContent) { | ||||
|             var textItems = textContent.items; | ||||
|             var str = []; | ||||
| @ -159,7 +166,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | ||||
|             self.pageContents.push(str.join('')); | ||||
| 
 | ||||
|             extractTextPromisesResolves[pageIndex](pageIndex); | ||||
|             if ((pageIndex + 1) < self.pdfPageSource.pages.length) { | ||||
|             if ((pageIndex + 1) < self.pdfViewer.pagesCount) { | ||||
|               extractPageText(pageIndex + 1); | ||||
|             } | ||||
|           } | ||||
| @ -189,7 +196,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | ||||
|     }, | ||||
| 
 | ||||
|     updatePage: function PDFFindController_updatePage(index) { | ||||
|       var page = this.pdfPageSource.pages[index]; | ||||
|       var page = this.pdfViewer.getPageView(index); | ||||
| 
 | ||||
|       if (this.selected.pageIdx === index) { | ||||
|         // If the page is selected, scroll the page into view, which triggers
 | ||||
| @ -205,8 +212,8 @@ var PDFFindController = (function PDFFindControllerClosure() { | ||||
| 
 | ||||
|     nextMatch: function PDFFindController_nextMatch() { | ||||
|       var previous = this.state.findPrevious; | ||||
|       var currentPageIndex = this.pdfPageSource.page - 1; | ||||
|       var numPages = this.pdfPageSource.pages.length; | ||||
|       var currentPageIndex = this.pdfViewer.currentPageNumber - 1; | ||||
|       var numPages = this.pdfViewer.pagesCount; | ||||
| 
 | ||||
|       this.active = true; | ||||
| 
 | ||||
| @ -346,7 +353,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | ||||
|      | ||||
|       this.updateUIState(state, this.state.findPrevious); | ||||
|       if (this.selected.pageIdx !== -1) { | ||||
|         this.updatePage(this.selected.pageIdx, true); | ||||
|         this.updatePage(this.selected.pageIdx); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* globals PDFJS, PDFView, PresentationMode */ | ||||
| /* globals PDFJS, PresentationMode */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| @ -22,12 +22,11 @@ var PDFHistory = { | ||||
|   initialized: false, | ||||
|   initialDestination: null, | ||||
| 
 | ||||
|   initialize: function pdfHistoryInitialize(fingerprint) { | ||||
|     if (PDFJS.disableHistory || PDFView.isViewerEmbedded) { | ||||
|       // The browsing history is only enabled when the viewer is standalone,
 | ||||
|       // i.e. not when it is embedded in a web page.
 | ||||
|       return; | ||||
|     } | ||||
|   /** | ||||
|    * @param {string} fingerprint | ||||
|    * @param {IPDFLinkService} linkService | ||||
|    */ | ||||
|   initialize: function pdfHistoryInitialize(fingerprint, linkService) { | ||||
|     this.initialized = true; | ||||
|     this.reInitialized = false; | ||||
|     this.allowHashChange = true; | ||||
| @ -42,6 +41,7 @@ var PDFHistory = { | ||||
|     this.nextHashParam = ''; | ||||
| 
 | ||||
|     this.fingerprint = fingerprint; | ||||
|     this.linkService = linkService; | ||||
|     this.currentUid = this.uid = 0; | ||||
|     this.current = {}; | ||||
| 
 | ||||
| @ -52,7 +52,7 @@ var PDFHistory = { | ||||
|       if (state.target.dest) { | ||||
|         this.initialDestination = state.target.dest; | ||||
|       } else { | ||||
|         PDFView.initialBookmark = state.target.hash; | ||||
|         linkService.setHash(state.target.hash); | ||||
|       } | ||||
|       this.currentUid = state.uid; | ||||
|       this.uid = state.uid + 1; | ||||
| @ -203,7 +203,7 @@ var PDFHistory = { | ||||
|       params.hash = (this.current.hash && this.current.dest && | ||||
|                      this.current.dest === params.dest) ? | ||||
|         this.current.hash : | ||||
|         PDFView.getDestinationHash(params.dest).split('#')[1]; | ||||
|         this.linkService.getDestinationHash(params.dest).split('#')[1]; | ||||
|     } | ||||
|     if (params.page) { | ||||
|       params.page |= 0; | ||||
| @ -212,7 +212,7 @@ var PDFHistory = { | ||||
|       var target = window.history.state.target; | ||||
|       if (!target) { | ||||
|         // Invoked when the user specifies an initial bookmark,
 | ||||
|         // thus setting PDFView.initialBookmark, when the document is loaded.
 | ||||
|         // thus setting initialBookmark, when the document is loaded.
 | ||||
|         this._pushToHistory(params, false); | ||||
|         this.previousHash = window.location.hash.substring(1); | ||||
|       } | ||||
| @ -337,9 +337,9 @@ var PDFHistory = { | ||||
|     this.historyUnlocked = false; | ||||
| 
 | ||||
|     if (state.target.dest) { | ||||
|       PDFView.navigateTo(state.target.dest); | ||||
|       this.linkService.navigateTo(state.target.dest); | ||||
|     } else { | ||||
|       PDFView.setHash(state.target.hash); | ||||
|       this.linkService.setHash(state.target.hash); | ||||
|     } | ||||
|     this.currentUid = state.uid; | ||||
|     if (state.uid > this.uid) { | ||||
|  | ||||
							
								
								
									
										176
									
								
								web/pdf_rendering_queue.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								web/pdf_rendering_queue.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,176 @@ | ||||
| /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||||
| /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ | ||||
| /* Copyright 2012 Mozilla Foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var CLEANUP_TIMEOUT = 30000; | ||||
| 
 | ||||
| var RenderingStates = { | ||||
|   INITIAL: 0, | ||||
|   RUNNING: 1, | ||||
|   PAUSED: 2, | ||||
|   FINISHED: 3 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Controls rendering of the views for pages and thumbnails. | ||||
|  * @class | ||||
|  */ | ||||
| var PDFRenderingQueue = (function PDFRenderingQueueClosure() { | ||||
|   /** | ||||
|    * @constructs | ||||
|    */ | ||||
|   function PDFRenderingQueue() { | ||||
|     this.pdfViewer = null; | ||||
|     this.pdfThumbnailViewer = null; | ||||
|     this.onIdle = null; | ||||
| 
 | ||||
|     this.highestPriorityPage = null; | ||||
|     this.idleTimeout = null; | ||||
|     this.printing = false; | ||||
|     this.isThumbnailViewEnabled = false; | ||||
|   } | ||||
| 
 | ||||
|   PDFRenderingQueue.prototype = /** @lends PDFRenderingQueue.prototype */ { | ||||
|     /** | ||||
|      * @param {PDFViewer} pdfViewer | ||||
|      */ | ||||
|     setViewer: function PDFRenderingQueue_setViewer(pdfViewer) { | ||||
|       this.pdfViewer = pdfViewer; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @param {PDFThumbnailViewer} pdfThumbnailViewer | ||||
|      */ | ||||
|     setThumbnailViewer: | ||||
|         function PDFRenderingQueue_setThumbnailViewer(pdfThumbnailViewer) { | ||||
|       this.pdfThumbnailViewer = pdfThumbnailViewer; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @param {IRenderableView} view | ||||
|      * @returns {boolean} | ||||
|      */ | ||||
|     isHighestPriority: function PDFRenderingQueue_isHighestPriority(view) { | ||||
|       return this.highestPriorityPage === view.renderingId; | ||||
|     }, | ||||
| 
 | ||||
|     renderHighestPriority: function | ||||
|         PDFRenderingQueue_renderHighestPriority(currentlyVisiblePages) { | ||||
|       if (this.idleTimeout) { | ||||
|         clearTimeout(this.idleTimeout); | ||||
|         this.idleTimeout = null; | ||||
|       } | ||||
| 
 | ||||
|       // Pages have a higher priority than thumbnails, so check them first.
 | ||||
|       if (this.pdfViewer.forceRendering(currentlyVisiblePages)) { | ||||
|         return; | ||||
|       } | ||||
|       // No pages needed rendering so check thumbnails.
 | ||||
|       if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled) { | ||||
|         if (this.pdfThumbnailViewer.forceRendering()) { | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (this.printing) { | ||||
|         // If printing is currently ongoing do not reschedule cleanup.
 | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       if (this.onIdle) { | ||||
|         this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     getHighestPriority: function | ||||
|         PDFRenderingQueue_getHighestPriority(visible, views, scrolledDown) { | ||||
|       // The state has changed figure out which page has the highest priority to
 | ||||
|       // render next (if any).
 | ||||
|       // Priority:
 | ||||
|       // 1 visible pages
 | ||||
|       // 2 if last scrolled down page after the visible pages
 | ||||
|       // 2 if last scrolled up page before the visible pages
 | ||||
|       var visibleViews = visible.views; | ||||
| 
 | ||||
|       var numVisible = visibleViews.length; | ||||
|       if (numVisible === 0) { | ||||
|         return false; | ||||
|       } | ||||
|       for (var i = 0; i < numVisible; ++i) { | ||||
|         var view = visibleViews[i].view; | ||||
|         if (!this.isViewFinished(view)) { | ||||
|           return view; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       // All the visible views have rendered, try to render next/previous pages.
 | ||||
|       if (scrolledDown) { | ||||
|         var nextPageIndex = visible.last.id; | ||||
|         // ID's start at 1 so no need to add 1.
 | ||||
|         if (views[nextPageIndex] && | ||||
|             !this.isViewFinished(views[nextPageIndex])) { | ||||
|           return views[nextPageIndex]; | ||||
|         } | ||||
|       } else { | ||||
|         var previousPageIndex = visible.first.id - 2; | ||||
|         if (views[previousPageIndex] && | ||||
|           !this.isViewFinished(views[previousPageIndex])) { | ||||
|           return views[previousPageIndex]; | ||||
|         } | ||||
|       } | ||||
|       // Everything that needs to be rendered has been.
 | ||||
|       return null; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @param {IRenderableView} view | ||||
|      * @returns {boolean} | ||||
|      */ | ||||
|     isViewFinished: function PDFRenderingQueue_isViewFinished(view) { | ||||
|       return view.renderingState === RenderingStates.FINISHED; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * Render a page or thumbnail view. This calls the appropriate function | ||||
|      * based on the views state. If the view is already rendered it will return | ||||
|      * false. | ||||
|      * @param {IRenderableView} view | ||||
|      */ | ||||
|     renderView: function PDFRenderingQueue_renderView(view) { | ||||
|       var state = view.renderingState; | ||||
|       switch (state) { | ||||
|         case RenderingStates.FINISHED: | ||||
|           return false; | ||||
|         case RenderingStates.PAUSED: | ||||
|           this.highestPriorityPage = view.renderingId; | ||||
|           view.resume(); | ||||
|           break; | ||||
|         case RenderingStates.RUNNING: | ||||
|           this.highestPriorityPage = view.renderingId; | ||||
|           break; | ||||
|         case RenderingStates.INITIAL: | ||||
|           this.highestPriorityPage = view.renderingId; | ||||
|           view.draw(this.renderHighestPriority.bind(this)); | ||||
|           break; | ||||
|       } | ||||
|       return true; | ||||
|     }, | ||||
|   }; | ||||
| 
 | ||||
|   return PDFRenderingQueue; | ||||
| })(); | ||||
							
								
								
									
										571
									
								
								web/pdf_viewer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										571
									
								
								web/pdf_viewer.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,571 @@ | ||||
| /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||||
| /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ | ||||
| /* Copyright 2014 Mozilla Foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  /*globals watchScroll, Cache, DEFAULT_CACHE_SIZE, PageView, UNKNOWN_SCALE, | ||||
|            SCROLLBAR_PADDING, VERTICAL_PADDING, MAX_AUTO_SCALE, CSS_UNITS, | ||||
|            getVisibleElements, RenderingStates, Promise, | ||||
|            PDFJS, TextLayerBuilder, PDFRenderingQueue */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var PresentationModeState = { | ||||
|   UNKNOWN: 0, | ||||
|   NORMAL: 1, | ||||
|   CHANGING: 2, | ||||
|   FULLSCREEN: 3, | ||||
| }; | ||||
| 
 | ||||
| var IGNORE_CURRENT_POSITION_ON_ZOOM = false; | ||||
| 
 | ||||
| //#include pdf_rendering_queue.js
 | ||||
| //#include page_view.js
 | ||||
| //#include text_layer_builder.js
 | ||||
| 
 | ||||
| /** | ||||
|  * @typedef {Object} PDFViewerOptions | ||||
|  * @property {HTMLDivElement} container - The container for the viewer element. | ||||
|  * @property {HTMLDivElement} viewer - (optional) The viewer element. | ||||
|  * @property {IPDFLinkService} linkService - The navigation/linking service. | ||||
|  * @property {PDFRenderingQueue} renderingQueue - (optional) The rendering | ||||
|  *   queue object. | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Simple viewer control to display PDF content/pages. | ||||
|  * @class | ||||
|  * @implements {ILastScrollSource} | ||||
|  * @implements {IRenderableView} | ||||
|  */ | ||||
| var PDFViewer = (function pdfViewer() { | ||||
|   /** | ||||
|    * @constructs PDFViewer | ||||
|    * @param {PDFViewerOptions} options | ||||
|    */ | ||||
|   function PDFViewer(options) { | ||||
|     this.container = options.container; | ||||
|     this.viewer = options.viewer || options.container.firstElementChild; | ||||
|     this.linkService = options.linkService; | ||||
| 
 | ||||
|     this.defaultRenderingQueue = !options.renderingQueue; | ||||
|     if (this.defaultRenderingQueue) { | ||||
|       // Custom rendering queue is not specified, using default one
 | ||||
|       this.renderingQueue = new PDFRenderingQueue(); | ||||
|       this.renderingQueue.setViewer(this); | ||||
|     } else { | ||||
|       this.renderingQueue = options.renderingQueue; | ||||
|     } | ||||
| 
 | ||||
|     this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this)); | ||||
|     this.lastScroll = 0; | ||||
|     this.updateInProgress = false; | ||||
|     this.presentationModeState = PresentationModeState.UNKNOWN; | ||||
|     this._resetView(); | ||||
|   } | ||||
| 
 | ||||
|   PDFViewer.prototype = /** @lends PDFViewer.prototype */{ | ||||
|     get pagesCount() { | ||||
|       return this.pages.length; | ||||
|     }, | ||||
| 
 | ||||
|     getPageView: function (index) { | ||||
|       return this.pages[index]; | ||||
|     }, | ||||
| 
 | ||||
|     get currentPageNumber() { | ||||
|       return this._currentPageNumber; | ||||
|     }, | ||||
| 
 | ||||
|     set currentPageNumber(val) { | ||||
|       if (!this.pdfDocument) { | ||||
|         this._currentPageNumber = val; | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       var event = document.createEvent('UIEvents'); | ||||
|       event.initUIEvent('pagechange', true, true, window, 0); | ||||
|       event.updateInProgress = this.updateInProgress; | ||||
| 
 | ||||
|       if (!(0 < val && val <= this.pagesCount)) { | ||||
|         event.pageNumber = this.page; | ||||
|         event.previousPageNumber = val; | ||||
|         this.container.dispatchEvent(event); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       this.pages[val - 1].updateStats(); | ||||
|       event.previousPageNumber = this._currentPageNumber; | ||||
|       this._currentPageNumber = val; | ||||
|       event.pageNumber = val; | ||||
|       this.container.dispatchEvent(event); | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @returns {number} | ||||
|      */ | ||||
|     get currentScale() { | ||||
|       return this._currentScale; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @param {number} val - Scale of the pages in percents. | ||||
|      */ | ||||
|     set currentScale(val) { | ||||
|       if (isNaN(val))  { | ||||
|         throw new Error('Invalid numeric scale'); | ||||
|       } | ||||
|       if (!this.pdfDocument) { | ||||
|         this._currentScale = val; | ||||
|         this._currentScaleValue = val.toString(); | ||||
|         return; | ||||
|       } | ||||
|       this._setScale(val, false); | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @returns {string} | ||||
|      */ | ||||
|     get currentScaleValue() { | ||||
|       return this._currentScaleValue; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @param val - The scale of the pages (in percent or predefined value). | ||||
|      */ | ||||
|     set currentScaleValue(val) { | ||||
|       if (!this.pdfDocument) { | ||||
|         this._currentScale = isNaN(val) ? UNKNOWN_SCALE : val; | ||||
|         this._currentScaleValue = val; | ||||
|         return; | ||||
|       } | ||||
|       this._setScale(val, false); | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @returns {number} | ||||
|      */ | ||||
|     get pagesRotation() { | ||||
|       return this._pagesRotation; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @param {number} rotation - The rotation of the pages (0, 90, 180, 270). | ||||
|      */ | ||||
|     set pagesRotation(rotation) { | ||||
|       this._pagesRotation = rotation; | ||||
| 
 | ||||
|       for (var i = 0, l = this.pages.length; i < l; i++) { | ||||
|         var page = this.pages[i]; | ||||
|         page.update(page.scale, rotation); | ||||
|       } | ||||
| 
 | ||||
|       this._setScale(this._currentScaleValue, true); | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @param pdfDocument {PDFDocument} | ||||
|      */ | ||||
|     setDocument: function (pdfDocument) { | ||||
|       if (this.pdfDocument) { | ||||
|         this._resetView(); | ||||
|       } | ||||
| 
 | ||||
|       this.pdfDocument = pdfDocument; | ||||
|       if (!pdfDocument) { | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       var pagesCount = pdfDocument.numPages; | ||||
|       var pagesRefMap = this.pagesRefMap = {}; | ||||
|       var self = this; | ||||
| 
 | ||||
|       var resolvePagesPromise; | ||||
|       var pagesPromise = new Promise(function (resolve) { | ||||
|         resolvePagesPromise = resolve; | ||||
|       }); | ||||
|       this.pagesPromise = pagesPromise; | ||||
|       pagesPromise.then(function () { | ||||
|         var event = document.createEvent('CustomEvent'); | ||||
|         event.initCustomEvent('pagesloaded', true, true, { | ||||
|           pagesCount: pagesCount | ||||
|         }); | ||||
|         self.container.dispatchEvent(event); | ||||
|       }); | ||||
| 
 | ||||
|       var isOnePageRenderedResolved = false; | ||||
|       var resolveOnePageRendered = null; | ||||
|       var onePageRendered = new Promise(function (resolve) { | ||||
|         resolveOnePageRendered = resolve; | ||||
|       }); | ||||
|       this.onePageRendered = onePageRendered; | ||||
| 
 | ||||
|       var bindOnAfterDraw = function (pageView) { | ||||
|         // when page is painted, using the image as thumbnail base
 | ||||
|         pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() { | ||||
|           if (!isOnePageRenderedResolved) { | ||||
|             isOnePageRenderedResolved = true; | ||||
|             resolveOnePageRendered(); | ||||
|           } | ||||
|           var event = document.createEvent('CustomEvent'); | ||||
|           event.initCustomEvent('pagerendered', true, true, { | ||||
|             pageNumber: pageView.id | ||||
|           }); | ||||
|           self.container.dispatchEvent(event); | ||||
|         }; | ||||
|       }; | ||||
| 
 | ||||
|       var firstPagePromise = pdfDocument.getPage(1); | ||||
|       this.firstPagePromise = firstPagePromise; | ||||
| 
 | ||||
|       // Fetch a single page so we can get a viewport that will be the default
 | ||||
|       // viewport for all pages
 | ||||
|       return firstPagePromise.then(function(pdfPage) { | ||||
|         var scale = this._currentScale || 1.0; | ||||
|         var viewport = pdfPage.getViewport(scale * CSS_UNITS); | ||||
|         for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { | ||||
|           var pageSource = new PDFPageSource(pdfDocument, pageNum); | ||||
|           var pageView = new PageView(this.viewer, pageNum, scale, | ||||
|                                       viewport.clone(), this.linkService, | ||||
|                                       this.renderingQueue, this.cache, | ||||
|                                       pageSource, this); | ||||
|           bindOnAfterDraw(pageView); | ||||
|           this.pages.push(pageView); | ||||
|         } | ||||
| 
 | ||||
|         // Fetch all the pages since the viewport is needed before printing
 | ||||
|         // starts to create the correct size canvas. Wait until one page is
 | ||||
|         // rendered so we don't tie up too many resources early on.
 | ||||
|         onePageRendered.then(function () { | ||||
|           if (!PDFJS.disableAutoFetch) { | ||||
|             var getPagesLeft = pagesCount; | ||||
|             for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { | ||||
|               pdfDocument.getPage(pageNum).then(function (pageNum, pdfPage) { | ||||
|                 var pageView = self.pages[pageNum - 1]; | ||||
|                 if (!pageView.pdfPage) { | ||||
|                   pageView.setPdfPage(pdfPage); | ||||
|                 } | ||||
|                 var refStr = pdfPage.ref.num + ' ' + pdfPage.ref.gen + ' R'; | ||||
|                 pagesRefMap[refStr] = pageNum; | ||||
|                 getPagesLeft--; | ||||
|                 if (!getPagesLeft) { | ||||
|                   resolvePagesPromise(); | ||||
|                 } | ||||
|               }.bind(null, pageNum)); | ||||
|             } | ||||
|           } else { | ||||
|             // XXX: Printing is semi-broken with auto fetch disabled.
 | ||||
|             resolvePagesPromise(); | ||||
|           } | ||||
|         }); | ||||
| 
 | ||||
|         if (this.defaultRenderingQueue) { | ||||
|           firstPagePromise.then(this.update.bind(this)); | ||||
|         } | ||||
|       }.bind(this)); | ||||
|     }, | ||||
| 
 | ||||
|     _resetView: function () { | ||||
|       this.cache = new Cache(DEFAULT_CACHE_SIZE); | ||||
|       this.pages = []; | ||||
|       this._currentPageNumber = 1; | ||||
|       this._currentScale = UNKNOWN_SCALE; | ||||
|       this._currentScaleValue = null; | ||||
|       this.location = null; | ||||
|       this._pagesRotation = 0; | ||||
| 
 | ||||
|       var container = this.viewer; | ||||
|       while (container.hasChildNodes()) { | ||||
|         container.removeChild(container.lastChild); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     _scrollUpdate: function () { | ||||
|       this.lastScroll = Date.now(); | ||||
| 
 | ||||
|       if (this.pagesCount === 0) { | ||||
|         return; | ||||
|       } | ||||
|       this.update(); | ||||
|     }, | ||||
| 
 | ||||
|     _setScaleUpdatePages: function pdfViewer_setScaleUpdatePages( | ||||
|         newScale, newValue, noScroll, preset) { | ||||
|       this._currentScaleValue = newValue; | ||||
|       if (newScale === this._currentScale) { | ||||
|         return; | ||||
|       } | ||||
|       for (var i = 0, ii = this.pages.length; i < ii; i++) { | ||||
|         this.pages[i].update(newScale); | ||||
|       } | ||||
|       this._currentScale = newScale; | ||||
| 
 | ||||
|       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) { | ||||
|           page = this.location.pageNumber; | ||||
|           dest = [null, { name: 'XYZ' }, this.location.left, | ||||
|             this.location.top, null]; | ||||
|         } | ||||
|         this.pages[page - 1].scrollIntoView(dest); | ||||
|       } | ||||
| 
 | ||||
|       var event = document.createEvent('UIEvents'); | ||||
|       event.initUIEvent('scalechange', true, true, window, 0); | ||||
|       event.scale = newScale; | ||||
|       if (preset) { | ||||
|         event.presetValue = newValue; | ||||
|       } | ||||
|       this.container.dispatchEvent(event); | ||||
|     }, | ||||
| 
 | ||||
|     _setScale: function pdfViewer_setScale(value, noScroll) { | ||||
|       if (value === 'custom') { | ||||
|         return; | ||||
|       } | ||||
|       var scale = parseFloat(value); | ||||
| 
 | ||||
|       if (scale > 0) { | ||||
|         this._setScaleUpdatePages(scale, value, noScroll, false); | ||||
|       } else { | ||||
|         var currentPage = this.pages[this._currentPageNumber - 1]; | ||||
|         if (!currentPage) { | ||||
|           return; | ||||
|         } | ||||
|         var inPresentationMode = | ||||
|           this.presentationModeState === PresentationModeState.FULLSCREEN; | ||||
|         var hPadding = inPresentationMode ? 0 : SCROLLBAR_PADDING; | ||||
|         var vPadding = inPresentationMode ? 0 : VERTICAL_PADDING; | ||||
|         var pageWidthScale = (this.container.clientWidth - hPadding) / | ||||
|                              currentPage.width * currentPage.scale; | ||||
|         var pageHeightScale = (this.container.clientHeight - vPadding) / | ||||
|                               currentPage.height * currentPage.scale; | ||||
|         switch (value) { | ||||
|           case 'page-actual': | ||||
|             scale = 1; | ||||
|             break; | ||||
|           case 'page-width': | ||||
|             scale = pageWidthScale; | ||||
|             break; | ||||
|           case 'page-height': | ||||
|             scale = pageHeightScale; | ||||
|             break; | ||||
|           case 'page-fit': | ||||
|             scale = Math.min(pageWidthScale, pageHeightScale); | ||||
|             break; | ||||
|           case 'auto': | ||||
|             var isLandscape = (currentPage.width > currentPage.height); | ||||
|             var horizontalScale = isLandscape ? pageHeightScale : | ||||
|                                                 pageWidthScale; | ||||
|             scale = Math.min(MAX_AUTO_SCALE, horizontalScale); | ||||
|             break; | ||||
|           default: | ||||
|             console.error('pdfViewSetScale: \'' + value + | ||||
|               '\' is an unknown zoom value.'); | ||||
|             return; | ||||
|         } | ||||
|         this._setScaleUpdatePages(scale, value, noScroll, true); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     _updateLocation: function (firstPage) { | ||||
|       var currentScale = this._currentScale; | ||||
|       var currentScaleValue = this._currentScaleValue; | ||||
|       var normalizedScaleValue = | ||||
|         parseFloat(currentScaleValue) === currentScale ? | ||||
|         Math.round(currentScale * 10000) / 100 : currentScaleValue; | ||||
| 
 | ||||
|       var pageNumber = firstPage.id; | ||||
|       var pdfOpenParams = '#page=' + pageNumber; | ||||
|       pdfOpenParams += '&zoom=' + normalizedScaleValue; | ||||
|       var currentPageView = this.pages[pageNumber - 1]; | ||||
|       var container = this.container; | ||||
|       var topLeft = currentPageView.getPagePoint( | ||||
|         (container.scrollLeft - firstPage.x), | ||||
|         (container.scrollTop - firstPage.y)); | ||||
|       var intLeft = Math.round(topLeft[0]); | ||||
|       var intTop = Math.round(topLeft[1]); | ||||
|       pdfOpenParams += ',' + intLeft + ',' + intTop; | ||||
| 
 | ||||
|       this.location = { | ||||
|         pageNumber: pageNumber, | ||||
|         scale: normalizedScaleValue, | ||||
|         top: intTop, | ||||
|         left: intLeft, | ||||
|         pdfOpenParams: pdfOpenParams | ||||
|       }; | ||||
|     }, | ||||
| 
 | ||||
|     update: function () { | ||||
|       var visible = this._getVisiblePages(); | ||||
|       var visiblePages = visible.views; | ||||
|       if (visiblePages.length === 0) { | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       this.updateInProgress = true; | ||||
| 
 | ||||
|       var suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE, | ||||
|           2 * visiblePages.length + 1); | ||||
|       this.cache.resize(suggestedCacheSize); | ||||
| 
 | ||||
|       this.renderingQueue.renderHighestPriority(visible); | ||||
| 
 | ||||
|       var currentId = this.currentPageNumber; | ||||
|       var firstPage = visible.first; | ||||
| 
 | ||||
|       for (var i = 0, ii = visiblePages.length, stillFullyVisible = false; | ||||
|            i < ii; ++i) { | ||||
|         var page = visiblePages[i]; | ||||
| 
 | ||||
|         if (page.percent < 100) { | ||||
|           break; | ||||
|         } | ||||
|         if (page.id === currentId) { | ||||
|           stillFullyVisible = true; | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (!stillFullyVisible) { | ||||
|         currentId = visiblePages[0].id; | ||||
|       } | ||||
| 
 | ||||
|       if (this.presentationModeState !== PresentationModeState.FULLSCREEN) { | ||||
|         this.currentPageNumber = currentId; | ||||
|       } | ||||
| 
 | ||||
|       this._updateLocation(firstPage); | ||||
| 
 | ||||
|       this.updateInProgress = false; | ||||
| 
 | ||||
|       var event = document.createEvent('UIEvents'); | ||||
|       event.initUIEvent('updateviewarea', true, true, window, 0); | ||||
|       this.container.dispatchEvent(event); | ||||
|     }, | ||||
| 
 | ||||
|     containsElement: function (element) { | ||||
|       return this.container.contains(element); | ||||
|     }, | ||||
| 
 | ||||
|     focus: function () { | ||||
|       this.container.focus(); | ||||
|     }, | ||||
| 
 | ||||
|     blur: function () { | ||||
|       this.container.blur(); | ||||
|     }, | ||||
| 
 | ||||
|     get isHorizontalScrollbarEnabled() { | ||||
|       return (this.presentationModeState === PresentationModeState.FULLSCREEN ? | ||||
|         false : (this.container.scrollWidth > this.container.clientWidth)); | ||||
|     }, | ||||
| 
 | ||||
|     _getVisiblePages: function () { | ||||
|       if (this.presentationModeState !== PresentationModeState.FULLSCREEN) { | ||||
|         return getVisibleElements(this.container, this.pages, true); | ||||
|       } else { | ||||
|         // The algorithm in getVisibleElements doesn't work in all browsers and
 | ||||
|         // configurations when presentation mode is active.
 | ||||
|         var visible = []; | ||||
|         var currentPage = this.pages[this._currentPageNumber - 1]; | ||||
|         visible.push({ id: currentPage.id, view: currentPage }); | ||||
|         return { first: currentPage, last: currentPage, views: visible }; | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     cleanup: function () { | ||||
|       for (var i = 0, ii = this.pages.length; i < ii; i++) { | ||||
|         if (this.pages[i] && | ||||
|           this.pages[i].renderingState !== RenderingStates.FINISHED) { | ||||
|           this.pages[i].reset(); | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     forceRendering: function (currentlyVisiblePages) { | ||||
|       var visiblePages = currentlyVisiblePages || this._getVisiblePages(); | ||||
|       var pageView = this.renderingQueue.getHighestPriority(visiblePages, | ||||
|                                                             this.pages, | ||||
|                                                             this.scroll.down); | ||||
|       if (pageView) { | ||||
|         this.renderingQueue.renderView(pageView); | ||||
|         return; | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     getPageTextContent: function (pageIndex) { | ||||
|       return this.pdfDocument.getPage(pageIndex + 1).then(function (page) { | ||||
|         return page.getTextContent(); | ||||
|       }); | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * @param textLayerDiv {HTMLDivElement} | ||||
|      * @param pageIndex {number} | ||||
|      * @param viewport {PageViewport} | ||||
|      * @returns {TextLayerBuilder} | ||||
|      */ | ||||
|     createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) { | ||||
|       var isViewerInPresentationMode = | ||||
|         this.presentationModeState === PresentationModeState.FULLSCREEN; | ||||
|       return new TextLayerBuilder({ | ||||
|         textLayerDiv: textLayerDiv, | ||||
|         pageIndex: pageIndex, | ||||
|         viewport: viewport, | ||||
|         lastScrollSource: this, | ||||
|         isViewerInPresentationMode: isViewerInPresentationMode, | ||||
|         findController: this.findController | ||||
|       }); | ||||
|     }, | ||||
| 
 | ||||
|     setFindController: function (findController) { | ||||
|       this.findController = findController; | ||||
|     }, | ||||
|   }; | ||||
| 
 | ||||
|   return PDFViewer; | ||||
| })(); | ||||
| 
 | ||||
| /** | ||||
|  * PDFPage object source. | ||||
|  * @class | ||||
|  */ | ||||
| var PDFPageSource = (function PDFPageSourceClosure() { | ||||
|   /** | ||||
|    * @constructs | ||||
|    * @param {PDFDocument} pdfDocument | ||||
|    * @param {number} pageNumber | ||||
|    * @constructor | ||||
|    */ | ||||
|   function PDFPageSource(pdfDocument, pageNumber) { | ||||
|     this.pdfDocument = pdfDocument; | ||||
|     this.pageNumber = pageNumber; | ||||
|   } | ||||
| 
 | ||||
|   PDFPageSource.prototype = /** @lends PDFPageSource.prototype */ { | ||||
|     /** | ||||
|      * @returns {Promise<PDFPage>} | ||||
|      */ | ||||
|     getPage: function () { | ||||
|       return this.pdfDocument.getPage(this.pageNumber); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return PDFPageSource; | ||||
| })(); | ||||
| @ -14,7 +14,7 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* globals PDFView, scrollIntoView, HandTool */ | ||||
| /* globals scrollIntoView, HandTool, PDFViewerApplication */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| @ -68,7 +68,7 @@ var PresentationMode = { | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Initialize a timeout that is used to reset PDFView.currentPosition when the | ||||
|    * 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, | ||||
| @ -81,9 +81,8 @@ var PresentationMode = { | ||||
|     } | ||||
|     this.switchInProgress = setTimeout(function switchInProgressTimeout() { | ||||
|       delete this.switchInProgress; | ||||
|       this._notifyStateChange(); | ||||
|     }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); | ||||
| 
 | ||||
|     PDFView.currentPosition = null; | ||||
|   }, | ||||
| 
 | ||||
|   _resetSwitchInProgress: function presentationMode_resetSwitchInProgress() { | ||||
| @ -94,11 +93,12 @@ var PresentationMode = { | ||||
|   }, | ||||
| 
 | ||||
|   request: function presentationModeRequest() { | ||||
|     if (!PDFView.supportsFullscreen || this.isFullscreen || | ||||
|     if (!PDFViewerApplication.supportsFullscreen || this.isFullscreen || | ||||
|         !this.viewer.hasChildNodes()) { | ||||
|       return false; | ||||
|     } | ||||
|     this._setSwitchInProgress(); | ||||
|     this._notifyStateChange(); | ||||
| 
 | ||||
|     if (this.container.requestFullscreen) { | ||||
|       this.container.requestFullscreen(); | ||||
| @ -113,23 +113,33 @@ var PresentationMode = { | ||||
|     } | ||||
| 
 | ||||
|     this.args = { | ||||
|       page: PDFView.page, | ||||
|       previousScale: PDFView.currentScaleValue | ||||
|       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() { | ||||
|       PDFView.page = this.args.page; | ||||
|       PDFView.setScale('page-fit', true); | ||||
|       PDFViewerApplication.page = this.args.page; | ||||
|       PDFViewerApplication.setScale('page-fit', true); | ||||
|     }.bind(this), 0); | ||||
| 
 | ||||
|     window.addEventListener('mousemove', this.mouseMove, false); | ||||
| @ -143,15 +153,17 @@ var PresentationMode = { | ||||
|   }, | ||||
| 
 | ||||
|   exit: function presentationModeExit() { | ||||
|     var page = PDFView.page; | ||||
|     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; | ||||
|       PDFView.setScale(this.args.previousScale); | ||||
|       PDFView.page = page; | ||||
|       this._notifyStateChange(); | ||||
| 
 | ||||
|       PDFViewerApplication.setScale(this.args.previousScale, true); | ||||
|       PDFViewerApplication.page = page; | ||||
|       this.args = null; | ||||
|     }.bind(this), 0); | ||||
| 
 | ||||
| @ -160,7 +172,7 @@ var PresentationMode = { | ||||
|     window.removeEventListener('contextmenu', this.contextMenu, false); | ||||
| 
 | ||||
|     this.hideControls(); | ||||
|     PDFView.clearMouseScrollState(); | ||||
|     PDFViewerApplication.clearMouseScrollState(); | ||||
|     HandTool.exitPresentationMode(); | ||||
|     this.container.removeAttribute('contextmenu'); | ||||
|     this.contextMenuOpen = false; | ||||
| @ -224,7 +236,7 @@ var PresentationMode = { | ||||
|       if (!isInternalLink) { | ||||
|         // Unless an internal link was clicked, advance one page.
 | ||||
|         evt.preventDefault(); | ||||
|         PDFView.page += (evt.shiftKey ? -1 : 1); | ||||
|         PDFViewerApplication.page += (evt.shiftKey ? -1 : 1); | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* globals PDFView, SCROLLBAR_PADDING */ | ||||
| /* globals PDFViewerApplication, SCROLLBAR_PADDING */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| @ -87,7 +87,7 @@ var SecondaryToolbar = { | ||||
|   }, | ||||
| 
 | ||||
|   downloadClick: function secondaryToolbarDownloadClick(evt) { | ||||
|     PDFView.download(); | ||||
|     PDFViewerApplication.download(); | ||||
|     this.close(); | ||||
|   }, | ||||
| 
 | ||||
| @ -96,23 +96,23 @@ var SecondaryToolbar = { | ||||
|   }, | ||||
| 
 | ||||
|   firstPageClick: function secondaryToolbarFirstPageClick(evt) { | ||||
|     PDFView.page = 1; | ||||
|     PDFViewerApplication.page = 1; | ||||
|     this.close(); | ||||
|   }, | ||||
| 
 | ||||
|   lastPageClick: function secondaryToolbarLastPageClick(evt) { | ||||
|     if (PDFView.pdfDocument) { | ||||
|       PDFView.page = PDFView.pdfDocument.numPages; | ||||
|     if (PDFViewerApplication.pdfDocument) { | ||||
|       PDFViewerApplication.page = PDFViewerApplication.pagesCount; | ||||
|     } | ||||
|     this.close(); | ||||
|   }, | ||||
| 
 | ||||
|   pageRotateCwClick: function secondaryToolbarPageRotateCwClick(evt) { | ||||
|     PDFView.rotatePages(90); | ||||
|     PDFViewerApplication.rotatePages(90); | ||||
|   }, | ||||
| 
 | ||||
|   pageRotateCcwClick: function secondaryToolbarPageRotateCcwClick(evt) { | ||||
|     PDFView.rotatePages(-90); | ||||
|     PDFViewerApplication.rotatePages(-90); | ||||
|   }, | ||||
| 
 | ||||
|   documentPropertiesClick: function secondaryToolbarDocumentPropsClick(evt) { | ||||
|  | ||||
| @ -28,11 +28,23 @@ function isAllWhitespace(str) { | ||||
|   return !NonWhitespaceRegexp.test(str); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @typedef {Object} TextLayerBuilderOptions | ||||
|  * @property {HTMLDivElement} textLayerDiv - The text layer container. | ||||
|  * @property {number} pageIndex - The page index. | ||||
|  * @property {PageViewport} viewport - The viewport of the text layer. | ||||
|  * @property {ILastScrollSource} lastScrollSource - The object that records when | ||||
|  *   last time scroll happened. | ||||
|  * @property {boolean} isViewerInPresentationMode | ||||
|  * @property {PDFFindController} findController | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * TextLayerBuilder provides text-selection functionality for the PDF. | ||||
|  * It does this by creating overlay divs over the PDF text. These divs | ||||
|  * contain text that matches the PDF text they are overlaying. This object | ||||
|  * also provides a way to highlight text that is being searched for. | ||||
|  * @class | ||||
|  */ | ||||
| var TextLayerBuilder = (function TextLayerBuilderClosure() { | ||||
|   function TextLayerBuilder(options) { | ||||
|  | ||||
| @ -14,16 +14,32 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* globals PDFView, mozL10n, RenderingStates */ | ||||
| /* globals mozL10n, RenderingStates, Promise, scrollIntoView, PDFPageSource, | ||||
|            watchScroll, getVisibleElements */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | ||||
| var THUMBNAIL_SCROLL_MARGIN = -19; | ||||
| 
 | ||||
| /** | ||||
|  * @constructor | ||||
|  * @param container | ||||
|  * @param id | ||||
|  * @param defaultViewport | ||||
|  * @param linkService | ||||
|  * @param renderingQueue | ||||
|  * @param pageSource | ||||
|  * | ||||
|  * @implements {IRenderableView} | ||||
|  */ | ||||
| var ThumbnailView = function thumbnailView(container, id, defaultViewport, | ||||
|                                            linkService, renderingQueue, | ||||
|                                            pageSource) { | ||||
|   var anchor = document.createElement('a'); | ||||
|   anchor.href = PDFView.getAnchorUrl('#page=' + id); | ||||
|   anchor.href = linkService.getAnchorUrl('#page=' + id); | ||||
|   anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}'); | ||||
|   anchor.onclick = function stopNavigation() { | ||||
|     PDFView.page = id; | ||||
|     linkService.page = id; | ||||
|     return false; | ||||
|   }; | ||||
| 
 | ||||
| @ -36,6 +52,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | ||||
|   this.pageHeight = this.viewport.height; | ||||
|   this.pageRatio = this.pageWidth / this.pageHeight; | ||||
|   this.id = id; | ||||
|   this.renderingId = 'thumbnail' + id; | ||||
| 
 | ||||
|   this.canvasWidth = 98; | ||||
|   this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; | ||||
| @ -62,6 +79,8 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | ||||
| 
 | ||||
|   this.hasImage = false; | ||||
|   this.renderingState = RenderingStates.INITIAL; | ||||
|   this.renderingQueue = renderingQueue; | ||||
|   this.pageSource = pageSource; | ||||
| 
 | ||||
|   this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) { | ||||
|     this.pdfPage = pdfPage; | ||||
| @ -125,7 +144,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | ||||
| 
 | ||||
|   this.draw = function thumbnailViewDraw(callback) { | ||||
|     if (!this.pdfPage) { | ||||
|       var promise = PDFView.getPage(this.id); | ||||
|       var promise = this.pageSource.getPage(this.id); | ||||
|       promise.then(function(pdfPage) { | ||||
|         this.setPdfPage(pdfPage); | ||||
|         this.draw(callback); | ||||
| @ -150,7 +169,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | ||||
|       canvasContext: ctx, | ||||
|       viewport: drawViewport, | ||||
|       continueCallback: function(cont) { | ||||
|         if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) { | ||||
|         if (!self.renderingQueue.isHighestPriority(self)) { | ||||
|           self.renderingState = RenderingStates.PAUSED; | ||||
|           self.resume = function() { | ||||
|             self.renderingState = RenderingStates.RUNNING; | ||||
| @ -187,7 +206,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | ||||
| 
 | ||||
|   this.setImage = function thumbnailViewSetImage(img) { | ||||
|     if (!this.pdfPage) { | ||||
|       var promise = PDFView.getPage(this.id); | ||||
|       var promise = this.pageSource.getPage(); | ||||
|       promise.then(function(pdfPage) { | ||||
|         this.setPdfPage(pdfPage); | ||||
|         this.setImage(img); | ||||
| @ -232,3 +251,134 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | ||||
| }; | ||||
| 
 | ||||
| ThumbnailView.tempImageCache = null; | ||||
| 
 | ||||
| /** | ||||
|  * @typedef {Object} PDFThumbnailViewerOptions | ||||
|  * @property {HTMLDivElement} container - The container for the thumbs elements. | ||||
|  * @property {IPDFLinkService} linkService - The navigation/linking service. | ||||
|  * @property {PDFRenderingQueue} renderingQueue - The rendering queue object. | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Simple viewer control to display thumbs for pages. | ||||
|  * @class | ||||
|  */ | ||||
| var PDFThumbnailViewer = (function pdfThumbnailViewer() { | ||||
|   /** | ||||
|    * @constructs | ||||
|    * @param {PDFThumbnailViewerOptions} options | ||||
|    */ | ||||
|   function PDFThumbnailViewer(options) { | ||||
|     this.container = options.container; | ||||
|     this.renderingQueue = options.renderingQueue; | ||||
|     this.linkService = options.linkService; | ||||
| 
 | ||||
|     this.scroll = watchScroll(this.container, this._scrollUpdated.bind(this)); | ||||
|     this._resetView(); | ||||
|   } | ||||
| 
 | ||||
|   PDFThumbnailViewer.prototype = { | ||||
|     _scrollUpdated: function PDFThumbnailViewer_scrollUpdated() { | ||||
|       this.renderingQueue.renderHighestPriority(); | ||||
|     }, | ||||
| 
 | ||||
|     getThumbnail: function PDFThumbnailViewer_getThumbnail(index) { | ||||
|       return this.thumbnails[index]; | ||||
|     }, | ||||
| 
 | ||||
|     _getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() { | ||||
|       return getVisibleElements(this.container, this.thumbnails); | ||||
|     }, | ||||
| 
 | ||||
|     scrollThumbnailIntoView: function (page) { | ||||
|       var selected = document.querySelector('.thumbnail.selected'); | ||||
|       if (selected) { | ||||
|         selected.classList.remove('selected'); | ||||
|       } | ||||
|       var thumbnail = document.getElementById('thumbnailContainer' + page); | ||||
|       thumbnail.classList.add('selected'); | ||||
|       var visibleThumbs = this._getVisibleThumbs(); | ||||
|       var numVisibleThumbs = visibleThumbs.views.length; | ||||
| 
 | ||||
|       // If the thumbnail isn't currently visible, scroll it into view.
 | ||||
|       if (numVisibleThumbs > 0) { | ||||
|         var first = visibleThumbs.first.id; | ||||
|         // Account for only one thumbnail being visible.
 | ||||
|         var last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first); | ||||
|         if (page <= first || page >= last) { | ||||
|           scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN }); | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     get pagesRotation() { | ||||
|       return this._pagesRotation; | ||||
|     }, | ||||
| 
 | ||||
|     set pagesRotation(rotation) { | ||||
|       this._pagesRotation = rotation; | ||||
|       for (var i = 0, l = this.thumbnails.length; i < l; i++) { | ||||
|         var thumb = this.thumbnails[i]; | ||||
|         thumb.update(rotation); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     cleanup: function PDFThumbnailViewer_cleanup() { | ||||
|       ThumbnailView.tempImageCache = null; | ||||
|     }, | ||||
| 
 | ||||
|     _resetView: function () { | ||||
|       this.thumbnails = []; | ||||
|       this._pagesRotation = 0; | ||||
|     }, | ||||
| 
 | ||||
|     setDocument: function (pdfDocument) { | ||||
|       if (this.pdfDocument) { | ||||
|         // cleanup of the elements and views
 | ||||
|         var thumbsView = this.container; | ||||
|         while (thumbsView.hasChildNodes()) { | ||||
|           thumbsView.removeChild(thumbsView.lastChild); | ||||
|         } | ||||
|         this._resetView(); | ||||
|       } | ||||
| 
 | ||||
|       this.pdfDocument = pdfDocument; | ||||
|       if (!pdfDocument) { | ||||
|         return Promise.resolve(); | ||||
|       } | ||||
| 
 | ||||
|       return pdfDocument.getPage(1).then(function (firstPage) { | ||||
|         var pagesCount = pdfDocument.numPages; | ||||
|         var viewport = firstPage.getViewport(1.0); | ||||
|         for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { | ||||
|           var pageSource = new PDFPageSource(pdfDocument, pageNum); | ||||
|           var thumbnail = new ThumbnailView(this.container, pageNum, | ||||
|                                             viewport.clone(), this.linkService, | ||||
|                                             this.renderingQueue, pageSource); | ||||
|           this.thumbnails.push(thumbnail); | ||||
|         } | ||||
|       }.bind(this)); | ||||
|     }, | ||||
| 
 | ||||
|     ensureThumbnailVisible: | ||||
|         function PDFThumbnailViewer_ensureThumbnailVisible(page) { | ||||
|       // Ensure that the thumbnail of the current page is visible
 | ||||
|       // when switching from another view.
 | ||||
|       scrollIntoView(document.getElementById('thumbnailContainer' + page)); | ||||
|     }, | ||||
| 
 | ||||
|     forceRendering: function () { | ||||
|       var visibleThumbs = this._getVisibleThumbs(); | ||||
|       var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, | ||||
|                                                              this.thumbnails, | ||||
|                                                              this.scroll.down); | ||||
|       if (thumbView) { | ||||
|         this.renderingQueue.renderView(thumbView); | ||||
|         return true; | ||||
|       } | ||||
|       return false; | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return PDFThumbnailViewer; | ||||
| })(); | ||||
|  | ||||
| @ -16,6 +16,14 @@ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var CSS_UNITS = 96.0 / 72.0; | ||||
| var DEFAULT_SCALE = 'auto'; | ||||
| var UNKNOWN_SCALE = 0; | ||||
| var MAX_AUTO_SCALE = 1.25; | ||||
| var SCROLLBAR_PADDING = 40; | ||||
| var VERTICAL_PADDING = 5; | ||||
| var DEFAULT_CACHE_SIZE = 10; | ||||
| 
 | ||||
| // optimised CSS custom property getter/setter
 | ||||
| var CustomStyle = (function CustomStyleClosure() { | ||||
| 
 | ||||
| @ -138,6 +146,91 @@ function scrollIntoView(element, spot) { | ||||
|   parent.scrollTop = offsetY; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Helper function to start monitoring the scroll event and converting them into | ||||
|  * PDF.js friendly one: with scroll debounce and scroll direction. | ||||
|  */ | ||||
| function watchScroll(viewAreaElement, callback) { | ||||
|   var debounceScroll = function debounceScroll(evt) { | ||||
|     if (rAF) { | ||||
|       return; | ||||
|     } | ||||
|     // schedule an invocation of scroll for next animation frame.
 | ||||
|     rAF = window.requestAnimationFrame(function viewAreaElementScrolled() { | ||||
|       rAF = null; | ||||
| 
 | ||||
|       var currentY = viewAreaElement.scrollTop; | ||||
|       var lastY = state.lastY; | ||||
|       if (currentY > lastY) { | ||||
|         state.down = true; | ||||
|       } else if (currentY < lastY) { | ||||
|         state.down = false; | ||||
|       } | ||||
|       state.lastY = currentY; | ||||
|       // else do nothing and use previous value
 | ||||
|       callback(state); | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   var state = { | ||||
|     down: true, | ||||
|     lastY: viewAreaElement.scrollTop, | ||||
|     _eventHandler: debounceScroll | ||||
|   }; | ||||
| 
 | ||||
|   var rAF = null; | ||||
|   viewAreaElement.addEventListener('scroll', debounceScroll, true); | ||||
|   return state; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Generic helper to find out what elements are visible within a scroll pane. | ||||
|  */ | ||||
| function getVisibleElements(scrollEl, views, sortByVisibility) { | ||||
|   var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight; | ||||
|   var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth; | ||||
| 
 | ||||
|   var visible = [], view; | ||||
|   var currentHeight, viewHeight, hiddenHeight, percentHeight; | ||||
|   var currentWidth, viewWidth; | ||||
|   for (var i = 0, ii = views.length; i < ii; ++i) { | ||||
|     view = views[i]; | ||||
|     currentHeight = view.el.offsetTop + view.el.clientTop; | ||||
|     viewHeight = view.el.clientHeight; | ||||
|     if ((currentHeight + viewHeight) < top) { | ||||
|       continue; | ||||
|     } | ||||
|     if (currentHeight > bottom) { | ||||
|       break; | ||||
|     } | ||||
|     currentWidth = view.el.offsetLeft + view.el.clientLeft; | ||||
|     viewWidth = view.el.clientWidth; | ||||
|     if ((currentWidth + viewWidth) < left || currentWidth > right) { | ||||
|       continue; | ||||
|     } | ||||
|     hiddenHeight = Math.max(0, top - currentHeight) + | ||||
|       Math.max(0, currentHeight + viewHeight - bottom); | ||||
|     percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0; | ||||
| 
 | ||||
|     visible.push({ id: view.id, x: currentWidth, y: currentHeight, | ||||
|       view: view, percent: percentHeight }); | ||||
|   } | ||||
| 
 | ||||
|   var first = visible[0]; | ||||
|   var last = visible[visible.length - 1]; | ||||
| 
 | ||||
|   if (sortByVisibility) { | ||||
|     visible.sort(function(a, b) { | ||||
|       var pc = a.percent - b.percent; | ||||
|       if (Math.abs(pc) > 0.001) { | ||||
|         return -pc; | ||||
|       } | ||||
|       return a.id - b.id; // ensure stability
 | ||||
|     }); | ||||
|   } | ||||
|   return {first: first, last: last, views: visible}; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Event handler to suppress context menu. | ||||
|  */ | ||||
|  | ||||
| @ -68,9 +68,11 @@ http://sourceforge.net/adobe/cmap/wiki/License/ | ||||
|     <script src="preferences.js"></script> | ||||
|     <script src="download_manager.js"></script> | ||||
|     <script src="view_history.js"></script> | ||||
|     <script src="pdf_rendering_queue.js"></script> | ||||
|     <script src="page_view.js"></script> | ||||
|     <script src="thumbnail_view.js"></script> | ||||
|     <script src="text_layer_builder.js"></script> | ||||
|     <script src="pdf_viewer.js"></script> | ||||
|     <script src="thumbnail_view.js"></script> | ||||
|     <script src="document_outline_view.js"></script> | ||||
|     <script src="document_attachments_view.js"></script> | ||||
|     <script src="pdf_find_bar.js"></script> | ||||
|  | ||||
							
								
								
									
										1054
									
								
								web/viewer.js
									
									
									
									
									
								
							
							
						
						
									
										1054
									
								
								web/viewer.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user