LibPDF: Move Type1FontProgram to use AK::Error instead of PDF::Error

Makes some of the errors a bit less descriptive. But this is pretty
stable by now and the errors fire basically never, so that seems ok.

Needing the explicit `AK::` prefix is a bit awkward, but that'll go
away once this class moves out of LibPDF.

Move error() into the two subclasses. I'll remove it from CFF in
a follow-up.

No real behavior change.
This commit is contained in:
Nico Weber 2024-04-14 09:08:47 -04:00 committed by Andreas Kling
commit 102ac331c6
Notes: sideshowbarker 2024-07-17 04:10:16 +09:00
6 changed files with 62 additions and 39 deletions

View file

@ -1144,4 +1144,20 @@ PDFErrorOr<CFF::DictOperand> CFF::load_dict_operand(u8 b0, Stream& reader)
return Error { Error::Type::MalformedPDF, ByteString::formatted("Unknown CFF dict element prefix: {}", b0) }; return Error { Error::Type::MalformedPDF, ByteString::formatted("Unknown CFF dict element prefix: {}", b0) };
} }
Error CFF::error(
ByteString const& message
#ifdef PDF_DEBUG
,
SourceLocation loc
#endif
)
{
#ifdef PDF_DEBUG
dbgln("\033[31m{} Type 1 font error: {}\033[0m", loc, message);
#endif
return Error { Error::Type::MalformedPDF, message };
}
} }

View file

@ -137,6 +137,14 @@ public:
static PDFErrorOr<Vector<SID>> parse_charset(Stream&&, size_t); static PDFErrorOr<Vector<SID>> parse_charset(Stream&&, size_t);
static PDFErrorOr<Vector<u8>> parse_fdselect(Stream&&, size_t); static PDFErrorOr<Vector<u8>> parse_fdselect(Stream&&, size_t);
static PDFErrorOr<Vector<u8>> parse_encoding(Stream&&, HashMap<Card8, SID>& supplemental); static PDFErrorOr<Vector<u8>> parse_encoding(Stream&&, HashMap<Card8, SID>& supplemental);
static Error error(
ByteString const& message
#ifdef PDF_DEBUG
,
SourceLocation loc = SourceLocation::current()
#endif
);
}; };
} }

View file

@ -237,4 +237,19 @@ bool PS1FontProgram::seek_name(Reader& reader, ByteString const& name)
return false; return false;
} }
Error PS1FontProgram::error(
ByteString const& message
#ifdef PDF_DEBUG
,
SourceLocation loc
#endif
)
{
#ifdef PDF_DEBUG
dbgln("\033[31m{} Type 1 font error: {}\033[0m", loc, message);
#endif
return Error { Error::Type::MalformedPDF, message };
}
} }

View file

@ -23,6 +23,14 @@ public:
static PDFErrorOr<NonnullRefPtr<Type1FontProgram>> create(ReadonlyBytes const&, RefPtr<Encoding>, size_t cleartext_length, size_t encrypted_length); static PDFErrorOr<NonnullRefPtr<Type1FontProgram>> create(ReadonlyBytes const&, RefPtr<Encoding>, size_t cleartext_length, size_t encrypted_length);
private: private:
static Error error(
ByteString const& message
#ifdef PDF_DEBUG
,
SourceLocation loc = SourceLocation::current()
#endif
);
PDFErrorOr<void> parse_encrypted_portion(ByteBuffer const&); PDFErrorOr<void> parse_encrypted_portion(ByteBuffer const&);
PDFErrorOr<Vector<ByteBuffer>> parse_subroutines(Reader&) const; PDFErrorOr<Vector<ByteBuffer>> parse_subroutines(Reader&) const;
static PDFErrorOr<Vector<float>> parse_number_array(Reader&, size_t length); static PDFErrorOr<Vector<float>> parse_number_array(Reader&, size_t length);

View file

