From 5c8778a16175eb620789560bcef20b9cca38433f Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 15 Feb 2024 07:44:22 -0500 Subject: [PATCH] LibPDF/CFF: Compute per-glyph glyph width in CID-keyed fonts Make TopDict's defaultWidthX and nominalWidthX Optional<>s so that we can check if they're set per fdselect-selected font dict, and if so use the value from there in CID-keyed fonts. Otherwise, keep using the value in the top dict. --- Userland/Libraries/LibPDF/Fonts/CFF.cpp | 24 +++++++++++++++++------- Userland/Libraries/LibPDF/Fonts/CFF.h | 4 ++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Userland/Libraries/LibPDF/Fonts/CFF.cpp b/Userland/Libraries/LibPDF/Fonts/CFF.cpp index d413bf2519..d7f525da6f 100644 --- a/Userland/Libraries/LibPDF/Fonts/CFF.cpp +++ b/Userland/Libraries/LibPDF/Fonts/CFF.cpp @@ -214,24 +214,34 @@ PDFErrorOr> CFF::create(ReadonlyBytes const& cff_bytes, RefPt } // CFF spec, "18 CID-keyed Fonts" + Vector font_dicts; if (top_dict.fdarray_offset != 0) { Reader fdarray_reader { cff_bytes.slice(top_dict.fdarray_offset) }; - auto font_dicts = TRY(parse_top_dicts(fdarray_reader, cff_bytes)); + font_dicts = TRY(parse_top_dicts(fdarray_reader, cff_bytes)); dbgln_if(CFF_DEBUG, "CFF has {} FDArray entries", font_dicts.size()); } // CFF spec, "19 FDSelect" + Vector fdselect; if (top_dict.fdselect_offset != 0) { - auto fdselect = TRY(parse_fdselect(Reader { cff_bytes.slice(top_dict.fdselect_offset) }, glyphs.size())); + fdselect = TRY(parse_fdselect(Reader { cff_bytes.slice(top_dict.fdselect_offset) }, glyphs.size())); dbgln_if(CFF_DEBUG, "CFF has {} FDSelect entries", fdselect.size()); } // Adjust glyphs' widths as they are deltas from nominalWidthX - for (auto& glyph : glyphs) { - if (!glyph.has_width()) - glyph.set_width(top_dict.defaultWidthX); - else - glyph.set_width(glyph.width() + top_dict.nominalWidthX); + for (size_t glyph_id = 0; glyph_id < glyphs.size(); glyph_id++) { + auto& glyph = glyphs[glyph_id]; + if (!glyph.has_width()) { + auto default_width = top_dict.defaultWidthX.value_or(0.0f); + if (top_dict.is_cid_keyed) + default_width = font_dicts[fdselect[glyph_id]].defaultWidthX.value_or(default_width); + glyph.set_width(default_width); + } else { + auto nominal_width = top_dict.nominalWidthX.value_or(0.0f); + if (top_dict.is_cid_keyed) + nominal_width = font_dicts[fdselect[glyph_id]].nominalWidthX.value_or(nominal_width); + glyph.set_width(glyph.width() + nominal_width); + } } for (size_t i = 0; i < glyphs.size(); i++) { diff --git a/Userland/Libraries/LibPDF/Fonts/CFF.h b/Userland/Libraries/LibPDF/Fonts/CFF.h index 0228009b6a..de5355c526 100644 --- a/Userland/Libraries/LibPDF/Fonts/CFF.h +++ b/Userland/Libraries/LibPDF/Fonts/CFF.h @@ -124,8 +124,8 @@ public: int encoding_offset = 0; int charstrings_offset = 0; Vector local_subroutines; - float defaultWidthX = 0; - float nominalWidthX = 0; + Optional defaultWidthX; + Optional nominalWidthX; bool is_cid_keyed = false; int fdselect_offset = 0; int fdarray_offset = 0;