mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-29 12:38:58 -06:00
style: cargo fmt on moved files
This commit is contained in:
@@ -92,10 +92,7 @@ fn unquoted_paths_with_spaces_are_rejoined() {
|
||||
let exists = |p: &str| have.contains(&p);
|
||||
let args = |a: &[&str]| a.iter().map(|s| s.to_string()).collect::<Vec<_>>();
|
||||
// The case an office program produced: one path, split at its space.
|
||||
assert_eq!(
|
||||
super::rejoin_split_paths(args(&["P:\\Archive\\00042A26", "Contract.PDF"]), exists),
|
||||
args(&["P:\\Archive\\00042A26 Contract.PDF"])
|
||||
);
|
||||
assert_eq!(super::rejoin_split_paths(args(&["P:\\Archive\\00042A26", "Contract.PDF"]), exists), args(&["P:\\Archive\\00042A26 Contract.PDF"]));
|
||||
// The longest run wins; files that exist on their own are left alone.
|
||||
assert_eq!(super::rejoin_split_paths(args(&["C:\\a", "b", "c.pdf", "C:\\a.pdf"]), exists), args(&["C:\\a b c.pdf", "C:\\a.pdf"]));
|
||||
assert_eq!(super::rejoin_split_paths(args(&["C:\\a.pdf", "C:\\x", "y.pdf"]), exists), args(&["C:\\a.pdf", "C:\\x y.pdf"]));
|
||||
@@ -159,9 +156,7 @@ fn a_software_renderer_is_shown_to_the_user() {
|
||||
fn gpu_setup_avoids_vulkan_and_stretched_resizes_on_windows_and_prefers_low_power() {
|
||||
let mut native = eframe::NativeOptions::default();
|
||||
super::configure_gpu(&mut native);
|
||||
let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &native.wgpu_options.wgpu_setup else {
|
||||
panic!("default setup creates its own instance")
|
||||
};
|
||||
let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &native.wgpu_options.wgpu_setup else { panic!("default setup creates its own instance") };
|
||||
if std::env::var_os("WGPU_POWER_PREF").is_none() {
|
||||
assert_eq!(setup.power_preference, eframe::wgpu::PowerPreference::LowPower);
|
||||
}
|
||||
@@ -270,15 +265,9 @@ fn a_window_larger_than_the_gpu_limit_gets_a_surface_within_it() {
|
||||
#[test]
|
||||
fn surface_fit_never_empties_or_overflows_a_surface() {
|
||||
use eframe::egui_wgpu::winit::surface_fit;
|
||||
for (w, h, max) in [
|
||||
(1, u32::MAX, 8192),
|
||||
(u32::MAX, 1, 2048),
|
||||
(u32::MAX, u32::MAX, 16384),
|
||||
(0, u32::MAX, 8192),
|
||||
(u32::MAX, 0, 8192),
|
||||
(5, 7, 0),
|
||||
(40_000, 3, 1),
|
||||
] {
|
||||
for (w, h, max) in
|
||||
[(1, u32::MAX, 8192), (u32::MAX, 1, 2048), (u32::MAX, u32::MAX, 16384), (0, u32::MAX, 8192), (u32::MAX, 0, 8192), (5, 7, 0), (40_000, 3, 1)]
|
||||
{
|
||||
let (fw, fh, scale) = surface_fit(w, h, max);
|
||||
assert!(fw <= max.max(1) && fh <= max.max(1), "{w} x {h} in {max}: {fw} x {fh}");
|
||||
// A side that wasn't zero stays non-zero (`Surface::configure` rejects an empty one),
|
||||
@@ -327,9 +316,7 @@ fn a_gpu_error_while_a_window_is_set_up_is_returned_not_a_panic() {
|
||||
use eframe::wgpu;
|
||||
let _gpu = gpu();
|
||||
let native = super::native_options(false, false, eframe::Renderer::Wgpu);
|
||||
let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &native.wgpu_options.wgpu_setup else {
|
||||
panic!("default setup creates its own instance")
|
||||
};
|
||||
let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &native.wgpu_options.wgpu_setup else { panic!("default setup creates its own instance") };
|
||||
let instance = pollster::block_on(native.wgpu_options.wgpu_setup.new_instance());
|
||||
let options = wgpu::RequestAdapterOptions { power_preference: setup.power_preference, ..Default::default() };
|
||||
// CI runners have a software adapter (WARP, llvmpipe); a machine without any skips.
|
||||
@@ -398,8 +385,8 @@ fn pipeline_creation_error_is_returned_and_device_remains_usable() {
|
||||
eprintln!("skipping pipeline regression: no GPU adapter");
|
||||
return;
|
||||
};
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(&(setup.device_descriptor)(&adapter)))
|
||||
.expect("the selected adapter must provide a test device");
|
||||
let (device, queue) =
|
||||
pollster::block_on(adapter.request_device(&(setup.device_descriptor)(&adapter))).expect("the selected adapter must provide a test device");
|
||||
native.wgpu_options.wgpu_setup =
|
||||
egui_wgpu::WgpuSetup::Existing(egui_wgpu::WgpuSetupExisting { instance: instance.clone(), adapter, device, queue });
|
||||
// Three samples is invalid on every backend, so this reproduces a pipeline error
|
||||
@@ -519,8 +506,7 @@ fn pick_adapter_keeps_the_integrated_gpu_on_hybrid_laptops() {
|
||||
fn pick_adapter_prefers_the_discrete_gpu_on_desktops_with_a_monitor_on_each() {
|
||||
// Issue #445: one monitor on the Intel iGPU, one on the NVIDIA card, no built-in panel.
|
||||
use eframe::wgpu::DeviceType;
|
||||
let desktop =
|
||||
[(INTEL_IGPU.0, INTEL_IGPU.1, DeviceType::IntegratedGpu), (NVIDIA.0, NVIDIA.1, DeviceType::DiscreteGpu), (0, 0, DeviceType::Cpu)];
|
||||
let desktop = [(INTEL_IGPU.0, INTEL_IGPU.1, DeviceType::IntegratedGpu), (NVIDIA.0, NVIDIA.1, DeviceType::DiscreteGpu), (0, 0, DeviceType::Cpu)];
|
||||
assert_eq!(super::pick_adapter(&desktop, &[monitor(INTEL_IGPU), monitor(NVIDIA)], None), Some(1));
|
||||
assert_eq!(super::pick_adapter(&desktop, &[monitor(NVIDIA), monitor(INTEL_IGPU)], None), Some(1));
|
||||
// A GPU driving no display still loses to one that does.
|
||||
|
||||
@@ -18,12 +18,7 @@ fn composite(doc: &mut Document, encoding: &str, w: Vec<Object>, to_unicode: &st
|
||||
let tu = Object::Ref(doc.add(Object::Stream(Stream::flate(Dict::new(), to_unicode.as_bytes()))));
|
||||
font(
|
||||
doc,
|
||||
vec![
|
||||
("Subtype", Object::name("Type0")),
|
||||
("Encoding", enc),
|
||||
("DescendantFonts", Object::Array(vec![Object::Dict(desc)])),
|
||||
("ToUnicode", tu),
|
||||
],
|
||||
vec![("Subtype", Object::name("Type0")), ("Encoding", enc), ("DescendantFonts", Object::Array(vec![Object::Dict(desc)])), ("ToUnicode", tu)],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -273,13 +268,10 @@ fn standard_fonts_without_widths_measure_the_glyph_their_differences_name() {
|
||||
let mut doc = Document::new_empty();
|
||||
let mut enc = Dict::new();
|
||||
enc.set(b"BaseEncoding".to_vec(), Object::name("WinAnsiEncoding"));
|
||||
let diffs =
|
||||
vec![Object::Int(65), Object::name("W"), Object::Int(87), Object::name("A"), Object::name("uni03A9"), Object::name("not.a.glyph")];
|
||||
let diffs = vec![Object::Int(65), Object::name("W"), Object::Int(87), Object::name("A"), Object::name("uni03A9"), Object::name("not.a.glyph")];
|
||||
enc.set(b"Differences".to_vec(), Object::Array(diffs));
|
||||
let f = font(
|
||||
&mut doc,
|
||||
vec![("Subtype", Object::name("Type1")), ("BaseFont", Object::name("Helvetica")), ("Encoding", Object::Dict(enc.clone()))],
|
||||
);
|
||||
let f =
|
||||
font(&mut doc, vec![("Subtype", Object::name("Type1")), ("BaseFont", Object::name("Helvetica")), ("Encoding", Object::Dict(enc.clone()))]);
|
||||
let m = Metrics::from_dict(&doc, &f);
|
||||
assert_eq!((m.width(65), m.width(87)), (0.944, 0.667), "A and W swap their widths");
|
||||
// Omega has no WinAnsi code and the last name reads as nothing: both keep their code's width.
|
||||
@@ -467,12 +459,7 @@ fn composite_subset_glyphs_of_the_default_width_are_present() {
|
||||
}
|
||||
desc.set(
|
||||
b"W".to_vec(),
|
||||
Object::Array(vec![
|
||||
Object::Int(0x55),
|
||||
Object::Array(vec![Object::Int(333)]),
|
||||
Object::Int(0x57),
|
||||
Object::Array(vec![Object::Int(277)]),
|
||||
]),
|
||||
Object::Array(vec![Object::Int(0x55), Object::Array(vec![Object::Int(333)]), Object::Int(0x57), Object::Array(vec![Object::Int(277)])]),
|
||||
);
|
||||
let f = font(
|
||||
&mut doc,
|
||||
|
||||
@@ -253,10 +253,7 @@ fn numbers_format_like_acrobat() {
|
||||
assert_eq!(make_number("(7)"), Some(-7.0));
|
||||
assert_eq!(make_number("abc"), None);
|
||||
assert_eq!(keystroke(&n(2, 0, 0, "$", true), "Total", "$1,000"), Ok("1000".into()));
|
||||
assert_eq!(
|
||||
keystroke(&n(2, 0, 0, "$", true), "Total", "ten"),
|
||||
Err("The value entered does not match the format of the field [ Total ]".into())
|
||||
);
|
||||
assert_eq!(keystroke(&n(2, 0, 0, "$", true), "Total", "ten"), Err("The value entered does not match the format of the field [ Total ]".into()));
|
||||
// Blank input clears a formatted field (#1323); without a format it is text like any other.
|
||||
assert_eq!(keystroke(&n(2, 0, 0, "$", true), "Total", " \t"), Ok(String::new()));
|
||||
assert_eq!(keystroke(&Format::None, "Name", " \t"), Ok(" \t".into()));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::document::{field_object, get_field, get_nth_field_name, noop, num_fields, page_num_get, page_num_set, print, reset_form, submit_form};
|
||||
use super::format::{printd, printf, printx, scand};
|
||||
use super::host::{arg, function, host, s, text, text_line};
|
||||
use super::model::{DISPLAY_HIDDEN, DISPLAY_NO_PRINT, DISPLAY_NO_VIEW, DISPLAY_VISIBLE, Event, Panel, Request};
|
||||
use super::format::{printd, printf, printx, scand};
|
||||
use super::*;
|
||||
|
||||
// ── app, util, console ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -35,26 +35,26 @@ use boa_engine::realm::Realm;
|
||||
use boa_engine::{Context, JsError, JsNativeError, JsObject, JsResult, JsString, JsValue, NativeFunction, Source, js_string};
|
||||
|
||||
mod document;
|
||||
mod format;
|
||||
mod globals;
|
||||
mod host;
|
||||
mod model;
|
||||
mod run;
|
||||
mod format;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) use format::PRINTD_SCANNED;
|
||||
use format::{printd, printf, printx, scand};
|
||||
pub(crate) use globals::menu_item;
|
||||
use globals::platform;
|
||||
use host::{arg, as_number, error, function, s, text};
|
||||
pub use model::{
|
||||
DISPLAY_HIDDEN, DISPLAY_NO_PRINT, DISPLAY_NO_VIEW, DISPLAY_VISIBLE, DocInfo, Event, FieldState, FieldType, Limits, Outcome, Panel, Request,
|
||||
};
|
||||
pub(crate) use run::{CheckedCodeFromStrings, MAX_SCRIPT_BYTES};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use run::SCRIPT_STACK;
|
||||
use run::refuse;
|
||||
pub(crate) use run::{CheckedCodeFromStrings, MAX_SCRIPT_BYTES};
|
||||
pub use run::{run, run_shared};
|
||||
#[cfg(test)]
|
||||
pub(crate) use format::PRINTD_SCANNED;
|
||||
use format::{printd, printf, printx, scand};
|
||||
|
||||
pub mod formcalc;
|
||||
pub mod xfa;
|
||||
|
||||
@@ -173,10 +173,8 @@ fn compressed_object_container_chain_does_not_recurse() {
|
||||
|
||||
#[test]
|
||||
fn compressed_objects_and_indirect_stream_length_still_load() {
|
||||
let pdf = compressed_length_pdf(
|
||||
&[(3, 4, 0), (5, 4, 1)],
|
||||
&[(4, b"<< /Type /ObjStm /N 2 /First 8 /Length 17 >>\nstream\n3 0 5 2 5 (value)\nendstream")],
|
||||
);
|
||||
let pdf =
|
||||
compressed_length_pdf(&[(3, 4, 0), (5, 4, 1)], &[(4, b"<< /Type /ObjStm /N 2 /First 8 /Length 17 >>\nstream\n3 0 5 2 5 (value)\nendstream")]);
|
||||
let doc = Document::load_mem_with_options(&pdf, LoadOptions { strict: true, ..Default::default() }).unwrap();
|
||||
assert_eq!(doc.get_object((3, 0)).unwrap().as_i64().unwrap(), 5);
|
||||
assert_eq!(doc.get_object((5, 0)).unwrap().as_str().unwrap(), b"value");
|
||||
@@ -187,8 +185,7 @@ fn compressed_objects_and_indirect_stream_length_still_load() {
|
||||
fn compressed_length_in_a_container_with_an_indirect_length_still_loads() {
|
||||
// Two hops, as in a valid file: stream 2's /Length (3) is compressed in container 4, whose own /Length (5) is
|
||||
// a plain indirect integer.
|
||||
let pdf =
|
||||
compressed_length_pdf(&[(3, 4, 0)], &[(4, b"<< /Type /ObjStm /N 1 /First 4 /Length 5 0 R >>\nstream\n3 0 5\nendstream"), (5, b"5")]);
|
||||
let pdf = compressed_length_pdf(&[(3, 4, 0)], &[(4, b"<< /Type /ObjStm /N 1 /First 4 /Length 5 0 R >>\nstream\n3 0 5\nendstream"), (5, b"5")]);
|
||||
let doc = Document::load_mem_with_options(&pdf, LoadOptions { strict: true, ..Default::default() }).unwrap();
|
||||
assert_eq!(doc.get_object((3, 0)).unwrap().as_i64().unwrap(), 5);
|
||||
assert_eq!(doc.get_object((5, 0)).unwrap().as_i64().unwrap(), 5);
|
||||
@@ -356,9 +353,7 @@ fn label_info(nums: Vec<Object>, kids: Vec<Object>) -> DocInfo {
|
||||
doc.objects.insert((1, 0), Object::Dictionary(catalog));
|
||||
doc.trailer.set("Root", Object::Reference((1, 0)));
|
||||
let mut info = DocInfo {
|
||||
pages: (1..=3)
|
||||
.map(|n| PageInfo { width: 200.0, height: 300.0, crop: [0.0, 0.0, 200.0, 300.0], rotation: 0, label: n.to_string() })
|
||||
.collect(),
|
||||
pages: (1..=3).map(|n| PageInfo { width: 200.0, height: 300.0, crop: [0.0, 0.0, 200.0, 300.0], rotation: 0, label: n.to_string() }).collect(),
|
||||
..Default::default()
|
||||
};
|
||||
Inspector::new(&doc).fill(&mut info);
|
||||
@@ -442,11 +437,7 @@ fn page_label_prefix_spaces_survive_public_inspection() {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(
|
||||
info.pages.iter().map(|p| p.label.clone()).collect::<Vec<_>>(),
|
||||
expected,
|
||||
"{prefix:?}, decimal={decimal}, indirect={indirect}"
|
||||
);
|
||||
assert_eq!(info.pages.iter().map(|p| p.label.clone()).collect::<Vec<_>>(), expected, "{prefix:?}, decimal={decimal}, indirect={indirect}");
|
||||
assert!(info.warnings.is_empty(), "{:?}", info.warnings);
|
||||
assert_eq!(info.title.as_deref(), Some("Metadata title"), "page-prefix decoding must not change metadata normalization");
|
||||
}
|
||||
@@ -454,12 +445,9 @@ fn page_label_prefix_spaces_survive_public_inspection() {
|
||||
|
||||
#[test]
|
||||
fn page_label_limits_keep_normal_pdf_numbering() {
|
||||
for (style, first, expected) in [
|
||||
("r", 4, ["iv", "v", "vi"]),
|
||||
("R", 1994, ["MCMXCIV", "MCMXCV", "MCMXCVI"]),
|
||||
("a", 26, ["z", "aa", "bb"]),
|
||||
("A", 52, ["ZZ", "AAA", "BBB"]),
|
||||
] {
|
||||
for (style, first, expected) in
|
||||
[("r", 4, ["iv", "v", "vi"]), ("R", 1994, ["MCMXCIV", "MCMXCV", "MCMXCVI"]), ("a", 26, ["z", "aa", "bb"]), ("A", 52, ["ZZ", "AAA", "BBB"])]
|
||||
{
|
||||
let info = label_info(vec![Object::Integer(0), label_spec(style, Vec::new(), first)], Vec::new());
|
||||
assert_eq!(info.pages.iter().map(|p| p.label.as_str()).collect::<Vec<_>>(), expected);
|
||||
assert!(info.warnings.is_empty(), "{:?}", info.warnings);
|
||||
@@ -537,9 +525,8 @@ fn page_label_limits_bound_total_custom_output_atomically() {
|
||||
let mut catalog = Dictionary::new();
|
||||
catalog.set("PageLabels", Object::Dictionary(tree));
|
||||
let count = MAX_LABEL_TOTAL_BYTES / MAX_LABEL_BYTES + 1;
|
||||
let mut pages: Vec<_> = (1..=count)
|
||||
.map(|n| PageInfo { width: 200.0, height: 300.0, crop: [0.0, 0.0, 200.0, 300.0], rotation: 0, label: n.to_string() })
|
||||
.collect();
|
||||
let mut pages: Vec<_> =
|
||||
(1..=count).map(|n| PageInfo { width: 200.0, height: 300.0, crop: [0.0, 0.0, 200.0, 300.0], rotation: 0, label: n.to_string() }).collect();
|
||||
let err = Inspector::new(&doc).page_labels(&catalog, &mut pages).unwrap_err();
|
||||
assert!(err.contains("4 MiB"), "{err}");
|
||||
assert!(pages.iter().enumerate().all(|(i, p)| p.label == (i + 1).to_string()));
|
||||
@@ -1491,8 +1478,7 @@ fn xfa_dynamic_render_is_read_from_config_acrobat7_only() {
|
||||
);
|
||||
assert_eq!(text(&xdp).as_deref(), Some("required"));
|
||||
// Only in the data, or nested in the template: no configuration at all.
|
||||
let xdp =
|
||||
format!("<xdp:xdp><xfa:datasets><xfa:data>{}</xfa:data></xfa:datasets></xdp:xdp>", config("<dynamicRender>forbidden</dynamicRender>"));
|
||||
let xdp = format!("<xdp:xdp><xfa:datasets><xfa:data>{}</xfa:data></xfa:datasets></xdp:xdp>", config("<dynamicRender>forbidden</dynamicRender>"));
|
||||
assert_eq!(text(&xdp), None);
|
||||
let xdp = format!("<xdp:xdp><template>{}</template></xdp:xdp>", config("<dynamicRender>forbidden</dynamicRender>"));
|
||||
assert_eq!(text(&xdp), None);
|
||||
|
||||
@@ -215,10 +215,7 @@ fn page_panic_retires_shared_generation_and_healthy_pages_use_private_parsers()
|
||||
// in the shared generation first (then only one parse would happen).
|
||||
let gate = render_gate(1, true);
|
||||
*lock(&pool.shared.render_gates) = vec![gate.clone()];
|
||||
pool.set_queue(vec![
|
||||
RenderRequest { page: 0, scale: 1.0, ..Default::default() },
|
||||
RenderRequest { page: 1, scale: 1.0, ..Default::default() },
|
||||
]);
|
||||
pool.set_queue(vec![RenderRequest { page: 0, scale: 1.0, ..Default::default() }, RenderRequest { page: 1, scale: 1.0, ..Default::default() }]);
|
||||
let crashed = receive_before_deadline(&pool);
|
||||
if gate.claimed.load(Ordering::Acquire) {
|
||||
gate.entered.wait();
|
||||
@@ -394,8 +391,7 @@ fn a_failed_page_stays_refused_at_every_scale_and_generation_but_other_pages_ren
|
||||
let pool = RenderPool::new(Arc::new(ONE_PAGE_TWICE.to_vec()), 1, RenderConfig::default());
|
||||
let bad = RenderRequest { page: 0, scale: 1.0, tag: 70, ..Default::default() };
|
||||
lock(&pool.shared.stuck).insert(bad.into());
|
||||
for req in [bad, RenderRequest { scale: 0.5, tag: 71, ..bad }, RenderRequest { tile: Some(Tile { x: 0, y: 0, w: 8, h: 8 }), tag: 72, ..bad }]
|
||||
{
|
||||
for req in [bad, RenderRequest { scale: 0.5, tag: 71, ..bad }, RenderRequest { tile: Some(Tile { x: 0, y: 0, w: 8, h: 8 }), tag: 72, ..bad }] {
|
||||
pool.set_queue(vec![req]);
|
||||
let failed = receive_before_deadline(&pool);
|
||||
assert_eq!(failed.request, req);
|
||||
@@ -478,14 +474,7 @@ fn worker_reuses_parser_and_releases_source_after_rendering() {
|
||||
}
|
||||
assert_eq!(
|
||||
pool.stats(),
|
||||
RenderStats {
|
||||
parser_builds: 1,
|
||||
page_interpretations: 2,
|
||||
render_requests: 3,
|
||||
tile_requests: 0,
|
||||
text_interpretations: 1,
|
||||
rasterizations: 2
|
||||
}
|
||||
RenderStats { parser_builds: 1, page_interpretations: 2, render_requests: 3, tile_requests: 0, text_interpretations: 1, rasterizations: 2 }
|
||||
);
|
||||
drop(pool);
|
||||
let until = std::time::Instant::now() + std::time::Duration::from_secs(8);
|
||||
@@ -806,12 +795,8 @@ fn indexed_palettes_over_lab_keep_their_colours() {
|
||||
// Palette entry 1 is <80 CC B2>: L* = 128/255·100, a* = -100 + 204/255·200,
|
||||
// b* = -100 + 178/255·200, about Lab (50.2 60 39.6): a warm red.
|
||||
let indexed = render("/I cs 1 sc 0 0 200 200 re f");
|
||||
let direct = render(&format!(
|
||||
"/L cs {} {} {} sc 0 0 200 200 re f",
|
||||
128.0 / 255.0 * 100.0,
|
||||
-100.0 + 204.0 / 255.0 * 200.0,
|
||||
-100.0 + 178.0 / 255.0 * 200.0
|
||||
));
|
||||
let direct =
|
||||
render(&format!("/L cs {} {} {} sc 0 0 200 200 re f", 128.0 / 255.0 * 100.0, -100.0 + 204.0 / 255.0 * 200.0, -100.0 + 178.0 / 255.0 * 200.0));
|
||||
for (channel, (got, want)) in indexed.iter().zip(direct).enumerate() {
|
||||
assert!(got.abs_diff(want) <= 1, "channel {channel}: indexed {indexed:?}, direct {direct:?}");
|
||||
}
|
||||
@@ -1033,9 +1018,8 @@ fn re_sent_queues_render_each_page_once() {
|
||||
}
|
||||
pdf += "trailer << /Root 1 0 R >>\n%%EOF";
|
||||
let pool = RenderPool::new(Arc::new(pdf.into_bytes()), 3, RenderConfig::default());
|
||||
let wanted: Vec<RenderRequest> = (0..pages)
|
||||
.map(|page| RenderRequest { page, kind: RequestKind::Pixels, tile: None, scale: 2.0, tag: 2000, ..Default::default() })
|
||||
.collect();
|
||||
let wanted: Vec<RenderRequest> =
|
||||
(0..pages).map(|page| RenderRequest { page, kind: RequestKind::Pixels, tile: None, scale: 2.0, tag: 2000, ..Default::default() }).collect();
|
||||
// The canvas's loop: take what arrived, then queue every page still missing whenever
|
||||
// that list changes (requests already rendering included).
|
||||
let mut got = vec![0; pages];
|
||||
@@ -1298,14 +1282,7 @@ fn heavy_vector_fixture_preserves_trailing_text_and_raster_output() {
|
||||
assert!(text.text.is_some_and(|page| page.plain_text().contains("TRAILING_MARKER")));
|
||||
assert_eq!(
|
||||
renderer.stats(),
|
||||
RenderStats {
|
||||
parser_builds: 1,
|
||||
page_interpretations: 1,
|
||||
render_requests: 2,
|
||||
tile_requests: 0,
|
||||
text_interpretations: 1,
|
||||
rasterizations: 1
|
||||
}
|
||||
RenderStats { parser_builds: 1, page_interpretations: 1, render_requests: 2, tile_requests: 0, text_interpretations: 1, rasterizations: 1 }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3783,14 +3760,7 @@ fn pages_in_one_object_stream(pages: usize) -> Vec<u8> {
|
||||
(1, "<< /Type /Catalog /Pages 2 0 R >>".to_string()),
|
||||
(2, format!("<< /Type /Pages /Kids [{}] /Count {pages} >>", kids.join(" "))),
|
||||
(3, format!("<< /Length {} >>\nstream\n{content}\nendstream", content.len())),
|
||||
(
|
||||
4,
|
||||
format!(
|
||||
"<< /Type /ObjStm /N {pages} /First {} /Length {} >>\nstream\n{index}{body}\nendstream",
|
||||
index.len(),
|
||||
index.len() + body.len()
|
||||
),
|
||||
),
|
||||
(4, format!("<< /Type /ObjStm /N {pages} /First {} /Length {} >>\nstream\n{index}{body}\nendstream", index.len(), index.len() + body.len())),
|
||||
] {
|
||||
offsets.push(pdf.len());
|
||||
pdf.extend_from_slice(format!("{num} 0 obj\n{obj}\nendobj\n").as_bytes());
|
||||
@@ -4236,11 +4206,13 @@ fn sampled_functions_with_billions_of_samples_are_refused() {
|
||||
let mut pdf = b"%PDF-1.7\n1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj\n2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj\n3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 40 40] /Contents 4 0 R /Resources << /Shading << /Sh0 5 0 R >> >> >> endobj\n".to_vec();
|
||||
pdf.extend_from_slice(format!("4 0 obj << /Length {} >> stream\n", page_content.len()).as_bytes());
|
||||
pdf.extend_from_slice(page_content);
|
||||
pdf.extend_from_slice(b"\nendstream endobj\n5 0 obj << /ShadingType 2 /ColorSpace /DeviceGray /Coords [0 0 40 0] /Function 6 0 R >> endobj\n");
|
||||
pdf.extend_from_slice(
|
||||
b"\nendstream endobj\n5 0 obj << /ShadingType 2 /ColorSpace /DeviceGray /Coords [0 0 40 0] /Function 6 0 R >> endobj\n",
|
||||
);
|
||||
pdf.extend_from_slice(
|
||||
format!("6 0 obj << /FunctionType 0 /Domain [0 1] /Range [0 1] /Size [1073741824] /BitsPerSample 1 /Filter /FlateDecode /Length {} >> stream\n", bomb.len()).as_bytes(),
|
||||
format!(
|
||||
"6 0 obj << /FunctionType 0 /Domain [0 1] /Range [0 1] /Size [1073741824] /BitsPerSample 1 /Filter /FlateDecode /Length {} >> stream\n",
|
||||
bomb.len()
|
||||
)
|
||||
.as_bytes(),
|
||||
);
|
||||
pdf.extend_from_slice(&bomb);
|
||||
pdf.extend_from_slice(b"\nendstream endobj\ntrailer << /Root 1 0 R >>\n%%EOF\n");
|
||||
@@ -4278,10 +4250,8 @@ fn shadings_with_large_sampled_functions_paint_quickly() {
|
||||
|
||||
const SAMPLES: usize = 1 << 21;
|
||||
let samples = zlib_zeros(SAMPLES);
|
||||
let function = format!(
|
||||
"<< /FunctionType 0 /Domain [0 1] /Range [0 1] /Size [{SAMPLES}] /BitsPerSample 8 /Filter /FlateDecode /Length {} >>",
|
||||
samples.len()
|
||||
);
|
||||
let function =
|
||||
format!("<< /FunctionType 0 /Domain [0 1] /Range [0 1] /Size [{SAMPLES}] /BitsPerSample 8 /Filter /FlateDecode /Length {} >>", samples.len());
|
||||
// Black ramp on the left half, 30 times over; a red square after it.
|
||||
let content = "q 0 0 20 40 re W n /Sh0 sh Q\n".repeat(30) + "1 0 0 rg 36 36 4 4 re f";
|
||||
let mut pdf = b"%PDF-1.7\n1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj\n2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj\n3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 40 40] /Contents 4 0 R /Resources << /Shading << /Sh0 5 0 R >> >> >> endobj\n".to_vec();
|
||||
@@ -5341,10 +5311,7 @@ fn raw_crop_unit_floor_reciprocal_does_not_trigger_letter_fallback() {
|
||||
let page = pdf.pages().first().expect("one page");
|
||||
let (width, height) = page.base_dimensions();
|
||||
// In f32, the nearest reciprocal of 41 or 47 multiplies back to 0.99999994.
|
||||
assert!(
|
||||
width * page.user_unit() >= 1.0 && height * page.user_unit() >= 1.0,
|
||||
"unit={unit}: floor must not round below one physical point"
|
||||
);
|
||||
assert!(width * page.user_unit() >= 1.0 && height * page.user_unit() >= 1.0, "unit={unit}: floor must not round below one physical point");
|
||||
let info = crate::inspect(Arc::new(bytes), None).expect("inspect the same small crop");
|
||||
let page = &info.pages[0];
|
||||
assert!(
|
||||
@@ -5979,8 +5946,7 @@ fn print_preview_requests_render_with_reading_colors_off() {
|
||||
/// flash wrong colours at tile seams.
|
||||
#[test]
|
||||
fn reading_colors_tiles_match_full_render() {
|
||||
let mut r =
|
||||
PageRenderer::new(Arc::new(ONE_PAGE.to_vec()), RenderConfig { reading_colors: ReadingColors::WHITE_ON_BLACK, ..Default::default() });
|
||||
let mut r = PageRenderer::new(Arc::new(ONE_PAGE.to_vec()), RenderConfig { reading_colors: ReadingColors::WHITE_ON_BLACK, ..Default::default() });
|
||||
let full = r.render(RenderRequest { page: 0, kind: RequestKind::Pixels, tile: None, scale: 2.0, tag: 0, preview: false });
|
||||
let tile = Tile { x: 30, y: 40, w: 50, h: 30 };
|
||||
let part = r.render(RenderRequest { page: 0, kind: RequestKind::Pixels, tile: Some(tile), scale: 2.0, tag: 0, preview: false });
|
||||
@@ -6342,8 +6308,7 @@ fn spot_colour_images_run_their_tint_transform_once_per_sample_value() {
|
||||
data.len()
|
||||
);
|
||||
let function = format!("<< /FunctionType 4 /Domain [0 1] /Range [0 1 0 1 0 1] /Length {} >>", program.len());
|
||||
let pdf =
|
||||
image_cache_pdf("q 130 0 0 70 0 0 cm /A Do Q", "<< /XObject << /A 5 0 R >> >>", &[(&image, &data), (&function, program.as_bytes())]);
|
||||
let pdf = image_cache_pdf("q 130 0 0 70 0 0 cm /A Do Q", "<< /XObject << /A 5 0 R >> >>", &[(&image, &data), (&function, program.as_bytes())]);
|
||||
// The count is per thread, and this render runs on this one.
|
||||
let before = hayro::hayro_interpret::color::tint_transform_runs();
|
||||
let out = render_first_page(pdf);
|
||||
@@ -6790,12 +6755,7 @@ endstream endobj
|
||||
let reference = render(sampled("{ pop 10 sub 4 div }"));
|
||||
for (x, expected) in [(2, 0), (9, 0), (10, 32), (11, 96), (12, 159), (13, 223), (14, 255), (30, 255)] {
|
||||
assert!((grey(&native, x) - expected).abs() <= 4, "axial, x {x}: {} instead of {expected}", grey(&native, x));
|
||||
assert!(
|
||||
(grey(&native, x) - grey(&reference, x)).abs() <= 4,
|
||||
"axial, x {x}: native {} vs sampled {}",
|
||||
grey(&native, x),
|
||||
grey(&reference, x)
|
||||
);
|
||||
assert!((grey(&native, x) - grey(&reference, x)).abs() <= 4, "axial, x {x}: native {} vs sampled {}", grey(&native, x), grey(&reference, x));
|
||||
}
|
||||
|
||||
// An extended radial shading matches the sampled one everywhere.
|
||||
|
||||
@@ -415,8 +415,7 @@ fn encoded_pages(pages: &[(lopdf::Object, &[u8])]) -> Pdf {
|
||||
let pages_id = doc.new_object_id();
|
||||
let mut kids = Vec::new();
|
||||
for (encoding, content) in pages {
|
||||
let font =
|
||||
doc.add_object(dictionary! { "Type" => "Font", "Subtype" => "Type1", "BaseFont" => "Helvetica", "Encoding" => encoding.clone() });
|
||||
let font = doc.add_object(dictionary! { "Type" => "Font", "Subtype" => "Type1", "BaseFont" => "Helvetica", "Encoding" => encoding.clone() });
|
||||
let content = doc.add_object(Stream::new(dictionary! {}, content.to_vec()));
|
||||
let page = doc.add_object(dictionary! { "Type" => "Page", "Parent" => pages_id, "MediaBox" => vec![Object::Integer(0), Object::Integer(0), Object::Integer(300), Object::Integer(300)], "Resources" => dictionary! {"Font" => dictionary! {"F1" => font}}, "Contents" => content });
|
||||
kids.push(Object::Reference(page));
|
||||
@@ -455,8 +454,7 @@ fn the_annex_d2_alias_codes_read_as_an_ordinary_hyphen_and_space() {
|
||||
(name("MacRomanEncoding"), &b"BT /F1 20 Tf 1 0 0 1 20 150 Tm (a\xcab) Tj ET"[..]),
|
||||
(differences, &b"BT /F1 20 Tf 1 0 0 1 20 150 Tm (aXbYc) Tj ET"[..]),
|
||||
]);
|
||||
let texts =
|
||||
|page| extract_page(&pdf, page, &InterpreterSettings::default()).unwrap().glyphs.iter().map(|g| g.text.clone()).collect::<Vec<_>>();
|
||||
let texts = |page| extract_page(&pdf, page, &InterpreterSettings::default()).unwrap().glyphs.iter().map(|g| g.text.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(texts(0), ["a", "-", "b", " ", "c"], "WinAnsi 0xAD and 0xA0");
|
||||
assert_eq!(texts(1), ["a", " ", "b"], "MacRoman 0xCA");
|
||||
assert_eq!(texts(2), ["a", "\u{ad}", "b", "\u{a0}", "c"], "a named glyph keeps its glyph list value");
|
||||
|
||||
@@ -489,13 +489,7 @@ fn keyboard_find_step_is_explicit_and_a_late_text_layer_cannot_undo_it() {
|
||||
|
||||
let ctx = egui::Context::default();
|
||||
ctx.input_mut(|i| {
|
||||
i.events.push(egui::Event::Key {
|
||||
key: egui::Key::G,
|
||||
physical_key: None,
|
||||
pressed: true,
|
||||
repeat: false,
|
||||
modifiers: egui::Modifiers::COMMAND,
|
||||
});
|
||||
i.events.push(egui::Event::Key { key: egui::Key::G, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::COMMAND });
|
||||
});
|
||||
shortcuts(&mut v, &ctx, Default::default());
|
||||
|
||||
@@ -1453,10 +1447,7 @@ fn many_open_documents_share_one_raster_allowance_and_close_releases_handles() {
|
||||
assert_eq!(app.active_ids().map(|(index, _)| index), Some(5));
|
||||
assert!(app.views.iter().zip(&expected).all(|(view, (request, dimensions))| {
|
||||
view.thumbs.len() == 1
|
||||
&& view
|
||||
.thumbs
|
||||
.get(&0)
|
||||
.is_some_and(|thumb| thumb.tag == request.tag && thumb.tex.size() == [dimensions.0 as usize, dimensions.1 as usize])
|
||||
&& view.thumbs.get(&0).is_some_and(|thumb| thumb.tag == request.tag && thumb.tex.size() == [dimensions.0 as usize, dimensions.1 as usize])
|
||||
}));
|
||||
|
||||
app.finish_render_frame(&ctx);
|
||||
@@ -1902,13 +1893,8 @@ fn destinations_set_the_zoom_mode_and_the_point_to_show() {
|
||||
fn page_text_failure_preserves_valid_search_match_without_jitter() {
|
||||
let mut v = view(3, PageLayout::Single, true);
|
||||
v.current = 1;
|
||||
v.find = Some(Find {
|
||||
query: "test".into(),
|
||||
case_query: "test".into(),
|
||||
matches: vec![(0, 0..4), (1, 5..9)],
|
||||
current: Some(0),
|
||||
..Default::default()
|
||||
});
|
||||
v.find =
|
||||
Some(Find { query: "test".into(), case_query: "test".into(), matches: vec![(0, 0..4), (1, 5..9)], current: Some(0), ..Default::default() });
|
||||
let req = RenderRequest { page: 0, kind: RequestKind::Text, ..Default::default() };
|
||||
v.last_queue = vec![req];
|
||||
let ctx = egui::Context::default();
|
||||
|
||||
@@ -159,20 +159,8 @@ fn a_started_request_finishes_its_batches_after_focus_moves() {
|
||||
since: web_time::Instant::now(),
|
||||
release: Vec::new(),
|
||||
batches: VecDeque::from([
|
||||
vec![egui::Event::Key {
|
||||
key: egui::Key::Tab,
|
||||
physical_key: None,
|
||||
pressed: true,
|
||||
repeat: false,
|
||||
modifiers: egui::Modifiers::NONE,
|
||||
}],
|
||||
vec![egui::Event::Key {
|
||||
key: egui::Key::Tab,
|
||||
physical_key: None,
|
||||
pressed: false,
|
||||
repeat: false,
|
||||
modifiers: egui::Modifiers::NONE,
|
||||
}],
|
||||
vec![egui::Event::Key { key: egui::Key::Tab, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE }],
|
||||
vec![egui::Event::Key { key: egui::Key::Tab, physical_key: None, pressed: false, repeat: false, modifiers: egui::Modifiers::NONE }],
|
||||
]),
|
||||
});
|
||||
}
|
||||
@@ -811,11 +799,7 @@ fn completed_screenshots_obey_the_admission_deadline_before_success_or_retry() {
|
||||
callback: None,
|
||||
region: None,
|
||||
reply,
|
||||
since: if expired {
|
||||
web_time::Instant::now().checked_sub(std::time::Duration::from_secs(10)).unwrap()
|
||||
} else {
|
||||
web_time::Instant::now()
|
||||
},
|
||||
since: if expired { web_time::Instant::now().checked_sub(std::time::Duration::from_secs(10)).unwrap() } else { web_time::Instant::now() },
|
||||
geometry,
|
||||
reserved: geometry.image_bytes().unwrap(),
|
||||
attempts: 0,
|
||||
|
||||
@@ -11,12 +11,12 @@ mod save;
|
||||
|
||||
pub use close::CloseRequest;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) use save::in_document_folder;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use save::PendingOverwrite;
|
||||
pub use save::{SaveTarget, write_atomically};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub(crate) use save::download;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) use save::in_document_folder;
|
||||
pub use save::{SaveTarget, write_atomically};
|
||||
#[cfg(test)]
|
||||
pub(crate) use save::{is_mail_temp_copy, save_dialog_folder};
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -279,11 +279,8 @@ fn ordinary_paths_are_not_mail_copies() {
|
||||
|
||||
/// A one-page document with a proper xref table.
|
||||
fn one_page_pdf() -> Vec<u8> {
|
||||
let objs = [
|
||||
"<< /Type /Catalog /Pages 2 0 R >>",
|
||||
"<< /Type /Pages /Kids [3 0 R] /Count 1 /MediaBox [0 0 200 300] >>",
|
||||
"<< /Type /Page /Parent 2 0 R >>",
|
||||
];
|
||||
let objs =
|
||||
["<< /Type /Catalog /Pages 2 0 R >>", "<< /Type /Pages /Kids [3 0 R] /Count 1 /MediaBox [0 0 200 300] >>", "<< /Type /Page /Parent 2 0 R >>"];
|
||||
let mut out = b"%PDF-1.7\n".to_vec();
|
||||
let mut offsets = Vec::new();
|
||||
for (i, o) in objs.iter().enumerate() {
|
||||
@@ -308,14 +305,8 @@ fn save_commits_the_open_text_box() {
|
||||
app.open_bytes("a.pdf", None, one_page_pdf()).unwrap();
|
||||
app.save_override = Some(dest.to_string_lossy().into_owned());
|
||||
let style = crate::content_ui::default_style();
|
||||
app.views[0].content.draft = Some(crate::content_ui::TextDraft {
|
||||
page: 0,
|
||||
index: None,
|
||||
rect: [20.0, 20.0, 120.0, 40.0],
|
||||
text: "Typed text".into(),
|
||||
style,
|
||||
focus: true,
|
||||
});
|
||||
app.views[0].content.draft =
|
||||
Some(crate::content_ui::TextDraft { page: 0, index: None, rect: [20.0, 20.0, 120.0, 40.0], text: "Typed text".into(), style, focus: true });
|
||||
|
||||
assert!(app.save_active(SaveTarget::InPlace));
|
||||
let id = app.views[0].id;
|
||||
|
||||
@@ -162,10 +162,8 @@ fn lookups_fall_back_to_english() {
|
||||
|
||||
#[test]
|
||||
fn catalog_kinds_are_parsed_and_looked_up() {
|
||||
let (c, errors) = Catalog::parse(
|
||||
"# c\n\tHello\tこんにちは\n@id\tfile.save\t保存する\nmenu\tWindows\tウィンドウ群\n@plural\t{n} file|{n} files\t{n} 個\n\n",
|
||||
1,
|
||||
);
|
||||
let (c, errors) =
|
||||
Catalog::parse("# c\n\tHello\tこんにちは\n@id\tfile.save\t保存する\nmenu\tWindows\tウィンドウ群\n@plural\t{n} file|{n} files\t{n} 個\n\n", 1);
|
||||
assert!(errors.is_empty(), "{errors:?}");
|
||||
assert_eq!(c.plain("Hello"), Some("こんにちは"));
|
||||
assert_eq!(c.id("file.save"), Some("保存する"));
|
||||
@@ -222,14 +220,8 @@ fn catalogs_handle_escapes_crlf_and_distinct_contexts() {
|
||||
|
||||
#[test]
|
||||
fn broken_catalog_falls_back_to_english() {
|
||||
static BROKEN: LangInfo = LangInfo {
|
||||
code: "broken",
|
||||
name: "Broken test catalog",
|
||||
source: "malformed\n\\",
|
||||
plural: plural_none,
|
||||
rtl: false,
|
||||
catalog: OnceLock::new(),
|
||||
};
|
||||
static BROKEN: LangInfo =
|
||||
LangInfo { code: "broken", name: "Broken test catalog", source: "malformed\n\\", plural: plural_none, rtl: false, catalog: OnceLock::new() };
|
||||
assert_eq!(tr(Lang(&BROKEN), "File"), "File");
|
||||
assert_eq!(trn(Lang(&BROKEN), 2, "{n} page", "{n} pages"), "2 pages");
|
||||
}
|
||||
|
||||
@@ -68,9 +68,9 @@ mod state;
|
||||
mod tools;
|
||||
mod workflows;
|
||||
|
||||
pub(crate) use app::{MAX_AUTHOR_CHARS, copy_refused, date_text_for_pdf, print_refused};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) use app::same_file;
|
||||
pub(crate) use app::{MAX_AUTHOR_CHARS, copy_refused, date_text_for_pdf, print_refused};
|
||||
use canvas::autoscroll;
|
||||
use canvas::crop;
|
||||
use canvas::fling;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
use egui::{Align2, Color32, CornerRadius, Rect, Response, Sense, Stroke, vec2};
|
||||
|
||||
use crate::theme::{self, Tokens};
|
||||
use crate::PdfCraftApp;
|
||||
use crate::theme::{self, Tokens};
|
||||
|
||||
pub(super) mod icon_data;
|
||||
pub mod icons;
|
||||
|
||||
@@ -23,17 +23,17 @@ mod session;
|
||||
mod table;
|
||||
mod view;
|
||||
|
||||
pub use files::{Columns, CombineFile, CombineView, ConflictPreview, Lock, SortKey};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) use files::Incoming;
|
||||
pub use files::{Columns, CombineFile, CombineView, ConflictPreview, Lock, SortKey};
|
||||
pub(crate) use files::{Preview, RowAction};
|
||||
use files::{Snapshot, UnlockPrompt};
|
||||
#[cfg(test)]
|
||||
pub(crate) use parts::{Part, moved_order, moved_pages, removed_pages, step_to};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) use parts::ago;
|
||||
pub(crate) use parts::range_of;
|
||||
#[cfg(test)]
|
||||
pub(crate) use parts::{Part, moved_order, moved_pages, removed_pages, step_to};
|
||||
#[cfg(test)]
|
||||
use parts::{title_of, utc_stamp};
|
||||
pub(crate) use view::page;
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ use crate::model::{
|
||||
};
|
||||
use crate::text::{self, Block, Face, Span};
|
||||
|
||||
mod common;
|
||||
mod draw;
|
||||
mod field;
|
||||
mod flow;
|
||||
mod common;
|
||||
mod items;
|
||||
mod measure;
|
||||
mod pages;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::field::auto_check_reserve;
|
||||
use super::common::clamp_opt;
|
||||
use super::field::auto_check_reserve;
|
||||
use super::*;
|
||||
|
||||
impl Layouter<'_> {
|
||||
|
||||
@@ -18,17 +18,17 @@ use std::io::Write as _;
|
||||
use pdfcraft_cos::{Dict, Document, ObjRef, Object, PdfString};
|
||||
use pdfcraft_forms::{FieldKind, FieldValue};
|
||||
|
||||
mod fdf;
|
||||
mod common;
|
||||
mod fdf;
|
||||
mod xfdf;
|
||||
|
||||
#[cfg(test)]
|
||||
use common::{MAX_DEPTH, MAX_XML_DEPTH, arr, nums_of, parse_hex, text_of, xml_nesting_depth};
|
||||
use common::{check_form_xml_depth, esc, parse_form_xml, walk_xfdf, xml_name};
|
||||
pub use fdf::export_fdf;
|
||||
use fdf::{ImportBudget, fdf_body, import_fdf, walk_fdf};
|
||||
#[cfg(test)]
|
||||
use fdf::{MAX_FDF_BYTES, MAX_FDF_OBJECTS};
|
||||
#[cfg(test)]
|
||||
use common::{MAX_DEPTH, MAX_XML_DEPTH, arr, nums_of, parse_hex, text_of, xml_nesting_depth};
|
||||
use common::{check_form_xml_depth, esc, parse_form_xml, walk_xfdf, xml_name};
|
||||
pub use xfdf::export_xfdf;
|
||||
#[cfg(test)]
|
||||
use xfdf::{LOCKED, find_by_name};
|
||||
|
||||
Reference in New Issue
Block a user