Files
BadNote/docs/plans/phase1-perf-results.md
Akiba So 2afc126f30 docs(plan): phase 1 rebuild plan + M1 gate results
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.
2026-06-21 20:15:13 +08:00

6.6 KiB
Raw Permalink Blame History

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.json key "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