Merge pull request #25 from storytold/pr/never-crash-edit-xfdf

Never crash: edit and xfdf have no expect calls
This commit is contained in:
Brandon Thomas authored and GitHub committed 2026-10-04 14:49:48 -04:00
commit f5e3255b80
3 files changed
+17 -8

No files matched your search

+2
View File
@@ -12,6 +12,8 @@
//!
//! Text uses standard Helvetica (WinAnsi) added to the page resources as `/PCHelv`.
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
use printcraft_cos::{Dict, Document, Object, Stream};
use printcraft_fonts::{helvetica_width, literal, win_ansi};
+11 -7
View File
@@ -400,7 +400,8 @@ pub fn text_lines(doc: &Document, page: usize) -> Result<Vec<TextLine>, EditErro
type Encoder = Box<dyn Fn(&str) -> Option<Vec<u8>>>;
/// The substitute font's resource name.
const SUBSTITUTE: &[u8] = b"PCEdHelv";
const SUBSTITUTE_NAME: &str = "PCEdHelv";
const SUBSTITUTE: &[u8] = SUBSTITUTE_NAME.as_bytes();
/// Replace the text of line `line` (an index into [`text_lines`]) on `page` with `text`.
pub fn replace_line(doc: &mut Document, page: usize, line: usize, text: &str) -> Result<LineEdit, EditError> {
@@ -440,7 +441,7 @@ pub fn replace_line(doc: &mut Document, page: usize, line: usize, text: &str) ->
}
// The size in text space: the current Tf's size.
let size = font_size_before(&ops, first).unwrap_or(target.size);
replacement.push(Op::new("Tf", vec![Object::name(std::str::from_utf8(SUBSTITUTE).expect("ascii")), printcraft_content::num(size)]));
replacement.push(Op::new("Tf", vec![Object::name(SUBSTITUTE_NAME), printcraft_content::num(size)]));
replacement.push(Op::new("Tj", vec![Object::String(PdfString::literal(win))]));
replacement.push(Op::new("Tf", vec![Object::name(&target.font), printcraft_content::num(size)]));
substituted = Some("Helvetica".to_string());
@@ -506,7 +507,8 @@ fn group_blocks(lines: &[TextLine]) -> Vec<TextBlock> {
for (i, l) in lines.iter().enumerate() {
let joins = i > 0
&& blocks.last().is_some_and(|b| {
let prev = &lines[*b.lines.last().expect("non-empty")];
let Some(&p) = b.lines.last() else { return false };
let prev = &lines[p];
let g = prev.origin.baseline - l.origin.baseline;
prev.stream == l.stream
&& prev.font == l.font
@@ -516,8 +518,11 @@ fn group_blocks(lines: &[TextLine]) -> Vec<TextBlock> {
&& g < l.size * 2.5
&& gap.is_none_or(|first| (g - first).abs() < first * 0.2)
});
if joins && let Some(b) = blocks.last_mut() {
let prev = &lines[*b.lines.last().expect("non-empty")];
if joins
&& let Some(b) = blocks.last_mut()
&& let Some(&p) = b.lines.last()
{
let prev = &lines[p];
gap.get_or_insert(prev.origin.baseline - l.origin.baseline);
if b.text.ends_with('-') {
b.text.pop();
@@ -643,8 +648,7 @@ pub fn rewrite_block(doc: &mut Document, page: usize, block: usize, text: Option
let wrapped = wrap(&text, width + 0.5, advance);
let mut substituted = None;
let new_font = !reuse;
let (show_font, encode): (String, Encoder) = if reuse {
let m = metrics.clone().expect("checked");
let (show_font, encode): (String, Encoder) = if let Some(m) = metrics.clone().filter(|_| reuse) {
(font_name.clone(), Box::new(move |s: &str| m.encode(s)))
} else {
let win = printcraft_fonts::win_ansi(&text);
+4 -1
View File
@@ -9,6 +9,8 @@
//! Import merges: a comment whose name (`/NM`) already exists on its page replaces it; field
//! values go through the form's own checks (formats, validation) and recalculate.
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
use std::collections::HashMap;
use std::fmt::Write as _;
@@ -389,7 +391,8 @@ pub fn export_fdf(doc: &Document, comments: bool, fields: bool, file: &str) -> V
}
let keys: Vec<Vec<u8>> = d.iter().filter(|(_, v)| matches!(v, Object::Ref(_))).map(|(k, _)| k.clone()).collect();
for k in keys {
let v = (*doc.resolve(d.get(&k).expect("listed"))).clone();
let Some(o) = d.get(&k) else { continue };
let v = (*doc.resolve(o)).clone();
if matches!(v, Object::Stream(_)) {
d.remove(&k);
} else {