fix(pdf): blend mode inheritance for Type 3 fallback, CharProcs budget via decoded_within, and docs clarification

This commit is contained in:
ruchirguitar
2026-11-13 23:00:54 +05:30
parent 66513d47fa
commit a52890ec0f
5 changed files with 12 additions and 28 deletions
+2 -11
View File
@@ -94,14 +94,7 @@ impl Builder<'_> {
}
/// A Type 3 glyph under an active ActualText span.
pub(super) fn actual_type3_glyph(
&mut self,
key: u128,
at: Placement,
look: Look,
opacity: f32,
advance: f64,
) -> bool {
pub(super) fn actual_type3_glyph(&mut self, key: u128, at: Placement, look: Look, opacity: f32, advance: f64) -> bool {
self.flush_glyphs();
self.flush_type3();
if let (Some(stroke), Some(line)) = (&look.stroke, &mut self.text)
@@ -115,9 +108,7 @@ impl Builder<'_> {
Some(text) if !text.is_empty() => TextContent::Actual(text),
_ => TextContent::Pen,
};
let place = |line: &mut TextLine| {
line.push_content(&look, at, opacity, advance, content)
};
let place = |line: &mut TextLine| line.push_content(&look, at, opacity, advance, content);
if !self.text.as_mut().is_some_and(place) {
self.flush_text();
let mut line = TextLine::new(at, opacity);
+4 -4
View File
@@ -558,7 +558,7 @@ impl<'p> Builder<'p> {
/// Read a soft mask, pattern cell or type 3 glyph (`read`) on its own: its art, in the
/// coordinates `page` has. `None` when nested too deeply.
pub(super) fn nested(&mut self, page: Rect, read: impl FnOnce(&mut Self)) -> Option<Vec<Arc<Node>>> {
pub(super) fn nested(&mut self, page: Rect, blend: BlendMode, read: impl FnOnce(&mut Self)) -> Option<Vec<Arc<Node>>> {
if self.nested >= MAX_NESTED {
return None;
}
@@ -567,7 +567,7 @@ impl<'p> Builder<'p> {
let saved = Saved {
stack: std::mem::replace(&mut self.stack, vec![Frame::new(FrameKind::Root)]),
root_groups: std::mem::take(&mut self.root_groups),
blend: std::mem::replace(&mut self.blend, BlendMode::Normal),
blend: std::mem::replace(&mut self.blend, blend),
mask: self.mask.take(),
page: std::mem::replace(&mut self.page, page),
type3_run: outer_type3,
@@ -589,7 +589,7 @@ impl<'p> Builder<'p> {
}
let page = self.page;
let saved = std::mem::replace(&mut self.white_images, m.mask_type() == MaskType::Alpha);
let art = self.nested(page, |b| m.interpret(b));
let art = self.nested(page, BlendMode::Normal, |b| m.interpret(b));
self.white_images = saved;
let spec = match art {
Some(art) => {
@@ -653,7 +653,7 @@ impl<'p> Builder<'p> {
// A swatch is shared with uses outside an alpha mask, and pattern paints keep their
// colours there: its images are read as they are.
let white = std::mem::take(&mut self.white_images);
let art = self.nested(Rect::ZERO, |b| {
let art = self.nested(Rect::ZERO, BlendMode::Normal, |b| {
// A cell whose content can't be decoded is empty.
let _ = t.interpret(b, Affine::IDENTITY, stroke);
});
+1 -1
View File
@@ -225,7 +225,7 @@ impl<'a> Device<'a> for Builder<'_> {
}
self.flush_glyphs();
self.flush_text();
let art = self.nested(self.page, |b| {
let art = self.nested(self.page, self.blend, |b| {
t3.interpret(b, transform, glyph_transform, paint);
});
if let Some(nodes) = art {
+2 -9
View File
@@ -678,7 +678,7 @@ impl Walker<'_, '_> {
colour = true;
break;
}
if let Ok(data) = stream.decoded() {
if let Ok(data) = stream.decoded_within(MAX_CHARPROC_BYTES.saturating_sub(decoded_bytes)) {
decoded_bytes = decoded_bytes.saturating_add(data.len());
let mut iter = TypedIter::new(data.as_ref());
while let Some(op) = iter.next() {
@@ -704,14 +704,7 @@ impl Walker<'_, '_> {
};
self.fonts.entry(f_key).or_insert_with(|| {
let embedded = embeds_glyphs(&f);
FontNote {
name,
embedded,
vertical: vertical_metrics(&f, embedded),
is_type3,
to_unicode,
is_colour,
}
FontNote { name, embedded, vertical: vertical_metrics(&f, embedded), is_type3, to_unicode, is_colour }
});
}
}
+3 -3
View File
File diff suppressed because one or more lines are too long