feat(p0.5): pdfrx-backed PageDocumentSource — static API source-pin (step 12/SF4)
Some checks failed
CI / Windows build (push) Has been cancelled
Some checks failed
CI / Windows build (push) Has been cancelled
Production adapter wrapping a pdfrx PdfDocument: snapshots page sizes via the real pdfrx 2.4.4 geometry API (PdfDocument.pages, PdfPage.width/height) so the pure layout math runs on the real document. Because it lives under lib/editor/, `flutter analyze lib/editor` (the Oracle) type-checks it against the installed pdfrx every run — a version bump that renames/retypes these members now FAILS analysis instead of silently drifting (SF4 source-pin, statically). Runtime contract + layout composition tested via the pdfium-free .fromSizes ctor; the .fromDocument pin is the static guarantee (exercising it needs pdfium = device path). flutter analyze lib/editor clean; 123/123 tests (+3). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
42
lib/editor/pdf/pdfrx_page_document_source.dart
Normal file
42
lib/editor/pdf/pdfrx_page_document_source.dart
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// lib/editor/pdf/pdfrx_page_document_source.dart
|
||||||
|
//
|
||||||
|
// Production [PageDocumentSource] backed by a pdfrx PdfDocument — the thin
|
||||||
|
// device-side adapter that feeds real page geometry into the (pure, tested)
|
||||||
|
// continuous-single layout math.
|
||||||
|
//
|
||||||
|
// SOURCE-PIN (plan SF4 / P0.5 step 12): this file references the exact pdfrx
|
||||||
|
// 2.4.4 page-geometry API (`PdfDocument.pages`, `PdfPage.width`, `PdfPage.height`).
|
||||||
|
// Because it lives under lib/editor/, the Oracle's `flutter analyze lib/editor`
|
||||||
|
// type-checks it against the installed pdfrx on every run — so a version bump
|
||||||
|
// that renames/retypes these members FAILS analysis instead of silently
|
||||||
|
// drifting. (Static pin only: exercising it needs pdfium at runtime, which is
|
||||||
|
// the device-gated path.)
|
||||||
|
|
||||||
|
import 'dart:ui' show Size;
|
||||||
|
|
||||||
|
import 'package:pdfrx/pdfrx.dart';
|
||||||
|
|
||||||
|
import 'pdf_document_source.dart';
|
||||||
|
|
||||||
|
/// Snapshots page sizes (PDF points) from an open pdfrx [PdfDocument] so the
|
||||||
|
/// layout layer can read them synchronously (pdfrx loads pages asynchronously;
|
||||||
|
/// once open, `document.pages[i].width/height` are available).
|
||||||
|
class PdfrxPageDocumentSource implements PageDocumentSource {
|
||||||
|
const PdfrxPageDocumentSource.fromSizes(this._sizes);
|
||||||
|
|
||||||
|
/// Snapshot the intrinsic size of every page from an open [document].
|
||||||
|
factory PdfrxPageDocumentSource.fromDocument(PdfDocument document) {
|
||||||
|
final sizes = document.pages
|
||||||
|
.map((page) => Size(page.width, page.height))
|
||||||
|
.toList(growable: false);
|
||||||
|
return PdfrxPageDocumentSource.fromSizes(sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Size> _sizes;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get pageCount => _sizes.length;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Size pageSize(int index) => _sizes[index];
|
||||||
|
}
|
||||||
41
test/pdfrx_page_document_source_test.dart
Normal file
41
test/pdfrx_page_document_source_test.dart
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// Runtime contract test for the pdfrx-backed PageDocumentSource (P0.5 step 12).
|
||||||
|
// The .fromDocument factory's pdfrx-API pin is verified statically by
|
||||||
|
// `flutter analyze lib/editor` (the Oracle); here we exercise the concrete
|
||||||
|
// type's PageDocumentSource behavior + composition with the layout math via the
|
||||||
|
// pdfium-free .fromSizes constructor.
|
||||||
|
|
||||||
|
import 'dart:ui' show Size;
|
||||||
|
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:badnote/editor/pdf/pdf_document_source.dart';
|
||||||
|
import 'package:badnote/editor/pdf/pdfrx_page_document_source.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('fromSizes implements the PageDocumentSource contract', () {
|
||||||
|
const src = PdfrxPageDocumentSource.fromSizes([
|
||||||
|
Size(600, 800),
|
||||||
|
Size(595, 842),
|
||||||
|
]);
|
||||||
|
expect(src, isA<PageDocumentSource>());
|
||||||
|
expect(src.pageCount, 2);
|
||||||
|
expect(src.pageSize(0), const Size(600, 800));
|
||||||
|
expect(src.pageSize(1), const Size(595, 842));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('composes with the fit-to-width layout math', () {
|
||||||
|
const src = PdfrxPageDocumentSource.fromSizes([
|
||||||
|
Size(600, 800), // portrait → at width 300, height 400
|
||||||
|
Size(800, 600), // landscape → at width 300, height 225
|
||||||
|
]);
|
||||||
|
final metrics = pageStackMetricsForWidth(src, 300, gap: 10);
|
||||||
|
expect(metrics.heightOf(0), closeTo(400, 1e-9));
|
||||||
|
expect(metrics.heightOf(1), closeTo(225, 1e-9));
|
||||||
|
expect(metrics.offsetOf(1), closeTo(410, 1e-9)); // 400 + 10 gap
|
||||||
|
});
|
||||||
|
|
||||||
|
test('empty document', () {
|
||||||
|
const src = PdfrxPageDocumentSource.fromSizes([]);
|
||||||
|
expect(src.pageCount, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user