summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibPDF/Fonts
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2022-03-25 08:19:34 -0700
committerAndreas Kling <kling@serenityos.org>2022-03-31 18:10:45 +0200
commit4d0f74a15cff9b5e3876a5f476d92c766afc1bad (patch)
tree174e29c405a5ea9c0cca0d681e28a6299d1c6dcc /Userland/Libraries/LibPDF/Fonts
parente831c374f4f2fd7a7a8fff46aca6eff7c7f17509 (diff)
downloadserenity-4d0f74a15cff9b5e3876a5f476d92c766afc1bad.zip
LibPDF: Add Type0 and TrueType fonts
Diffstat (limited to 'Userland/Libraries/LibPDF/Fonts')
-rw-r--r--Userland/Libraries/LibPDF/Fonts/PDFFont.cpp6
-rw-r--r--Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp65
-rw-r--r--Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h29
-rw-r--r--Userland/Libraries/LibPDF/Fonts/Type0Font.cpp97
-rw-r--r--Userland/Libraries/LibPDF/Fonts/Type0Font.h35
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;
+};
+
+}