Merge pull request #1931 from storytold/fix/sec-pdf-link-bytes

fix(pdf): drop an oversized hyperlink before it is copied once per line
This commit is contained in:
BFlat authored and GitHub committed 2026-11-07 10:31:12 +08:00
commit 03a7256447
2 files changed
+20 -1

No files matched your search

+17
View File
@@ -284,3 +284,20 @@ fn depth_samples() {
std::fs::write(format!("{stem}-{name}.png"), figcraft_render::encode_png(&pix).unwrap()).unwrap();
}
}
#[test]
fn an_oversized_link_is_dropped_before_it_is_copied_per_line() {
// One link far past MAX_URL on text that wraps onto many lines: no annotation, and the
// destination is never copied once per line on the way to being refused.
let mut d = Document::new("long link");
let p = d.first_page().unwrap_or(NodeId(0));
let f = d.create(p, NodeKind::Frame, "F", 0.0, 0.0, 300.0, 4000.0).unwrap();
let words = "word ".repeat(2_000);
let mut td = TextData::new(words.trim_end());
td.style.font_size = 20.0;
td.style.link = Some("https://example.com/".to_string() + &"a".repeat(1 << 20));
let t = d.create(f, NodeKind::Text(td), "T", 10.0, 10.0, 280.0, 3980.0).unwrap();
d.get_mut(t).unwrap().fills = vec![Paint::solid(Color::BLACK)];
let pdf = export_pdf(&d, &[f], &PdfOptions::default()).unwrap();
assert_eq!(text(&pdf).matches("/Subtype/Link").count(), 0);
}
+3 -1
View File
@@ -121,7 +121,9 @@ fn record_links(ex: &mut Exporter, layout: &TextLayout, gxf: Affine) {
let glyphs = layout.glyphs.get(line.glyph_start..line.glyph_end).unwrap_or(&[]);
for g in glyphs.iter().map(Some).chain([None]) {
let link = g.and_then(|g| {
let url = layout.styles.get(g.style)?.link.as_deref().filter(|u| !u.trim().is_empty())?;
// Checked here, not when the annotation is written: every linked line copies
// the destination, so one oversized link must not be copied at all.
let url = layout.styles.get(g.style)?.link.as_deref().map(str::trim).filter(|u| !u.is_empty() && u.len() <= crate::MAX_URL)?;
let (a, b) = (g.x, g.x + g.advance);
(a.is_finite() && b.is_finite()).then(|| (url, a.min(b), a.max(b)))
});