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

LibPDF: Prepare for more encodings than just Identity-H in Type0 code

Introduces CIDIterator, an iterator type for iterating over CIDs.

Also introduces Type0CMap which can return a CIDIterator given some
bytes.

The existing code of treating the bytes as an identity map of
big-endian u16s is now implemented in IdentityType0CMap.

No behavior change.
This commit is contained in:
Nico Weber 2024-03-01 09:29:32 -05:00 committed by Andreas Kling
parent b9a4689af3
commit 6348a857ea
2 changed files with 66 additions and 20 deletions

View file

@ -237,21 +237,60 @@ void CIDFontType2::set_font_size(float font_size)
Type0Font::Type0Font() = default;
Type0Font::~Type0Font() = default;
class IdentityType0CMap : public Type0CMap {
public:
virtual PDFErrorOr<NonnullOwnPtr<CIDIterator>> iterate(ReadonlyBytes bytes) const override
{
// 9.7.5.2 Predefined CMaps:
// "When the current font is a Type 0 font whose Encoding entry is Identity-H or Identity-V,
// the string to be shown shall contain pairs of bytes representing CIDs, high-order byte first."
if (bytes.size() % 2 != 0)
return Error::malformed_error("Identity-H but length not multiple of 2");
class IdentityCIDIterator : public CIDIterator {
public:
IdentityCIDIterator(ReadonlyBytes bytes)
: m_bytes(bytes)
{
}
virtual bool has_next() const override { return m_index < m_bytes.size(); }
virtual u32 next() override
{
u32 result = (m_bytes[m_index] << 8) | m_bytes[m_index + 1];
m_index += 2;
return result;
}
private:
ReadonlyBytes m_bytes;
size_t m_index { 0 };
};
return make<IdentityCIDIterator>(bytes);
}
};
static PDFErrorOr<NonnullOwnPtr<Type0CMap>> make_cmap(NonnullRefPtr<Object> const& cmap_value)
{
// FIXME: Support arbitrary CMaps
if (!cmap_value->is<NameObject>())
return Error::rendering_unsupported_error("Type0 font: support for general type 0 cmaps not yet implemented");
auto cmap_name = cmap_value->cast<NameObject>()->name();
if (cmap_name != CommonNames::IdentityH)
return Error::rendering_unsupported_error("Type0 font: unimplemented named type 0 cmap {}", cmap_name);
return make<IdentityType0CMap>();
}
PDFErrorOr<void> Type0Font::initialize(Document* document, NonnullRefPtr<DictObject> const& dict, float font_size)
{
TRY(PDFFont::initialize(document, dict, font_size));
m_base_font_name = TRY(dict->get_name(document, CommonNames::BaseFont))->name();
// FIXME: Support arbitrary CMaps
auto cmap_value = TRY(dict->get_object(document, CommonNames::Encoding));
if (!cmap_value->is<NameObject>())
return Error::rendering_unsupported_error("Type0 font: support for general type 0 cmaps not yet implemented");
auto cmap_name = cmap_value->cast<NameObject>()->name();
if (cmap_name != CommonNames::IdentityH) {
return Error::rendering_unsupported_error("Type0 font: unimplemented named type 0 cmap {}", cmap_name);
}
m_cmap = TRY(make_cmap(TRY(dict->get_object(document, CommonNames::Encoding))));
auto descendant_font_value = TRY(dict->get_array(document, CommonNames::DescendantFonts));
auto descendant_font = TRY(descendant_font_value->get_dict_at(document, 0));
@ -387,16 +426,6 @@ PDFErrorOr<Gfx::FloatPoint> Type0Font::draw_string(Gfx::Painter& painter, Gfx::F
// if no match is found, a second byte shall be extracted, and the 2-byte code shall be matched against 2-byte
// codespace ranges [...]"
// 9.7.5.2 Predefined CMaps:
// "When the current font is a Type 0 font whose Encoding entry is Identity-H or Identity-V,
// the string to be shown shall contain pairs of bytes representing CIDs, high-order byte first."
// Type0Font::initialize() currently rejects everything except Identity-H.
// FIXME: Support more.
if (string.length() % 2 != 0)
return Error::malformed_error("Identity-H but length not multiple of 2");
auto cids = ReadonlySpan<BigEndian<u16>>(reinterpret_cast<BigEndian<u16> const*>(string.characters()), string.length() / 2);
auto horizontal_scaling = renderer.text_state().horizontal_scaling;
auto const& text_rendering_matrix = renderer.calculate_text_rendering_matrix();
@ -409,7 +438,10 @@ PDFErrorOr<Gfx::FloatPoint> Type0Font::draw_string(Gfx::Painter& painter, Gfx::F
auto character_spacing = renderer.text_state().character_spacing;
auto word_spacing = renderer.text_state().word_spacing;
for (auto cid : cids) {
auto cids = TRY(m_cmap->iterate(string.bytes()));
while (cids->has_next()) {
auto cid = cids->next();
// Use the width specified in the font's dictionary if available,
// and use the default width for the given font otherwise.
float glyph_width;

View file

@ -20,6 +20,19 @@ struct CIDSystemInfo {
u8 supplement;
};
class CIDIterator {
public:
virtual ~CIDIterator() = default;
virtual bool has_next() const = 0;
virtual u32 next() = 0;
};
class Type0CMap {
public:
virtual ~Type0CMap() = default;
virtual PDFErrorOr<NonnullOwnPtr<CIDIterator>> iterate(ReadonlyBytes) const = 0;
};
class Type0Font : public PDFFont {
public:
Type0Font();
@ -51,6 +64,7 @@ private:
HashMap<u16, VerticalMetric> m_vertical_metrics;
OwnPtr<CIDFontType> m_cid_font_type;
OwnPtr<Type0CMap> m_cmap;
};
}