@ -136,14 +136,14 @@ void Type1FontProgram::consolidate_glyphs()
} }
} }
PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes const& data, Vector<ByteBuffer> const& local_subroutines, Vector<ByteBuffer> const& global_subroutines, GlyphParserState& state, bool is_type2) ErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes const& data, Vector<ByteBuffer> const& local_subroutines, Vector<ByteBuffer> 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 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 // Type 2 Charstring Format: https://adobe-type-tools.github.io/font-tech-notes/pdfs/5177.Type2.pdf
auto push = [&](float value) -> PDFErrorOr<void> { auto push = [&](float value) -> ErrorOr<void> {
if (state.sp >= state.stack.size()) if (state.sp >= state.stack.size())
return error("Operand stack overflow"); return AK::Error::from_string_literal("Operand stack overflow");
state.stack[state.sp++] = value; state.stack[state.sp++] = value;
return {}; return {};
}; };
@ -260,9 +260,9 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
// Parse the stream of parameters and commands that make up a glyph outline. // Parse the stream of parameters and commands that make up a glyph outline.
for (size_t i = 0; i < data.size(); ++i) { for (size_t i = 0; i < data.size(); ++i) {
auto require = [&](unsigned num) -> PDFErrorOr<void> { auto require = [&](unsigned num) -> ErrorOr<void> {
if (i + num >= data.size()) if (i + num >= data.size())
return error("Malformed glyph outline definition"); return AK::Error::from_string_literal("Malformed glyph outline definition");
return {}; return {};
}; };
@ -299,7 +299,7 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
i += 2; i += 2;
TRY(push(a)); TRY(push(a));
} else { } else {
return error("CFF Subr command 28 only valid in type2 data"); return AK::Error::from_string_literal("CFF Subr command 28 only valid in type2 data");
} }
} else { } else {
// Not a parameter but a command byte. // Not a parameter but a command byte.
@ -389,7 +389,7 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
case CallGsubr: case CallGsubr:
if (!is_type2) if (!is_type2)
return error(ByteString::formatted("CFF Gsubr only valid in type2 data")); return AK::Error::from_string_literal("CFF Gsubr only valid in type2 data");
[[fallthrough]]; [[fallthrough]];
case CallSubr: { case CallSubr: {
Vector<ByteBuffer> const& subroutines = v == CallSubr ? local_subroutines : global_subroutines; Vector<ByteBuffer> const& subroutines = v == CallSubr ? local_subroutines : global_subroutines;
@ -410,11 +410,11 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
} }
if (static_cast<size_t>(subr_number) >= subroutines.size()) if (static_cast<size_t>(subr_number) >= subroutines.size())
return error("Subroutine index out of range"); return AK::Error::from_string_literal("Subroutine index out of range");
auto const& subr = subroutines[subr_number]; auto const& subr = subroutines[subr_number];
if (subr.is_empty()) if (subr.is_empty())
return error("Empty subroutine"); return AK::Error::from_string_literal("Empty subroutine");
TRY(parse_glyph(subr, local_subroutines, global_subroutines, state, is_type2)); TRY(parse_glyph(subr, local_subroutines, global_subroutines, state, is_type2));
break; break;
@ -483,7 +483,7 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
switch ((OtherSubrCommand)othersubr_number) { switch ((OtherSubrCommand)othersubr_number) {
case EndFlex: { case EndFlex: {
if (n != 3) if (n != 3)
return error("Unexpected argument code for othersubr 0"); return AK::Error::from_string_literal("Unexpected argument code for othersubr 0");
auto y = pop(); auto y = pop();
auto x = pop(); auto x = pop();
@ -512,14 +512,14 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
} }
case StartFlex: case StartFlex:
if (n != 0) if (n != 0)
return error("Unexpected argument code for othersubr 1"); return AK::Error::from_string_literal("Unexpected argument code for othersubr 1");
state.flex_feature = true; state.flex_feature = true;
state.flex_index = 0; state.flex_index = 0;
state.sp = 0; state.sp = 0;
break; break;
case AddFlexPoint: case AddFlexPoint:
if (n != 0) if (n != 0)
return error("Unexpected argument code for othersubr 2"); return AK::Error::from_string_literal("Unexpected argument code for othersubr 2");
// We do this directly in move_to(). // We do this directly in move_to().
state.sp = 0; state.sp = 0;
break; break;
@ -633,7 +633,7 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
default: default:
dbgln("Unhandled command: 12 {}", data[i]); dbgln("Unhandled command: 12 {}", data[i]);
return error("Unhandled command"); return AK::Error::from_string_literal("Unhandled command");
} }
break; break;
} }
@ -747,19 +747,4 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
return state.glyph; return state.glyph;
} }
Error Type1FontProgram::error(
ByteString const& message
#ifdef PDF_DEBUG
,
SourceLocation loc
#endif
)
{
#ifdef PDF_DEBUG
dbgln("\033[31m{} Type 1 font error: {}\033[0m", loc, message);
#endif
return Error { Error::Type::MalformedPDF, message };
}
} }

View file

@ -11,7 +11,6 @@
#include <LibGfx/Font/Font.h> #include <LibGfx/Font/Font.h>
#include <LibGfx/Path.h> #include <LibGfx/Path.h>
#include <LibPDF/Encoding.h> #include <LibPDF/Encoding.h>
#include <LibPDF/Error.h>
namespace PDF { namespace PDF {
@ -90,15 +89,7 @@ protected:
bool is_first_command { true }; bool is_first_command { true };
}; };
static PDFErrorOr<Glyph> parse_glyph(ReadonlyBytes const&, Vector<ByteBuffer> const& local_subroutines, Vector<ByteBuffer> const& global_subroutines, GlyphParserState&, bool is_type2); static ErrorOr<Glyph> parse_glyph(ReadonlyBytes const&, Vector<ByteBuffer> const& local_subroutines, Vector<ByteBuffer> const& global_subroutines, GlyphParserState&, bool is_type2);
static Error error(
ByteString const& message
#ifdef PDF_DEBUG
,
SourceLocation loc = SourceLocation::current()
#endif
);
void set_encoding(RefPtr<Encoding>&& encoding) void set_encoding(RefPtr<Encoding>&& encoding)
{ {
@ -110,7 +101,7 @@ protected:
m_font_matrix = move(font_matrix); m_font_matrix = move(font_matrix);
} }
PDFErrorOr<void> add_glyph(DeprecatedFlyString name, Glyph&& glyph) ErrorOr<void> add_glyph(DeprecatedFlyString name, Glyph&& glyph)
{ {
TRY(m_glyph_map.try_set(move(name), move(glyph))); TRY(m_glyph_map.try_set(move(name), move(glyph)));
return {}; return {};