pdfrx render core, static/live ink layers, RenderProxyBox pen/touch arbitration, infinite board, text boxes. Planner-Architect-Critic consensus APPROVE. MUST #1 (API source-pin) and MUST #2 (coordinate assertion) verified on pdfium; MUST #3/#4/#5 pending on Surface Pen.
6.6 KiB
BadNote Phase 1 — Performance Gate Results
Status: IN PROGRESS — MUST #1 (API source-pin) GREEN on pdfrx 2.4.4 (Dart-only verification, done). MUST #2/#4/#5 require a device/profile run; MUST #3 requires the physical Surface Pen. Spike code compiles clean (flutter analyze: no issues).
M1 Gate Results
| Gate | Target | Result | Device | Commit | PASS/FAIL |
|---|---|---|---|---|---|
| MUST #1 — pdfrx API source-pin | All [VERIFY-IN-M1] tags replaced with pinned signatures from ~/.pub-cache/…/pdfrx-2.4.4/lib/src/ |
All APIs confirmed; match plan (see table below) | Dev box (Linux) | feat/m1-pdfrx-spike | PASS |
| MUST #2 — Coordinate assertion | Stroke at normalized (0.5, 0.5) lands at visual page center at fit / 2× / 4× zoom | PASS on real pdfium (integration_test/coordinate_assertion_test.dart, "All tests passed", PDF load 74ms). Re-confirm on Windows. |
Linux desktop (WSL2) | feat/m1-pdfrx-spike | PASS (Linux) |
| MUST #3 — Pen/touch arbitration on Surface Pen | Pen draws AND single-finger touch scrolls AND pinch zooms simultaneously in same overlay; no mode switching | PENDING | Surface Pro (physical device) | — | PENDING |
| MUST #4 — pdfrx-alone perf (300-page fling-scroll) | Median frame (build+raster) ≤ 16.6 ms, p95 ≤ 22 ms; N ≥ 120 frames; profile mode | Harness ready (integration_test/perf_scroll_bench.dart). NOT measured — WSL2 dev box was under heavy concurrent load → invalid signal, discarded. |
— | — | PENDING (run on Surface, profile, idle machine) |
| MUST #5 — ink-overlay build cost (300 synthetic strokes/page) | Median BUILD time ≤ 16.6 ms during fling-scroll; N ≥ 120 frames; profile mode | Harness ready (same bench, ink-load toggle). NOT measured (same reason). | — | — | PENDING (run on Surface, profile, idle machine) |
Pinned pdfrx APIs
To be filled during M1 sub-task 1 (flutter pub add pdfrx + read ~/.pub-cache/…/pdfrx-*/lib/src/).
All signatures verified against ~/.pub-cache/hosted/pub.dev/pdfrx-2.4.4/ on 2026-06-21.
| API | Pinned signature / notes | Source file:line |
|---|---|---|
pageOverlaysBuilder |
typedef PdfPageOverlaysBuilder = List<Widget> Function(BuildContext context, Rect pageRectInViewer, PdfPage page). pageRectInViewer is already scrolled+zoomed (viewer coords). Children laid out in a per-page Stack. Matches plan §2.1. |
lib/src/widgets/pdf_viewer_params.dart:1623, field :554 |
viewerOverlayBuilder |
typedef PdfViewerOverlaysBuilder = List<Widget> Function(BuildContext context, Size size, PdfViewerHandleLinkTap handleLinkTap). Docs: a GestureDetector here must use HitTestBehavior.translucent + IgnorePointer child to let events reach the viewer. |
:1572, field :513 |
PdfViewerController.goToPage |
Future<void> goToPage({required int pageNumber, PdfPageAnchor? anchor, Duration duration = 200ms}). (Also goToRectInsidePage({required int pageNumber, required PdfRect rect, ...}).) |
lib/src/widgets/pdf_viewer.dart:4140 |
PdfViewerController.currentZoom |
double get currentZoom => value.zoom; |
:4318 |
PdfViewerController.layout |
PdfPageLayout get layout; → layout.pageLayouts is List<Rect> in document coords (index by page). |
:4029; pageLayouts usage :895,1068 |
PdfViewerController.globalToDocument |
Offset? globalToDocument(Offset global) (public). Also Offset documentToGlobal, Offset? localToGlobal. |
:4403 |
PdfViewerController.documentToLocal |
Offset documentToLocal(Offset document) (public). |
:4412 |
PdfRect.toRect |
Extension in pdfrx_flutter: Rect toRect({required PdfPage page, Size? scaledPageSize, int? rotation}) — handles rotation (removes our bespoke rotate math). Also toRectInDocument({required PdfPage page, required Rect pageRect}). |
lib/src/pdfrx_flutter.dart:107 |
| Gesture recognizer (pan/zoom) | pdfrx pan+zoom is an internal InteractiveViewer using GestureDetector(onScaleStart/Update/End) (scale gesture covers pan+pinch). Default GestureDetector accepts all device kinds incl. stylus → a stylus drag WOULD be claimed by the scale recognizer unless intercepted above. Confirms R1 and justifies the PenCaptureRegion arena-bypass. |
lib/src/widgets/interactive_viewer.dart:1560-1564, 839-948 |
PdfOverlayInteractionRegion (fallback) |
Exists (class PdfOverlayInteractionRegion extends StatefulWidget), but pdfrx docs state it is tap-oriented only (tap/double-tap/long-press/secondary) — NOT a freehand-drag stream. ∴ it cannot be the primary draw transport; PenCaptureRegion (RenderProxyBox per-kind hit-test) is THE path, not just a preference. |
lib/src/widgets/pdf_viewer.dart:4659; docs pdf_viewer_params.dart:483-538 |
PdfPage.render (thumbnails) |
To confirm in M6 prep — pdfrx exposes page render via PdfPage (pdfrx_engine); verify exact RGBA path before removing syncfusion-viewer dep. |
(deferred to M6 prep) |
panAxis |
Still [VERIFY-IN-M1 on device] whether PanAxis.vertical blocks the horizontal component of a pinch-zoom pan; spike uses it — confirm on tablet whether PanAxis.free is needed when zoomed. |
pdf_viewer_params.dart (panAxis field) |
Transport finding (R1): Flutter hit-tests a pointer only on its DOWN and caches the path; RenderBox.hitTest receives only the position, not the pointer kind. The spike resolves this with PenCaptureBinding (overrides GestureBinding.handlePointerEvent to stash the in-flight event.kind before the synchronous hit-test) which _RenderPenCapture.hitTest reads — capturing stylus outside the gesture arena while touch/mouse fall through to pdfrx. Compiles clean; empirical pen-vs-touch behavior remains MUST #3 (physical Surface Pen).
Sample Protocol (§7.1)
- Minimum sample size: N ≥ 120 frames per measurement.
- Mode: profile build (
flutter run --profile), not debug. - Cache: warm cache — scroll once end-to-end before recording.
- Runs: 3 independent runs; report median across runs.
- Asset:
test/assets/large_300p.pdf(300 pages, non-blank content). - Stroke asset:
test/assets/dense_strokes.jsonkey"2000"for MUST #5 (~300 strokes/page spread across visible pages). - Reporting: paste Flutter DevTools frame chart screenshot + numeric summary (median, p95, p99) into this doc with commit hash and device spec.
Device Specs
| Field | Value |
|---|---|
| Device | PENDING |
| OS | PENDING |
| Flutter version | PENDING |
| Dart version | PENDING |
| pdfrx version (resolved) | PENDING |
| Surface Pen model | PENDING |