From 6b4c2da2e1e0369298c9fa5e36f73a4aa6a198e2 Mon Sep 17 00:00:00 2001 From: Pdf Bot Date: Sun, 24 Apr 2016 14:35:02 +0100 Subject: [PATCH] PDF.js version 1.5.201 - See mozilla/pdf.js@55581b162e81f152d3d8f58467e90b11963706c9 --- bower.json | 2 +- build/pdf.combined.js | 4 +- build/pdf.js | 4 +- build/pdf.worker.js | 4 +- package.json | 2 +- web/pdf_viewer.js | 408 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 416 insertions(+), 8 deletions(-) diff --git a/bower.json b/bower.json index 3ffa37bbc..eb68cf26a 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "pdfjs-dist", - "version": "1.5.196", + "version": "1.5.201", "main": [ "build/pdf.js", "build/pdf.worker.js" diff --git a/build/pdf.combined.js b/build/pdf.combined.js index 2a60f3a72..34db224b5 100644 --- a/build/pdf.combined.js +++ b/build/pdf.combined.js @@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdfCombined = {})); // Use strict in our context only - users might not want it 'use strict'; -var pdfjsVersion = '1.5.196'; -var pdfjsBuild = 'ff6669d'; +var pdfjsVersion = '1.5.201'; +var pdfjsBuild = '55581b1'; var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? diff --git a/build/pdf.js b/build/pdf.js index 0c0211ff4..3d42fbbfa 100644 --- a/build/pdf.js +++ b/build/pdf.js @@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdf = {})); // Use strict in our context only - users might not want it 'use strict'; -var pdfjsVersion = '1.5.196'; -var pdfjsBuild = 'ff6669d'; +var pdfjsVersion = '1.5.201'; +var pdfjsBuild = '55581b1'; var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? diff --git a/build/pdf.worker.js b/build/pdf.worker.js index 808b22d04..3fea41e71 100644 --- a/build/pdf.worker.js +++ b/build/pdf.worker.js @@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdfWorker = {})); // Use strict in our context only - users might not want it 'use strict'; -var pdfjsVersion = '1.5.196'; -var pdfjsBuild = 'ff6669d'; +var pdfjsVersion = '1.5.201'; +var pdfjsBuild = '55581b1'; var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? diff --git a/package.json b/package.json index 70a35502b..9c31c71ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pdfjs-dist", - "version": "1.5.196", + "version": "1.5.201", "main": "build/pdf.js", "description": "Generic build of Mozilla's PDF.js library.", "keywords": [ diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 90ea26571..3676eeee4 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -1495,6 +1495,412 @@ exports.binarySearchFirstItem = binarySearchFirstItem; })); +(function (root, factory) { + { + factory((root.pdfjsWebPDFFindController = {}), root.pdfjsWebUIUtils); + } +}(this, function (exports, uiUtils, firefoxCom) { + +var scrollIntoView = uiUtils.scrollIntoView; + +var FindStates = { + FIND_FOUND: 0, + FIND_NOTFOUND: 1, + FIND_WRAPPED: 2, + FIND_PENDING: 3 +}; + +var FIND_SCROLL_OFFSET_TOP = -50; +var FIND_SCROLL_OFFSET_LEFT = -400; + +var CHARACTERS_TO_NORMALIZE = { + '\u2018': '\'', // Left single quotation mark + '\u2019': '\'', // Right single quotation mark + '\u201A': '\'', // Single low-9 quotation mark + '\u201B': '\'', // Single high-reversed-9 quotation mark + '\u201C': '"', // Left double quotation mark + '\u201D': '"', // Right double quotation mark + '\u201E': '"', // Double low-9 quotation mark + '\u201F': '"', // Double high-reversed-9 quotation mark + '\u00BC': '1/4', // Vulgar fraction one quarter + '\u00BD': '1/2', // Vulgar fraction one half + '\u00BE': '3/4', // Vulgar fraction three quarters +}; + +/** + * Provides "search" or "find" functionality for the PDF. + * This object actually performs the search for a given string. + */ +var PDFFindController = (function PDFFindControllerClosure() { + function PDFFindController(options) { + this.pdfViewer = options.pdfViewer || null; + + this.onUpdateResultsCount = null; + this.onUpdateState = null; + + this.reset(); + + // Compile the regular expression for text normalization once. + var replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(''); + this.normalizationRegex = new RegExp('[' + replace + ']', 'g'); + } + + PDFFindController.prototype = { + listenWindowEvents: function PDFFindController_listenWindowEvents() { + var events = [ + 'find', + 'findagain', + 'findhighlightallchange', + 'findcasesensitivitychange' + ]; + var handleEvent = function (e) { + this.executeCommand(e.type, e.detail); + }.bind(this); + + for (var i = 0, len = events.length; i < len; i++) { + window.addEventListener(events[i], handleEvent); + } + }, + + reset: function PDFFindController_reset() { + this.startedTextExtraction = false; + this.extractTextPromises = []; + this.pendingFindMatches = Object.create(null); + this.active = false; // If active, find results will be highlighted. + this.pageContents = []; // Stores the text for each page. + this.pageMatches = []; + this.matchCount = 0; + this.selected = { // Currently selected match. + pageIdx: -1, + matchIdx: -1 + }; + this.offset = { // Where the find algorithm currently is in the document. + pageIdx: null, + matchIdx: null + }; + this.pagesToSearch = null; + this.resumePageIdx = null; + this.state = null; + this.dirtyMatch = false; + this.findTimeout = null; + + this.firstPagePromise = new Promise(function (resolve) { + this.resolveFirstPage = resolve; + }.bind(this)); + }, + + normalize: function PDFFindController_normalize(text) { + return text.replace(this.normalizationRegex, function (ch) { + return CHARACTERS_TO_NORMALIZE[ch]; + }); + }, + + calcFindMatch: function PDFFindController_calcFindMatch(pageIndex) { + var pageContent = this.normalize(this.pageContents[pageIndex]); + var query = this.normalize(this.state.query); + var caseSensitive = this.state.caseSensitive; + var queryLen = query.length; + + if (queryLen === 0) { + // Do nothing: the matches should be wiped out already. + return; + } + + if (!caseSensitive) { + pageContent = pageContent.toLowerCase(); + query = query.toLowerCase(); + } + + var matches = []; + var matchIdx = -queryLen; + while (true) { + matchIdx = pageContent.indexOf(query, matchIdx + queryLen); + if (matchIdx === -1) { + break; + } + matches.push(matchIdx); + } + this.pageMatches[pageIndex] = matches; + this.updatePage(pageIndex); + if (this.resumePageIdx === pageIndex) { + this.resumePageIdx = null; + this.nextPageMatch(); + } + + // Update the matches count + if (matches.length > 0) { + this.matchCount += matches.length; + this.updateUIResultsCount(); + } + }, + + extractText: function PDFFindController_extractText() { + if (this.startedTextExtraction) { + return; + } + this.startedTextExtraction = true; + + this.pageContents = []; + var extractTextPromisesResolves = []; + var numPages = this.pdfViewer.pagesCount; + for (var i = 0; i < numPages; i++) { + this.extractTextPromises.push(new Promise(function (resolve) { + extractTextPromisesResolves.push(resolve); + })); + } + + var self = this; + function extractPageText(pageIndex) { + self.pdfViewer.getPageTextContent(pageIndex).then( + function textContentResolved(textContent) { + var textItems = textContent.items; + var str = []; + + for (var i = 0, len = textItems.length; i < len; i++) { + str.push(textItems[i].str); + } + + // Store the pageContent as a string. + self.pageContents.push(str.join('')); + + extractTextPromisesResolves[pageIndex](pageIndex); + if ((pageIndex + 1) < self.pdfViewer.pagesCount) { + extractPageText(pageIndex + 1); + } + } + ); + } + extractPageText(0); + }, + + executeCommand: function PDFFindController_executeCommand(cmd, state) { + if (this.state === null || cmd !== 'findagain') { + this.dirtyMatch = true; + } + this.state = state; + this.updateUIState(FindStates.FIND_PENDING); + + this.firstPagePromise.then(function() { + this.extractText(); + + clearTimeout(this.findTimeout); + if (cmd === 'find') { + // Only trigger the find action after 250ms of silence. + this.findTimeout = setTimeout(this.nextMatch.bind(this), 250); + } else { + this.nextMatch(); + } + }.bind(this)); + }, + + updatePage: function PDFFindController_updatePage(index) { + if (this.selected.pageIdx === index) { + // If the page is selected, scroll the page into view, which triggers + // rendering the page, which adds the textLayer. Once the textLayer is + // build, it will scroll onto the selected match. + this.pdfViewer.scrollPageIntoView(index + 1); + } + + var page = this.pdfViewer.getPageView(index); + if (page.textLayer) { + page.textLayer.updateMatches(); + } + }, + + nextMatch: function PDFFindController_nextMatch() { + var previous = this.state.findPrevious; + var currentPageIndex = this.pdfViewer.currentPageNumber - 1; + var numPages = this.pdfViewer.pagesCount; + + this.active = true; + + if (this.dirtyMatch) { + // Need to recalculate the matches, reset everything. + this.dirtyMatch = false; + this.selected.pageIdx = this.selected.matchIdx = -1; + this.offset.pageIdx = currentPageIndex; + this.offset.matchIdx = null; + this.hadMatch = false; + this.resumePageIdx = null; + this.pageMatches = []; + this.matchCount = 0; + var self = this; + + for (var i = 0; i < numPages; i++) { + // Wipe out any previous highlighted matches. + this.updatePage(i); + + // As soon as the text is extracted start finding the matches. + if (!(i in this.pendingFindMatches)) { + this.pendingFindMatches[i] = true; + this.extractTextPromises[i].then(function(pageIdx) { + delete self.pendingFindMatches[pageIdx]; + self.calcFindMatch(pageIdx); + }); + } + } + } + + // If there's no query there's no point in searching. + if (this.state.query === '') { + this.updateUIState(FindStates.FIND_FOUND); + return; + } + + // If we're waiting on a page, we return since we can't do anything else. + if (this.resumePageIdx) { + return; + } + + var offset = this.offset; + // Keep track of how many pages we should maximally iterate through. + this.pagesToSearch = numPages; + // If there's already a matchIdx that means we are iterating through a + // page's matches. + if (offset.matchIdx !== null) { + var numPageMatches = this.pageMatches[offset.pageIdx].length; + if ((!previous && offset.matchIdx + 1 < numPageMatches) || + (previous && offset.matchIdx > 0)) { + // The simple case; we just have advance the matchIdx to select + // the next match on the page. + this.hadMatch = true; + offset.matchIdx = (previous ? offset.matchIdx - 1 : + offset.matchIdx + 1); + this.updateMatch(true); + return; + } + // We went beyond the current page's matches, so we advance to + // the next page. + this.advanceOffsetPage(previous); + } + // Start searching through the page. + this.nextPageMatch(); + }, + + matchesReady: function PDFFindController_matchesReady(matches) { + var offset = this.offset; + var numMatches = matches.length; + var previous = this.state.findPrevious; + + if (numMatches) { + // There were matches for the page, so initialize the matchIdx. + this.hadMatch = true; + offset.matchIdx = (previous ? numMatches - 1 : 0); + this.updateMatch(true); + return true; + } else { + // No matches, so attempt to search the next page. + this.advanceOffsetPage(previous); + if (offset.wrapped) { + offset.matchIdx = null; + if (this.pagesToSearch < 0) { + // No point in wrapping again, there were no matches. + this.updateMatch(false); + // while matches were not found, searching for a page + // with matches should nevertheless halt. + return true; + } + } + // Matches were not found (and searching is not done). + return false; + } + }, + + /** + * The method is called back from the text layer when match presentation + * is updated. + * @param {number} pageIndex - page index. + * @param {number} index - match index. + * @param {Array} elements - text layer div elements array. + * @param {number} beginIdx - start index of the div array for the match. + * @param {number} endIdx - end index of the div array for the match. + */ + updateMatchPosition: function PDFFindController_updateMatchPosition( + pageIndex, index, elements, beginIdx, endIdx) { + if (this.selected.matchIdx === index && + this.selected.pageIdx === pageIndex) { + var spot = { + top: FIND_SCROLL_OFFSET_TOP, + left: FIND_SCROLL_OFFSET_LEFT + }; + scrollIntoView(elements[beginIdx], spot, + /* skipOverflowHiddenElements = */ true); + } + }, + + nextPageMatch: function PDFFindController_nextPageMatch() { + if (this.resumePageIdx !== null) { + console.error('There can only be one pending page.'); + } + do { + var pageIdx = this.offset.pageIdx; + var matches = this.pageMatches[pageIdx]; + if (!matches) { + // The matches don't exist yet for processing by "matchesReady", + // so set a resume point for when they do exist. + this.resumePageIdx = pageIdx; + break; + } + } while (!this.matchesReady(matches)); + }, + + advanceOffsetPage: function PDFFindController_advanceOffsetPage(previous) { + var offset = this.offset; + var numPages = this.extractTextPromises.length; + offset.pageIdx = (previous ? offset.pageIdx - 1 : offset.pageIdx + 1); + offset.matchIdx = null; + + this.pagesToSearch--; + + if (offset.pageIdx >= numPages || offset.pageIdx < 0) { + offset.pageIdx = (previous ? numPages - 1 : 0); + offset.wrapped = true; + } + }, + + updateMatch: function PDFFindController_updateMatch(found) { + var state = FindStates.FIND_NOTFOUND; + var wrapped = this.offset.wrapped; + this.offset.wrapped = false; + + if (found) { + var previousPage = this.selected.pageIdx; + this.selected.pageIdx = this.offset.pageIdx; + this.selected.matchIdx = this.offset.matchIdx; + state = (wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND); + // Update the currently selected page to wipe out any selected matches. + if (previousPage !== -1 && previousPage !== this.selected.pageIdx) { + this.updatePage(previousPage); + } + } + + this.updateUIState(state, this.state.findPrevious); + if (this.selected.pageIdx !== -1) { + this.updatePage(this.selected.pageIdx); + } + }, + + updateUIResultsCount: + function PDFFindController_updateUIResultsCount() { + if (this.onUpdateResultsCount) { + this.onUpdateResultsCount(this.matchCount); + } + }, + + updateUIState: function PDFFindController_updateUIState(state, previous) { + if (this.onUpdateState) { + this.onUpdateState(state, previous, this.matchCount); + } + } + }; + return PDFFindController; +})(); + +exports.FindStates = FindStates; +exports.PDFFindController = PDFFindController; +})); + + (function (root, factory) { { factory((root.pdfjsWebPDFLinkService = {}), root.pdfjsWebUIUtils); @@ -3325,6 +3731,8 @@ exports.PDFViewer = PDFViewer; PDFJS.DefaultAnnotationLayerFactory = pdfViewerLibs.pdfjsWebAnnotationLayerBuilder.DefaultAnnotationLayerFactory; PDFJS.PDFHistory = pdfViewerLibs.pdfjsWebPDFHistory.PDFHistory; + PDFJS.PDFFindController = + pdfViewerLibs.pdfjsWebPDFFindController.PDFFindController; PDFJS.DownloadManager = pdfViewerLibs.pdfjsWebDownloadManager.DownloadManager; PDFJS.ProgressBar = pdfViewerLibs.pdfjsWebUIUtils.ProgressBar;