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.
This commit is contained in:
Jonas Jenwald 2026-01-30 15:55:47 +01:00
parent 839c257f87
commit 023af46186
16 changed files with 106 additions and 96 deletions

View File

@ -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";

View File

@ -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";

View File

@ -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;

View File

@ -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 };

View File

@ -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 } = {}) {

View File

@ -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;

View File

@ -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) {

View File

@ -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";
/**

View File

@ -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;

View File

@ -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",

View File

@ -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";

View File

@ -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;

71
web/renderable_view.js Normal file
View File

@ -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 };

View File

@ -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,

View File

@ -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")

View File

@ -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")