From 1c2b0feb7b59f58a34d24856c9491248ef3c71ed Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 13 Nov 2023 21:22:56 -0500 Subject: [PATCH] LibPDF: Change how CFF optional width prefix is stored Per 5177.Type2.pdf 3.1 "Type 2 Charstring Organization", a glyph's charstring looks like: w? {hs* vs* cm* hm* mt subpath}? {mt subpath}* endchar The `w?` is the width of the glyph, but it's optional. So all possible commands after it (hstem* vstem* cntrmask hintmask moveto endchar) check if there's an extra number at the start and interpret it as a width, for the very first command we read. This was done by having an `is_first_command` local bool that got set to false after the first command. That didn't work with subrs: If the first command was a call to a subr that just pushed a bunch of numbers, then the second command after it is the actual first command. Instead, move that bool into the state. Set it to false the first time we try to read a width, since that means we just read a command that could've been prefixed by a width. --- Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp | 9 ++++----- Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp b/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp index b325b97dc0..8a94bf9290 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp +++ b/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp @@ -244,15 +244,16 @@ PDFErrorOr Type1FontProgram::parse_glyph(ReadonlyBytes }; // Potential font width parsing for some commands (type2 only) - bool is_first_command = true; enum EvenOrOdd { Even, Odd }; auto maybe_read_width = [&](EvenOrOdd required_argument_count) { - if (!is_type2 || !is_first_command || state.sp % 2 != required_argument_count) + if (!is_type2 || !state.is_first_command) return; - state.glyph.set_width(pop_front()); + state.is_first_command = false; + if (state.sp % 2 == required_argument_count) + state.glyph.set_width(pop_front()); }; // Parse the stream of parameters and commands that make up a glyph outline. @@ -717,8 +718,6 @@ PDFErrorOr Type1FontProgram::parse_glyph(ReadonlyBytes dbgln("Unhandled command: {}", v); return error("Unhandled command"); } - - is_first_command = false; } } diff --git a/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h b/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h index 714babb41d..8462e6611d 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h +++ b/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h @@ -79,6 +79,8 @@ protected: size_t postscript_sp { 0 }; Array postscript_stack; + + bool is_first_command { true }; }; static PDFErrorOr parse_glyph(ReadonlyBytes const&, Vector const& local_subroutines, Vector const& global_subroutines, GlyphParserState&, bool is_type2);