mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-03 17:24:42 +00:00
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:
1 parent
d08097f286
commit
f62c1cfafe
5 files changed
+31
-37
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user