Version: pdfjs-dist 6.3.289 (same code on master, web/text_layer_builder.js, checked against v6.4.299)
Setup: two PDFViewer instances on one page, each created with its own abortSignal (for example a page reader plus a modal reader).
Steps
- Mount viewer A with
abortSignal: a.signal and render a page with a text layer.
- Mount viewer B with
abortSignal: b.signal and render a page with a text layer.
- Abort
a (viewer A is torn down; viewer B stays).
- In viewer B, press the mouse on the text layer, drag, release.
Expected: the selection works, and on pointerup the text layer drops its selecting class.
Actual: after the first mousedown, the text layer keeps selecting. With the stock CSS, .textLayer.selecting .endOfContent { top: 0 } makes endOfContent cover the whole layer (user-select: none), and .textLayer.selecting ~ .annotationLayer section { pointer-events: none } disables the link annotations. New drag selections and links on that page stop working until every text layer is gone.
Cause: #enableGlobalSelectionListener(globalAbortSignal) binds the document listeners (pointerdown, pointerup, blur, keyup, selectionchange) on AbortSignal.any([#selectionChangeAC.signal, globalAbortSignal]), where globalAbortSignal is the signal of the FIRST viewer that registered a text layer. It returns early while #selectionChangeAC is set, and #selectionChangeAC is cleared only when #textLayers.size === 0. When the first viewer's signal aborts, the listeners go away, but #selectionChangeAC stays set because viewer B's text layer is still in #textLayers, so no later call binds them again.
Possible fix: the shared listeners should not live on one viewer's signal. For example, keep each text layer's abortSignal beside its endOfContent in #textLayers; when the signal the listeners were bound with aborts, drop that viewer's layers, clear #selectionChangeAC, and if text layers remain, bind again with a remaining layer's signal. Checking only #selectionChangeAC's own signal at the next #bindMouse is not enough: the surviving viewer's existing layers never call #bindMouse again.
Version: pdfjs-dist 6.3.289 (same code on master,
web/text_layer_builder.js, checked against v6.4.299)Setup: two
PDFViewerinstances on one page, each created with its ownabortSignal(for example a page reader plus a modal reader).Steps
abortSignal: a.signaland render a page with a text layer.abortSignal: b.signaland render a page with a text layer.a(viewer A is torn down; viewer B stays).Expected: the selection works, and on pointerup the text layer drops its
selectingclass.Actual: after the first mousedown, the text layer keeps
selecting. With the stock CSS,.textLayer.selecting .endOfContent { top: 0 }makesendOfContentcover the whole layer (user-select: none), and.textLayer.selecting ~ .annotationLayer section { pointer-events: none }disables the link annotations. New drag selections and links on that page stop working until every text layer is gone.Cause:
#enableGlobalSelectionListener(globalAbortSignal)binds the document listeners (pointerdown, pointerup, blur, keyup, selectionchange) onAbortSignal.any([#selectionChangeAC.signal, globalAbortSignal]), whereglobalAbortSignalis the signal of the FIRST viewer that registered a text layer. It returns early while#selectionChangeACis set, and#selectionChangeACis cleared only when#textLayers.size === 0. When the first viewer's signal aborts, the listeners go away, but#selectionChangeACstays set because viewer B's text layer is still in#textLayers, so no later call binds them again.Possible fix: the shared listeners should not live on one viewer's signal. For example, keep each text layer's
abortSignalbeside itsendOfContentin#textLayers; when the signal the listeners were bound with aborts, drop that viewer's layers, clear#selectionChangeAC, and if text layers remain, bind again with a remaining layer's signal. Checking only#selectionChangeAC's own signal at the next#bindMouseis not enough: the surviving viewer's existing layers never call#bindMouseagain.