Skip to content

fix(pdf-server): render page before O(numPages) annotation scans#581

Merged
ochafik merged 1 commit intomainfrom
fix/pdf-loading-regression
Apr 1, 2026
Merged

fix(pdf-server): render page before O(numPages) annotation scans#581
ochafik merged 1 commit intomainfrom
fix/pdf-loading-regression

Conversation

@ochafik
Copy link
Copy Markdown
Contributor

@ochafik ochafik commented Apr 1, 2026

Problem

After the loading spinner clears, the viewer briefly shows an empty document — toolbar visible, page counter reads "1 of 1", canvas is a tiny blank white rectangle at default size — before the real page paints. ~400ms with a 15-page doc, scales linearly with page count.

Root cause

#506 added loadBaselineAnnotations() and buildFieldNameMap() between showViewer() and renderPage(). Both iterate every page calling getPage() + getAnnotations(). The canvas isn't sized until renderPage() runs, so the viewer sits empty for the duration of those scans.

Same pattern at the reload path.

Fix

Render first, scan after. Neither scan blocks the canvas — page.render() only needs canvasContext + viewport. renderAnnotationsForPage() reads annotationMap (graceful empty), AnnotationLayer.render() takes cachedFieldObjects (graceful null). A second renderPage() after the scans overlays baseline annotations and restored form values; for PDFs with neither, the canvas content is identical so there's no flicker.

Restores pre-#506 timing: page visible <50ms after showViewer().

Before/after (1706.03762, 15 pages)

Time Before After
~800ms spinner spinner
~1200ms spinner rendered
~1500ms empty viewer, blank canvas rendered
~1800ms rendered rendered

PR #506 added loadBaselineAnnotations() and buildFieldNameMap() between
showViewer() and renderPage(). Both iterate every page calling
getPage()+getAnnotations(), so the viewer sat with an unsized empty
canvas for ~400ms (15-page doc, scales linearly) before painting.

Neither scan blocks the canvas — page.render() only needs canvasContext
+ viewport. renderAnnotationsForPage() reads annotationMap (graceful
empty), AnnotationLayer.render() takes cachedFieldObjects (graceful
null). So: render first, scan after, re-render to overlay annotations
+ form values. Same fix at the reload path.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 1, 2026

Open in StackBlitz

@modelcontextprotocol/ext-apps

npm i https://pkg.pr.new/@modelcontextprotocol/ext-apps@581

@modelcontextprotocol/server-basic-preact

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-preact@581

@modelcontextprotocol/server-basic-react

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-react@581

@modelcontextprotocol/server-basic-solid

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-solid@581

@modelcontextprotocol/server-basic-svelte

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-svelte@581

@modelcontextprotocol/server-basic-vanillajs

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vanillajs@581

@modelcontextprotocol/server-basic-vue

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vue@581

@modelcontextprotocol/server-budget-allocator

npm i https://pkg.pr.new/@modelcontextprotocol/server-budget-allocator@581

@modelcontextprotocol/server-cohort-heatmap

npm i https://pkg.pr.new/@modelcontextprotocol/server-cohort-heatmap@581

@modelcontextprotocol/server-customer-segmentation

npm i https://pkg.pr.new/@modelcontextprotocol/server-customer-segmentation@581

@modelcontextprotocol/server-debug

npm i https://pkg.pr.new/@modelcontextprotocol/server-debug@581

@modelcontextprotocol/server-map

npm i https://pkg.pr.new/@modelcontextprotocol/server-map@581

@modelcontextprotocol/server-pdf

npm i https://pkg.pr.new/@modelcontextprotocol/server-pdf@581

@modelcontextprotocol/server-scenario-modeler

npm i https://pkg.pr.new/@modelcontextprotocol/server-scenario-modeler@581

@modelcontextprotocol/server-shadertoy

npm i https://pkg.pr.new/@modelcontextprotocol/server-shadertoy@581

@modelcontextprotocol/server-sheet-music

npm i https://pkg.pr.new/@modelcontextprotocol/server-sheet-music@581

@modelcontextprotocol/server-system-monitor

npm i https://pkg.pr.new/@modelcontextprotocol/server-system-monitor@581

@modelcontextprotocol/server-threejs

npm i https://pkg.pr.new/@modelcontextprotocol/server-threejs@581

@modelcontextprotocol/server-transcript

npm i https://pkg.pr.new/@modelcontextprotocol/server-transcript@581

@modelcontextprotocol/server-video-resource

npm i https://pkg.pr.new/@modelcontextprotocol/server-video-resource@581

@modelcontextprotocol/server-wiki-explorer

npm i https://pkg.pr.new/@modelcontextprotocol/server-wiki-explorer@581

commit: a490373

