refactor(text): share source font names and selection defaults

Reuse the existing subset-tag parser through the engine facade and share the fallback formatting state.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
This commit is contained in:
FredAppsandCodex GPT-6.1 committed 2026-11-01 12:54:52 +01:00
1 parent d08097f286
commit f62c1cfafe
5 files changed
+31 -37

No files matched your search

+1
View File
@@ -35,6 +35,7 @@ pub type Rgb = [f64; 3];
pub mod backdrop;
pub use backdrop::{Backdrop, backdrops_left_off, page_backdrop, page_backdrops};
pub use text::strip_subset_tag;
mod background;
pub use background::page_background;
pub mod objects;
+2 -1
View File
@@ -24,6 +24,7 @@ use crate::EditError;
mod regions;
#[path = "text_session.rs"]
mod session;
pub use fallback::strip_subset_tag;
use regions::{alignment_frame, group_blocks, is_centred, rewrite_styled_block};
pub use session::TextSession;
@@ -47,7 +48,7 @@ pub use editor::{TextEditLayout, TextEditorFont, register_text_font, text_edit_l
pub(crate) use fallback::SOURCE_SPACE_CALLS;
use fallback::{
MAX_TYPE3_GLYPHS, Type3Glyph, fallback_face, needs_type3, no_fallback_font, no_glyph_for, same_base_font, same_font, source_encodes,
source_family, source_program, source_show, source_space, source_width, strip_subset_tag, type3_faces, type3_glyph, write_type3_glyphs,
source_family, source_program, source_show, source_space, source_width, type3_faces, type3_glyph, write_type3_glyphs,
};
#[cfg(test)]
use fallback::{add_type3_font, is_type3_fallback};
+1 -1
View File
@@ -163,7 +163,7 @@ pub(crate) fn same_base_font(a: &str, b: &str) -> bool {
}
/// `ABCDEF+Arial` → `Arial`. A name without a subset tag is returned unchanged.
pub(crate) fn strip_subset_tag(name: &str) -> &str {
pub fn strip_subset_tag(name: &str) -> &str {
let bytes = name.as_bytes();
let is_tag = bytes.get(6) == Some(&b'+') && bytes.get(..6).is_some_and(|tag| tag.iter().all(u8::is_ascii_uppercase));
if is_tag { name.get(7..).unwrap_or(name) } else { name }
+1
View File
@@ -65,6 +65,7 @@ use std::sync::Arc;
pub use links::{
MAX_REMOTE_DOCUMENT_BYTES, RemoteDocumentPathError, read_remote_document, remote_document_path_is_absolute, resolve_remote_document_path,
};
pub use pdfcraft_edit::strip_subset_tag;
pub use signature_image::{ImageSignaturePreview, SignatureImage};
pub use signature_scan::{PhotoRect, ScanError, SignaturePhoto, Turn};
pub use stamp_preview::{CommentLayer, StampPreview};
+26 -35
View File
@@ -240,10 +240,7 @@ impl LineEditor {
}
let base = self.source.as_ref().map(|(block, _)| block.base_font.as_str()).unwrap_or_default();
// "ABCDEF+Calibri" is a subset of Calibri.
let name = match base.split_once('+') {
Some((tag, rest)) if tag.len() == 6 && tag.bytes().all(|b| b.is_ascii_uppercase()) => rest,
_ => base,
};
let name = pdfcraft_engine::strip_subset_tag(base);
if name.is_empty() { tl!("Keep source fonts").to_string() } else { name.to_string() }
}
@@ -363,16 +360,20 @@ impl LineEditor {
self.original = self.text.clone();
}
fn current_formatting(&self, sources: &[(String, String)]) -> SelectionFormatting {
SelectionFormatting {
font_shown: self.font_shown(sources),
size: Some(self.look.size),
family: Some(self.look.family),
bold: Some(self.look.bold),
italic: Some(self.look.italic),
color: Some(self.look.color),
}
}
pub fn selection_formatting(&self, sources: &[(String, String)]) -> SelectionFormatting {
let Some((block, lines)) = &self.source else {
return SelectionFormatting {
font_shown: self.font_shown(sources),
size: Some(self.look.size),
family: Some(self.look.family),
bold: Some(self.look.bold),
italic: Some(self.look.italic),
color: Some(self.look.color),
};
return self.current_formatting(sources);
};
let spans = block.edited_spans(&self.text);
@@ -383,26 +384,16 @@ impl LineEditor {
_ => spans.iter().filter_map(|(_, idx)| lines.get(*idx)).collect(),
};
if matching_lines.is_empty() {
return SelectionFormatting {
font_shown: self.font_shown(sources),
size: Some(self.look.size),
family: Some(self.look.family),
bold: Some(self.look.bold),
italic: Some(self.look.italic),
color: Some(self.look.color),
};
}
let Some(first) = matching_lines.first().copied() else {
return self.current_formatting(sources);
};
let line_font = |l: &pdfcraft_engine::TextLine| -> String {
if let Some((_, face)) = sources.iter().find(|(res, _)| res == &l.font) {
return face.clone();
}
let base = l.base_font.as_str();
let name = match base.split_once('+') {
Some((tag, rest)) if tag.len() == 6 && tag.bytes().all(|b| b.is_ascii_uppercase()) => rest,
_ => base,
};
let name = pdfcraft_engine::strip_subset_tag(base);
if let Some((_, face)) = sources.iter().find(|(_, face)| face.as_str() == name) {
return face.clone();
}
@@ -414,7 +405,7 @@ impl LineEditor {
if name.is_empty() { tl!("Keep source fonts").to_string() } else { name.to_string() }
};
let first_font = line_font(matching_lines[0]);
let first_font = line_font(first);
let same_font = matching_lines.iter().skip(1).all(|l| line_font(l) == first_font);
let font_shown = if same_font {
if self.font_resource.is_some() || self.look.family != self.look0.family || self.family_chosen {
@@ -426,19 +417,19 @@ impl LineEditor {
tl!("Mixed").to_string()
};
let first_size = (matching_lines[0].size * 10.0).round() / 10.0;
let first_size = (first.size * 10.0).round() / 10.0;
let same_size = matching_lines.iter().skip(1).all(|l| ((l.size * 10.0).round() / 10.0 - first_size).abs() < 0.05);
let size = if same_size { Some(first_size) } else { None };
let first_look = look_of_line(matching_lines[0]);
let first_look = look_of_line(first);
let same_family = matching_lines.iter().skip(1).all(|l| look_of_line(l).family == first_look.family);
let family = if same_family { Some(first_look.family) } else { None };
let same_bold = matching_lines.iter().skip(1).all(|l| l.bold == matching_lines[0].bold);
let bold = if same_bold { Some(matching_lines[0].bold) } else { None };
let same_italic = matching_lines.iter().skip(1).all(|l| l.italic == matching_lines[0].italic);
let italic = if same_italic { Some(matching_lines[0].italic) } else { None };
let same_color = matching_lines.iter().skip(1).all(|l| l.color == matching_lines[0].color);
let color = if same_color { Some(matching_lines[0].color) } else { None };
let same_bold = matching_lines.iter().skip(1).all(|l| l.bold == first.bold);
let bold = if same_bold { Some(first.bold) } else { None };
let same_italic = matching_lines.iter().skip(1).all(|l| l.italic == first.italic);
let italic = if same_italic { Some(first.italic) } else { None };
let same_color = matching_lines.iter().skip(1).all(|l| l.color == first.color);
let color = if same_color { Some(first.color) } else { None };
SelectionFormatting { font_shown, size, family, bold, italic, color }
}