diff --git a/Userland/Libraries/LibPDF/Fonts/CFF.cpp b/Userland/Libraries/LibPDF/Fonts/CFF.cpp index 5169af8334..91c89393c7 100644 --- a/Userland/Libraries/LibPDF/Fonts/CFF.cpp +++ b/Userland/Libraries/LibPDF/Fonts/CFF.cpp @@ -221,11 +221,9 @@ PDFErrorOr> CFF::create(ReadonlyBytes const& cff_bytes, RefPt TRY(parse_index(reader, [&](ReadonlyBytes const& subroutine_bytes) -> PDFErrorOr { return TRY(global_subroutines.try_append(TRY(ByteBuffer::copy(subroutine_bytes)))); })); - if (!global_subroutines.is_empty()) - dbgln("CFF data contains Global subrs, which aren't implemented yet"); // FIXME // Create glyphs (now that we have the subroutines) and associate missing information to store them and their encoding - auto glyphs = TRY(parse_charstrings(Reader(cff_bytes.slice(charstrings_offset)), local_subroutines)); + auto glyphs = TRY(parse_charstrings(Reader(cff_bytes.slice(charstrings_offset)), local_subroutines, global_subroutines)); // CFF spec, "Table 16 Encoding ID" // FIXME: Only read this if the built-in encoding is actually needed? (ie. `if (!encoding)`) @@ -765,13 +763,13 @@ PDFErrorOr> CFF::parse_charset(Reader&& reader, size return names; } -PDFErrorOr> CFF::parse_charstrings(Reader&& reader, Vector const& subroutines) +PDFErrorOr> CFF::parse_charstrings(Reader&& reader, Vector const& local_subroutines, Vector const& global_subroutines) { // CFF spec, "14 CharStrings INDEX" Vector glyphs; TRY(parse_index(reader, [&](ReadonlyBytes const& charstring_data) -> PDFErrorOr { GlyphParserState state; - auto glyph = TRY(parse_glyph(charstring_data, subroutines, state, true)); + auto glyph = TRY(parse_glyph(charstring_data, local_subroutines, global_subroutines, state, true)); return TRY(glyphs.try_append(glyph)); })); return glyphs; diff --git a/Userland/Libraries/LibPDF/Fonts/CFF.h b/Userland/Libraries/LibPDF/Fonts/CFF.h index 11d0fb305a..fadb013c94 100644 --- a/Userland/Libraries/LibPDF/Fonts/CFF.h +++ b/Userland/Libraries/LibPDF/Fonts/CFF.h @@ -94,7 +94,7 @@ public: static PDFErrorOr> parse_strings(Reader&); - static PDFErrorOr> parse_charstrings(Reader&&, Vector const& subroutines); + static PDFErrorOr> parse_charstrings(Reader&&, Vector const& local_subroutines, Vector const& global_subroutines); static DeprecatedFlyString resolve_sid(SID, Vector const&); static PDFErrorOr> parse_charset(Reader&&, size_t, Vector const&); diff --git a/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp b/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp index f46f4ab673..0a40383b1a 100644 --- a/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp +++ b/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp @@ -92,7 +92,7 @@ PDFErrorOr PS1FontProgram::parse_encrypted_portion(ByteBuffer const& buffe reader.move_by(encrypted_size); auto glyph_name = word.substring_view(1); GlyphParserState state; - TRY(add_glyph(glyph_name, TRY(parse_glyph(line, subroutines, state, false)))); + TRY(add_glyph(glyph_name, TRY(parse_glyph(line, subroutines, {}, state, false)))); } } } diff --git a/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp b/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp index 8e0604f194..003ed0a150 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp +++ b/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.cpp @@ -34,7 +34,8 @@ enum Command { RLineCurve, VVCurveTo, HHCurveTo, - VHCurveTo = 30, + CallGsubr = 29, // Type 2 only + VHCurveTo, HVCurveTo }; @@ -133,7 +134,7 @@ void Type1FontProgram::consolidate_glyphs() } } -PDFErrorOr Type1FontProgram::parse_glyph(ReadonlyBytes const& data, Vector const& subroutines, GlyphParserState& state, bool is_type2) +PDFErrorOr Type1FontProgram::parse_glyph(ReadonlyBytes const& data, Vector const& local_subroutines, Vector const& global_subroutines, GlyphParserState& state, bool is_type2) { // Type 1 Font Format: https://adobe-type-tools.github.io/font-tech-notes/pdfs/T1_SPEC.pdf (Chapter 6: CharStrings dictionary) // Type 2 Charstring Format: https://adobe-type-tools.github.io/font-tech-notes/pdfs/5177.Type2.pdf @@ -371,7 +372,12 @@ PDFErrorOr Type1FontProgram::parse_glyph(ReadonlyBytes state.sp = 0; break; + case CallGsubr: + if (!is_type2) + return error(DeprecatedString::formatted("CFF Gsubr only valid in type2 data")); + [[fallthrough]]; case CallSubr: { + Vector const& subroutines = v == CallSubr ? local_subroutines : global_subroutines; auto subr_number = pop(); if (is_type2) { @@ -420,7 +426,7 @@ PDFErrorOr Type1FontProgram::parse_glyph(ReadonlyBytes if (subr.is_empty()) return error("Empty subroutine"); - TRY(parse_glyph(subr, subroutines, state, is_type2)); + TRY(parse_glyph(subr, local_subroutines, global_subroutines, state, is_type2)); } break; } diff --git a/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h b/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h index dadc9c1546..714babb41d 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h +++ b/Userland/Libraries/LibPDF/Fonts/Type1FontProgram.h @@ -81,7 +81,7 @@ protected: Array postscript_stack; }; - static PDFErrorOr parse_glyph(ReadonlyBytes const&, Vector const&, GlyphParserState&, bool is_type2); + static PDFErrorOr parse_glyph(ReadonlyBytes const&, Vector const& local_subroutines, Vector const& global_subroutines, GlyphParserState&, bool is_type2); static Error error( DeprecatedString const& message