From 023af46186fc4361dcf0121b6558a7198b56ac3c Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Fri, 30 Jan 2026 15:55:47 +0100 Subject: [PATCH] Replace the `IRenderableView` interface with an abstract `RenderableView` class This should help reduce the maintenance burden of the code, since you no longer need to remember to update separate code when touching the different page/thumbnail classes. --- test/unit/pdf_viewer.component_spec.js | 2 +- web/app.js | 2 +- web/base_pdf_page_view.js | 9 ++-- web/interfaces.js | 47 ----------------- web/pdf_page_detail_view.js | 11 ++-- web/pdf_page_view.js | 6 +-- web/pdf_rendering_queue.js | 9 ++-- web/pdf_scripting_manager.js | 3 +- web/pdf_thumbnail_view.js | 22 ++++---- web/pdf_thumbnail_viewer.js | 2 +- web/pdf_viewer.component.js | 2 +- web/pdf_viewer.js | 2 +- web/renderable_view.js | 71 ++++++++++++++++++++++++++ web/ui_utils.js | 8 --- web/viewer-geckoview.js | 3 +- web/viewer.js | 3 +- 16 files changed, 106 insertions(+), 96 deletions(-) delete mode 100644 web/interfaces.js create mode 100644 web/renderable_view.js diff --git a/test/unit/pdf_viewer.component_spec.js b/test/unit/pdf_viewer.component_spec.js index a511a353f..8ea31f93d 100644 --- a/test/unit/pdf_viewer.component_spec.js +++ b/test/unit/pdf_viewer.component_spec.js @@ -22,7 +22,6 @@ import { import { parseQueryString, ProgressBar, - RenderingStates, ScrollMode, SpreadMode, } from "../../web/ui_utils.js"; @@ -35,6 +34,7 @@ import { PDFPageView } from "../../web/pdf_page_view.js"; import { PDFScriptingManager } from "../../web/pdf_scripting_manager.component.js"; import { PDFSinglePageViewer } from "../../web/pdf_single_page_viewer.js"; import { PDFViewer } from "../../web/pdf_viewer.js"; +import { RenderingStates } from "../../web/renderable_view.js"; import { StructTreeLayerBuilder } from "../../web/struct_tree_layer_builder.js"; import { TextLayerBuilder } from "../../web/text_layer_builder.js"; import { XfaLayerBuilder } from "../../web/xfa_layer_builder.js"; diff --git a/web/app.js b/web/app.js index 056f3fdcd..6da406881 100644 --- a/web/app.js +++ b/web/app.js @@ -33,7 +33,6 @@ import { normalizeWheelEventDirection, parseQueryString, ProgressBar, - RenderingStates, ScrollMode, SidebarView, SpreadMode, @@ -91,6 +90,7 @@ import { PdfTextExtractor } from "./pdf_text_extractor.js"; import { PDFThumbnailViewer } from "web-pdf_thumbnail_viewer"; import { PDFViewer } from "./pdf_viewer.js"; import { Preferences } from "web-preferences"; +import { RenderingStates } from "./renderable_view.js"; import { SecondaryToolbar } from "web-secondary_toolbar"; import { SignatureManager } from "web-signature_manager"; import { Toolbar } from "web-toolbar"; diff --git a/web/base_pdf_page_view.js b/web/base_pdf_page_view.js index 4c8ab5e95..c37b5e4e2 100644 --- a/web/base_pdf_page_view.js +++ b/web/base_pdf_page_view.js @@ -13,10 +13,10 @@ * limitations under the License. */ +import { RenderableView, RenderingStates } from "./renderable_view.js"; import { RenderingCancelledException } from "pdfjs-lib"; -import { RenderingStates } from "./ui_utils.js"; -class BasePDFPageView { +class BasePDFPageView extends RenderableView { #loadingId = null; #minDurationToUpdateCanvas = 0; @@ -48,11 +48,8 @@ class BasePDFPageView { renderingQueue = null; - renderTask = null; - - resume = null; - constructor(options) { + super(); this.eventBus = options.eventBus; this.id = options.id; this.pageColors = options.pageColors || null; diff --git a/web/interfaces.js b/web/interfaces.js deleted file mode 100644 index 428c5de58..000000000 --- a/web/interfaces.js +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2018 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. - */ -/* eslint-disable getter-return */ - -/** @typedef {import("../src/display/api").PDFPageProxy} PDFPageProxy */ -// eslint-disable-next-line max-len -/** @typedef {import("../src/display/display_utils").PageViewport} PageViewport */ -/** @typedef {import("./ui_utils").RenderingStates} RenderingStates */ - -/** - * @interface - */ -class IRenderableView { - constructor() { - /** @type {function | null} */ - this.resume = null; - } - - /** - * @type {string} - Unique ID for rendering queue. - */ - get renderingId() {} - - /** - * @type {RenderingStates} - */ - get renderingState() {} - - /** - * @returns {Promise} Resolved on draw completion. - */ - async draw() {} -} - -export { IRenderableView }; diff --git a/web/pdf_page_detail_view.js b/web/pdf_page_detail_view.js index b1f814ec3..eda8d5cea 100644 --- a/web/pdf_page_detail_view.js +++ b/web/pdf_page_detail_view.js @@ -15,13 +15,8 @@ import { BasePDFPageView } from "./base_pdf_page_view.js"; import { OutputScale } from "pdfjs-lib"; -import { RenderingStates } from "./ui_utils.js"; +import { RenderingStates } from "./renderable_view.js"; -/** @typedef {import("./interfaces").IRenderableView} IRenderableView */ - -/** - * @implements {IRenderableView} - */ class PDFPageDetailView extends BasePDFPageView { #detailArea = null; @@ -54,9 +49,9 @@ class PDFPageDetailView extends BasePDFPageView { return super.renderingState; } - set renderingState(value) { + set renderingState(state) { this.renderingCancelled = false; - super.renderingState = value; + super.renderingState = state; } reset({ keepCanvas = false } = {}) { diff --git a/web/pdf_page_view.js b/web/pdf_page_view.js index 045b566eb..37e888ffb 100644 --- a/web/pdf_page_view.js +++ b/web/pdf_page_view.js @@ -18,7 +18,6 @@ // eslint-disable-next-line max-len /** @typedef {import("../src/display/optional_content_config").OptionalContentConfig} OptionalContentConfig */ /** @typedef {import("./event_utils").EventBus} EventBus */ -/** @typedef {import("./interfaces").IRenderableView} IRenderableView */ // eslint-disable-next-line max-len /** @typedef {import("./pdf_rendering_queue").PDFRenderingQueue} PDFRenderingQueue */ /** @typedef {import("./comment_manager.js").CommentManager} CommentManager */ @@ -36,7 +35,6 @@ import { calcRound, DEFAULT_SCALE, floorToDivide, - RenderingStates, TextLayerMode, } from "./ui_utils.js"; import { AnnotationEditorLayerBuilder } from "./annotation_editor_layer_builder.js"; @@ -47,6 +45,7 @@ import { BasePDFPageView } from "./base_pdf_page_view.js"; import { DrawLayerBuilder } from "./draw_layer_builder.js"; import { GenericL10n } from "web-null_l10n"; import { PDFPageDetailView } from "./pdf_page_detail_view.js"; +import { RenderingStates } from "./renderable_view.js"; import { SimpleLinkService } from "./pdf_link_service.js"; import { StructTreeLayerBuilder } from "./struct_tree_layer_builder.js"; import { TextAccessibilityManager } from "./text_accessibility.js"; @@ -129,9 +128,6 @@ const LAYERS_ORDER = new Map([ ["xfaLayer", 3], ]); -/** - * @implements {IRenderableView} - */ class PDFPageView extends BasePDFPageView { #annotationMode = AnnotationMode.ENABLE_FORMS; diff --git a/web/pdf_rendering_queue.js b/web/pdf_rendering_queue.js index bbcb51fc3..0b2a5975a 100644 --- a/web/pdf_rendering_queue.js +++ b/web/pdf_rendering_queue.js @@ -13,13 +13,12 @@ * limitations under the License. */ -/** @typedef {import("./interfaces").IRenderableView} IRenderableView */ /** @typedef {import("./pdf_viewer").PDFViewer} PDFViewer */ // eslint-disable-next-line max-len /** @typedef {import("./pdf_thumbnail_viewer").PDFThumbnailViewer} PDFThumbnailViewer */ import { RenderingCancelledException } from "pdfjs-lib"; -import { RenderingStates } from "./ui_utils.js"; +import { RenderingStates } from "./renderable_view.js"; const CLEANUP_TIMEOUT = 30000; @@ -59,7 +58,7 @@ class PDFRenderingQueue { } /** - * @param {IRenderableView} view + * @param {RenderableView} view * @returns {boolean} */ isHighestPriority(view) { @@ -183,7 +182,7 @@ class PDFRenderingQueue { } /** - * @param {IRenderableView} view + * @param {RenderableView} view * @returns {boolean} */ isViewFinished(view) { @@ -195,7 +194,7 @@ class PDFRenderingQueue { * based on the views state. If the view is already rendered it will return * `false`. * - * @param {IRenderableView} view + * @param {RenderableView} view */ renderView(view) { switch (view.renderingState) { diff --git a/web/pdf_scripting_manager.js b/web/pdf_scripting_manager.js index 402613f87..4583285b5 100644 --- a/web/pdf_scripting_manager.js +++ b/web/pdf_scripting_manager.js @@ -15,7 +15,8 @@ /** @typedef {import("./event_utils").EventBus} EventBus */ -import { apiPageLayoutToViewerModes, RenderingStates } from "./ui_utils.js"; +import { apiPageLayoutToViewerModes } from "./ui_utils.js"; +import { RenderingStates } from "./renderable_view.js"; import { shadow } from "pdfjs-lib"; /** diff --git a/web/pdf_thumbnail_view.js b/web/pdf_thumbnail_view.js index b7fbc458e..706febbbe 100644 --- a/web/pdf_thumbnail_view.js +++ b/web/pdf_thumbnail_view.js @@ -18,7 +18,6 @@ // eslint-disable-next-line max-len /** @typedef {import("../src/display/display_utils").PageViewport} PageViewport */ /** @typedef {import("./event_utils").EventBus} EventBus */ -/** @typedef {import("./interfaces").IRenderableView} IRenderableView */ // eslint-disable-next-line max-len /** @typedef {import("./pdf_rendering_queue").PDFRenderingQueue} PDFRenderingQueue */ @@ -27,8 +26,8 @@ import { OutputScale, RenderingCancelledException, } from "pdfjs-lib"; +import { RenderableView, RenderingStates } from "./renderable_view.js"; import { AppOptions } from "./app_options.js"; -import { RenderingStates } from "./ui_utils.js"; const DRAW_UPSCALE_FACTOR = 2; // See comment in `PDFThumbnailView.draw` below. const MAX_NUM_SCALING_STEPS = 3; @@ -78,10 +77,9 @@ class TempImageFactory { } } -/** - * @implements {IRenderableView} - */ -class PDFThumbnailView { +class PDFThumbnailView extends RenderableView { + #renderingState = RenderingStates.INITIAL; + /** * @param {PDFThumbnailViewOptions} options */ @@ -98,6 +96,7 @@ class PDFThumbnailView { pageColors, enableSplitMerge = false, }) { + super(); this.id = id; this.renderingId = `thumbnail${id}`; this.pageLabel = null; @@ -115,9 +114,6 @@ class PDFThumbnailView { this.linkService = linkService; this.renderingQueue = renderingQueue; - this.renderTask = null; - this.renderingState = RenderingStates.INITIAL; - this.resume = null; this.placeholder = null; const imageContainer = (this.div = document.createElement("div")); @@ -162,6 +158,14 @@ class PDFThumbnailView { this.image.style.height = `${canvasHeight}px`; } + get renderingState() { + return this.#renderingState; + } + + set renderingState(state) { + this.#renderingState = state; + } + setPdfPage(pdfPage) { this.pdfPage = pdfPage; this.pdfPageRotate = pdfPage.rotate; diff --git a/web/pdf_thumbnail_viewer.js b/web/pdf_thumbnail_viewer.js index 3a527bcce..fe0816af3 100644 --- a/web/pdf_thumbnail_viewer.js +++ b/web/pdf_thumbnail_viewer.js @@ -23,12 +23,12 @@ import { binarySearchFirstItem, getVisibleElements, isValidRotation, - RenderingStates, watchScroll, } from "./ui_utils.js"; import { MathClamp, noContextMenu, PagesMapper, stopEvent } from "pdfjs-lib"; import { Menu } from "./menu.js"; import { PDFThumbnailView } from "./pdf_thumbnail_view.js"; +import { RenderingStates } from "./renderable_view.js"; const SCROLL_OPTIONS = { behavior: "instant", diff --git a/web/pdf_viewer.component.js b/web/pdf_viewer.component.js index 5e142a018..d282539d2 100644 --- a/web/pdf_viewer.component.js +++ b/web/pdf_viewer.component.js @@ -22,7 +22,6 @@ import { import { parseQueryString, ProgressBar, - RenderingStates, ScrollMode, SpreadMode, } from "./ui_utils.js"; @@ -35,6 +34,7 @@ import { PDFPageView } from "./pdf_page_view.js"; import { PDFScriptingManager } from "./pdf_scripting_manager.component.js"; import { PDFSinglePageViewer } from "./pdf_single_page_viewer.js"; import { PDFViewer } from "./pdf_viewer.js"; +import { RenderingStates } from "./renderable_view.js"; import { StructTreeLayerBuilder } from "./struct_tree_layer_builder.js"; import { TextLayerBuilder } from "./text_layer_builder.js"; import { XfaLayerBuilder } from "./xfa_layer_builder.js"; diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 525a8a839..1d97482d1 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -52,7 +52,6 @@ import { MIN_SCALE, PresentationModeState, removeNullCharacters, - RenderingStates, SCROLLBAR_PADDING, scrollIntoView, ScrollMode, @@ -65,6 +64,7 @@ import { import { GenericL10n } from "web-null_l10n"; import { PDFPageView } from "./pdf_page_view.js"; import { PDFRenderingQueue } from "./pdf_rendering_queue.js"; +import { RenderingStates } from "./renderable_view.js"; import { SimpleLinkService } from "./pdf_link_service.js"; const DEFAULT_CACHE_SIZE = 10; diff --git a/web/renderable_view.js b/web/renderable_view.js new file mode 100644 index 000000000..086d8f03a --- /dev/null +++ b/web/renderable_view.js @@ -0,0 +1,71 @@ +/* Copyright 2018 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. + */ + +const RenderingStates = { + INITIAL: 0, + RUNNING: 1, + PAUSED: 2, + FINISHED: 3, +}; + +class RenderableView { + /** + * Unique ID for rendering queue. + * @type {string} + */ + renderingId = ""; + + /** + * @type {RenderTask | null} + */ + renderTask = null; + + /** + * @type {function | null} + */ + resume = null; + + constructor() { + if ( + (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) && + this.constructor === RenderableView + ) { + throw new Error("Cannot initialize RenderableView."); + } + } + + /** + * @type {RenderingStates} + */ + get renderingState() { + throw new Error("Abstract getter `renderingState` accessed"); + } + + /** + * @param {RenderingStates} + */ + set renderingState(state) { + throw new Error("Abstract setter `renderingState` accessed"); + } + + /** + * @returns {Promise} Resolved on draw completion. + */ + async draw() { + throw new Error("Not implemented: draw"); + } +} + +export { RenderableView, RenderingStates }; diff --git a/web/ui_utils.js b/web/ui_utils.js index a4199e611..ab695144a 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -25,13 +25,6 @@ const MAX_AUTO_SCALE = 1.25; const SCROLLBAR_PADDING = 40; const VERTICAL_PADDING = 5; -const RenderingStates = { - INITIAL: 0, - RUNNING: 1, - PAUSED: 2, - FINISHED: 3, -}; - const PresentationModeState = { UNKNOWN: 0, NORMAL: 1, @@ -914,7 +907,6 @@ export { PresentationModeState, ProgressBar, removeNullCharacters, - RenderingStates, SCROLLBAR_PADDING, scrollIntoView, ScrollMode, diff --git a/web/viewer-geckoview.js b/web/viewer-geckoview.js index 71113e2f3..de060d589 100644 --- a/web/viewer-geckoview.js +++ b/web/viewer-geckoview.js @@ -13,10 +13,11 @@ * limitations under the License. */ -import { RenderingStates, ScrollMode, SpreadMode } from "./ui_utils.js"; +import { ScrollMode, SpreadMode } from "./ui_utils.js"; import { AppOptions } from "./app_options.js"; import { LinkTarget } from "./pdf_link_service.js"; import { PDFViewerApplication } from "./app.js"; +import { RenderingStates } from "./renderable_view.js"; const AppConstants = typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC") diff --git a/web/viewer.js b/web/viewer.js index af35be762..dc6696c69 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -13,10 +13,11 @@ * limitations under the License. */ -import { RenderingStates, ScrollMode, SpreadMode } from "./ui_utils.js"; +import { ScrollMode, SpreadMode } from "./ui_utils.js"; import { AppOptions } from "./app_options.js"; import { LinkTarget } from "./pdf_link_service.js"; import { PDFViewerApplication } from "./app.js"; +import { RenderingStates } from "./renderable_view.js"; const AppConstants = typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")