From 661f425934e20dff50ce74231d179ba421bb8d6c Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Wed, 9 Nov 2022 11:09:22 +0100 Subject: [PATCH] [GV] Add an option in the find controller to update matches count only when the last page is reached (bug 1803188). In GeckoView, on an event, a callback must be executed with the result of an action, but the callback can be used only one time. So for each FindInPage event, we must trigger only one matches count update. --- test/unit/pdf_find_controller_spec.js | 38 ++++++++++++++++++++++++++- web/app.js | 2 ++ web/pdf_find_controller.js | 22 +++++++++++++--- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/test/unit/pdf_find_controller_spec.js b/test/unit/pdf_find_controller_spec.js index bdb6ffd6e..b7f3b1861 100644 --- a/test/unit/pdf_find_controller_spec.js +++ b/test/unit/pdf_find_controller_spec.js @@ -51,7 +51,10 @@ class MockLinkService extends SimpleLinkService { } } -async function initPdfFindController(filename) { +async function initPdfFindController( + filename, + updateMatchesCountOnProgress = true +) { const loadingTask = getDocument( buildGetDocumentParams(filename || tracemonkeyFileName, { ...CMAP_PARAMS, @@ -67,6 +70,7 @@ async function initPdfFindController(filename) { const pdfFindController = new PDFFindController({ linkService, eventBus, + updateMatchesCountOnProgress, }); pdfFindController.setDocument(pdfDocument); // Enable searching. @@ -81,6 +85,7 @@ function testSearch({ selectedMatch, pageMatches = null, pageMatchesLength = null, + countUpdate = null, }) { return new Promise(function (resolve) { const eventState = Object.assign( @@ -125,6 +130,9 @@ function testSearch({ eventBus.on( "updatefindmatchescount", function onUpdateFindMatchesCount(evt) { + if (countUpdate) { + countUpdate[0] += 1; + } if (pdfFindController.pageMatches.length !== totalPages) { return; } @@ -191,6 +199,7 @@ function testEmptySearch({ eventBus, pdfFindController, state }) { describe("pdf_find_controller", function () { it("performs a normal search", async function () { const { eventBus, pdfFindController } = await initPdfFindController(); + const countUpdate = [0]; await testSearch({ eventBus, @@ -203,7 +212,34 @@ describe("pdf_find_controller", function () { pageIndex: 0, matchIndex: 0, }, + countUpdate, }); + + expect(countUpdate[0]).toBe(9); + }); + + it("performs a normal search but the total counts is only updated one time", async function () { + const { eventBus, pdfFindController } = await initPdfFindController( + null, + false + ); + const countUpdate = [0]; + + await testSearch({ + eventBus, + pdfFindController, + state: { + query: "Dynamic", + }, + matchesPerPage: [11, 5, 0, 3, 0, 0, 0, 1, 1, 1, 0, 3, 4, 4], + selectedMatch: { + pageIndex: 0, + matchIndex: 0, + }, + countUpdate, + }); + + expect(countUpdate[0]).toBe(1); }); it("performs a normal search and finds the previous result", async function () { diff --git a/web/app.js b/web/app.js index e9389632d..11b7b0f7e 100644 --- a/web/app.js +++ b/web/app.js @@ -458,6 +458,8 @@ const PDFViewerApplication = { const findController = new PDFFindController({ linkService: pdfLinkService, eventBus, + updateMatchesCountOnProgress: + typeof PDFJSDev === "undefined" || !PDFJSDev.test("GECKOVIEW"), }); this.findController = findController; diff --git a/web/pdf_find_controller.js b/web/pdf_find_controller.js index 0ea48f124..2fcfbce7d 100644 --- a/web/pdf_find_controller.js +++ b/web/pdf_find_controller.js @@ -339,18 +339,26 @@ function getOriginalIndex(diffs, pos, len) { * @typedef {Object} PDFFindControllerOptions * @property {IPDFLinkService} linkService - The navigation/linking service. * @property {EventBus} eventBus - The application event bus. + * @property {boolean} updateMatchesCountOnProgress - True if the matches + * count must be updated on progress or only when the last page is reached. + * The default value is `true`. */ /** * Provides search functionality to find a given string in a PDF document. */ class PDFFindController { + #updateMatchesCountOnProgress = true; + + #visitedPagesCount = 0; + /** * @param {PDFFindControllerOptions} options */ - constructor({ linkService, eventBus }) { + constructor({ linkService, eventBus, updateMatchesCountOnProgress = true }) { this._linkService = linkService; this._eventBus = eventBus; + this.#updateMatchesCountOnProgress = updateMatchesCountOnProgress; this.#reset(); eventBus._on("find", this.#onFind.bind(this)); @@ -489,6 +497,7 @@ class PDFFindController { this._pdfDocument = null; this._pageMatches = []; this._pageMatchesLength = []; + this.#visitedPagesCount = 0; this._state = null; // Currently selected match. this._selected = { @@ -742,8 +751,14 @@ class PDFFindController { // Update the match count. const pageMatchesCount = this._pageMatches[pageIndex].length; - if (pageMatchesCount > 0) { - this._matchesCountTotal += pageMatchesCount; + this._matchesCountTotal += pageMatchesCount; + if (this.#updateMatchesCountOnProgress) { + if (pageMatchesCount > 0) { + this.#updateUIResultsCount(); + } + } else if (++this.#visitedPagesCount === this._linkService.pagesCount) { + // For example, in GeckoView we want to have only the final update because + // the Java side provides only one object to update the counts. this.#updateUIResultsCount(); } } @@ -838,6 +853,7 @@ class PDFFindController { this._resumePageIdx = null; this._pageMatches.length = 0; this._pageMatchesLength.length = 0; + this.#visitedPagesCount = 0; this._matchesCountTotal = 0; this.#updateAllPages(); // Wipe out any previously highlighted matches.