From 4c180fd58ba8607e725b700854c9117b6da7a4c6 Mon Sep 17 00:00:00 2001 From: neon <18559658+neonsolstice@users.noreply.github.com> Date: Mon, 24 Aug 2026 22:21:18 +0000 Subject: [PATCH] fix(reader): patch embedpdf zoom to release startup gate on custom zoom Apply a patch to @embedpdf/plugin-zoom@2.15.0 so numeric default zoom levels release the startup viewport gate once resize metrics are measured. Add unit test to verify custom zoom initialization and scale calculation under EmbedPDF. Closes #1126 --- .../pdf-v4/__tests__/embedpdf-zoom.spec.ts | 68 +++++++++++++++++++ patches/@embedpdf__plugin-zoom@2.15.0.patch | 15 ++++ pnpm-lock.yaml | 5 +- pnpm-workspace.yaml | 1 + 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 client/src/features/reader/pdf-v4/__tests__/embedpdf-zoom.spec.ts create mode 100644 patches/@embedpdf__plugin-zoom@2.15.0.patch diff --git a/client/src/features/reader/pdf-v4/__tests__/embedpdf-zoom.spec.ts b/client/src/features/reader/pdf-v4/__tests__/embedpdf-zoom.spec.ts new file mode 100644 index 000000000..08315b1d3 --- /dev/null +++ b/client/src/features/reader/pdf-v4/__tests__/embedpdf-zoom.spec.ts @@ -0,0 +1,68 @@ +import { afterEach, describe, expect, it } from 'vitest' +import { PluginRegistry, setDocumentLoaded, startLoadingDocument } from '@embedpdf/core' +import { Rotation, type PdfDocumentObject, type PdfEngine } from '@embedpdf/models' +import { ScrollPluginPackage, ScrollStrategy } from '@embedpdf/plugin-scroll' +import { ViewportPlugin, ViewportPluginPackage } from '@embedpdf/plugin-viewport' +import { ZoomPlugin, ZoomPluginPackage } from '@embedpdf/plugin-zoom' + +describe('patched EmbedPDF custom zoom initialization', () => { + let registry: PluginRegistry | null = null + + afterEach(async () => { + await registry?.destroy() + registry = null + }) + + it('applies a numeric default zoom and releases the startup gate after viewport measurement', async () => { + registry = new PluginRegistry({} as PdfEngine) + registry.registerPlugin(ViewportPluginPackage, { viewportGap: 12 }) + registry.registerPlugin(ScrollPluginPackage, { + defaultStrategy: ScrollStrategy.Vertical, + defaultPageGap: 12, + defaultBufferSize: 3, + }) + registry.registerPlugin(ZoomPluginPackage, { + defaultZoomLevel: 1.2, + minZoom: 0.25, + maxZoom: 4, + }) + await registry.initialize() + + const store = registry.getStore() + const documentId = 'custom-zoom-document' + const document: PdfDocumentObject = { + id: documentId, + pageCount: 1, + pages: [{ index: 0, size: { width: 600, height: 800 }, rotation: Rotation.Degree0, objectNumber: 1 }], + isEncrypted: false, + isOwnerUnlocked: true, + permissions: 0, + normalizedRotation: true, + } + + store.dispatchToCore(startLoadingDocument(documentId, 'PDF')) + store.dispatchToCore(setDocumentLoaded(documentId, document)) + + const viewport = registry.getPlugin(ViewportPlugin.id) + const zoom = registry.getPlugin(ZoomPlugin.id) + expect(viewport?.provides().hasGate('zoom', documentId)).toBe(true) + + viewport?.setViewportResizeMetrics(documentId, { + width: 1000, + height: 700, + clientWidth: 1000, + clientHeight: 700, + scrollTop: 0, + scrollLeft: 0, + scrollWidth: 1000, + scrollHeight: 700, + clientLeft: 0, + clientTop: 0, + }) + await new Promise((resolve) => setTimeout(resolve, 175)) + + expect(viewport?.provides().hasGate('zoom', documentId)).toBe(false) + expect(zoom?.provides().forDocument(documentId).getState()).toMatchObject({ zoomLevel: 1.2, currentZoomLevel: 1.2 }) + expect(store.getState().core.documents[documentId]?.scale).toBe(1.2) + }) +}) diff --git a/patches/@embedpdf__plugin-zoom@2.15.0.patch b/patches/@embedpdf__plugin-zoom@2.15.0.patch new file mode 100644 index 000000000..7e96635c0 --- /dev/null +++ b/patches/@embedpdf__plugin-zoom@2.15.0.patch @@ -0,0 +1,15 @@ +diff --git a/dist/index.js b/dist/index.js +index f33d50ed18a00f00cba6b102f5e7ab18f141364e..bb9085c18a295b7ac1e621423e94652803a647fc 100644 +--- a/dist/index.js ++++ b/dist/index.js +@@ -609,6 +609,10 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin { + recalcAuto(documentId, focus) { + const docState = this.getDocumentState(documentId); + if (!docState) return; ++ if (typeof docState.zoomLevel === "number") { ++ if (this.viewport.hasGate("zoom", documentId)) this.handleRequest({ level: docState.zoomLevel, focus }, documentId); ++ return; ++ } + if (docState.zoomLevel === ZoomMode.Automatic || docState.zoomLevel === ZoomMode.FitPage || docState.zoomLevel === ZoomMode.FitWidth) { + this.handleRequest({ level: docState.zoomLevel, focus }, documentId); + } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a5a34363..8961ea33c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,6 +30,7 @@ patchedDependencies: '@embedpdf/core@2.15.0': 2000da4fd605dad67860a28724f4ab90eafa7215b89abe29df3f001bebc15a77 '@embedpdf/engines@2.15.0': b4b3f0ea41ff20fd1f076c2b0a880f5b580a3ebdf5c69c95a7ee09a91183f924 '@embedpdf/plugin-scroll@2.15.0': ef47017e5f4370e4c13ae1a5b523683acaaa68db36290094f8badab4614c6d0d + '@embedpdf/plugin-zoom@2.15.0': 39f7f5ddd05c0dadd63f5fc076e679140d1b0f8761a4899176076b563e361d77 importers: @@ -133,7 +134,7 @@ importers: version: 2.15.0(@embedpdf/core@2.15.0(patch_hash=2000da4fd605dad67860a28724f4ab90eafa7215b89abe29df3f001bebc15a77)(preact@10.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(svelte@5.56.4(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)))(preact@10.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(svelte@5.56.4(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) '@embedpdf/plugin-zoom': specifier: 2.15.0 - version: 2.15.0(bae5492da052cd1ccfa4d859ce720d47) + version: 2.15.0(patch_hash=39f7f5ddd05c0dadd63f5fc076e679140d1b0f8761a4899176076b563e361d77)(bae5492da052cd1ccfa4d859ce720d47) '@fontsource-variable/fraunces': specifier: ^5.3.0 version: 5.3.0 @@ -10542,7 +10543,7 @@ snapshots: svelte: 5.56.4(@typescript-eslint/types@8.67.0) vue: 3.5.41(typescript@6.0.3) - '@embedpdf/plugin-zoom@2.15.0(bae5492da052cd1ccfa4d859ce720d47)': + '@embedpdf/plugin-zoom@2.15.0(patch_hash=39f7f5ddd05c0dadd63f5fc076e679140d1b0f8761a4899176076b563e361d77)(bae5492da052cd1ccfa4d859ce720d47)': dependencies: '@embedpdf/core': 2.15.0(patch_hash=2000da4fd605dad67860a28724f4ab90eafa7215b89abe29df3f001bebc15a77)(preact@10.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(svelte@5.56.4(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) '@embedpdf/models': 2.15.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 879b461b8..68b3b5ec6 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -54,6 +54,7 @@ patchedDependencies: "@embedpdf/core@2.15.0": patches/@embedpdf__core@2.15.0.patch "@embedpdf/engines@2.15.0": patches/@embedpdf__engines@2.15.0.patch "@embedpdf/plugin-scroll@2.15.0": patches/@embedpdf__plugin-scroll@2.15.0.patch + "@embedpdf/plugin-zoom@2.15.0": patches/@embedpdf__plugin-zoom@2.15.0.patch minimumReleaseAgeExclude: - "@tsconfig/node24@24.0.5" - "@vue/language-core@3.3.10"