From 22932f7b68bdaf3fac7097af540cfc69e14b8429 Mon Sep 17 00:00:00 2001 From: calixteman Date: Sat, 27 Dec 2025 22:20:15 +0100 Subject: [PATCH] Fix the loca table length when there is enough space for it It fixes #13425. --- src/core/fonts.js | 39 ++++++++++++++++++++++++++--------- test/pdfs/issue13425.pdf.link | 1 + test/test_manifest.json | 8 +++++++ 3 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 test/pdfs/issue13425.pdf.link diff --git a/src/core/fonts.js b/src/core/fonts.js index 97ea14c70fd62..532896e0acbaa 100644 --- a/src/core/fonts.js +++ b/src/core/fonts.js @@ -2702,13 +2702,36 @@ class Font { writeUint32(tables.maxp.data, 0, version); } + let isGlyphLocationsLong = int16( + tables.head.data[50], + tables.head.data[51] + ); + if (tables.loca) { + const locaLength = isGlyphLocationsLong + ? (numGlyphs + 1) * 4 + : (numGlyphs + 1) * 2; + if (tables.loca.length !== locaLength) { + warn("Incorrect 'loca' table length -- attempting to fix it."); + // The length of the loca table is wrong (see #13425), so we check if we + // have enough space to fix it. + const sortedTables = Object.values(tables) + .filter(Boolean) + .sort((a, b) => a.offset - b.offset); + const locaIndex = sortedTables.indexOf(tables.loca); + const nextTable = sortedTables[locaIndex + 1] || null; + if (nextTable && tables.loca.offset + locaLength < nextTable.offset) { + const previousPos = font.pos; + font.pos = font.start || 0; + font.skip(tables.loca.offset); + tables.loca.data = font.getBytes(locaLength); + tables.loca.length = locaLength; + font.pos = previousPos; + } + } + } + if (properties.scaleFactors?.length === numGlyphs && isTrueType) { const { scaleFactors } = properties; - const isGlyphLocationsLong = int16( - tables.head.data[50], - tables.head.data[51] - ); - const glyphs = new GlyfTable({ glyfTable: tables.glyf.data, isGlyphLocationsLong, @@ -2723,7 +2746,7 @@ class Font { if (isLocationLong !== !!isGlyphLocationsLong) { tables.head.data[50] = 0; - tables.head.data[51] = isLocationLong ? 1 : 0; + isGlyphLocationsLong = tables.head.data[51] = isLocationLong ? 1 : 0; } const metrics = tables.hmtx.data; @@ -2801,10 +2824,6 @@ class Font { let missingGlyphs = Object.create(null); if (isTrueType) { - const isGlyphLocationsLong = int16( - tables.head.data[50], - tables.head.data[51] - ); const glyphsInfo = sanitizeGlyphLocations( tables.loca, tables.glyf, diff --git a/test/pdfs/issue13425.pdf.link b/test/pdfs/issue13425.pdf.link new file mode 100644 index 0000000000000..96cd322c69574 --- /dev/null +++ b/test/pdfs/issue13425.pdf.link @@ -0,0 +1 @@ +https://github.com/mozilla/pdf.js/files/6529459/20200927_204903_509.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 4ea18bc5421fc..03f53f1394729 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -13115,5 +13115,13 @@ "md5": "b85c798b9a4cc2cd4337d335321cc612", "rounds": 1, "type": "eq" + }, + { + "id": "issue13425", + "file": "pdfs/issue13425.pdf", + "md5": "36854e6ad43b8e0446d3d64e8f2950bf", + "rounds": 1, + "link": true, + "type": "eq" } ]