From a04e20dbb6a88e590e31fcbf54b98f7fde5ece81 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Mon, 9 Nov 2026 01:05:47 +0700 Subject: [PATCH] Grouped Thai text writes its Type 3 fonts through shaped_text The grouped-text writer that landed in #6627 called Add text's old type3_shaped, which this branch moved into pdfcraft_fonts::shaped_text. shaped_text now offers add_type3_font, so both share one writer. --- crates/edit/src/added/draw.rs | 19 ++++++++++++------- crates/fonts/src/shaped_text.rs | 11 +++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/crates/edit/src/added/draw.rs b/crates/edit/src/added/draw.rs index 2506adccf5..8e0ec75791 100644 --- a/crates/edit/src/added/draw.rs +++ b/crates/edit/src/added/draw.rs @@ -253,9 +253,9 @@ pub(crate) fn thai_glyph_resources( if shaped.glyphs.len() > 65_534 { return Err(EditError::Invalid("shaped row exceeds its geometry budget".into())); } - let mut outlines = HashMap::new(); + let mut outlines = std::collections::HashMap::new(); let mut clusters = Vec::new(); - let mut index = HashMap::new(); + let mut index = std::collections::HashMap::new(); let mut indices = Vec::new(); for glyph in &shaped.glyphs { let id = glyph.id.to_u32(); @@ -266,7 +266,12 @@ pub(crate) fn thai_glyph_resources( let at = *index.entry((id, glyph.text.as_str())).or_insert_with(|| { let at = clusters.len(); let width = outlines.get(&key).map_or(0.0, |g| g.width); - clusters.push(ShapedCluster { script: ShapedScript::Thai, glyphs: vec![(id, [0.0, 0.0])], advance: width, text: glyph.text.clone() }); + clusters.push(pdfcraft_fonts::ShapedCluster { + script: ShapedScript::Thai, + glyphs: vec![(id, [0.0, 0.0])], + advance: width, + text: glyph.text.clone(), + }); at }); indices.push(at); @@ -274,9 +279,9 @@ pub(crate) fn thai_glyph_resources( // Validate all outlines before adding resources. Type 3 character codes are single bytes; // shard long rows and return the appropriate resource/code for every positioned glyph. let mut names = Vec::new(); - for chunk in clusters.chunks(GLYPHS_PER_FONT) { + for chunk in clusters.chunks(shaped_text::GLYPHS_PER_FONT) { let refs: Vec<_> = chunk.iter().collect(); - let font = type3_shaped(doc, &refs, &outlines); + let font = shaped_text::add_type3_font(doc, &refs, &outlines); doc.update_dict(font, |f| f.set(b"Name".to_vec(), Object::name("PCThai")))?; let mut name = format!("PCThai{}", font.num); while fonts.contains(name.as_bytes()) { @@ -288,8 +293,8 @@ pub(crate) fn thai_glyph_resources( indices .into_iter() .map(|at| { - let name = names.get(at / GLYPHS_PER_FONT).ok_or_else(|| EditError::Invalid("Thai font resource is missing".into()))?; - let code = u8::try_from(at % GLYPHS_PER_FONT + 1).map_err(|_| EditError::Invalid("Thai glyph limit".into()))?; + let name = names.get(at / shaped_text::GLYPHS_PER_FONT).ok_or_else(|| EditError::Invalid("Thai font resource is missing".into()))?; + let code = u8::try_from(at % shaped_text::GLYPHS_PER_FONT + 1).map_err(|_| EditError::Invalid("Thai glyph limit".into()))?; Ok((name.clone(), vec![code])) }) .collect() diff --git a/crates/fonts/src/shaped_text.rs b/crates/fonts/src/shaped_text.rs index 7dbc900fa6..c85de92f64 100644 --- a/crates/fonts/src/shaped_text.rs +++ b/crates/fonts/src/shaped_text.rs @@ -292,6 +292,17 @@ pub fn thai_refusal(text: &str) -> Option { text.split(['\n', '\r']).filter(|l| l.chars().any(is_thai)).find_map(|l| thai_pieces(l).err().map(|e| thai_message(e, l))) } +/// [`type3_font`] written into `doc`, with its glyphs, descriptor and ToUnicode as objects of their +/// own: for content that draws `clusters` (at most [`GLYPHS_PER_FONT`]) as codes 1… directly. +pub fn add_type3_font( + doc: &mut Document, + clusters: &[&ShapedCluster], + outlines: &HashMap<(ShapedScript, u32), GlyphOutline>, +) -> pdfcraft_cos::ObjRef { + let font = type3_font(clusters, outlines, &mut |o| Object::Ref(doc.add(o))); + doc.add(Object::Dict(font)) +} + /// A Type 3 font with `clusters` as codes 1…, each drawn from its script face's glyph `outlines`. fn type3_font(clusters: &[&ShapedCluster], outlines: &HashMap<(ShapedScript, u32), GlyphOutline>, store: &mut dyn FnMut(Object) -> Object) -> Dict { let mut charprocs = Dict::new();