Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
- pdf-graphics: new cff, truetype, cjk_cmap, disk_cache, document_ai, path, reflow, text_diff modules + port tests (all green); syntax/type fixes for the aarch64 build (stray brace, &u8 derefs, f2dot14 assign). - pdf-document: ocr, pdf_a, xmp modules + roundtrip tests; annotation editor updates. - pdf-makepad: handle RenderCommand::SetOverprint (report via TransparencyError per ADR 0009, no silent drop); renderer/page_view updates for the new recording ops. - matrix_client: nimanyatta native module (ungated; the aarch64 wrapper needs it unconditionally). - pageflipnav home_screen: project_store sync is host-only until cad-ui's Widget Script derive is fixed for aarch64. Verified: cargo check on all four crates clean at fork 66cc4f15f; nigig-pdf-graphics tests pass; pageflipnav aarch64 release links.
98 lines
4.6 KiB
Rust
98 lines
4.6 KiB
Rust
//! 1:1 port of `dart-pdf/packages/pdf_graphics/test/interpreter_test.dart` (first tranche)
|
|
//! Covers path ops (m, l, c, v, y, h, re) and aggregated device path.
|
|
|
|
use nigig_pdf_graphics::content::parse_content_stream;
|
|
use nigig_pdf_graphics::recording::{RecordingDevice, RenderCommand};
|
|
use nigig_pdf_graphics::PdfDevice;
|
|
|
|
fn cmds(content: &[u8]) -> Vec<RenderCommand> {
|
|
let ops = parse_content_stream(content).expect("parse");
|
|
RecordingDevice::from_ops(&ops)
|
|
}
|
|
|
|
#[test]
|
|
fn path_ops_m_l_c_h_re() {
|
|
// m 10 20, l 30 40, c 1 2 3 4 5 6, h, re
|
|
let content = b"10 20 m\n30 40 l\n1 2 3 4 5 6 c\nh\n10 20 100 50 re\n";
|
|
let ops = parse_content_stream(content).expect("parse");
|
|
// m, l, c, h, re
|
|
assert!(ops.iter().any(|op| matches!(op, nigig_pdf_graphics::content::PdfOp::MoveTo(10.0, 20.0))));
|
|
assert!(ops.iter().any(|op| matches!(op, nigig_pdf_graphics::content::PdfOp::LineTo(30.0, 40.0))));
|
|
assert!(ops.iter().any(|op| matches!(op, nigig_pdf_graphics::content::PdfOp::CurveTo(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))));
|
|
assert!(ops.iter().any(|op| matches!(op, nigig_pdf_graphics::content::PdfOp::ClosePath)));
|
|
assert!(ops.iter().any(|op| matches!(op, nigig_pdf_graphics::content::PdfOp::Rectangle(10.0, 20.0, 100.0, 50.0))));
|
|
|
|
let c = cmds(content);
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::MoveTo(10.0, 20.0))));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::LineTo(30.0, 40.0))));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::CurveTo(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::ClosePath)));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::Rectangle(10.0, 20.0, 100.0, 50.0))));
|
|
}
|
|
|
|
#[test]
|
|
fn path_ops_v_and_y_use_current_point() {
|
|
// v and y are the two short forms of c that reuse the current point
|
|
let content_v = b"10 20 m\n30 40 50 60 v\n";
|
|
let c_v = cmds(content_v);
|
|
// v with current (10,20) -> curve (10,20, 30,40, 50,60)
|
|
assert!(c_v.iter().any(|c| matches!(c, RenderCommand::CurveTo(10.0, 20.0, 30.0, 40.0, 50.0, 60.0))));
|
|
|
|
let content_y = b"10 20 m\n30 40 50 60 y\n";
|
|
let c_y = cmds(content_y);
|
|
// y with current (10,20) -> curve (30,40, 10,20, 50,60)
|
|
assert!(c_y.iter().any(|c| matches!(c, RenderCommand::CurveTo(30.0, 40.0, 10.0, 20.0, 50.0, 60.0))));
|
|
}
|
|
|
|
#[test]
|
|
fn graphics_state_save_restore_and_transform() {
|
|
let content = b"q\n1 0 0 1 10 20 cm\nQ\n";
|
|
let c = cmds(content);
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::Save)));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::SetTransform(1.0, 0.0, 0.0, 1.0, 10.0, 20.0))));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::Restore)));
|
|
}
|
|
|
|
#[test]
|
|
fn color_ops_produce_set_color() {
|
|
let content = b"1 0 0 rg\n0.5 g\n1 0 0 RG\n0.5 G\n";
|
|
let c = cmds(content);
|
|
// rg/g are fill (non-stroking), RG/G are stroke (stroking)
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::SetFillColor(_))));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::SetStrokeColor(_))));
|
|
// Specific values: rg 1 0 0 -> red fill, RG 1 0 0 -> red stroke
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::SetFillColor([r, g, b, _]) if *r==1.0 && *g==0.0 && *b==0.0)));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::SetStrokeColor([r, g, b, _]) if *r==1.0 && *g==0.0 && *b==0.0)));
|
|
}
|
|
|
|
#[test]
|
|
fn text_ops_produce_text_commands() {
|
|
let content = b"BT\n/F1 12 Tf\n100 700 Td\n(Hello) Tj\nET\n";
|
|
let c = cmds(content);
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::BeginText)));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::EndText)));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::ShowTextWithMetrics { .. })));
|
|
}
|
|
|
|
#[test]
|
|
fn clipping_ops() {
|
|
let content = b"10 20 m\n30 40 l\nh\nW\nW*\n";
|
|
let c = cmds(content);
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::ClipWinding)));
|
|
assert!(c.iter().any(|c| matches!(c, RenderCommand::ClipEvenOdd)));
|
|
}
|
|
|
|
#[test]
|
|
fn aggregated_path_via_device() {
|
|
// Direct device aggregated call, as dart's test does with fillPath(path, color, rule, alpha)
|
|
let mut device = RecordingDevice::new();
|
|
let mut builder = nigig_pdf_graphics::path::PdfPathBuilder::new();
|
|
builder.move_to(0.0, 0.0);
|
|
builder.line_to(100.0, 0.0);
|
|
builder.line_to(100.0, 100.0);
|
|
builder.close();
|
|
let path = builder.take_path();
|
|
device.fill_path(path, [1.0, 0.0, 0.0, 1.0], nigig_pdf_graphics::path::PdfFillRule::NonZero, 1.0);
|
|
assert!(device.commands.iter().any(|c| matches!(c, RenderCommand::Path(_))));
|
|
assert!(device.commands.iter().any(|c| matches!(c, RenderCommand::FillWinding)));
|
|
}
|