Rect annotations for fixed-layout: fraction-space overlay + hit-testing

Adds a parallel annotation pipeline for PDF/comic pages (the CFI
overlayer pipeline only exists for the reflowable paginator):

- addRectAnnotation({key, index, rects, color}) /
  removeRectAnnotation(key): rects are page-fraction [x,y,w,h]
  quads, stored per key and rendered into a full-bleed SVG injected
  into the page iframe. The SVG uses viewBox 0 0 100 100 with
  preserveAspectRatio none, so fraction rects stay aligned through
  iframe CSS-zoom (comics), the host transform-based pan/zoom, and
  PDF hi-res re-renders (pdf.js rebuilds canvas/textLayer but not
  body children) — no re-anchoring hooks needed anywhere.
- Frames carry their section index; annotations re-render into each
  freshly created iframe (#showSpread destroys and recreates frames
  on every spread change).
- Clicks are hit-tested against the fraction rects (in iframe
  coordinate space, denominator = img or documentElement bounding
  rect so PDF's devicePixelRatio transform cancels) and emit
  show-rect-annotation with host-space popover coordinates. Skipped
  while a text selection is active so drag-selecting text doesn't
  pop the editor.
- Comic page img is now display:block so the document box equals
  the image box (no inline-baseline gap inflating denominators).
This commit is contained in:
2026-08-16 12:44:22 -04:00
parent e9e61d885b
commit aba68d8723
2 changed files with 115 additions and 3 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ export const makeComicBook = ({ entries, loadBlob, getSize }, file) => {
if (cache.has(name)) return cache.get(name)
const src = URL.createObjectURL(await loadBlob(name))
const page = URL.createObjectURL(
new Blob([`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body style="margin: 0; touch-action: none"><img src="${src}" style="image-rendering: high-quality"></body></html>`], { type: 'text/html' }))
new Blob([`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body style="margin: 0; touch-action: none"><img src="${src}" style="display: block; image-rendering: high-quality"></body></html>`], { type: 'text/html' }))
urls.set(name, [src, page])
cache.set(name, page)
return page