mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-12 17:31:35 +00:00
fix(fonts): a CMap's codespace ranges are at most four bytes and listed once
This commit is contained in:
1 parent
9ce6d89f46
commit
217effb1b2
2 files changed
+15
-1
No files matched your search
@@ -564,6 +564,7 @@ fn number(t: &Tok) -> Option<u32> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn parse_cmap(data: &[u8]) -> (Vec<(usize, Vec<u8>, Vec<u8>)>, Vec<(u32, u32, u32)>) {
|
||||
let (mut spaces, mut cids) = (Vec::new(), Vec::new());
|
||||
let mut seen = HashSet::new();
|
||||
let mut toks = Lexer::new(data);
|
||||
while let Some(t) = toks.next() {
|
||||
match t {
|
||||
@@ -571,7 +572,10 @@ fn parse_cmap(data: &[u8]) -> (Vec<(usize, Vec<u8>, Vec<u8>)>, Vec<(u32, u32, u3
|
||||
while let Some([lo, hi]) = entry(&mut toks, b"endcodespacerange") {
|
||||
if let (Tok::Hex(Some(lo)), Tok::Hex(Some(hi))) = (lo, hi)
|
||||
&& lo.len() == hi.len()
|
||||
// A code is at most four bytes; a repeated range can never match first, so it only costs every glyph a comparison.
|
||||
&& (1..=4).contains(&lo.len())
|
||||
&& spaces.len() < MAX_CMAP_RANGES
|
||||
&& seen.insert((lo.clone(), hi.clone()))
|
||||
{
|
||||
spaces.push((lo.len(), lo, hi));
|
||||
}
|
||||
@@ -654,7 +658,7 @@ impl Metrics {
|
||||
m.code_len = match &m.codes {
|
||||
Codes::One => 1,
|
||||
Codes::Two => 2,
|
||||
Codes::Ranges(r) => r.last().map_or(2, |x| x.0),
|
||||
Codes::Ranges(r) => r.last().map_or(2, |x| x.0.clamp(1, 4)),
|
||||
};
|
||||
m.unicode = unicode_map(doc, font, m.composite);
|
||||
if m.std14.is_some() {
|
||||
|
||||
@@ -795,3 +795,13 @@ fn low_codes_resolve_to_the_covering_range() {
|
||||
assert_eq!(covered, [5, 6, 7, 100, 101]);
|
||||
assert_eq!((u.covering(0xFFFF).is_some(), u.covering(0x1_0001).is_some(), u.covering(0x1_0002).is_none()), (true, true, true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn codespaces_are_deduplicated_and_at_most_four_bytes() {
|
||||
let cmap = "3 begincodespacerange <00> <7F> <00> <7F> <0000000000> <FFFFFFFFFF> endcodespacerange";
|
||||
let (spaces, _) = parse_cmap(cmap.as_bytes());
|
||||
assert_eq!(spaces, vec![(1, vec![0x00], vec![0x7F])]);
|
||||
let many: String = (0..2000).map(|_| "<0000> <FFFF>\n").collect();
|
||||
let (spaces, _) = parse_cmap(format!("2000 begincodespacerange\n{many}endcodespacerange").as_bytes());
|
||||
assert_eq!(spaces.len(), 1);
|
||||
}
|
||||
Reference in new issue
Block a user