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. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /* globals chrome, PDFJS, PDFView */ | /* globals chrome, PDFJS, PDFViewerApplication */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var ChromeCom = (function ChromeComClosure() { | var ChromeCom = (function ChromeComClosure() { | ||||||
| @ -64,10 +64,10 @@ var ChromeCom = (function ChromeComClosure() { | |||||||
|         var streamUrl = response.streamUrl; |         var streamUrl = response.streamUrl; | ||||||
|         if (streamUrl) { |         if (streamUrl) { | ||||||
|           console.log('Found data stream for ' + file); |           console.log('Found data stream for ' + file); | ||||||
|           PDFView.open(streamUrl, 0, undefined, undefined, { |           PDFViewerApplication.open(streamUrl, 0, undefined, undefined, { | ||||||
|             length: response.contentLength |             length: response.contentLength | ||||||
|           }); |           }); | ||||||
|           PDFView.setTitleUsingUrl(file); |           PDFViewerApplication.setTitleUsingUrl(file); | ||||||
|           return; |           return; | ||||||
|         } |         } | ||||||
|         if (isFTPFile && !response.extensionSupportsFTP) { |         if (isFTPFile && !response.extensionSupportsFTP) { | ||||||
| @ -91,7 +91,7 @@ var ChromeCom = (function ChromeComClosure() { | |||||||
|         resolveLocalFileSystemURL(file, function onResolvedFSURL(fileEntry) { |         resolveLocalFileSystemURL(file, function onResolvedFSURL(fileEntry) { | ||||||
|           fileEntry.file(function(fileObject) { |           fileEntry.file(function(fileObject) { | ||||||
|             var blobUrl = URL.createObjectURL(fileObject); |             var blobUrl = URL.createObjectURL(fileObject); | ||||||
|             PDFView.open(blobUrl, 0, undefined, undefined, { |             PDFViewerApplication.open(blobUrl, 0, undefined, undefined, { | ||||||
|               length: fileObject.size |               length: fileObject.size | ||||||
|             }); |             }); | ||||||
|           }); |           }); | ||||||
| @ -100,11 +100,11 @@ var ChromeCom = (function ChromeComClosure() { | |||||||
|           // usual way of getting the File's data (via the Web worker).
 |           // usual way of getting the File's data (via the Web worker).
 | ||||||
|           console.warn('Cannot resolve file ' + file + ', ' + error.name + ' ' + |           console.warn('Cannot resolve file ' + file + ', ' + error.name + ' ' + | ||||||
|                        error.message); |                        error.message); | ||||||
|           PDFView.open(file, 0); |           PDFViewerApplication.open(file, 0); | ||||||
|         }); |         }); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       PDFView.open(file, 0); |       PDFViewerApplication.open(file, 0); | ||||||
|     }); |     }); | ||||||
|   }; |   }; | ||||||
|   return ChromeCom; |   return ChromeCom; | ||||||
|  | |||||||
| @ -14,20 +14,18 @@ | |||||||
|  * See the License for the specific language governing permissions and |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| /* globals PDFView, DownloadManager, getFileName */ | /* globals DownloadManager, getFileName */ | ||||||
| 
 | 
 | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var DocumentAttachmentsView = function documentAttachmentsView(attachments) { | var DocumentAttachmentsView = function documentAttachmentsView(options) { | ||||||
|   var attachmentsView = document.getElementById('attachmentsView'); |   var attachments = options.attachments; | ||||||
|  |   var attachmentsView = options.attachmentsView; | ||||||
|   while (attachmentsView.firstChild) { |   while (attachmentsView.firstChild) { | ||||||
|     attachmentsView.removeChild(attachmentsView.firstChild); |     attachmentsView.removeChild(attachmentsView.firstChild); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (!attachments) { |   if (!attachments) { | ||||||
|     if (!attachmentsView.classList.contains('hidden')) { |  | ||||||
|       PDFView.switchSidebarView('thumbs'); |  | ||||||
|     } |  | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,27 +14,26 @@ | |||||||
|  * See the License for the specific language governing permissions and |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| /* globals PDFView */ |  | ||||||
| 
 | 
 | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var DocumentOutlineView = function documentOutlineView(outline) { | var DocumentOutlineView = function documentOutlineView(options) { | ||||||
|   var outlineView = document.getElementById('outlineView'); |   var outline = options.outline; | ||||||
|  |   var outlineView = options.outlineView; | ||||||
|   while (outlineView.firstChild) { |   while (outlineView.firstChild) { | ||||||
|     outlineView.removeChild(outlineView.firstChild); |     outlineView.removeChild(outlineView.firstChild); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (!outline) { |   if (!outline) { | ||||||
|     if (!outlineView.classList.contains('hidden')) { |  | ||||||
|       PDFView.switchSidebarView('thumbs'); |  | ||||||
|     } |  | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   var linkService = options.linkService; | ||||||
|  | 
 | ||||||
|   function bindItemLink(domObj, item) { |   function bindItemLink(domObj, item) { | ||||||
|     domObj.href = PDFView.getDestinationHash(item.dest); |     domObj.href = linkService.getDestinationHash(item.dest); | ||||||
|     domObj.onclick = function documentOutlineViewOnclick(e) { |     domObj.onclick = function documentOutlineViewOnclick(e) { | ||||||
|       PDFView.navigateTo(item.dest); |       linkService.navigateTo(item.dest); | ||||||
|       return false; |       return false; | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
|  * See the License for the specific language governing permissions and |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| /* globals PDFView, Promise, mozL10n, getPDFFileNameFromURL, OverlayManager */ | /* globals Promise, mozL10n, getPDFFileNameFromURL, OverlayManager */ | ||||||
| 
 | 
 | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| @ -35,6 +35,8 @@ var DocumentProperties = { | |||||||
|   producerField: null, |   producerField: null, | ||||||
|   versionField: null, |   versionField: null, | ||||||
|   pageCountField: null, |   pageCountField: null, | ||||||
|  |   url: null, | ||||||
|  |   pdfDocument: null, | ||||||
| 
 | 
 | ||||||
|   initialize: function documentPropertiesInitialize(options) { |   initialize: function documentPropertiesInitialize(options) { | ||||||
|     this.overlayName = options.overlayName; |     this.overlayName = options.overlayName; | ||||||
| @ -72,7 +74,7 @@ var DocumentProperties = { | |||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     // Get the file size (if it hasn't already been set).
 |     // 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) { |       if (data.length === this.rawFileSize) { | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
| @ -81,10 +83,10 @@ var DocumentProperties = { | |||||||
|     }.bind(this)); |     }.bind(this)); | ||||||
| 
 | 
 | ||||||
|     // Get the document properties.
 |     // Get the document properties.
 | ||||||
|     PDFView.pdfDocument.getMetadata().then(function(data) { |     this.pdfDocument.getMetadata().then(function(data) { | ||||||
|       var fields = [ |       var fields = [ | ||||||
|         { field: this.fileNameField, |         { field: this.fileNameField, | ||||||
|           content: getPDFFileNameFromURL(PDFView.url) }, |           content: getPDFFileNameFromURL(this.url) }, | ||||||
|         { field: this.fileSizeField, content: this.parseFileSize() }, |         { field: this.fileSizeField, content: this.parseFileSize() }, | ||||||
|         { field: this.titleField, content: data.info.Title }, |         { field: this.titleField, content: data.info.Title }, | ||||||
|         { field: this.authorField, content: data.info.Author }, |         { field: this.authorField, content: data.info.Author }, | ||||||
| @ -97,7 +99,7 @@ var DocumentProperties = { | |||||||
|         { field: this.creatorField, content: data.info.Creator }, |         { field: this.creatorField, content: data.info.Creator }, | ||||||
|         { field: this.producerField, content: data.info.Producer }, |         { field: this.producerField, content: data.info.Producer }, | ||||||
|         { field: this.versionField, content: data.info.PDFFormatVersion }, |         { 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.
 |       // 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 |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| /* globals RenderingStates, PDFView, PDFHistory, PDFJS, mozL10n, CustomStyle, | /* globals RenderingStates, PDFJS, mozL10n, CustomStyle, | ||||||
|            PresentationMode, scrollIntoView, SCROLLBAR_PADDING, CSS_UNITS, |            SCROLLBAR_PADDING, CSS_UNITS, UNKNOWN_SCALE, DEFAULT_SCALE, | ||||||
|            UNKNOWN_SCALE, DEFAULT_SCALE, getOutputScale, TextLayerBuilder, |            getOutputScale, scrollIntoView, Stats, PresentationModeState */ | ||||||
|            cache, Stats */ |  | ||||||
| 
 | 
 | ||||||
| 'use strict'; | '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.id = id; | ||||||
|  |   this.renderingId = 'page' + id; | ||||||
| 
 | 
 | ||||||
|   this.rotation = 0; |   this.rotation = 0; | ||||||
|   this.scale = scale || 1.0; |   this.scale = scale || 1.0; | ||||||
| @ -31,6 +46,12 @@ var PageView = function pageView(container, id, scale, | |||||||
|   this.pdfPageRotate = defaultViewport.rotation; |   this.pdfPageRotate = defaultViewport.rotation; | ||||||
|   this.hasRestrictedScaling = false; |   this.hasRestrictedScaling = false; | ||||||
| 
 | 
 | ||||||
|  |   this.linkService = linkService; | ||||||
|  |   this.renderingQueue = renderingQueue; | ||||||
|  |   this.cache = cache; | ||||||
|  |   this.pageSource = pageSource; | ||||||
|  |   this.viewer = viewer; | ||||||
|  | 
 | ||||||
|   this.renderingState = RenderingStates.INITIAL; |   this.renderingState = RenderingStates.INITIAL; | ||||||
|   this.resume = null; |   this.resume = null; | ||||||
| 
 | 
 | ||||||
| @ -241,10 +262,10 @@ var PageView = function pageView(container, id, scale, | |||||||
|   function setupAnnotations(pageDiv, pdfPage, viewport) { |   function setupAnnotations(pageDiv, pdfPage, viewport) { | ||||||
| 
 | 
 | ||||||
|     function bindLink(link, dest) { |     function bindLink(link, dest) { | ||||||
|       link.href = PDFView.getDestinationHash(dest); |       link.href = linkService.getDestinationHash(dest); | ||||||
|       link.onclick = function pageViewSetupLinksOnclick() { |       link.onclick = function pageViewSetupLinksOnclick() { | ||||||
|         if (dest) { |         if (dest) { | ||||||
|           PDFView.navigateTo(dest); |           linkService.navigateTo(dest); | ||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|       }; |       }; | ||||||
| @ -254,47 +275,9 @@ var PageView = function pageView(container, id, scale, | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function bindNamedAction(link, action) { |     function bindNamedAction(link, action) { | ||||||
|       link.href = PDFView.getAnchorUrl(''); |       link.href = linkService.getAnchorUrl(''); | ||||||
|       link.onclick = function pageViewSetupNamedActionOnClick() { |       link.onclick = function pageViewSetupNamedActionOnClick() { | ||||||
|         // See PDF reference, table 8.45 - Named action
 |         linkService.executeNamedAction(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
 |  | ||||||
|         } |  | ||||||
|         return false; |         return false; | ||||||
|       }; |       }; | ||||||
|       link.className = 'internalLink'; |       link.className = 'internalLink'; | ||||||
| @ -376,14 +359,16 @@ var PageView = function pageView(container, id, scale, | |||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   this.scrollIntoView = function pageViewScrollIntoView(dest) { |   this.scrollIntoView = function pageViewScrollIntoView(dest) { | ||||||
|     if (PresentationMode.active) { |     if (this.viewer.presentationModeState === | ||||||
|       if (PDFView.page !== this.id) { |         PresentationModeState.FULLSCREEN) { | ||||||
|         // Avoid breaking PDFView.getVisiblePages in presentation mode.
 |       if (this.linkService.page !== this.id) { | ||||||
|         PDFView.page = this.id; |         // Avoid breaking getVisiblePages in presentation mode.
 | ||||||
|  |         this.linkService.page = this.id; | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       dest = null; |       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) { |     if (!dest) { | ||||||
|       scrollIntoView(div); |       scrollIntoView(div); | ||||||
| @ -431,9 +416,10 @@ var PageView = function pageView(container, id, scale, | |||||||
|         y = dest[3]; |         y = dest[3]; | ||||||
|         width = dest[4] - x; |         width = dest[4] - x; | ||||||
|         height = dest[5] - y; |         height = dest[5] - y; | ||||||
|         widthScale = (PDFView.container.clientWidth - SCROLLBAR_PADDING) / |         var viewerContainer = this.viewer.container; | ||||||
|  |         widthScale = (viewerContainer.clientWidth - SCROLLBAR_PADDING) / | ||||||
|           width / CSS_UNITS; |           width / CSS_UNITS; | ||||||
|         heightScale = (PDFView.container.clientHeight - SCROLLBAR_PADDING) / |         heightScale = (viewerContainer.clientHeight - SCROLLBAR_PADDING) / | ||||||
|           height / CSS_UNITS; |           height / CSS_UNITS; | ||||||
|         scale = Math.min(Math.abs(widthScale), Math.abs(heightScale)); |         scale = Math.min(Math.abs(widthScale), Math.abs(heightScale)); | ||||||
|         break; |         break; | ||||||
| @ -441,10 +427,10 @@ var PageView = function pageView(container, id, scale, | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (scale && scale !== PDFView.currentScale) { |     if (scale && scale !== this.viewer.currentScale) { | ||||||
|       PDFView.setScale(scale, true, true); |       this.viewer.currentScaleValue = scale; | ||||||
|     } else if (PDFView.currentScale === UNKNOWN_SCALE) { |     } else if (this.viewer.currentScale === UNKNOWN_SCALE) { | ||||||
|       PDFView.setScale(DEFAULT_SCALE, true, true); |       this.viewer.currentScaleValue = DEFAULT_SCALE; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (scale === 'page-fit' && !dest[4]) { |     if (scale === 'page-fit' && !dest[4]) { | ||||||
| @ -462,12 +448,6 @@ var PageView = function pageView(container, id, scale, | |||||||
|     scrollIntoView(div, { left: left, top: top }); |     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) { |   this.draw = function pageviewDraw(callback) { | ||||||
|     var pdfPage = this.pdfPage; |     var pdfPage = this.pdfPage; | ||||||
| 
 | 
 | ||||||
| @ -475,7 +455,7 @@ var PageView = function pageView(container, id, scale, | |||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     if (!pdfPage) { |     if (!pdfPage) { | ||||||
|       var promise = PDFView.getPage(this.id); |       var promise = this.pageSource.getPage(); | ||||||
|       promise.then(function(pdfPage) { |       promise.then(function(pdfPage) { | ||||||
|         delete this.pagePdfPromise; |         delete this.pagePdfPromise; | ||||||
|         this.setPdfPage(pdfPage); |         this.setPdfPage(pdfPage); | ||||||
| @ -543,6 +523,7 @@ var PageView = function pageView(container, id, scale, | |||||||
|     canvas._viewport = viewport; |     canvas._viewport = viewport; | ||||||
| 
 | 
 | ||||||
|     var textLayerDiv = null; |     var textLayerDiv = null; | ||||||
|  |     var textLayer = null; | ||||||
|     if (!PDFJS.disableTextLayer) { |     if (!PDFJS.disableTextLayer) { | ||||||
|       textLayerDiv = document.createElement('div'); |       textLayerDiv = document.createElement('div'); | ||||||
|       textLayerDiv.className = 'textLayer'; |       textLayerDiv.className = 'textLayer'; | ||||||
| @ -554,16 +535,12 @@ var PageView = function pageView(container, id, scale, | |||||||
|       } else { |       } else { | ||||||
|         div.appendChild(textLayerDiv); |         div.appendChild(textLayerDiv); | ||||||
|       } |       } | ||||||
|  | 
 | ||||||
|  |       textLayer = this.viewer.createTextLayerBuilder(textLayerDiv, this.id - 1, | ||||||
|  |                                                      this.viewport); | ||||||
|     } |     } | ||||||
|     var textLayer = this.textLayer = |     this.textLayer = textLayer; | ||||||
|       textLayerDiv ? new TextLayerBuilder({ | 
 | ||||||
|         textLayerDiv: textLayerDiv, |  | ||||||
|         pageIndex: this.id - 1, |  | ||||||
|         lastScrollSource: PDFView, |  | ||||||
|         viewport: this.viewport, |  | ||||||
|         isViewerInPresentationMode: PresentationMode.active, |  | ||||||
|         findController: PDFView.findController |  | ||||||
|       }) : null; |  | ||||||
|     // TODO(mack): use data attributes to store these
 |     // TODO(mack): use data attributes to store these
 | ||||||
|     ctx._scaleX = outputScale.sx; |     ctx._scaleX = outputScale.sx; | ||||||
|     ctx._scaleY = outputScale.sy; |     ctx._scaleY = outputScale.sy; | ||||||
| @ -598,22 +575,7 @@ var PageView = function pageView(container, id, scale, | |||||||
|         self.zoomLayer = null; |         self.zoomLayer = null; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
| //#if (FIREFOX || MOZCENTRAL)
 |       self.error = error; | ||||||
| //    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.stats = pdfPage.stats; |       self.stats = pdfPage.stats; | ||||||
|       self.updateStats(); |       self.updateStats(); | ||||||
|       if (self.onAfterDraw) { |       if (self.onAfterDraw) { | ||||||
| @ -626,18 +588,6 @@ var PageView = function pageView(container, id, scale, | |||||||
|       }); |       }); | ||||||
|       div.dispatchEvent(event); |       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(); |       callback(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -646,7 +596,7 @@ var PageView = function pageView(container, id, scale, | |||||||
|       viewport: this.viewport, |       viewport: this.viewport, | ||||||
|       // intent: 'default', // === 'display'
 |       // intent: 'default', // === 'display'
 | ||||||
|       continueCallback: function pdfViewcContinueCallback(cont) { |       continueCallback: function pdfViewcContinueCallback(cont) { | ||||||
|         if (PDFView.highestPriorityPage !== 'page' + self.id) { |         if (!self.renderingQueue.isHighestPriority(self)) { | ||||||
|           self.renderingState = RenderingStates.PAUSED; |           self.renderingState = RenderingStates.PAUSED; | ||||||
|           self.resume = function resumeCallback() { |           self.resume = function resumeCallback() { | ||||||
|             self.renderingState = RenderingStates.RUNNING; |             self.renderingState = RenderingStates.RUNNING; | ||||||
| @ -663,7 +613,7 @@ var PageView = function pageView(container, id, scale, | |||||||
|       function pdfPageRenderCallback() { |       function pdfPageRenderCallback() { | ||||||
|         pageViewDrawCallback(null); |         pageViewDrawCallback(null); | ||||||
|         if (textLayer) { |         if (textLayer) { | ||||||
|           self.getTextContent().then( |           self.pdfPage.getTextContent().then( | ||||||
|             function textContentResolved(textContent) { |             function textContentResolved(textContent) { | ||||||
|               textLayer.setTextContent(textContent); |               textLayer.setTextContent(textContent); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -13,10 +13,17 @@ | |||||||
|  * See the License for the specific language governing permissions and |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| /* globals PDFJS, FindStates, FirefoxCom, Promise */ | /* globals PDFJS, FirefoxCom, Promise */ | ||||||
| 
 | 
 | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
|  | var FindStates = { | ||||||
|  |   FIND_FOUND: 0, | ||||||
|  |   FIND_NOTFOUND: 1, | ||||||
|  |   FIND_WRAPPED: 2, | ||||||
|  |   FIND_PENDING: 3 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Provides "search" or "find" functionality for the PDF. |  * Provides "search" or "find" functionality for the PDF. | ||||||
|  * This object actually performs the search for a given string. |  * This object actually performs the search for a given string. | ||||||
| @ -41,7 +48,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
|     this.state = null; |     this.state = null; | ||||||
|     this.dirtyMatch = false; |     this.dirtyMatch = false; | ||||||
|     this.findTimeout = null; |     this.findTimeout = null; | ||||||
|     this.pdfPageSource = options.pdfPageSource || null; |     this.pdfViewer = options.pdfViewer || null; | ||||||
|     this.integratedFind = options.integratedFind || false; |     this.integratedFind = options.integratedFind || false; | ||||||
|     this.charactersToNormalize = { |     this.charactersToNormalize = { | ||||||
|       '\u2018': '\'', // Left single quotation mark
 |       '\u2018': '\'', // Left single quotation mark
 | ||||||
| @ -137,7 +144,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
| 
 | 
 | ||||||
|       this.pageContents = []; |       this.pageContents = []; | ||||||
|       var extractTextPromisesResolves = []; |       var extractTextPromisesResolves = []; | ||||||
|       var numPages = this.pdfPageSource.pdfDocument.numPages; |       var numPages = this.pdfViewer.pagesCount; | ||||||
|       for (var i = 0; i < numPages; i++) { |       for (var i = 0; i < numPages; i++) { | ||||||
|         this.extractTextPromises.push(new Promise(function (resolve) { |         this.extractTextPromises.push(new Promise(function (resolve) { | ||||||
|           extractTextPromisesResolves.push(resolve); |           extractTextPromisesResolves.push(resolve); | ||||||
| @ -146,7 +153,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
| 
 | 
 | ||||||
|       var self = this; |       var self = this; | ||||||
|       function extractPageText(pageIndex) { |       function extractPageText(pageIndex) { | ||||||
|         self.pdfPageSource.pages[pageIndex].getTextContent().then( |         self.pdfViewer.getPageTextContent(pageIndex).then( | ||||||
|           function textContentResolved(textContent) { |           function textContentResolved(textContent) { | ||||||
|             var textItems = textContent.items; |             var textItems = textContent.items; | ||||||
|             var str = []; |             var str = []; | ||||||
| @ -159,7 +166,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
|             self.pageContents.push(str.join('')); |             self.pageContents.push(str.join('')); | ||||||
| 
 | 
 | ||||||
|             extractTextPromisesResolves[pageIndex](pageIndex); |             extractTextPromisesResolves[pageIndex](pageIndex); | ||||||
|             if ((pageIndex + 1) < self.pdfPageSource.pages.length) { |             if ((pageIndex + 1) < self.pdfViewer.pagesCount) { | ||||||
|               extractPageText(pageIndex + 1); |               extractPageText(pageIndex + 1); | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
| @ -189,7 +196,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     updatePage: function PDFFindController_updatePage(index) { |     updatePage: function PDFFindController_updatePage(index) { | ||||||
|       var page = this.pdfPageSource.pages[index]; |       var page = this.pdfViewer.getPageView(index); | ||||||
| 
 | 
 | ||||||
|       if (this.selected.pageIdx === index) { |       if (this.selected.pageIdx === index) { | ||||||
|         // If the page is selected, scroll the page into view, which triggers
 |         // If the page is selected, scroll the page into view, which triggers
 | ||||||
| @ -205,8 +212,8 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
| 
 | 
 | ||||||
|     nextMatch: function PDFFindController_nextMatch() { |     nextMatch: function PDFFindController_nextMatch() { | ||||||
|       var previous = this.state.findPrevious; |       var previous = this.state.findPrevious; | ||||||
|       var currentPageIndex = this.pdfPageSource.page - 1; |       var currentPageIndex = this.pdfViewer.currentPageNumber - 1; | ||||||
|       var numPages = this.pdfPageSource.pages.length; |       var numPages = this.pdfViewer.pagesCount; | ||||||
| 
 | 
 | ||||||
|       this.active = true; |       this.active = true; | ||||||
| 
 | 
 | ||||||
| @ -346,7 +353,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
|      |      | ||||||
|       this.updateUIState(state, this.state.findPrevious); |       this.updateUIState(state, this.state.findPrevious); | ||||||
|       if (this.selected.pageIdx !== -1) { |       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 |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| /* globals PDFJS, PDFView, PresentationMode */ | /* globals PDFJS, PresentationMode */ | ||||||
| 
 | 
 | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| @ -22,12 +22,11 @@ var PDFHistory = { | |||||||
|   initialized: false, |   initialized: false, | ||||||
|   initialDestination: null, |   initialDestination: null, | ||||||
| 
 | 
 | ||||||
|   initialize: function pdfHistoryInitialize(fingerprint) { |   /** | ||||||
|     if (PDFJS.disableHistory || PDFView.isViewerEmbedded) { |    * @param {string} fingerprint | ||||||
|       // The browsing history is only enabled when the viewer is standalone,
 |    * @param {IPDFLinkService} linkService | ||||||
|       // i.e. not when it is embedded in a web page.
 |    */ | ||||||
|       return; |   initialize: function pdfHistoryInitialize(fingerprint, linkService) { | ||||||
|     } |  | ||||||
|     this.initialized = true; |     this.initialized = true; | ||||||
|     this.reInitialized = false; |     this.reInitialized = false; | ||||||
|     this.allowHashChange = true; |     this.allowHashChange = true; | ||||||
| @ -42,6 +41,7 @@ var PDFHistory = { | |||||||
|     this.nextHashParam = ''; |     this.nextHashParam = ''; | ||||||
| 
 | 
 | ||||||
|     this.fingerprint = fingerprint; |     this.fingerprint = fingerprint; | ||||||
|  |     this.linkService = linkService; | ||||||
|     this.currentUid = this.uid = 0; |     this.currentUid = this.uid = 0; | ||||||
|     this.current = {}; |     this.current = {}; | ||||||
| 
 | 
 | ||||||
| @ -52,7 +52,7 @@ var PDFHistory = { | |||||||
|       if (state.target.dest) { |       if (state.target.dest) { | ||||||
|         this.initialDestination = state.target.dest; |         this.initialDestination = state.target.dest; | ||||||
|       } else { |       } else { | ||||||
|         PDFView.initialBookmark = state.target.hash; |         linkService.setHash(state.target.hash); | ||||||
|       } |       } | ||||||
|       this.currentUid = state.uid; |       this.currentUid = state.uid; | ||||||
|       this.uid = state.uid + 1; |       this.uid = state.uid + 1; | ||||||
| @ -203,7 +203,7 @@ var PDFHistory = { | |||||||
|       params.hash = (this.current.hash && this.current.dest && |       params.hash = (this.current.hash && this.current.dest && | ||||||
|                      this.current.dest === params.dest) ? |                      this.current.dest === params.dest) ? | ||||||
|         this.current.hash : |         this.current.hash : | ||||||
|         PDFView.getDestinationHash(params.dest).split('#')[1]; |         this.linkService.getDestinationHash(params.dest).split('#')[1]; | ||||||
|     } |     } | ||||||
|     if (params.page) { |     if (params.page) { | ||||||
|       params.page |= 0; |       params.page |= 0; | ||||||
| @ -212,7 +212,7 @@ var PDFHistory = { | |||||||
|       var target = window.history.state.target; |       var target = window.history.state.target; | ||||||
|       if (!target) { |       if (!target) { | ||||||
|         // Invoked when the user specifies an initial bookmark,
 |         // 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._pushToHistory(params, false); | ||||||
|         this.previousHash = window.location.hash.substring(1); |         this.previousHash = window.location.hash.substring(1); | ||||||
|       } |       } | ||||||
| @ -337,9 +337,9 @@ var PDFHistory = { | |||||||
|     this.historyUnlocked = false; |     this.historyUnlocked = false; | ||||||
| 
 | 
 | ||||||
|     if (state.target.dest) { |     if (state.target.dest) { | ||||||
|       PDFView.navigateTo(state.target.dest); |       this.linkService.navigateTo(state.target.dest); | ||||||
|     } else { |     } else { | ||||||
|       PDFView.setHash(state.target.hash); |       this.linkService.setHash(state.target.hash); | ||||||
|     } |     } | ||||||
|     this.currentUid = state.uid; |     this.currentUid = state.uid; | ||||||
|     if (state.uid > this.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 |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| /* globals PDFView, scrollIntoView, HandTool */ | /* globals scrollIntoView, HandTool, PDFViewerApplication */ | ||||||
| 
 | 
 | ||||||
| 'use strict'; | '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 |    * browser transitions to fullscreen mode. Since resize events are triggered | ||||||
|    * multiple times during the switch to fullscreen mode, this is necessary in |    * multiple times during the switch to fullscreen mode, this is necessary in | ||||||
|    * order to prevent the page from being scrolled partially, or completely, |    * order to prevent the page from being scrolled partially, or completely, | ||||||
| @ -81,9 +81,8 @@ var PresentationMode = { | |||||||
|     } |     } | ||||||
|     this.switchInProgress = setTimeout(function switchInProgressTimeout() { |     this.switchInProgress = setTimeout(function switchInProgressTimeout() { | ||||||
|       delete this.switchInProgress; |       delete this.switchInProgress; | ||||||
|  |       this._notifyStateChange(); | ||||||
|     }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); |     }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); | ||||||
| 
 |  | ||||||
|     PDFView.currentPosition = null; |  | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   _resetSwitchInProgress: function presentationMode_resetSwitchInProgress() { |   _resetSwitchInProgress: function presentationMode_resetSwitchInProgress() { | ||||||
| @ -94,11 +93,12 @@ var PresentationMode = { | |||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   request: function presentationModeRequest() { |   request: function presentationModeRequest() { | ||||||
|     if (!PDFView.supportsFullscreen || this.isFullscreen || |     if (!PDFViewerApplication.supportsFullscreen || this.isFullscreen || | ||||||
|         !this.viewer.hasChildNodes()) { |         !this.viewer.hasChildNodes()) { | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|     this._setSwitchInProgress(); |     this._setSwitchInProgress(); | ||||||
|  |     this._notifyStateChange(); | ||||||
| 
 | 
 | ||||||
|     if (this.container.requestFullscreen) { |     if (this.container.requestFullscreen) { | ||||||
|       this.container.requestFullscreen(); |       this.container.requestFullscreen(); | ||||||
| @ -113,23 +113,33 @@ var PresentationMode = { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this.args = { |     this.args = { | ||||||
|       page: PDFView.page, |       page: PDFViewerApplication.page, | ||||||
|       previousScale: PDFView.currentScaleValue |       previousScale: PDFViewerApplication.currentScaleValue | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     return true; |     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() { |   enter: function presentationModeEnter() { | ||||||
|     this.active = true; |     this.active = true; | ||||||
|     this._resetSwitchInProgress(); |     this._resetSwitchInProgress(); | ||||||
|  |     this._notifyStateChange(); | ||||||
| 
 | 
 | ||||||
|     // Ensure that the correct page is scrolled into view when entering
 |     // Ensure that the correct page is scrolled into view when entering
 | ||||||
|     // Presentation Mode, by waiting until fullscreen mode in enabled.
 |     // Presentation Mode, by waiting until fullscreen mode in enabled.
 | ||||||
|     // Note: This is only necessary in non-Mozilla browsers.
 |     // Note: This is only necessary in non-Mozilla browsers.
 | ||||||
|     setTimeout(function enterPresentationModeTimeout() { |     setTimeout(function enterPresentationModeTimeout() { | ||||||
|       PDFView.page = this.args.page; |       PDFViewerApplication.page = this.args.page; | ||||||
|       PDFView.setScale('page-fit', true); |       PDFViewerApplication.setScale('page-fit', true); | ||||||
|     }.bind(this), 0); |     }.bind(this), 0); | ||||||
| 
 | 
 | ||||||
|     window.addEventListener('mousemove', this.mouseMove, false); |     window.addEventListener('mousemove', this.mouseMove, false); | ||||||
| @ -143,15 +153,17 @@ var PresentationMode = { | |||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   exit: function presentationModeExit() { |   exit: function presentationModeExit() { | ||||||
|     var page = PDFView.page; |     var page = PDFViewerApplication.page; | ||||||
| 
 | 
 | ||||||
|     // Ensure that the correct page is scrolled into view when exiting
 |     // Ensure that the correct page is scrolled into view when exiting
 | ||||||
|     // Presentation Mode, by waiting until fullscreen mode is disabled.
 |     // Presentation Mode, by waiting until fullscreen mode is disabled.
 | ||||||
|     // Note: This is only necessary in non-Mozilla browsers.
 |     // Note: This is only necessary in non-Mozilla browsers.
 | ||||||
|     setTimeout(function exitPresentationModeTimeout() { |     setTimeout(function exitPresentationModeTimeout() { | ||||||
|       this.active = false; |       this.active = false; | ||||||
|       PDFView.setScale(this.args.previousScale); |       this._notifyStateChange(); | ||||||
|       PDFView.page = page; | 
 | ||||||
|  |       PDFViewerApplication.setScale(this.args.previousScale, true); | ||||||
|  |       PDFViewerApplication.page = page; | ||||||
|       this.args = null; |       this.args = null; | ||||||
|     }.bind(this), 0); |     }.bind(this), 0); | ||||||
| 
 | 
 | ||||||
| @ -160,7 +172,7 @@ var PresentationMode = { | |||||||
|     window.removeEventListener('contextmenu', this.contextMenu, false); |     window.removeEventListener('contextmenu', this.contextMenu, false); | ||||||
| 
 | 
 | ||||||
|     this.hideControls(); |     this.hideControls(); | ||||||
|     PDFView.clearMouseScrollState(); |     PDFViewerApplication.clearMouseScrollState(); | ||||||
|     HandTool.exitPresentationMode(); |     HandTool.exitPresentationMode(); | ||||||
|     this.container.removeAttribute('contextmenu'); |     this.container.removeAttribute('contextmenu'); | ||||||
|     this.contextMenuOpen = false; |     this.contextMenuOpen = false; | ||||||
| @ -224,7 +236,7 @@ var PresentationMode = { | |||||||
|       if (!isInternalLink) { |       if (!isInternalLink) { | ||||||
|         // Unless an internal link was clicked, advance one page.
 |         // Unless an internal link was clicked, advance one page.
 | ||||||
|         evt.preventDefault(); |         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 |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| /* globals PDFView, SCROLLBAR_PADDING */ | /* globals PDFViewerApplication, SCROLLBAR_PADDING */ | ||||||
| 
 | 
 | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| @ -87,7 +87,7 @@ var SecondaryToolbar = { | |||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   downloadClick: function secondaryToolbarDownloadClick(evt) { |   downloadClick: function secondaryToolbarDownloadClick(evt) { | ||||||
|     PDFView.download(); |     PDFViewerApplication.download(); | ||||||
|     this.close(); |     this.close(); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
| @ -96,23 +96,23 @@ var SecondaryToolbar = { | |||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   firstPageClick: function secondaryToolbarFirstPageClick(evt) { |   firstPageClick: function secondaryToolbarFirstPageClick(evt) { | ||||||
|     PDFView.page = 1; |     PDFViewerApplication.page = 1; | ||||||
|     this.close(); |     this.close(); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   lastPageClick: function secondaryToolbarLastPageClick(evt) { |   lastPageClick: function secondaryToolbarLastPageClick(evt) { | ||||||
|     if (PDFView.pdfDocument) { |     if (PDFViewerApplication.pdfDocument) { | ||||||
|       PDFView.page = PDFView.pdfDocument.numPages; |       PDFViewerApplication.page = PDFViewerApplication.pagesCount; | ||||||
|     } |     } | ||||||
|     this.close(); |     this.close(); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   pageRotateCwClick: function secondaryToolbarPageRotateCwClick(evt) { |   pageRotateCwClick: function secondaryToolbarPageRotateCwClick(evt) { | ||||||
|     PDFView.rotatePages(90); |     PDFViewerApplication.rotatePages(90); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   pageRotateCcwClick: function secondaryToolbarPageRotateCcwClick(evt) { |   pageRotateCcwClick: function secondaryToolbarPageRotateCcwClick(evt) { | ||||||
|     PDFView.rotatePages(-90); |     PDFViewerApplication.rotatePages(-90); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   documentPropertiesClick: function secondaryToolbarDocumentPropsClick(evt) { |   documentPropertiesClick: function secondaryToolbarDocumentPropsClick(evt) { | ||||||
|  | |||||||
| @ -28,11 +28,23 @@ function isAllWhitespace(str) { | |||||||
|   return !NonWhitespaceRegexp.test(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. |  * TextLayerBuilder provides text-selection functionality for the PDF. | ||||||
|  * It does this by creating overlay divs over the PDF text. These divs |  * 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 |  * contain text that matches the PDF text they are overlaying. This object | ||||||
|  * also provides a way to highlight text that is being searched for. |  * also provides a way to highlight text that is being searched for. | ||||||
|  |  * @class | ||||||
|  */ |  */ | ||||||
| var TextLayerBuilder = (function TextLayerBuilderClosure() { | var TextLayerBuilder = (function TextLayerBuilderClosure() { | ||||||
|   function TextLayerBuilder(options) { |   function TextLayerBuilder(options) { | ||||||
|  | |||||||
| @ -14,16 +14,32 @@ | |||||||
|  * See the License for the specific language governing permissions and |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| /* globals PDFView, mozL10n, RenderingStates */ | /* globals mozL10n, RenderingStates, Promise, scrollIntoView, PDFPageSource, | ||||||
|  |            watchScroll, getVisibleElements */ | ||||||
| 
 | 
 | ||||||
| 'use strict'; | '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'); |   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.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}'); | ||||||
|   anchor.onclick = function stopNavigation() { |   anchor.onclick = function stopNavigation() { | ||||||
|     PDFView.page = id; |     linkService.page = id; | ||||||
|     return false; |     return false; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -36,6 +52,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | |||||||
|   this.pageHeight = this.viewport.height; |   this.pageHeight = this.viewport.height; | ||||||
|   this.pageRatio = this.pageWidth / this.pageHeight; |   this.pageRatio = this.pageWidth / this.pageHeight; | ||||||
|   this.id = id; |   this.id = id; | ||||||
|  |   this.renderingId = 'thumbnail' + id; | ||||||
| 
 | 
 | ||||||
|   this.canvasWidth = 98; |   this.canvasWidth = 98; | ||||||
|   this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; |   this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; | ||||||
| @ -62,6 +79,8 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | |||||||
| 
 | 
 | ||||||
|   this.hasImage = false; |   this.hasImage = false; | ||||||
|   this.renderingState = RenderingStates.INITIAL; |   this.renderingState = RenderingStates.INITIAL; | ||||||
|  |   this.renderingQueue = renderingQueue; | ||||||
|  |   this.pageSource = pageSource; | ||||||
| 
 | 
 | ||||||
|   this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) { |   this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) { | ||||||
|     this.pdfPage = pdfPage; |     this.pdfPage = pdfPage; | ||||||
| @ -125,7 +144,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | |||||||
| 
 | 
 | ||||||
|   this.draw = function thumbnailViewDraw(callback) { |   this.draw = function thumbnailViewDraw(callback) { | ||||||
|     if (!this.pdfPage) { |     if (!this.pdfPage) { | ||||||
|       var promise = PDFView.getPage(this.id); |       var promise = this.pageSource.getPage(this.id); | ||||||
|       promise.then(function(pdfPage) { |       promise.then(function(pdfPage) { | ||||||
|         this.setPdfPage(pdfPage); |         this.setPdfPage(pdfPage); | ||||||
|         this.draw(callback); |         this.draw(callback); | ||||||
| @ -150,7 +169,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | |||||||
|       canvasContext: ctx, |       canvasContext: ctx, | ||||||
|       viewport: drawViewport, |       viewport: drawViewport, | ||||||
|       continueCallback: function(cont) { |       continueCallback: function(cont) { | ||||||
|         if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) { |         if (!self.renderingQueue.isHighestPriority(self)) { | ||||||
|           self.renderingState = RenderingStates.PAUSED; |           self.renderingState = RenderingStates.PAUSED; | ||||||
|           self.resume = function() { |           self.resume = function() { | ||||||
|             self.renderingState = RenderingStates.RUNNING; |             self.renderingState = RenderingStates.RUNNING; | ||||||
| @ -187,7 +206,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | |||||||
| 
 | 
 | ||||||
|   this.setImage = function thumbnailViewSetImage(img) { |   this.setImage = function thumbnailViewSetImage(img) { | ||||||
|     if (!this.pdfPage) { |     if (!this.pdfPage) { | ||||||
|       var promise = PDFView.getPage(this.id); |       var promise = this.pageSource.getPage(); | ||||||
|       promise.then(function(pdfPage) { |       promise.then(function(pdfPage) { | ||||||
|         this.setPdfPage(pdfPage); |         this.setPdfPage(pdfPage); | ||||||
|         this.setImage(img); |         this.setImage(img); | ||||||
| @ -232,3 +251,134 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ThumbnailView.tempImageCache = null; | 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'; | '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
 | // optimised CSS custom property getter/setter
 | ||||||
| var CustomStyle = (function CustomStyleClosure() { | var CustomStyle = (function CustomStyleClosure() { | ||||||
| 
 | 
 | ||||||
| @ -138,6 +146,91 @@ function scrollIntoView(element, spot) { | |||||||
|   parent.scrollTop = offsetY; |   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. |  * Event handler to suppress context menu. | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -68,9 +68,11 @@ http://sourceforge.net/adobe/cmap/wiki/License/ | |||||||
|     <script src="preferences.js"></script> |     <script src="preferences.js"></script> | ||||||
|     <script src="download_manager.js"></script> |     <script src="download_manager.js"></script> | ||||||
|     <script src="view_history.js"></script> |     <script src="view_history.js"></script> | ||||||
|  |     <script src="pdf_rendering_queue.js"></script> | ||||||
|     <script src="page_view.js"></script> |     <script src="page_view.js"></script> | ||||||
|     <script src="thumbnail_view.js"></script> |  | ||||||
|     <script src="text_layer_builder.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_outline_view.js"></script> | ||||||
|     <script src="document_attachments_view.js"></script> |     <script src="document_attachments_view.js"></script> | ||||||
|     <script src="pdf_find_bar.js"></script> |     <script src="pdf_find_bar.js"></script> | ||||||
|  | |||||||
							
								
								
									
										1058
									
								
								web/viewer.js
									
									
									
									
									
								
							
							
						
						
									
										1058
									
								
								web/viewer.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user