From 1eaa3b8a0862505ad00381b7726fc56e5dbf702a Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 23 Sep 2018 13:47:33 +0200 Subject: [PATCH 1/2] Dispatch a 'pagecancelled' event, in `PDFPageView.cancelRendering`, when rendering is cancelled Also, the patch updates `TextLayerBuilder` to use the new 'pagecancelled' event for (future) event removal purposes. --- web/pdf_page_view.js | 10 ++++++++++ web/text_layer_builder.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/web/pdf_page_view.js b/web/pdf_page_view.js index 3b4f91425ecba..2e76ec6aa61fa 100644 --- a/web/pdf_page_view.js +++ b/web/pdf_page_view.js @@ -260,6 +260,8 @@ class PDFPageView { } cancelRendering(keepAnnotations = false) { + const renderingState = this.renderingState; + if (this.paintTask) { this.paintTask.cancel(); this.paintTask = null; @@ -275,6 +277,14 @@ class PDFPageView { this.annotationLayer.cancel(); this.annotationLayer = null; } + + if (renderingState !== RenderingStates.INITIAL) { + this.eventBus.dispatch('pagecancelled', { + source: this, + pageNumber: this.id, + renderingState, + }); + } } cssTransform(target, redrawAnnotations = false) { diff --git a/web/text_layer_builder.js b/web/text_layer_builder.js index da78332918658..d8194b2958d9f 100644 --- a/web/text_layer_builder.js +++ b/web/text_layer_builder.js @@ -56,6 +56,9 @@ class TextLayerBuilder { this.textLayerRenderTask = null; this.enhanceTextSelection = enhanceTextSelection; + this._boundEvents = Object.create(null); + this._bindEvents(); + this._bindMouse(); } @@ -331,6 +334,33 @@ class TextLayerBuilder { this.renderMatches(this.matches); } + /** + * @private + */ + _bindEvents() { + const { eventBus, _boundEvents, } = this; + + _boundEvents.pageCancelled = (evt) => { + if (evt.pageNumber !== this.pageNumber) { + return; + } + if (this.textLayerRenderTask) { + console.error('TextLayerBuilder._bindEvents: `this.cancel()` should ' + + 'have been called when the page was reset, or rendering cancelled.'); + return; + } + // Ensure that all event listeners are cleaned up when the page is reset, + // since re-rendering will create new `TextLayerBuilder` instances and the + // number of (stale) event listeners would otherwise grow without bound. + for (const name in _boundEvents) { + eventBus.off(name.toLowerCase(), _boundEvents[name]); + delete _boundEvents[name]; + } + }; + + eventBus.on('pagecancelled', _boundEvents.pageCancelled); + } + /** * Improves text selection by adding an additional div where the mouse was * clicked. This reduces flickering of the content if the mouse is slowly From f29b4d1116642ae12a5e8c3418df462b1e4e0bd5 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 22 Sep 2018 15:31:33 +0200 Subject: [PATCH 2/2] Clear all find highlights when the findbar is closed (issue 7468) Please note that this will require a `mozilla-central` follow-up patch, in order for this to work in the built-in Firefox PDF viewer as well. --- web/firefoxcom.js | 21 ++++++++++++++------- web/pdf_find_bar.js | 3 ++- web/pdf_find_controller.js | 17 +++++++++++++++-- web/text_layer_builder.js | 9 ++++++++- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/web/firefoxcom.js b/web/firefoxcom.js index 4ac860f3f746e..27cf9d4ff6b5c 100644 --- a/web/firefoxcom.js +++ b/web/firefoxcom.js @@ -169,20 +169,27 @@ class MozL10n { 'findhighlightallchange', 'findcasesensitivitychange', 'findentirewordchange', + 'findbarclose', ]; - let handleEvent = function(evt) { + let handleEvent = function({ type, detail, }) { if (!PDFViewerApplication.initialized) { return; } + if (type === 'findbarclose') { + PDFViewerApplication.eventBus.dispatch('findbarclose', { + source: window, + }); + return; + } PDFViewerApplication.eventBus.dispatch('find', { source: window, - type: evt.type.substring('find'.length), - query: evt.detail.query, + type: type.substring('find'.length), + query: detail.query, phraseSearch: true, - caseSensitive: !!evt.detail.caseSensitive, - entireWord: !!evt.detail.entireWord, - highlightAll: !!evt.detail.highlightAll, - findPrevious: !!evt.detail.findPrevious, + caseSensitive: !!detail.caseSensitive, + entireWord: !!detail.entireWord, + highlightAll: !!detail.highlightAll, + findPrevious: !!detail.findPrevious, }); }; diff --git a/web/pdf_find_bar.js b/web/pdf_find_bar.js index 310acd2bbdc90..61362099fd26a 100644 --- a/web/pdf_find_bar.js +++ b/web/pdf_find_bar.js @@ -216,7 +216,8 @@ class PDFFindBar { this.opened = false; this.toggleButton.classList.remove('toggled'); this.bar.classList.add('hidden'); - this.findController.active = false; + + this.eventBus.dispatch('findbarclose', { source: this, }); } toggle() { diff --git a/web/pdf_find_controller.js b/web/pdf_find_controller.js index fd3d9d17d03e4..71457d9dfb43c 100644 --- a/web/pdf_find_controller.js +++ b/web/pdf_find_controller.js @@ -53,11 +53,24 @@ class PDFFindController { this.reset(); + eventBus.on('findbarclose', () => { + this._highlightMatches = false; + + eventBus.dispatch('updatetextlayermatches', { + source: this, + pageIndex: -1, + }); + }); + // Compile the regular expression for text normalization once. const replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(''); this._normalizationRegex = new RegExp(`[${replace}]`, 'g'); } + get highlightMatches() { + return this._highlightMatches; + } + get pageMatches() { return this._pageMatches; } @@ -75,7 +88,7 @@ class PDFFindController { } reset() { - this.active = false; // If active, find results will be highlighted. + this._highlightMatches = false; this._pageMatches = []; this._pageMatchesLength = null; this._state = null; @@ -353,7 +366,7 @@ class PDFFindController { const currentPageIndex = this._pdfViewer.currentPageNumber - 1; const numPages = this._pdfViewer.pagesCount; - this.active = true; + this._highlightMatches = true; if (this._dirtyMatch) { // Need to recalculate the matches, reset everything. diff --git a/web/text_layer_builder.js b/web/text_layer_builder.js index d8194b2958d9f..281f22a888ccd 100644 --- a/web/text_layer_builder.js +++ b/web/text_layer_builder.js @@ -317,7 +317,7 @@ class TextLayerBuilder { clearedUntilDivIdx = match.end.divIdx + 1; } - if (this.findController === null || !this.findController.active) { + if (!this.findController || !this.findController.highlightMatches) { return; } @@ -357,8 +357,15 @@ class TextLayerBuilder { delete _boundEvents[name]; } }; + _boundEvents.updateTextLayerMatches = (evt) => { + if (evt.pageIndex !== -1) { + return; + } + this.updateMatches(); + }; eventBus.on('pagecancelled', _boundEvents.pageCancelled); + eventBus.on('updatetextlayermatches', _boundEvents.updateTextLayerMatches); } /**