From f0af8887d143cd2a6b976a9b643b6582cab001cd Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 26 May 2026 22:05:13 +0200 Subject: [PATCH] Strengthen text-layer debug + log highlight render path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first cut of "Debug text layer" only painted direct `` children of `.textLayer`. PDF.js 4.x wraps marked content in nested spans/divs, so the entire selectable area wasn't visible — making it hard to tell whether a region is "no text layer at all" vs. "text layer present but small/dense". Changes: - CSS now targets every descendant of `.textLayer`, dims the canvas underneath, and outlines the `.textLayer` container itself so its full extent is obvious. - TextHighlight rectangles flip to green in debug mode so saved highlights don't get washed out by the debug yellow. - The viewer now logs: [ce] viewer highlights — which annotations rendered, which were skipped, with rects + page [ce] scrollToAnnotation — whether the target was found in the highlights array when an activation arrived This is the diagnostic loop for the "viewport scrolls but the highlight doesn't appear" report — if highlight count is > 0 in the first log but the green rectangle is off-screen, the saved rects inherited the same text-layer misalignment that caused the partial selection captures in the first place. Co-Authored-By: Claude Opus 4.7 --- src/anchor/debug-textlayer.css | 28 +++++++++++++++++++------ src/anchor/pdf-viewer-adapter-spike.tsx | 27 ++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/anchor/debug-textlayer.css b/src/anchor/debug-textlayer.css index 0d33326..a36e578 100644 --- a/src/anchor/debug-textlayer.css +++ b/src/anchor/debug-textlayer.css @@ -11,14 +11,30 @@ */ .ce-debug-textlayer .textLayer { - outline: 1px dashed rgba(255, 0, 0, 0.5); + outline: 2px dashed rgba(255, 0, 0, 0.5); + background: rgba(255, 0, 0, 0.05); } -.ce-debug-textlayer .textLayer > span, -.ce-debug-textlayer .textLayer > br { - background: rgba(255, 220, 0, 0.35) !important; +/* PDF.js 4.x wraps marked content in nested spans/divs — cover every + descendant so the entire selectable area is visible regardless of how + the renderer nested things. */ +.ce-debug-textlayer .textLayer * { + background: rgba(255, 220, 0, 0.45) !important; color: rgba(0, 0, 100, 0.85) !important; opacity: 1 !important; - /* Reveal the per-glyph span borders so misalignment is visible. */ - outline: 1px solid rgba(0, 100, 255, 0.25); + outline: 1px solid rgba(0, 100, 255, 0.3); +} + +/* Make the canvas-rendered layer dim so the text-layer overlay stands + out by contrast. */ +.ce-debug-textlayer canvas { + opacity: 0.35; +} + +/* Make any existing TextHighlight rectangles obvious even in debug + mode (the highlighter's own yellow gets washed out by our debug + yellow). */ +.ce-debug-textlayer .TextHighlight__part { + background: rgba(0, 200, 0, 0.45) !important; + outline: 2px solid rgba(0, 120, 0, 0.7) !important; } diff --git a/src/anchor/pdf-viewer-adapter-spike.tsx b/src/anchor/pdf-viewer-adapter-spike.tsx index d279b90..20e21da 100644 --- a/src/anchor/pdf-viewer-adapter-spike.tsx +++ b/src/anchor/pdf-viewer-adapter-spike.tsx @@ -194,21 +194,44 @@ export function PdfSpikeViewer(props: PdfSpikeViewerProps) { const highlights = useMemo(() => { const out: Highlight[] = []; + const skipped: { id: string; reason: string }[] = []; for (const a of storedAnnotations) { const h = highlightFromSelectors(a.id, a.text, a.selectors); if (h) out.push(h); + else skipped.push({ id: a.id, reason: "no PdfRectSelector / empty boundingRect" }); + } + if (debugTextLayer) { + console.log("[ce] viewer highlights", { + in: storedAnnotations.length, + rendered: out.length, + rendered_detail: out.map((h) => ({ + id: h.id, + page: h.position.boundingRect.pageNumber, + bounding: h.position.boundingRect, + rectCount: h.position.rects.length, + })), + skipped, + }); } return out; - }, [storedAnnotations]); + }, [storedAnnotations, debugTextLayer]); useEffect(() => { if (!scrollToAnnotationId || didScroll === scrollToAnnotationId) return; const utils = utilsRef.current; const target = highlights.find((h) => h.id === scrollToAnnotationId); + if (debugTextLayer) { + console.log("[ce] scrollToAnnotation requested", { + id: scrollToAnnotationId, + utilsAvailable: !!utils, + targetFound: !!target, + knownIds: highlights.map((h) => h.id), + }); + } if (!utils || !target) return; utils.scrollToHighlight(target); setDidScroll(scrollToAnnotationId); - }, [scrollToAnnotationId, highlights, didScroll]); + }, [scrollToAnnotationId, highlights, didScroll, debugTextLayer]); return (