diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2022-03-25 08:19:34 -0700 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-03-31 18:10:45 +0200 |
commit | 4d0f74a15cff9b5e3876a5f476d92c766afc1bad (patch) | |
tree | 174e29c405a5ea9c0cca0d681e28a6299d1c6dcc /Userland/Libraries/LibPDF/Fonts | |
parent | e831c374f4f2fd7a7a8fff46aca6eff7c7f17509 (diff) | |
download | serenity-4d0f74a15cff9b5e3876a5f476d92c766afc1bad.zip |
LibPDF: Add Type0 and TrueType fonts
Diffstat (limited to 'Userland/Libraries/LibPDF/Fonts')
-rw-r--r-- | Userland/Libraries/LibPDF/Fonts/PDFFont.cpp | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp | 65 | ||||
-rw-r--r-- | Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h | 29 | ||||
-rw-r--r-- | Userland/Libraries/LibPDF/Fonts/Type0Font.cpp | 97 | ||||
-rw-r--r-- | Userland/Libraries/LibPDF/Fonts/Type0Font.h | 35 |
5 files changed, 232 insertions, 0 deletions
diff --git a/Userland/Libraries/LibPDF/Fonts/PDFFont.cpp b/Userland/Libraries/LibPDF/Fonts/PDFFont.cpp index 289169abe9..999d9d48da 100644 --- a/Userland/Libraries/LibPDF/Fonts/PDFFont.cpp +++ b/Userland/Libraries/LibPDF/Fonts/PDFFont.cpp @@ -6,6 +6,8 @@ #include <LibPDF/CommonNames.h> #include <LibPDF/Fonts/PDFFont.h> +#include <LibPDF/Fonts/TrueTypeFont.h> +#include <LibPDF/Fonts/Type0Font.h> #include <LibPDF/Fonts/Type1Font.h> namespace PDF { @@ -14,8 +16,12 @@ PDFErrorOr<NonnullRefPtr<PDFFont>> PDFFont::create(Document* document, NonnullRe { auto subtype = TRY(dict->get_name(document, CommonNames::Subtype))->name(); + if (subtype == "Type0") + return TRY(Type0Font::create(document, dict)); if (subtype == "Type1") return TRY(Type1Font::create(document, dict)); + if (subtype == "TrueType") + return TRY(TrueTypeFont::create(document, dict)); dbgln("Unknown font subtype: {}", subtype); TODO(); diff --git a/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp new file mode 100644 index 0000000000..9a04255873 --- /dev/null +++ b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022, Matthew Olsson <mattco@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibPDF/CommonNames.h> +#include <LibPDF/Fonts/TrueTypeFont.h> +#include <LibPDF/Fonts/Type1Font.h> + +namespace PDF { + +PDFErrorOr<NonnullRefPtr<PDFFont>> TrueTypeFont::create(Document* document, NonnullRefPtr<DictObject> dict) +{ + auto font_descriptor = TRY(dict->get_dict(document, CommonNames::FontDescriptor)); + + if (!dict->contains(CommonNames::FontFile2)) { + // FIXME: The TTF is one of the standard 14 fonts. These should be built into + // the system, and their attributes hardcoded. Until we have them, just + // treat this as a Type1 font (which are very similar to TTF fonts) + return TRY(Type1Font::create(document, dict)); + } + + auto font_file = TRY(dict->get_stream(document, CommonNames::FontFile2)); + auto ttf_font = TRY(TTF::Font::try_load_from_externally_owned_memory(font_file->bytes())); + auto data = TRY(Type1Font::parse_data(document, dict)); + + return adopt_ref(*new TrueTypeFont(ttf_font, move(data))); +} + +TrueTypeFont::TrueTypeFont(NonnullRefPtr<TTF::Font> ttf_font, Type1Font::Data data) + : m_ttf_font(ttf_font) + , m_data(data) +{ +} + +u32 TrueTypeFont::char_code_to_code_point(u16 char_code) const +{ + if (m_data.to_unicode) + TODO(); + + auto descriptor = m_data.encoding->get_char_code_descriptor(char_code); + return descriptor.code_point; +} + +float TrueTypeFont::get_char_width(u16 char_code, float font_size) const +{ + u16 width; + if (auto char_code_width = m_data.widths.get(char_code); char_code_width.has_value()) { + width = char_code_width.value(); + } else { + // FIXME: Should we do something with m_data.missing_width here? + float units_per_em = m_ttf_font->units_per_em(); + auto scale = (font_size * DEFAULT_DPI) / (POINTS_PER_INCH * units_per_em); + + auto code_point = char_code_to_code_point(char_code); + auto id = m_ttf_font->glyph_id_for_code_point(code_point); + auto metrics = m_ttf_font->glyph_metrics(id, scale, scale); + width = metrics.advance_width; + } + + return static_cast<float>(width) / 1000.0f; +} + +} diff --git a/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h new file mode 100644 index 0000000000..87c0f6f86e --- /dev/null +++ b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022, Matthew Olsson <mattco@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibGfx/TrueTypeFont/Font.h> +#include <LibPDF/Fonts/Type1Font.h> + +namespace PDF { + +class TrueTypeFont : public PDFFont { +public: + static PDFErrorOr<NonnullRefPtr<PDFFont>> create(Document*, NonnullRefPtr<DictObject>); + + TrueTypeFont(NonnullRefPtr<TTF::Font> ttf_font, Type1Font::Data); + ~TrueTypeFont() override = default; + + u32 char_code_to_code_point(u16 char_code) const override; + float get_char_width(u16 char_code, float font_size) const override; + +private: + NonnullRefPtr<TTF::Font> m_ttf_font; + Type1Font::Data m_data; +}; + +} diff --git a/Userland/Libraries/LibPDF/Fonts/Type0Font.cpp b/Userland/Libraries/LibPDF/Fonts/Type0Font.cpp new file mode 100644 index 0000000000..d7921a74d6 --- /dev/null +++ b/Userland/Libraries/LibPDF/Fonts/Type0Font.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2022, Matthew Olsson <mattco@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibPDF/CommonNames.h> +#include <LibPDF/Fonts/Type0Font.h> + +namespace PDF { + +PDFErrorOr<NonnullRefPtr<Type0Font>> Type0Font::create(Document* document, NonnullRefPtr<DictObject> dict) +{ + // FIXME: Support arbitrary CMaps + auto cmap_value = TRY(dict->get_object(document, CommonNames::Encoding)); + if (!cmap_value->is<NameObject>() || cmap_value->cast<NameObject>()->name() != CommonNames::IdentityH) + TODO(); + + auto descendant_font_value = TRY(dict->get_array(document, CommonNames::DescendantFonts)); + auto descendant_font = TRY(descendant_font_value->get_dict_at(document, 0)); + + auto system_info_dict = TRY(descendant_font->get_dict(document, CommonNames::CIDSystemInfo)); + auto registry = TRY(system_info_dict->get_string(document, CommonNames::Registry))->string(); + auto ordering = TRY(system_info_dict->get_string(document, CommonNames::Ordering))->string(); + u8 supplement = system_info_dict->get_value(CommonNames::Supplement).get<int>(); + CIDSystemInfo system_info { registry, ordering, supplement }; + + auto font_descriptor = TRY(descendant_font->get_dict(document, CommonNames::FontDescriptor)); + + u16 default_width = 1000; + if (descendant_font->contains(CommonNames::DW)) + default_width = descendant_font->get_value(CommonNames::DW).get<int>(); + + HashMap<u16, u16> widths; + + if (descendant_font->contains(CommonNames::W)) { + auto widths_array = MUST(descendant_font->get_array(document, CommonNames::W)); + Optional<u16> pending_code; + + for (size_t i = 0; i < widths_array->size(); i++) { + auto& value = widths_array->at(i); + if (!pending_code.has_value()) { + pending_code = value.get<int>(); + } else if (value.has<NonnullRefPtr<Object>>()) { + auto array = value.get<NonnullRefPtr<Object>>()->cast<ArrayObject>(); + auto code = pending_code.release_value(); + for (auto& width : *array) + widths.set(code++, width.get<int>()); + } else { + auto first_code = pending_code.release_value(); + auto last_code = value.get<int>(); + auto width = widths_array->at(i + 1).get<int>(); + for (u16 code = first_code; code <= last_code; code++) + widths.set(code, width); + + i++; + } + } + } + + if (dict->contains(CommonNames::CIDToGIDMap)) { + auto value = TRY(dict->get_object(document, CommonNames::CIDToGIDMap)); + if (value->is<StreamObject>()) { + TODO(); + } else if (value->cast<NameObject>()->name() != "Identity") { + TODO(); + } + } + + return adopt_ref(*new Type0Font(system_info, widths, default_width)); +} + +Type0Font::Type0Font(CIDSystemInfo const& system_info, HashMap<u16, u16> const& widths, u16 missing_width) + : m_system_info(system_info) + , m_widths(widths) + , m_missing_width(missing_width) +{ +} + +u32 Type0Font::char_code_to_code_point(u16 char_code) const +{ + return char_code; +} + +float Type0Font::get_char_width(u16 char_code, float) const +{ + u16 width; + if (auto char_code_width = m_widths.get(char_code); char_code_width.has_value()) { + width = char_code_width.value(); + } else { + width = m_missing_width; + } + + return static_cast<float>(width) / 1000.0f; +} + +} diff --git a/Userland/Libraries/LibPDF/Fonts/Type0Font.h b/Userland/Libraries/LibPDF/Fonts/Type0Font.h new file mode 100644 index 0000000000..7f17d96f5e --- /dev/null +++ b/Userland/Libraries/LibPDF/Fonts/Type0Font.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022, Matthew Olsson <mattco@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibPDF/Fonts/PDFFont.h> + +namespace PDF { + +struct CIDSystemInfo { + String registry; + String ordering; + u8 supplement; +}; + +class Type0Font : public PDFFont { +public: + static PDFErrorOr<NonnullRefPtr<Type0Font>> create(Document*, NonnullRefPtr<DictObject>); + + Type0Font(CIDSystemInfo const&, HashMap<u16, u16> const& widths, u16 missing_width); + ~Type0Font() override = default; + + u32 char_code_to_code_point(u16 char_code) const override; + float get_char_width(u16 char_code, float font_size) const override; + +private: + CIDSystemInfo m_system_info; + HashMap<u16, u16> m_widths; + u16 m_missing_width; +}; + +} |