1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:37:35 +00:00

LibPDF: Implement stream CIDToGIDMaps for Type0 CIDFontType2 fonts

Of my 1000 test files, 73 have stream Type0 truetype fonts with stream
CIDToGIDMaps. This makes that work.

(With this patch, the number of files in my 1000 test files complaining
"Font is missing Name" increases from 41 to 75, so a bit under half of
the fonts using stream CIDToGIDMaps also have no 'name' table. So that's
next.)

Increases files without issues from 652 to 681.
This commit is contained in:
Nico Weber 2024-02-16 21:39:24 -05:00 committed by Tim Flynn
parent ac49617183
commit 012f6d46e7

View file

@ -129,32 +129,61 @@ private:
RefPtr<Gfx::Font> m_font;
};
static PDFErrorOr<NonnullOwnPtr<OpenType::CharCodeToGlyphIndex>> create_cid_to_gid_map(Document* document, NonnullRefPtr<DictObject> const& dict)
{
// "If the value is a stream, the bytes in the stream contain the mapping from CIDs to glyph indices:
// the glyph index for a particular CID value c is a 2-byte value stored in bytes 2×c and 2×c+1, where the first byte is the high-order byte.
// If the value of CIDToGIDMap is a name, it must be Identity, indicating that the mapping between CIDs and glyph indices is the identity mapping.
// Default value: Identity."
class IdentityCIDToGIDMap : public OpenType::CharCodeToGlyphIndex {
public:
virtual u32 glyph_id_for_code_point(u32 char_code) const override { return char_code; }
};
class StreamCIDToGIDMap : public OpenType::CharCodeToGlyphIndex {
public:
StreamCIDToGIDMap(ReadonlyBytes bytes)
: m_bytes(move(bytes))
{
}
virtual u32 glyph_id_for_code_point(u32 char_code) const override
{
u32 index = char_code * 2;
if (index + 1 >= m_bytes.size()) {
// This can happen because Font::populate_glyph_page() with CIDs not used on the page and hence not in the font.
return 0;
}
return (m_bytes[index] << 8) | m_bytes[index + 1];
}
private:
ReadonlyBytes m_bytes;
};
if (!dict->contains(CommonNames::CIDToGIDMap))
return make<IdentityCIDToGIDMap>();
auto value = TRY(dict->get_object(document, CommonNames::CIDToGIDMap));
if (value->is<StreamObject>())
return make<StreamCIDToGIDMap>(value->cast<StreamObject>()->bytes());
if (value->cast<NameObject>()->name() != "Identity")
return Error::rendering_unsupported_error("Type0 font: The only valid CIDToGIDMap name is 'Identity'");
return make<IdentityCIDToGIDMap>();
}
PDFErrorOr<NonnullOwnPtr<CIDFontType2>> CIDFontType2::create(Document* document, NonnullRefPtr<DictObject> const& descendant, float font_size)
{
auto descriptor = TRY(descendant->get_dict(document, CommonNames::FontDescriptor));
if (descendant->contains(CommonNames::CIDToGIDMap)) {
auto value = TRY(descendant->get_object(document, CommonNames::CIDToGIDMap));
if (value->is<StreamObject>()) {
return Error::rendering_unsupported_error("Type0 font subtype 2: support for stream cid maps not yet implemented");
} else if (value->cast<NameObject>()->name() != "Identity") {
return Error::rendering_unsupported_error("Type0 font: support for non-Identity named cid maps not yet implemented");
}
}
class IdentityCIDToGIDMap : public OpenType::CharCodeToGlyphIndex {
public:
virtual u32 glyph_id_for_code_point(u32 char_code) const override
{
return char_code;
}
};
auto cid_to_gid_map = TRY(create_cid_to_gid_map(document, descendant));
RefPtr<Gfx::Font> font;
if (descriptor->contains(CommonNames::FontFile2)) {
auto font_file_stream = TRY(descriptor->get_stream(document, CommonNames::FontFile2));
float point_size = (font_size * POINTS_PER_INCH) / DEFAULT_DPI;
auto ttf_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(font_file_stream->bytes(), 0, make<IdentityCIDToGIDMap>()));
auto ttf_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(font_file_stream->bytes(), 0, move(cid_to_gid_map)));
font = adopt_ref(*new Gfx::ScaledFont(*ttf_font, point_size, point_size));
}