diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 223011cf..1ffe7811 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -48,7 +48,7 @@ android { defaultConfig { applicationId = "app.grapheneos.pdfviewer" minSdk = 26 - targetSdk = 35 + targetSdk = 36 versionCode = 32 versionName = versionCode.toString() } diff --git a/app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java b/app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java index 936f7085..e91a9094 100644 --- a/app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java +++ b/app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java @@ -29,7 +29,10 @@ import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.ViewModelProvider; @@ -38,6 +41,8 @@ import com.google.android.material.snackbar.Snackbar; +import org.json.JSONObject; + import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -265,6 +270,23 @@ public void onLoaded() { public String getPassword() { return mEncryptedDocumentPassword != null ? mEncryptedDocumentPassword : ""; } + + @JavascriptInterface + public String getInsets() { + WindowInsetsCompat wic = ViewCompat.getRootWindowInsets(binding.getRoot()); + int types = WindowInsetsCompat.Type.statusBars() + | WindowInsetsCompat.Type.navigationBars() + | WindowInsetsCompat.Type.displayCutout(); + Insets insets = (wic != null) ? wic.getInsetsIgnoringVisibility(types) : Insets.NONE; + + HashMap insetMap = new HashMap<>(4); + insetMap.put("top", insets.top + binding.toolbar.getHeight()); + insetMap.put("right", insets.right); + insetMap.put("bottom", insets.bottom); + insetMap.put("left", insets.left); + + return new JSONObject(insetMap).toString(); + } } private void showWebViewCrashed() { @@ -279,11 +301,19 @@ private void showWebViewCrashed() { @SuppressLint({"SetJavaScriptEnabled"}) protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + WindowCompat.enableEdgeToEdge(getWindow()); binding = PdfviewerBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); + + ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> { + if (mUri != null) { + binding.webview.evaluateJavascript("updateInsets()", null); + } + return insets; + }); + viewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(PdfViewModel.class); viewModel.getOutline().observe(this, requested -> { diff --git a/app/src/main/res/layout/pdfviewer.xml b/app/src/main/res/layout/pdfviewer.xml index dc73b98a..7796b6ec 100644 --- a/app/src/main/res/layout/pdfviewer.xml +++ b/app/src/main/res/layout/pdfviewer.xml @@ -4,6 +4,11 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + - - = 10" }, "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "0.1.78", - "@napi-rs/canvas-darwin-arm64": "0.1.78", - "@napi-rs/canvas-darwin-x64": "0.1.78", - "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.78", - "@napi-rs/canvas-linux-arm64-gnu": "0.1.78", - "@napi-rs/canvas-linux-arm64-musl": "0.1.78", - "@napi-rs/canvas-linux-riscv64-gnu": "0.1.78", - "@napi-rs/canvas-linux-x64-gnu": "0.1.78", - "@napi-rs/canvas-linux-x64-musl": "0.1.78", - "@napi-rs/canvas-win32-x64-msvc": "0.1.78" + "@napi-rs/canvas-android-arm64": "0.1.80", + "@napi-rs/canvas-darwin-arm64": "0.1.80", + "@napi-rs/canvas-darwin-x64": "0.1.80", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.80", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.80", + "@napi-rs/canvas-linux-arm64-musl": "0.1.80", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-musl": "0.1.80", + "@napi-rs/canvas-win32-x64-msvc": "0.1.80" } }, "node_modules/@napi-rs/canvas-android-arm64": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.78.tgz", - "integrity": "sha512-N1ikxztjrRmh8xxlG5kYm1RuNr8ZW1EINEDQsLhhuy7t0pWI/e7SH91uFVLZKCMDyjel1tyWV93b5fdCAi7ggw==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.80.tgz", + "integrity": "sha512-sk7xhN/MoXeuExlggf91pNziBxLPVUqF2CAVnB57KLG/pz7+U5TKG8eXdc3pm0d7Od0WreB6ZKLj37sX9muGOQ==", "cpu": [ "arm64" ], @@ -707,9 +707,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-arm64": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.78.tgz", - "integrity": "sha512-FA3aCU3G5yGc74BSmnLJTObnZRV+HW+JBTrsU+0WVVaNyVKlb5nMvYAQuieQlRVemsAA2ek2c6nYtHh6u6bwFw==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz", + "integrity": "sha512-O64APRTXRUiAz0P8gErkfEr3lipLJgM6pjATwavZ22ebhjYl/SUbpgM0xcWPQBNMP1n29afAC/Us5PX1vg+JNQ==", "cpu": [ "arm64" ], @@ -724,9 +724,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-x64": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.78.tgz", - "integrity": "sha512-xVij69o9t/frixCDEoyWoVDKgE3ksLGdmE2nvBWVGmoLu94MWUlv2y4Qzf5oozBmydG5Dcm4pRHFBM7YWa1i6g==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz", + "integrity": "sha512-FqqSU7qFce0Cp3pwnTjVkKjjOtxMqRe6lmINxpIZYaZNnVI0H5FtsaraZJ36SiTHNjZlUB69/HhxNDT1Aaa9vA==", "cpu": [ "x64" ], @@ -741,9 +741,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.78.tgz", - "integrity": "sha512-aSEXrLcIpBtXpOSnLhTg4jPsjJEnK7Je9KqUdAWjc7T8O4iYlxWxrXFIF8rV8J79h5jNdScgZpAUWYnEcutR3g==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz", + "integrity": "sha512-eyWz0ddBDQc7/JbAtY4OtZ5SpK8tR4JsCYEZjCE3dI8pqoWUC8oMwYSBGCYfsx2w47cQgQCgMVRVTFiiO38hHQ==", "cpu": [ "arm" ], @@ -758,9 +758,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-gnu": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.78.tgz", - "integrity": "sha512-dlEPRX1hLGKaY3UtGa1dtkA1uGgFITn2mDnfI6YsLlYyLJQNqHx87D1YTACI4zFCUuLr/EzQDzuX+vnp9YveVg==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz", + "integrity": "sha512-qwA63t8A86bnxhuA/GwOkK3jvb+XTQaTiVML0vAWoHyoZYTjNs7BzoOONDgTnNtr8/yHrq64XXzUoLqDzU+Uuw==", "cpu": [ "arm64" ], @@ -775,9 +775,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-musl": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.78.tgz", - "integrity": "sha512-TsCfjOPZtm5Q/NO1EZHR5pwDPSPjPEttvnv44GL32Zn1uvudssjTLbvaG1jHq81Qxm16GTXEiYLmx4jOLZQYlg==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz", + "integrity": "sha512-1XbCOz/ymhj24lFaIXtWnwv/6eFHXDrjP0jYkc6iHQ9q8oXKzUX1Lc6bu+wuGiLhGh2GS/2JlfORC5ZcXimRcg==", "cpu": [ "arm64" ], @@ -792,9 +792,9 @@ } }, "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.78.tgz", - "integrity": "sha512-+cpTTb0GDshEow/5Fy8TpNyzaPsYb3clQIjgWRmzRcuteLU+CHEU/vpYvAcSo7JxHYPJd8fjSr+qqh+nI5AtmA==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz", + "integrity": "sha512-XTzR125w5ZMs0lJcxRlS1K3P5RaZ9RmUsPtd1uGt+EfDyYMu4c6SEROYsxyatbbu/2+lPe7MPHOO/0a0x7L/gw==", "cpu": [ "riscv64" ], @@ -809,9 +809,9 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-gnu": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.78.tgz", - "integrity": "sha512-wxRcvKfvYBgtrO0Uy8OmwvjlnTcHpY45LLwkwVNIWHPqHAsyoTyG/JBSfJ0p5tWRzMOPDCDqdhpIO4LOgXjeyg==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz", + "integrity": "sha512-BeXAmhKg1kX3UCrJsYbdQd3hIMDH/K6HnP/pG2LuITaXhXBiNdh//TVVVVCBbJzVQaV5gK/4ZOCMrQW9mvuTqA==", "cpu": [ "x64" ], @@ -826,9 +826,9 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-musl": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.78.tgz", - "integrity": "sha512-vQFOGwC9QDP0kXlhb2LU1QRw/humXgcbVp8mXlyBqzc/a0eijlLF9wzyarHC1EywpymtS63TAj8PHZnhTYN6hg==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz", + "integrity": "sha512-x0XvZWdHbkgdgucJsRxprX/4o4sEed7qo9rCQA9ugiS9qE2QvP0RIiEugtZhfLH3cyI+jIRFJHV4Fuz+1BHHMg==", "cpu": [ "x64" ], @@ -843,9 +843,9 @@ } }, "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "0.1.78", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.78.tgz", - "integrity": "sha512-/eKlTZBtGUgpRKalzOzRr6h7KVSuziESWXgBcBnXggZmimwIJWPJlEcbrx5Tcwj8rPuZiANXQOG9pPgy9Q4LTQ==", + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz", + "integrity": "sha512-Z8jPsM6df5V8B1HrCHB05+bDiCxjE9QA//3YrkKIdVDEwn5RKaqOxCJDRJkl48cJbylcrJbW4HxZbTte8juuPg==", "cpu": [ "x64" ], @@ -1660,16 +1660,16 @@ } }, "node_modules/pdfjs-dist": { - "version": "5.4.149", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.149.tgz", - "integrity": "sha512-Xe8/1FMJEQPUVSti25AlDpwpUm2QAVmNOpFP0SIahaPIOKBKICaefbzogLdwey3XGGoaP4Lb9wqiw2e9Jqp0LA==", + "version": "5.4.296", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz", + "integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==", "dev": true, "license": "Apache-2.0", "engines": { "node": ">=20.16.0 || >=22.3.0" }, "optionalDependencies": { - "@napi-rs/canvas": "^0.1.77" + "@napi-rs/canvas": "^0.1.80" } }, "node_modules/picomatch": { diff --git a/package.json b/package.json index c6c4292e..173db666 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,6 @@ "@stylistic/eslint-plugin": "^5.4.0", "esbuild": "^0.25.10", "eslint": "^9.37.0", - "pdfjs-dist": "^5.4.149" + "pdfjs-dist": "^5.4.296" } } diff --git a/viewer/css/pdf_viewer.css b/viewer/css/pdf_viewer.css index d4b7e477..50666f23 100644 --- a/viewer/css/pdf_viewer.css +++ b/viewer/css/pdf_viewer.css @@ -1,53 +1,65 @@ html, body { + width: 100%; height: 100%; } -body, -canvas { - padding: 0; - margin: 0; -} - body { + margin: 0; + padding: 0; background-color: #c0c0c0; } #container { --scale-factor: 1; + + --inset-top: 0; + --inset-right: 0; + --inset-bottom: 0; + --inset-left: 0; + + --padding: 8px; + + position: fixed; + overflow: auto; + inset: 0; + padding-top: calc(var(--padding) + var(--inset-top)); + padding-right: calc(var(--padding) + var(--inset-right)); + padding-bottom: calc(var(--padding) + var(--inset-bottom)); + padding-left: calc(var(--padding) + var(--inset-left)); +} + +#container .page { --user-unit: 1; --total-scale-factor: calc(var(--scale-factor) * var(--user-unit)); --scale-round-x: 1px; --scale-round-y: 1px; - width: 100%; - height: 100%; - display: grid; - place-items: center; -} + --page-width: 0; + --page-height: 0; -#container canvas, -#container .textLayer { - /* overlay child elements on top of each other */ - grid-row-start: 1; - grid-column-start: 1; + position: relative; + width: round(down, var(--total-scale-factor) * var(--page-width), var(--scale-round-x)); + height: round(down, var(--total-scale-factor) * var(--page-height), var(--scale-round-y)); + margin: 0 auto; } -canvas { - display: inline-block; - position: relative; +.page canvas { + position: absolute; + width: 100%; + height: 100%; } [data-main-rotation="90"] { - transform: rotate(90deg); + transform: rotate(90deg) translateY(-100%); } [data-main-rotation="180"] { - transform: rotate(180deg); + transform: rotate(180deg) translate(-100%, -100%); } [data-main-rotation="270"] { - transform: rotate(270deg); + transform: rotate(270deg) translateX(-100%); } .hiddenCanvasElement { diff --git a/viewer/css/text_layer.css b/viewer/css/text_layer.css index b636b99e..9d7c3e07 100644 --- a/viewer/css/text_layer.css +++ b/viewer/css/text_layer.css @@ -3,13 +3,15 @@ } .textLayer { - text-align: initial; position: absolute; + text-align: initial; + inset: 0; overflow: clip; opacity: 1; line-height: 1; text-size-adjust: none; forced-color-adjust: none; + transform-origin: 0 0; caret-color: CanvasText; z-index: 0; } diff --git a/viewer/index.html b/viewer/index.html index 65eefa76..4a975615 100644 --- a/viewer/index.html +++ b/viewer/index.html @@ -8,8 +8,10 @@
- -
+
+ +
+
diff --git a/viewer/js/index.js b/viewer/js/index.js index 3eed8fee..d502681d 100644 --- a/viewer/js/index.js +++ b/viewer/js/index.js @@ -14,6 +14,7 @@ let renderPending = false; let renderPendingZoom = 0; const canvas = document.getElementById("content"); const container = document.getElementById("container"); +const singlePageView = document.getElementById("single-page-view"); let orientationDegrees = 0; let zoomRatio = 1; let textLayerDiv = document.getElementById("text"); @@ -59,31 +60,41 @@ function doPrerender(pageNumber, prerenderTrigger) { } } -function display(newCanvas, zoom) { +function display(page, newCanvas, zoom, orientationDegrees) { + const viewport = getViewport(page, 1, orientationDegrees); + singlePageView.style.setProperty("--page-width", `${viewport.width}px`); + singlePageView.style.setProperty("--page-height", `${viewport.height}px`); + canvas.height = newCanvas.height; canvas.width = newCanvas.width; - canvas.style.height = newCanvas.style.height; - canvas.style.width = newCanvas.style.width; canvas.getContext("2d", { alpha: false }).drawImage(newCanvas, 0, 0); if (!zoom) { - scrollTo(0, 0); + container.scrollTo(0, 0); } } -function setLayerTransform(pageWidth, pageHeight, layerDiv) { - const translate = { - X: Math.max(0, pageWidth - document.body.clientWidth) / 2, - Y: Math.max(0, pageHeight - document.body.clientHeight) / 2 +function getContainerPadding() { + const containerStyle = getComputedStyle(container); + return { + top: parseFloat(containerStyle.paddingTop), + right: parseFloat(containerStyle.paddingRight), + bottom: parseFloat(containerStyle.paddingBottom), + left: parseFloat(containerStyle.paddingLeft) }; - layerDiv.style.translate = `${translate.X}px ${translate.Y}px`; } function getDefaultZoomRatio(page, orientationDegrees) { - const totalRotation = (orientationDegrees + page.rotate) % 360; - const viewport = page.getViewport({scale: 1, rotation: totalRotation}); - const widthZoomRatio = document.body.clientWidth / viewport.width; - const heightZoomRatio = document.body.clientHeight / viewport.height; - return Math.max(Math.min(widthZoomRatio, heightZoomRatio, channel.getMaxZoomRatio()), channel.getMinZoomRatio()); + const viewport = getViewport(page, 1, orientationDegrees); + const containerPadding = getContainerPadding(); + const containerHorizontalPadding = containerPadding.left + containerPadding.right; + const containerInnerWidth = container.clientWidth - containerHorizontalPadding; + const widthZoomRatio = containerInnerWidth / viewport.width; + return Math.max(Math.min(widthZoomRatio, channel.getMaxZoomRatio()), channel.getMinZoomRatio()); +} + +function getViewport(page, scale, orientationDegrees) { + const rotation = (page.rotate + orientationDegrees) % 360; + return page.getViewport({scale, rotation}); } /** @@ -187,18 +198,17 @@ function renderPage(pageNumber, zoom, prerender, prerenderTrigger = 0) { ", orientationDegrees: " + orientationDegrees + ", prerender: " + prerender); for (let i = 0; i < cache.length; i++) { const cached = cache[i]; - if (cached.pageNumber === pageNumber && cached.zoomRatio === newZoomRatio && + if (cached.page.pageNumber === pageNumber && cached.zoomRatio === newZoomRatio && cached.orientationDegrees === orientationDegrees) { if (useRender) { cache.splice(i, 1); cache.push(cached); - display(cached.canvas, zoom); + container.style.setProperty("--scale-factor", newZoomRatio.toString()); + display(cached.page, cached.canvas, zoom, orientationDegrees); textLayerDiv.replaceWith(cached.textLayerDiv); textLayerDiv = cached.textLayerDiv; - setLayerTransform(cached.pageWidth, cached.pageHeight, textLayerDiv); - container.style.setProperty("--scale-factor", newZoomRatio.toString()); textLayerDiv.hidden = false; } @@ -221,16 +231,14 @@ function renderPage(pageNumber, zoom, prerender, prerenderTrigger = 0) { channel.setZoomRatio(defaultZoomRatio); } - const totalRotation = (orientationDegrees + page.rotate) % 360; - const viewport = page.getViewport({scale: newZoomRatio, rotation: totalRotation}); + const viewport = getViewport(page, newZoomRatio, orientationDegrees); const scaleFactor = newZoomRatio / zoomRatio; const ratio = globalThis.devicePixelRatio; if (useRender) { if (newZoomRatio !== zoomRatio) { - canvas.style.height = viewport.height + "px"; - canvas.style.width = viewport.width + "px"; + container.style.setProperty("--scale-factor", newZoomRatio); } zoomRatio = newZoomRatio; } @@ -239,14 +247,15 @@ function renderPage(pageNumber, zoom, prerender, prerenderTrigger = 0) { textLayerDiv.hidden = true; pageRendering = false; + const containerPadding = getContainerPadding(); // zoom focus relative to page origin, rather than screen origin - const globalFocusX = channel.getZoomFocusX() / ratio + globalThis.scrollX; - const globalFocusY = channel.getZoomFocusY() / ratio + globalThis.scrollY; + const globalFocusX = channel.getZoomFocusX() / ratio + container.scrollLeft - containerPadding.left; + const globalFocusY = channel.getZoomFocusY() / ratio + container.scrollTop - containerPadding.top; const translationFactor = scaleFactor - 1; const scrollX = globalFocusX * translationFactor; const scrollY = globalFocusY * translationFactor; - scrollBy(scrollX, scrollY); + container.scrollBy(scrollX, scrollY); return; } @@ -260,18 +269,12 @@ function renderPage(pageNumber, zoom, prerender, prerenderTrigger = 0) { if (renderPixels > maxRenderPixels) { console.log(`resolution ${renderPixels} exceeds maximum allowed ${maxRenderPixels}`); const adjustedScale = Math.sqrt(maxRenderPixels / renderPixels); - newViewport = page.getViewport({ - scale: newZoomRatio * adjustedScale, - rotation: totalRotation - }); + newViewport = getViewport(page, newZoomRatio * adjustedScale, orientationDegrees); } const newCanvas = document.createElement("canvas"); newCanvas.height = newViewport.height * ratio; newCanvas.width = newViewport.width * ratio; - // use original viewport height for CSS zoom - newCanvas.style.height = viewport.height + "px"; - newCanvas.style.width = viewport.width + "px"; const newContext = newCanvas.getContext("2d", { alpha: false }); newContext.scale(ratio, ratio); @@ -288,7 +291,8 @@ function renderPage(pageNumber, zoom, prerender, prerenderTrigger = 0) { if (!useRender || rendered) { return; } - display(newCanvas, zoom); + container.style.setProperty("--scale-factor", newZoomRatio.toString()); + display(page, newCanvas, zoom, orientationDegrees); rendered = true; } render(); @@ -308,11 +312,9 @@ function renderPage(pageNumber, zoom, prerender, prerenderTrigger = 0) { render(); - setLayerTransform(viewport.width, viewport.height, newTextLayerDiv); if (useRender) { textLayerDiv.replaceWith(newTextLayerDiv); textLayerDiv = newTextLayerDiv; - container.style.setProperty("--scale-factor", newZoomRatio.toString()); textLayerDiv.hidden = false; } @@ -320,13 +322,11 @@ function renderPage(pageNumber, zoom, prerender, prerenderTrigger = 0) { cache.shift(); } cache.push({ - pageNumber: pageNumber, + page: page, zoomRatio: newZoomRatio, orientationDegrees: orientationDegrees, canvas: newCanvas, - textLayerDiv: newTextLayerDiv, - pageWidth: viewport.width, - pageHeight: viewport.height + textLayerDiv: newTextLayerDiv }); pageRendering = false; @@ -436,6 +436,15 @@ globalThis.loadDocument = function () { }); }; -globalThis.onresize = () => { - setLayerTransform(canvas.clientWidth, canvas.clientHeight, textLayerDiv); +globalThis.updateInsets = function () { + const insets = JSON.parse(channel.getInsets()); + const ratio = globalThis.devicePixelRatio; + const toCssPx = v => `${(Number(v) || 0) / ratio}px`; + + container.style.setProperty("--inset-top", toCssPx(insets.top)); + container.style.setProperty("--inset-right", toCssPx(insets.right)); + container.style.setProperty("--inset-bottom", toCssPx(insets.bottom)); + container.style.setProperty("--inset-left", toCssPx(insets.left)); }; + +addEventListener("DOMContentLoaded", globalThis.updateInsets);