@ochafik ochafik merged commit 9d55050 into main Apr 1, 2026
20 checks passed
ochafik added a commit that referenced this pull request Apr 1, 2026
Changes since 1.3.2:
- feat: add addEventListener/removeEventListener with DOM-model on* semantics (#573)
- feat(pdf-server): add save_as interact action (#580)
- fix(pdf-server): viewer liveness, 1:1 batch results, fullscreen jitter (#579)
- fix(pdf-server): render page before O(numPages) annotation scans (#581)
- fix(pdf-server): radio + dropdown in fill_form/save (#577)
- fix(deps): bump path-to-regexp 8.3.0 → 8.4.1 to patch ReDoS CVEs (#576)
ochafik added a commit that referenced this pull request Apr 2, 2026
Changes since 1.3.2:
- feat: add addEventListener/removeEventListener with DOM-model on* semantics (#573)
- feat(pdf-server): add save_as interact action (#580)
- feat(pdf-server): fit-to-page on fullscreen + pinch-to-zoom (#583)
- fix(pdf-server): viewer liveness, 1:1 batch results, fullscreen jitter (#579)
- fix(pdf-server): render page before O(numPages) annotation scans (#581)
- fix(pdf-server): radio + dropdown in fill_form/save (#577)
- fix(deps): bump path-to-regexp 8.3.0 → 8.4.1 to patch ReDoS CVEs (#576)
ochafik added a commit that referenced this pull request Apr 2, 2026
Changes since 1.3.2:
- feat: add addEventListener/removeEventListener with DOM-model on* semantics (#573)
- feat(pdf-server): add save_as interact action (#580)
- feat(pdf-server): fit-to-page on fullscreen + pinch-to-zoom (#583)
- fix(pdf-server): npx DOMMatrix crash + broken MCPB bundle (#584)
- fix(pdf-server): viewer liveness, 1:1 batch results, fullscreen jitter (#579)
- fix(pdf-server): render page before O(numPages) annotation scans (#581)
- fix(pdf-server): radio + dropdown in fill_form/save (#577)
- fix(deps): bump path-to-regexp 8.3.0 → 8.4.1 to patch ReDoS CVEs (#576)
ochafik added a commit that referenced this pull request Apr 2, 2026
Changes since 1.3.2:
- feat: add addEventListener/removeEventListener with DOM-model on* semantics (#573)
- feat(pdf-server): add save_as interact action (#580)
- feat(pdf-server): fit-to-page on fullscreen + pinch-to-zoom (#583)
- fix(pdf-server): npx DOMMatrix crash + broken MCPB bundle (#584)
- fix(pdf-server): viewer liveness, 1:1 batch results, fullscreen jitter (#579)
- fix(pdf-server): render page before O(numPages) annotation scans (#581)
- fix(pdf-server): radio + dropdown in fill_form/save (#577)
- fix(deps): bump path-to-regexp 8.3.0 → 8.4.1 to patch ReDoS CVEs (#576)
- chore(deps): npm audit fix — sdk 1.29.0, systeminformation 5.31.5, +13 transitives (#585, #586)
ochafik pushed a commit that referenced this pull request Apr 2, 2026
Changes since 1.3.2:

SDK
- feat: add addEventListener/removeEventListener with DOM-model on* semantics (#573)

pdf-server
- feat: add save_as interact action (#580)
- feat: fit-to-page on fullscreen + pinch-to-zoom (#583)
- fix: npx DOMMatrix crash + broken MCPB bundle (#584)
- fix: viewer liveness, 1:1 batch results, fullscreen jitter (#579)
- fix: render page before O(numPages) annotation scans (#581)
- fix: radio + dropdown in fill_form/save (#577)

Dependencies
- chore: npm audit fix — sdk 1.29.0, systeminformation 5.31.5, +13 transitives (#585, #586)
- fix: bump path-to-regexp 8.3.0 → 8.4.1 to patch ReDoS CVEs (#576)
ochafik added a commit that referenced this pull request Apr 2, 2026
Changes since 1.3.2:

SDK
- feat: add addEventListener/removeEventListener with DOM-model on* semantics (#573)

pdf-server
- feat: add save_as interact action (#580)
- feat: fit-to-page on fullscreen + pinch-to-zoom (#583)
- fix: npx DOMMatrix crash + broken MCPB bundle (#584)
- fix: viewer liveness, 1:1 batch results, fullscreen jitter (#579)
- fix: render page before O(numPages) annotation scans (#581)
- fix: radio + dropdown in fill_form/save (#577)

Dependencies
- chore: npm audit fix — sdk 1.29.0, systeminformation 5.31.5, +13 transitives (#585, #586)
- fix: bump path-to-regexp 8.3.0 → 8.4.1 to patch ReDoS CVEs (#576)
ochafik added a commit that referenced this pull request Apr 2, 2026
* chore: bump ext-apps to 1.4.0

Changes since 1.3.2:

SDK
- feat: add addEventListener/removeEventListener with DOM-model on* semantics (#573)

pdf-server
- feat: add save_as interact action (#580)
- feat: fit-to-page on fullscreen + pinch-to-zoom (#583)
- fix: npx DOMMatrix crash + broken MCPB bundle (#584)
- fix: viewer liveness, 1:1 batch results, fullscreen jitter (#579)
- fix: render page before O(numPages) annotation scans (#581)
- fix: radio + dropdown in fill_form/save (#577)

Dependencies
- chore: npm audit fix — sdk 1.29.0, systeminformation 5.31.5, +13 transitives (#585, #586)
- fix: bump path-to-regexp 8.3.0 → 8.4.1 to patch ReDoS CVEs (#576)

* chore: update e2e snapshots [skip ci]

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant