1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 07:07:34 +00:00

LibPDF/CFF: Implement some special handling for CID-keyed fonts

* FDArray, FDSelect must be present
* Encoding must not be present
* Charset maps from GID (Glyph ID) to CID (Character ID),
  instead of to character name
This commit is contained in:
Nico Weber 2024-02-14 09:14:15 -05:00 committed by Andreas Kling
parent 7494f24430
commit 1d1e406b3a

View file

@ -128,6 +128,21 @@ PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPt
if (top_dict.is_cid_keyed) {
// CFF spec, "18 CID-keyed Fonts"
// "* The FDArray operator is expected to be present"
if (top_dict.fdarray_offset == 0)
return error("CID-keyed CFFs must have an FDArray");
// "* The charset data, although in the same format as non-CIDFonts, will represent CIDs rather than SIDs"
// (Done below.)
// "* The Top DICT will include an FDSelect operator"
if (top_dict.fdselect_offset == 0)
return error("CID-keyed CFFs must have FDSelect");
// "* no Encoding operator will be present and the default StandardEncoding should not be applied"
if (top_dict.encoding_offset != 0)
return error("CID-keyed CFFs must not have Encoding");
cff->set_kind(CFF::Kind::CIDKeyed);
}
@ -148,6 +163,7 @@ PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPt
// FIXME: Only read this if the built-in encoding is actually needed? (ie. `if (!encoding)`)
Vector<u8> encoding_codes; // Maps GID to its codepoint.
HashMap<Card8, SID> encoding_supplemental; // Maps codepoint to SID.
if (!top_dict.is_cid_keyed) {
switch (top_dict.encoding_offset) {
case 0:
dbgln_if(CFF_DEBUG, "CFF predefined encoding Standard");
@ -163,9 +179,14 @@ PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPt
encoding_codes = TRY(parse_encoding(Reader(cff_bytes.slice(top_dict.encoding_offset)), encoding_supplemental));
break;
}
}
// CFF spec, "Table 22 Charset ID"
Vector<DeprecatedFlyString> charset_names;
Vector<SID> charset; // Maps GID to CIDs for CID-keyed, to SIDs otherwise.
Vector<DeprecatedFlyString> charset_names; // Only valid for non-CID-keyed fonts.
if (top_dict.is_cid_keyed) {
charset = TRY(parse_charset(Reader { cff_bytes.slice(top_dict.charset_offset) }, glyphs.size()));
} else {
switch (top_dict.charset_offset) {
case 0:
dbgln_if(CFF_DEBUG, "CFF predefined charset ISOAdobe");
@ -184,12 +205,13 @@ PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPt
TRY(charset_names.try_append(resolve_sid(sid, strings)));
break;
default: {
auto charset = TRY(parse_charset(Reader { cff_bytes.slice(top_dict.charset_offset) }, glyphs.size()));
charset = TRY(parse_charset(Reader { cff_bytes.slice(top_dict.charset_offset) }, glyphs.size()));
for (SID sid : charset)
TRY(charset_names.try_append(resolve_sid(sid, strings)));
break;
}
}
}
// CFF spec, "18 CID-keyed Fonts"
if (top_dict.fdarray_offset != 0) {
@ -226,7 +248,7 @@ PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPt
if (encoding) {
dbgln_if(CFF_DEBUG, "CFF using external encoding");
cff->set_encoding(move(encoding));
} else {
} else if (!top_dict.is_cid_keyed) {
dbgln_if(CFF_DEBUG, "CFF using embedded encoding");
auto encoding = Encoding::create();
for (size_t i = 0; i < glyphs.size(); i++) {