mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 15:27:35 +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:
parent
b9a4689af3
commit
6348a857ea
2 changed files with 66 additions and 20 deletions
|
@ -237,21 +237,60 @@ void CIDFontType2::set_font_size(float font_size)
|
||||||
Type0Font::Type0Font() = default;
|
Type0Font::Type0Font() = default;
|
||||||
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)
|
PDFErrorOr<void> Type0Font::initialize(Document* document, NonnullRefPtr<DictObject> const& dict, float font_size)
|
||||||
{
|
{
|
||||||
TRY(PDFFont::initialize(document, dict, font_size));
|
TRY(PDFFont::initialize(document, dict, font_size));
|
||||||
|
|
||||||
m_base_font_name = TRY(dict->get_name(document, CommonNames::BaseFont))->name();
|
m_base_font_name = TRY(dict->get_name(document, CommonNames::BaseFont))->name();
|
||||||
|
|
||||||
// FIXME: Support arbitrary CMaps
|
m_cmap = TRY(make_cmap(TRY(dict->get_object(document, CommonNames::Encoding))));
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto descendant_font_value = TRY(dict->get_array(document, CommonNames::DescendantFonts));
|
auto descendant_font_value = TRY(dict->get_array(document, CommonNames::DescendantFonts));
|
||||||
auto descendant_font = TRY(descendant_font_value->get_dict_at(document, 0));
|
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
|
// if no match is found, a second byte shall be extracted, and the 2-byte code shall be matched against 2-byte
|
||||||
// codespace ranges [...]"
|
// 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 horizontal_scaling = renderer.text_state().horizontal_scaling;
|
||||||
|
|
||||||
auto const& text_rendering_matrix = renderer.calculate_text_rendering_matrix();
|
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 character_spacing = renderer.text_state().character_spacing;
|
||||||
auto word_spacing = renderer.text_state().word_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,
|
// Use the width specified in the font's dictionary if available,
|
||||||
// and use the default width for the given font otherwise.
|
// and use the default width for the given font otherwise.
|
||||||
float glyph_width;
|
float glyph_width;
|
||||||
|
|
|
@ -20,6 +20,19 @@ struct CIDSystemInfo {
|
||||||
u8 supplement;
|
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 {
|
class Type0Font : public PDFFont {
|
||||||
public:
|
public:
|
||||||
Type0Font();
|
Type0Font();
|
||||||
|
@ -51,6 +64,7 @@ private:
|
||||||
HashMap<u16, VerticalMetric> m_vertical_metrics;
|
HashMap<u16, VerticalMetric> m_vertical_metrics;
|
||||||
|
|
||||||
OwnPtr<CIDFontType> m_cid_font_type;
|
OwnPtr<CIDFontType> m_cid_font_type;
|
||||||
|
OwnPtr<Type0CMap> m_cmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue