LibPDF: Move rest of CFF from Reader to Stream

parse_index_data() wants to take ReadonlyByte views of the stream
data, so we need FixedMemoryStream::read_in_place(size_t). All
other remaining code indirectly calls parse_index_data(), so that
all operates on FixedMemoryStreams too.

No behavior change.
This commit is contained in:
Nico Weber 2024-04-13 22:05:28 -04:00 committed by Andreas Kling
commit 2b905cc482
Notes: sideshowbarker 2024-07-17 07:43:05 +09:00
2 changed files with 27 additions and 30 deletions

View file

@ -13,7 +13,6 @@
#include <LibPDF/Encoding.h> #include <LibPDF/Encoding.h>
#include <LibPDF/Error.h> #include <LibPDF/Error.h>
#include <LibPDF/Fonts/CFF.h> #include <LibPDF/Fonts/CFF.h>
#include <LibPDF/Reader.h>
namespace PDF { namespace PDF {
@ -97,15 +96,15 @@ static constexpr auto s_predefined_charset_expert_subset = to_array<CFF::SID>({
PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPtr<Encoding> encoding) PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPtr<Encoding> encoding)
{ {
Reader reader(cff_bytes); FixedMemoryStream reader(cff_bytes);
// CFF spec, "6 Header" // CFF spec, "6 Header"
// skip major, minor version // skip major, minor version
reader.consume(2); TRY(reader.discard(2));
auto header_size = TRY(reader.try_read<Card8>()); auto header_size = TRY(reader.read_value<Card8>());
// skip offset size // skip offset size
reader.consume(1); TRY(reader.discard(1));
reader.move_to(header_size); TRY(reader.seek(header_size));
// CFF spec, "7 Name INDEX" // CFF spec, "7 Name INDEX"
Vector<String> font_names; Vector<String> font_names;
@ -157,7 +156,7 @@ PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPt
dbgln_if(CFF_DEBUG, "CFF has {} gsubr entries", global_subroutines.size()); dbgln_if(CFF_DEBUG, "CFF has {} gsubr entries", global_subroutines.size());
// Create glyphs (now that we have the subroutines) and associate missing information to store them and their encoding // 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(top_dict.charstrings_offset)), top_dict.local_subroutines, global_subroutines)); auto glyphs = TRY(parse_charstrings(FixedMemoryStream(cff_bytes.slice(top_dict.charstrings_offset)), top_dict.local_subroutines, global_subroutines));
// CFF spec, "Table 16 Encoding ID" // CFF spec, "Table 16 Encoding ID"
// FIXME: Only read this if the built-in encoding is actually needed? (ie. `if (!encoding)`) // FIXME: Only read this if the built-in encoding is actually needed? (ie. `if (!encoding)`)
@ -216,7 +215,7 @@ PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPt
// CFF spec, "18 CID-keyed Fonts" // CFF spec, "18 CID-keyed Fonts"
Vector<TopDict> font_dicts; Vector<TopDict> font_dicts;
if (top_dict.fdarray_offset != 0) { if (top_dict.fdarray_offset != 0) {
Reader fdarray_reader { cff_bytes.slice(top_dict.fdarray_offset) }; FixedMemoryStream fdarray_reader { cff_bytes.slice(top_dict.fdarray_offset) };
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()); dbgln_if(CFF_DEBUG, "CFF has {} FDArray entries", font_dicts.size());
} }
@ -294,7 +293,7 @@ PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPt
return cff; return cff;
} }
PDFErrorOr<Vector<CFF::TopDict>> CFF::parse_top_dicts(Reader& reader, ReadonlyBytes const& cff_bytes) PDFErrorOr<Vector<CFF::TopDict>> CFF::parse_top_dicts(FixedMemoryStream& reader, ReadonlyBytes const& cff_bytes)
{ {
Vector<TopDict> top_dicts; Vector<TopDict> top_dicts;
@ -379,7 +378,7 @@ PDFErrorOr<Vector<CFF::TopDict>> CFF::parse_top_dicts(Reader& reader, ReadonlyBy
// CFF spec, "16 Local/Global Subrs INDEXes" // CFF spec, "16 Local/Global Subrs INDEXes"
// "Local subrs are stored in an INDEX structure which is located via the offset operand of the Subrs operator in the Private DICT." // "Local subrs are stored in an INDEX structure which is located via the offset operand of the Subrs operator in the Private DICT."
auto subrs_offset = operands[0].get<int>(); auto subrs_offset = operands[0].get<int>();
Reader subrs_reader { cff_bytes.slice(private_dict_offset + subrs_offset) }; FixedMemoryStream subrs_reader { cff_bytes.slice(private_dict_offset + subrs_offset) };
TRY(parse_index(subrs_reader, [&](ReadonlyBytes const& subroutine_bytes) -> PDFErrorOr<void> { TRY(parse_index(subrs_reader, [&](ReadonlyBytes const& subroutine_bytes) -> PDFErrorOr<void> {
return TRY(top_dict.local_subroutines.try_append(TRY(ByteBuffer::copy(subroutine_bytes)))); return TRY(top_dict.local_subroutines.try_append(TRY(ByteBuffer::copy(subroutine_bytes))));
})); }));
@ -831,7 +830,7 @@ static constexpr Array s_cff_builtin_names {
"Semibold"sv, "Semibold"sv,
}; };
PDFErrorOr<Vector<StringView>> CFF::parse_strings(Reader& reader) PDFErrorOr<Vector<StringView>> CFF::parse_strings(FixedMemoryStream& reader)
{ {
// CFF spec "10 String Index" // CFF spec "10 String Index"
Vector<StringView> strings; Vector<StringView> strings;
@ -940,7 +939,7 @@ PDFErrorOr<Vector<u8>> CFF::parse_fdselect(Stream&& reader, size_t glyph_count)
return fd_selector_array; return fd_selector_array;
} }
PDFErrorOr<Vector<CFF::Glyph>> CFF::parse_charstrings(Reader&& reader, Vector<ByteBuffer> const& local_subroutines, Vector<ByteBuffer> const& global_subroutines) PDFErrorOr<Vector<CFF::Glyph>> CFF::parse_charstrings(FixedMemoryStream&& reader, Vector<ByteBuffer> const& local_subroutines, Vector<ByteBuffer> const& global_subroutines)
{ {
// CFF spec, "14 CharStrings INDEX" // CFF spec, "14 CharStrings INDEX"
Vector<Glyph> glyphs; Vector<Glyph> glyphs;
@ -1034,19 +1033,19 @@ PDFErrorOr<OperatorT> CFF::parse_dict_operator(u8 b0, Stream& reader)
template PDFErrorOr<CFF::TopDictOperator> CFF::parse_dict_operator(u8, Stream&); template PDFErrorOr<CFF::TopDictOperator> CFF::parse_dict_operator(u8, Stream&);
PDFErrorOr<void> CFF::parse_index(Reader& reader, IndexDataHandler&& data_handler) PDFErrorOr<void> CFF::parse_index(FixedMemoryStream& reader, IndexDataHandler&& data_handler)
{ {
// CFF spec, "5 INDEX Data" // CFF spec, "5 INDEX Data"
Card16 count = TRY(reader.try_read<BigEndian<Card16>>()); Card16 count = TRY(reader.read_value<BigEndian<Card16>>());
if (count == 0) if (count == 0)
return {}; return {};
auto offset_size = TRY(reader.try_read<OffSize>()); auto offset_size = TRY(reader.read_value<OffSize>());
if (offset_size > 4) if (offset_size > 4)
return error("CFF INDEX Data offset_size > 4 not supported"); return error("CFF INDEX Data offset_size > 4 not supported");
return parse_index_data(offset_size, count, reader, data_handler); return parse_index_data(offset_size, count, reader, data_handler);
} }
PDFErrorOr<void> CFF::parse_index_data(OffSize offset_size, Card16 count, Reader& reader, IndexDataHandler& handler) PDFErrorOr<void> CFF::parse_index_data(OffSize offset_size, Card16 count, FixedMemoryStream& reader, IndexDataHandler& handler)
{ {
// CFF spec, "5 INDEX Data" // CFF spec, "5 INDEX Data"
u32 last_data_end = 1; u32 last_data_end = 1;
@ -1054,24 +1053,24 @@ PDFErrorOr<void> CFF::parse_index_data(OffSize offset_size, Card16 count, Reader
auto read_offset = [&]() -> PDFErrorOr<u32> { auto read_offset = [&]() -> PDFErrorOr<u32> {
u32 offset = 0; u32 offset = 0;
for (OffSize i = 0; i < offset_size; ++i) for (OffSize i = 0; i < offset_size; ++i)
offset = (offset << 8) | TRY(reader.try_read<u8>()); offset = (offset << 8) | TRY(reader.read_value<u8>());
return offset; return offset;
}; };
auto offset_refpoint = reader.offset() + offset_size * (count + 1) - 1; auto offset_refpoint = reader.offset() + offset_size * (count + 1) - 1;
for (u16 i = 0; i < count; i++) { for (u16 i = 0; i < count; i++) {
reader.save(); auto saved_offset = TRY(reader.tell());
reader.move_by(offset_size * i); TRY(reader.seek(offset_size * i, SeekMode::FromCurrentPosition));
u32 data_start = TRY(read_offset()); u32 data_start = TRY(read_offset());
last_data_end = TRY(read_offset()); last_data_end = TRY(read_offset());
auto data_size = last_data_end - data_start; auto data_size = last_data_end - data_start;
reader.move_to(offset_refpoint + data_start); TRY(reader.seek(offset_refpoint + data_start));
TRY(handler(reader.bytes().slice(reader.offset(), data_size))); TRY(handler(TRY(reader.read_in_place<u8 const>(data_size))));
reader.load(); TRY(reader.seek(saved_offset));
} }
reader.move_to(offset_refpoint + last_data_end); TRY(reader.seek(offset_refpoint + last_data_end));
return {}; return {};
} }

View file

@ -12,8 +12,6 @@
namespace PDF { namespace PDF {
class Reader;
// CFF spec: https://adobe-type-tools.github.io/font-tech-notes/pdfs/5176.CFF.pdf // CFF spec: https://adobe-type-tools.github.io/font-tech-notes/pdfs/5176.CFF.pdf
class CFF : public Type1FontProgram { class CFF : public Type1FontProgram {
@ -104,9 +102,9 @@ public:
static PDFErrorOr<DictOperand> load_dict_operand(u8, Stream&); static PDFErrorOr<DictOperand> load_dict_operand(u8, Stream&);
using IndexDataHandler = Function<PDFErrorOr<void>(ReadonlyBytes const&)>; using IndexDataHandler = Function<PDFErrorOr<void>(ReadonlyBytes const&)>;
static PDFErrorOr<void> parse_index(Reader& reader, IndexDataHandler&&); static PDFErrorOr<void> parse_index(FixedMemoryStream&, IndexDataHandler&&);
static PDFErrorOr<void> parse_index_data(OffSize offset_size, Card16 count, Reader& reader, IndexDataHandler&); static PDFErrorOr<void> parse_index_data(OffSize offset_size, Card16 count, FixedMemoryStream&, IndexDataHandler&);
template<typename OperatorT> template<typename OperatorT>
using DictEntryHandler = Function<PDFErrorOr<void>(OperatorT, Vector<DictOperand> const&)>; using DictEntryHandler = Function<PDFErrorOr<void>(OperatorT, Vector<DictOperand> const&)>;
@ -129,11 +127,11 @@ public:
int fdselect_offset = 0; int fdselect_offset = 0;
int fdarray_offset = 0; int fdarray_offset = 0;
}; };
static PDFErrorOr<Vector<TopDict>> parse_top_dicts(Reader&, ReadonlyBytes const& cff_bytes); static PDFErrorOr<Vector<TopDict>> parse_top_dicts(FixedMemoryStream&, ReadonlyBytes const& cff_bytes);
static PDFErrorOr<Vector<StringView>> parse_strings(Reader&); static PDFErrorOr<Vector<StringView>> parse_strings(FixedMemoryStream&);
static PDFErrorOr<Vector<CFF::Glyph>> parse_charstrings(Reader&&, Vector<ByteBuffer> const& local_subroutines, Vector<ByteBuffer> const& global_subroutines); static PDFErrorOr<Vector<CFF::Glyph>> parse_charstrings(FixedMemoryStream&&, Vector<ByteBuffer> const& local_subroutines, Vector<ByteBuffer> const& global_subroutines);
static DeprecatedFlyString resolve_sid(SID, Vector<StringView> const&); static DeprecatedFlyString resolve_sid(SID, Vector<StringView> const&);
static PDFErrorOr<Vector<SID>> parse_charset(Stream&&, size_t); static PDFErrorOr<Vector<SID>> parse_charset(Stream&&, size_t);