summaryrefslogtreecommitdiff
path: root/Libraries/LibGfx
diff options
context:
space:
mode:
authorStephan Unverwerth <s.unverwerth@gmx.de>2020-12-31 14:01:59 +0100
committerAndreas Kling <kling@serenityos.org>2020-12-31 23:40:27 +0100
commitbb27b212de2544186b58928759c8c2a2e56944f9 (patch)
tree2292fa75c9a45c9271e0108648e52612c3c5d7b2 /Libraries/LibGfx
parentac50bc79e4f0992edf69196efd2788f7be81730c (diff)
downloadserenity-bb27b212de2544186b58928759c8c2a2e56944f9.zip
LibGfx: Introduce provisional font interface
Old font functionality has been moved into BitmapFont and an abstract Font interface has been introduced to faciliate further development of TTF font integration.
Diffstat (limited to 'Libraries/LibGfx')
-rw-r--r--Libraries/LibGfx/BitmapFont.cpp325
-rw-r--r--Libraries/LibGfx/BitmapFont.h150
-rw-r--r--Libraries/LibGfx/CMakeLists.txt1
-rw-r--r--Libraries/LibGfx/Font.cpp299
-rw-r--r--Libraries/LibGfx/Font.h120
5 files changed, 509 insertions, 386 deletions
diff --git a/Libraries/LibGfx/BitmapFont.cpp b/Libraries/LibGfx/BitmapFont.cpp
new file mode 100644
index 0000000000..9933a7af4e
--- /dev/null
+++ b/Libraries/LibGfx/BitmapFont.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "BitmapFont.h"
+#include "Bitmap.h"
+#include "Emoji.h"
+#include <AK/MappedFile.h>
+#include <AK/StdLibExtras.h>
+#include <AK/StringBuilder.h>
+#include <AK/Utf32View.h>
+#include <AK/Utf8View.h>
+#include <AK/Vector.h>
+#include <AK/kmalloc.h>
+#include <LibCore/FileStream.h>
+#include <LibGfx/FontDatabase.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+namespace Gfx {
+
+struct [[gnu::packed]] FontFileHeader {
+ char magic[4];
+ u8 glyph_width;
+ u8 glyph_height;
+ u8 type;
+ u8 is_variable_width;
+ u8 glyph_spacing;
+ u8 baseline;
+ u8 mean_line;
+ u8 presentation_size;
+ u16 weight;
+ char name[32];
+ char family[32];
+};
+
+NonnullRefPtr<Font> BitmapFont::clone() const
+{
+ size_t bytes_per_glyph = sizeof(u32) * glyph_height();
+ auto* new_rows = static_cast<unsigned*>(malloc(bytes_per_glyph * m_glyph_count));
+ memcpy(new_rows, m_rows, bytes_per_glyph * m_glyph_count);
+ auto* new_widths = static_cast<u8*>(malloc(m_glyph_count));
+ if (m_glyph_widths)
+ memcpy(new_widths, m_glyph_widths, m_glyph_count);
+ else
+ memset(new_widths, m_glyph_width, m_glyph_count);
+ return adopt(*new BitmapFont(m_name, m_family, new_rows, new_widths, m_fixed_width, m_glyph_width, m_glyph_height, m_glyph_spacing, m_type, m_baseline, m_mean_line, m_presentation_size, m_weight, true));
+}
+
+NonnullRefPtr<BitmapFont> BitmapFont::create(u8 glyph_height, u8 glyph_width, bool fixed, FontTypes type)
+{
+ size_t bytes_per_glyph = sizeof(u32) * glyph_height;
+ size_t count = glyph_count_by_type(type);
+ auto* new_rows = static_cast<unsigned*>(malloc(bytes_per_glyph * count));
+ memset(new_rows, 0, bytes_per_glyph * count);
+ auto* new_widths = static_cast<u8*>(malloc(count));
+ memset(new_widths, glyph_width, count);
+ return adopt(*new BitmapFont("Untitled", "Untitled", new_rows, new_widths, fixed, glyph_width, glyph_height, 1, type, 0, 0, 0, 400, true));
+}
+
+BitmapFont::BitmapFont(String name, String family, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line, u8 presentation_size, u16 weight, bool owns_arrays)
+ : m_name(name)
+ , m_family(family)
+ , m_type(type)
+ , m_rows(rows)
+ , m_glyph_widths(widths)
+ , m_glyph_width(glyph_width)
+ , m_glyph_height(glyph_height)
+ , m_min_glyph_width(glyph_width)
+ , m_max_glyph_width(glyph_width)
+ , m_glyph_spacing(glyph_spacing)
+ , m_baseline(baseline)
+ , m_mean_line(mean_line)
+ , m_presentation_size(presentation_size)
+ , m_weight(weight)
+ , m_fixed_width(is_fixed_width)
+ , m_owns_arrays(owns_arrays)
+{
+ update_x_height();
+
+ m_glyph_count = glyph_count_by_type(m_type);
+
+ if (!m_fixed_width) {
+ u8 maximum = 0;
+ u8 minimum = 255;
+ for (size_t i = 0; i < m_glyph_count; ++i) {
+ minimum = min(minimum, m_glyph_widths[i]);
+ maximum = max(maximum, m_glyph_widths[i]);
+ }
+ m_min_glyph_width = minimum;
+ m_max_glyph_width = maximum;
+ }
+}
+
+BitmapFont::~BitmapFont()
+{
+ if (m_owns_arrays) {
+ free(m_glyph_widths);
+ free(m_rows);
+ }
+}
+
+RefPtr<BitmapFont> BitmapFont::load_from_memory(const u8* data)
+{
+ auto& header = *reinterpret_cast<const FontFileHeader*>(data);
+ if (memcmp(header.magic, "!Fnt", 4)) {
+ dbgprintf("header.magic != '!Fnt', instead it's '%c%c%c%c'\n", header.magic[0], header.magic[1], header.magic[2], header.magic[3]);
+ return nullptr;
+ }
+ if (header.name[sizeof(header.name) - 1] != '\0') {
+ dbgprintf("Font name not fully null-terminated\n");
+ return nullptr;
+ }
+
+ if (header.family[sizeof(header.family) - 1] != '\0') {
+ dbgprintf("Font family not fully null-terminated\n");
+ return nullptr;
+ }
+
+ FontTypes type;
+ if (header.type == 0)
+ type = FontTypes::Default;
+ else if (header.type == 1)
+ type = FontTypes::LatinExtendedA;
+ else
+ ASSERT_NOT_REACHED();
+
+ size_t count = glyph_count_by_type(type);
+ size_t bytes_per_glyph = sizeof(unsigned) * header.glyph_height;
+
+ auto* rows = const_cast<unsigned*>((const unsigned*)(data + sizeof(FontFileHeader)));
+ u8* widths = nullptr;
+ if (header.is_variable_width)
+ widths = (u8*)(rows) + count * bytes_per_glyph;
+ return adopt(*new BitmapFont(String(header.name), String(header.family), rows, widths, !header.is_variable_width, header.glyph_width, header.glyph_height, header.glyph_spacing, type, header.baseline, header.mean_line, header.presentation_size, header.weight));
+}
+
+size_t BitmapFont::glyph_count_by_type(FontTypes type)
+{
+ if (type == FontTypes::Default)
+ return 256;
+
+ if (type == FontTypes::LatinExtendedA)
+ return 384;
+
+ dbg() << "Unknown font type:" << type;
+ ASSERT_NOT_REACHED();
+}
+
+RefPtr<BitmapFont> BitmapFont::load_from_file(const StringView& path)
+{
+ MappedFile mapped_file(path);
+ if (!mapped_file.is_valid())
+ return nullptr;
+
+ auto font = load_from_memory((const u8*)mapped_file.data());
+ if (!font)
+ return nullptr;
+
+ font->m_mapped_file = move(mapped_file);
+ return font;
+}
+
+bool BitmapFont::write_to_file(const StringView& path)
+{
+ FontFileHeader header;
+ memset(&header, 0, sizeof(FontFileHeader));
+ memcpy(header.magic, "!Fnt", 4);
+ header.glyph_width = m_glyph_width;
+ header.glyph_height = m_glyph_height;
+ header.type = m_type;
+ header.baseline = m_baseline;
+ header.mean_line = m_mean_line;
+ header.is_variable_width = !m_fixed_width;
+ header.glyph_spacing = m_glyph_spacing;
+ header.presentation_size = m_presentation_size;
+ header.weight = m_weight;
+ memcpy(header.name, m_name.characters(), min(m_name.length(), sizeof(header.name) - 1));
+ memcpy(header.family, m_family.characters(), min(m_family.length(), sizeof(header.family) - 1));
+
+ size_t bytes_per_glyph = sizeof(unsigned) * m_glyph_height;
+ size_t count = glyph_count_by_type(m_type);
+
+ auto stream_result = Core::OutputFileStream::open_buffered(path);
+ if (stream_result.is_error())
+ return false;
+ auto& stream = stream_result.value();
+
+ stream << ReadonlyBytes { &header, sizeof(header) };
+ stream << ReadonlyBytes { m_rows, count * bytes_per_glyph };
+ stream << ReadonlyBytes { m_glyph_widths, count };
+
+ stream.flush();
+ if (stream.handle_any_error())
+ return false;
+
+ return true;
+}
+
+GlyphBitmap BitmapFont::glyph_bitmap(u32 code_point) const
+{
+ return GlyphBitmap(&m_rows[code_point * m_glyph_height], { glyph_width(code_point), m_glyph_height });
+}
+
+int BitmapFont::glyph_or_emoji_width(u32 code_point) const
+{
+ if (code_point < m_glyph_count)
+ return glyph_width(code_point);
+
+ if (m_fixed_width)
+ return m_glyph_width;
+
+ auto* emoji = Emoji::emoji_for_code_point(code_point);
+ if (emoji == nullptr)
+ return glyph_width('?');
+ return emoji->size().width();
+}
+
+int BitmapFont::width(const StringView& string) const
+{
+ Utf8View utf8 { string };
+ return width(utf8);
+}
+
+int BitmapFont::width(const Utf8View& utf8) const
+{
+ bool first = true;
+ int width = 0;
+
+ for (u32 code_point : utf8) {
+ if (!first)
+ width += glyph_spacing();
+ first = false;
+ width += glyph_or_emoji_width(code_point);
+ }
+
+ return width;
+}
+
+int BitmapFont::width(const Utf32View& view) const
+{
+ if (view.length() == 0)
+ return 0;
+ int width = (view.length() - 1) * glyph_spacing();
+ for (size_t i = 0; i < view.length(); ++i)
+ width += glyph_or_emoji_width(view.code_points()[i]);
+ return width;
+}
+
+void BitmapFont::set_type(FontTypes type)
+{
+ if (type == m_type)
+ return;
+
+ if (type == FontTypes::Default)
+ return;
+
+ size_t new_glyph_count = glyph_count_by_type(type);
+ if (new_glyph_count <= m_glyph_count) {
+ m_glyph_count = new_glyph_count;
+ return;
+ }
+
+ int item_count_to_copy = min(m_glyph_count, new_glyph_count);
+
+ size_t bytes_per_glyph = sizeof(u32) * glyph_height();
+
+ auto* new_rows = static_cast<unsigned*>(kmalloc(bytes_per_glyph * new_glyph_count));
+ memset(new_rows, (unsigned)0, bytes_per_glyph * new_glyph_count);
+ memcpy(new_rows, m_rows, bytes_per_glyph * item_count_to_copy);
+
+ auto* new_widths = static_cast<u8*>(kmalloc(new_glyph_count));
+ memset(new_widths, (u8)0, new_glyph_count);
+ memcpy(new_widths, m_glyph_widths, item_count_to_copy);
+
+ kfree(m_rows);
+ kfree(m_glyph_widths);
+
+ m_type = type;
+ m_glyph_count = new_glyph_count;
+ m_rows = new_rows;
+ m_glyph_widths = new_widths;
+}
+
+String BitmapFont::qualified_name() const
+{
+ return String::formatted("{} {} {}", family(), presentation_size(), weight());
+}
+
+const Font& BitmapFont::bold_variant() const
+{
+ if (m_bold_variant)
+ return *m_bold_variant;
+ m_bold_variant = Gfx::FontDatabase::the().get(m_family, m_presentation_size, 700);
+ if (!m_bold_variant)
+ m_bold_variant = this;
+ return *m_bold_variant;
+}
+
+}
diff --git a/Libraries/LibGfx/BitmapFont.h b/Libraries/LibGfx/BitmapFont.h
new file mode 100644
index 0000000000..ef62a63da6
--- /dev/null
+++ b/Libraries/LibGfx/BitmapFont.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <AK/MappedFile.h>
+#include <AK/RefCounted.h>
+#include <AK/RefPtr.h>
+#include <AK/String.h>
+#include <AK/Types.h>
+#include <LibGfx/Font.h>
+#include <LibGfx/Size.h>
+
+namespace Gfx {
+
+enum FontTypes {
+ Default = 0,
+ LatinExtendedA = 1
+};
+
+class BitmapFont : public Font {
+public:
+ NonnullRefPtr<Font> clone() const;
+ static NonnullRefPtr<BitmapFont> create(u8 glyph_height, u8 glyph_width, bool fixed, FontTypes type);
+
+ static RefPtr<BitmapFont> load_from_file(const StringView& path);
+ bool write_to_file(const StringView& path);
+
+ ~BitmapFont();
+
+ u8 presentation_size() const { return m_presentation_size; }
+ void set_presentation_size(u8 size) { m_presentation_size = size; }
+
+ u16 weight() const { return m_weight; }
+ void set_weight(u16 weight) { m_weight = weight; }
+
+ GlyphBitmap glyph_bitmap(u32 code_point) const;
+
+ u8 glyph_width(size_t ch) const { return m_fixed_width ? m_glyph_width : m_glyph_widths[ch]; }
+ int glyph_or_emoji_width(u32 code_point) const;
+ u8 glyph_height() const { return m_glyph_height; }
+ int x_height() const { return m_x_height; }
+
+ u8 min_glyph_width() const { return m_min_glyph_width; }
+ u8 max_glyph_width() const { return m_max_glyph_width; }
+ u8 glyph_fixed_width() const { return m_glyph_width; }
+
+ u8 baseline() const { return m_baseline; }
+ void set_baseline(u8 baseline)
+ {
+ m_baseline = baseline;
+ update_x_height();
+ }
+
+ u8 mean_line() const { return m_mean_line; }
+ void set_mean_line(u8 mean_line)
+ {
+ m_mean_line = mean_line;
+ update_x_height();
+ }
+
+ int width(const StringView&) const;
+ int width(const Utf8View&) const;
+ int width(const Utf32View&) const;
+
+ const String& name() const { return m_name; }
+ void set_name(String name) { m_name = move(name); }
+
+ bool is_fixed_width() const { return m_fixed_width; }
+ void set_fixed_width(bool b) { m_fixed_width = b; }
+
+ u8 glyph_spacing() const { return m_glyph_spacing; }
+ void set_glyph_spacing(u8 spacing) { m_glyph_spacing = spacing; }
+
+ void set_glyph_width(size_t ch, u8 width)
+ {
+ ASSERT(m_glyph_widths);
+ m_glyph_widths[ch] = width;
+ }
+
+ int glyph_count() const { return m_glyph_count; }
+
+ FontTypes type() { return m_type; }
+ void set_type(FontTypes type);
+
+ const String& family() const { return m_family; }
+ void set_family(String family) { m_family = move(family); }
+
+ String qualified_name() const;
+
+ const Font& bold_variant() const;
+
+private:
+ BitmapFont(String name, String family, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line, u8 presentation_size, u16 weight, bool owns_arrays = false);
+
+ static RefPtr<BitmapFont> load_from_memory(const u8*);
+ static size_t glyph_count_by_type(FontTypes type);
+
+ void update_x_height() { m_x_height = m_baseline - m_mean_line; };
+
+ String m_name;
+ String m_family;
+ FontTypes m_type;
+ size_t m_glyph_count { 256 };
+
+ unsigned* m_rows { nullptr };
+ u8* m_glyph_widths { nullptr };
+ MappedFile m_mapped_file;
+
+ u8 m_glyph_width { 0 };
+ u8 m_glyph_height { 0 };
+ u8 m_x_height { 0 };
+ u8 m_min_glyph_width { 0 };
+ u8 m_max_glyph_width { 0 };
+ u8 m_glyph_spacing { 0 };
+ u8 m_baseline { 0 };
+ u8 m_mean_line { 0 };
+ u8 m_presentation_size { 0 };
+ u16 m_weight { 0 };
+
+ bool m_fixed_width { false };
+ bool m_owns_arrays { false };
+
+ mutable RefPtr<Gfx::Font> m_bold_variant;
+};
+
+}
diff --git a/Libraries/LibGfx/CMakeLists.txt b/Libraries/LibGfx/CMakeLists.txt
index b919b3246a..2a6d9750db 100644
--- a/Libraries/LibGfx/CMakeLists.txt
+++ b/Libraries/LibGfx/CMakeLists.txt
@@ -1,6 +1,7 @@
set(SOURCES
AffineTransform.cpp
Bitmap.cpp
+ BitmapFont.cpp
BMPLoader.cpp
BMPWriter.cpp
CharacterBitmap.cpp
diff --git a/Libraries/LibGfx/Font.cpp b/Libraries/LibGfx/Font.cpp
index 1706a90846..073279c4f8 100644
--- a/Libraries/LibGfx/Font.cpp
+++ b/Libraries/LibGfx/Font.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@gmx.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,302 +24,17 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "Font.h"
-#include "Bitmap.h"
-#include "Emoji.h"
-#include <AK/MappedFile.h>
-#include <AK/StdLibExtras.h>
-#include <AK/StringBuilder.h>
-#include <AK/Utf32View.h>
-#include <AK/Utf8View.h>
-#include <AK/Vector.h>
-#include <AK/kmalloc.h>
-#include <LibCore/FileStream.h>
-#include <LibGfx/FontDatabase.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
+#include <LibGfx/BitmapFont.h>
+#include <LibGfx/Font.h>
namespace Gfx {
-struct [[gnu::packed]] FontFileHeader {
- char magic[4];
- u8 glyph_width;
- u8 glyph_height;
- u8 type;
- u8 is_variable_width;
- u8 glyph_spacing;
- u8 baseline;
- u8 mean_line;
- u8 presentation_size;
- u16 weight;
- char name[32];
- char family[32];
-};
-
-NonnullRefPtr<Font> Font::clone() const
-{
- size_t bytes_per_glyph = sizeof(u32) * glyph_height();
- auto* new_rows = static_cast<unsigned*>(malloc(bytes_per_glyph * m_glyph_count));
- memcpy(new_rows, m_rows, bytes_per_glyph * m_glyph_count);
- auto* new_widths = static_cast<u8*>(malloc(m_glyph_count));
- if (m_glyph_widths)
- memcpy(new_widths, m_glyph_widths, m_glyph_count);
- else
- memset(new_widths, m_glyph_width, m_glyph_count);
- return adopt(*new Font(m_name, m_family, new_rows, new_widths, m_fixed_width, m_glyph_width, m_glyph_height, m_glyph_spacing, m_type, m_baseline, m_mean_line, m_presentation_size, m_weight, true));
-}
-
-NonnullRefPtr<Font> Font::create(u8 glyph_height, u8 glyph_width, bool fixed, FontTypes type)
-{
- size_t bytes_per_glyph = sizeof(u32) * glyph_height;
- size_t count = glyph_count_by_type(type);
- auto* new_rows = static_cast<unsigned*>(malloc(bytes_per_glyph * count));
- memset(new_rows, 0, bytes_per_glyph * count);
- auto* new_widths = static_cast<u8*>(malloc(count));
- memset(new_widths, glyph_width, count);
- return adopt(*new Font("Untitled", "Untitled", new_rows, new_widths, fixed, glyph_width, glyph_height, 1, type, 0, 0, 0, 400, true));
-}
-
-Font::Font(String name, String family, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line, u8 presentation_size, u16 weight, bool owns_arrays)
- : m_name(name)
- , m_family(family)
- , m_type(type)
- , m_rows(rows)
- , m_glyph_widths(widths)
- , m_glyph_width(glyph_width)
- , m_glyph_height(glyph_height)
- , m_min_glyph_width(glyph_width)
- , m_max_glyph_width(glyph_width)
- , m_glyph_spacing(glyph_spacing)
- , m_baseline(baseline)
- , m_mean_line(mean_line)
- , m_presentation_size(presentation_size)
- , m_weight(weight)
- , m_fixed_width(is_fixed_width)
- , m_owns_arrays(owns_arrays)
-{
- update_x_height();
-
- m_glyph_count = glyph_count_by_type(m_type);
-
- if (!m_fixed_width) {
- u8 maximum = 0;
- u8 minimum = 255;
- for (size_t i = 0; i < m_glyph_count; ++i) {
- minimum = min(minimum, m_glyph_widths[i]);
- maximum = max(maximum, m_glyph_widths[i]);
- }
- m_min_glyph_width = minimum;
- m_max_glyph_width = maximum;
- }
-}
-
-Font::~Font()
-{
- if (m_owns_arrays) {
- free(m_glyph_widths);
- free(m_rows);
- }
-}
-
-RefPtr<Font> Font::load_from_memory(const u8* data)
-{
- auto& header = *reinterpret_cast<const FontFileHeader*>(data);
- if (memcmp(header.magic, "!Fnt", 4)) {
- dbgprintf("header.magic != '!Fnt', instead it's '%c%c%c%c'\n", header.magic[0], header.magic[1], header.magic[2], header.magic[3]);
- return nullptr;
- }
- if (header.name[sizeof(header.name) - 1] != '\0') {
- dbgprintf("Font name not fully null-terminated\n");
- return nullptr;
- }
-
- if (header.family[sizeof(header.family) - 1] != '\0') {
- dbgprintf("Font family not fully null-terminated\n");
- return nullptr;
- }
-
- FontTypes type;
- if (header.type == 0)
- type = FontTypes::Default;
- else if (header.type == 1)
- type = FontTypes::LatinExtendedA;
- else
- ASSERT_NOT_REACHED();
-
- size_t count = glyph_count_by_type(type);
- size_t bytes_per_glyph = sizeof(unsigned) * header.glyph_height;
-
- auto* rows = const_cast<unsigned*>((const unsigned*)(data + sizeof(FontFileHeader)));
- u8* widths = nullptr;
- if (header.is_variable_width)
- widths = (u8*)(rows) + count * bytes_per_glyph;
- return adopt(*new Font(String(header.name), String(header.family), rows, widths, !header.is_variable_width, header.glyph_width, header.glyph_height, header.glyph_spacing, type, header.baseline, header.mean_line, header.presentation_size, header.weight));
-}
-
-size_t Font::glyph_count_by_type(FontTypes type)
-{
- if (type == FontTypes::Default)
- return 256;
-
- if (type == FontTypes::LatinExtendedA)
- return 384;
-
- dbg() << "Unknown font type:" << type;
- ASSERT_NOT_REACHED();
-}
-
RefPtr<Font> Font::load_from_file(const StringView& path)
{
- MappedFile mapped_file(path);
- if (!mapped_file.is_valid())
- return nullptr;
-
- auto font = load_from_memory((const u8*)mapped_file.data());
- if (!font)
- return nullptr;
-
- font->m_mapped_file = move(mapped_file);
- return font;
-}
-
-bool Font::write_to_file(const StringView& path)
-{
- FontFileHeader header;
- memset(&header, 0, sizeof(FontFileHeader));
- memcpy(header.magic, "!Fnt", 4);
- header.glyph_width = m_glyph_width;
- header.glyph_height = m_glyph_height;
- header.type = m_type;
- header.baseline = m_baseline;
- header.mean_line = m_mean_line;
- header.is_variable_width = !m_fixed_width;
- header.glyph_spacing = m_glyph_spacing;
- header.presentation_size = m_presentation_size;
- header.weight = m_weight;
- memcpy(header.name, m_name.characters(), min(m_name.length(), sizeof(header.name) - 1));
- memcpy(header.family, m_family.characters(), min(m_family.length(), sizeof(header.family) - 1));
-
- size_t bytes_per_glyph = sizeof(unsigned) * m_glyph_height;
- size_t count = glyph_count_by_type(m_type);
-
- auto stream_result = Core::OutputFileStream::open_buffered(path);
- if (stream_result.is_error())
- return false;
- auto& stream = stream_result.value();
-
- stream << ReadonlyBytes { &header, sizeof(header) };
- stream << ReadonlyBytes { m_rows, count * bytes_per_glyph };
- stream << ReadonlyBytes { m_glyph_widths, count };
-
- stream.flush();
- if (stream.handle_any_error())
- return false;
-
- return true;
-}
-
-GlyphBitmap Font::glyph_bitmap(u32 code_point) const
-{
- return GlyphBitmap(&m_rows[code_point * m_glyph_height], { glyph_width(code_point), m_glyph_height });
-}
-
-int Font::glyph_or_emoji_width(u32 code_point) const
-{
- if (code_point < m_glyph_count)
- return glyph_width(code_point);
-
- if (m_fixed_width)
- return m_glyph_width;
-
- auto* emoji = Emoji::emoji_for_code_point(code_point);
- if (emoji == nullptr)
- return glyph_width('?');
- return emoji->size().width();
-}
-
-int Font::width(const StringView& string) const
-{
- Utf8View utf8 { string };
- return width(utf8);
-}
-
-int Font::width(const Utf8View& utf8) const
-{
- bool first = true;
- int width = 0;
-
- for (u32 code_point : utf8) {
- if (!first)
- width += glyph_spacing();
- first = false;
- width += glyph_or_emoji_width(code_point);
- }
-
- return width;
-}
-
-int Font::width(const Utf32View& view) const
-{
- if (view.length() == 0)
- return 0;
- int width = (view.length() - 1) * glyph_spacing();
- for (size_t i = 0; i < view.length(); ++i)
- width += glyph_or_emoji_width(view.code_points()[i]);
- return width;
-}
-
-void Font::set_type(FontTypes type)
-{
- if (type == m_type)
- return;
-
- if (type == FontTypes::Default)
- return;
-
- size_t new_glyph_count = glyph_count_by_type(type);
- if (new_glyph_count <= m_glyph_count) {
- m_glyph_count = new_glyph_count;
- return;
+ if (path.ends_with(".font")) {
+ return BitmapFont::load_from_file(path);
}
-
- int item_count_to_copy = min(m_glyph_count, new_glyph_count);
-
- size_t bytes_per_glyph = sizeof(u32) * glyph_height();
-
- auto* new_rows = static_cast<unsigned*>(kmalloc(bytes_per_glyph * new_glyph_count));
- memset(new_rows, (unsigned)0, bytes_per_glyph * new_glyph_count);
- memcpy(new_rows, m_rows, bytes_per_glyph * item_count_to_copy);
-
- auto* new_widths = static_cast<u8*>(kmalloc(new_glyph_count));
- memset(new_widths, (u8)0, new_glyph_count);
- memcpy(new_widths, m_glyph_widths, item_count_to_copy);
-
- kfree(m_rows);
- kfree(m_glyph_widths);
-
- m_type = type;
- m_glyph_count = new_glyph_count;
- m_rows = new_rows;
- m_glyph_widths = new_widths;
-}
-
-String Font::qualified_name() const
-{
- return String::formatted("{} {} {}", family(), presentation_size(), weight());
+ return {};
}
-const Font& Font::bold_variant() const
-{
- if (m_bold_variant)
- return *m_bold_variant;
- m_bold_variant = Gfx::FontDatabase::the().get(m_family, m_presentation_size, 700);
- if (!m_bold_variant)
- m_bold_variant = this;
- return *m_bold_variant;
-}
-
-}
+} \ No newline at end of file
diff --git a/Libraries/LibGfx/Font.h b/Libraries/LibGfx/Font.h
index a997a53d0f..2e74798725 100644
--- a/Libraries/LibGfx/Font.h
+++ b/Libraries/LibGfx/Font.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@gmx.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,14 +35,9 @@
namespace Gfx {
-enum FontTypes {
- Default = 0,
- LatinExtendedA = 1
-};
-
// FIXME: Make a MutableGlyphBitmap buddy class for FontEditor instead?
class GlyphBitmap {
- friend class Font;
+ friend class BitmapFont;
public:
const unsigned* rows() const { return m_rows; }
@@ -75,108 +70,45 @@ private:
class Font : public RefCounted<Font> {
public:
- NonnullRefPtr<Font> clone() const;
- static NonnullRefPtr<Font> create(u8 glyph_height, u8 glyph_width, bool fixed, FontTypes type);
-
static RefPtr<Font> load_from_file(const StringView& path);
- bool write_to_file(const StringView& path);
-
- ~Font();
-
- u8 presentation_size() const { return m_presentation_size; }
- void set_presentation_size(u8 size) { m_presentation_size = size; }
-
- u16 weight() const { return m_weight; }
- void set_weight(u16 weight) { m_weight = weight; }
-
- GlyphBitmap glyph_bitmap(u32 code_point) const;
-
- u8 glyph_width(size_t ch) const { return m_fixed_width ? m_glyph_width : m_glyph_widths[ch]; }
- int glyph_or_emoji_width(u32 code_point) const;
- u8 glyph_height() const { return m_glyph_height; }
- int x_height() const { return m_x_height; }
-
- u8 min_glyph_width() const { return m_min_glyph_width; }
- u8 max_glyph_width() const { return m_max_glyph_width; }
- u8 glyph_fixed_width() const { return m_glyph_width; }
-
- u8 baseline() const { return m_baseline; }
- void set_baseline(u8 baseline)
- {
- m_baseline = baseline;
- update_x_height();
- }
-
- u8 mean_line() const { return m_mean_line; }
- void set_mean_line(u8 mean_line)
- {
- m_mean_line = mean_line;
- update_x_height();
- }
- int width(const StringView&) const;
- int width(const Utf8View&) const;
- int width(const Utf32View&) const;
+ virtual NonnullRefPtr<Font> clone() const = 0;
+ virtual ~Font() {};
- const String& name() const { return m_name; }
- void set_name(String name) { m_name = move(name); }
+ virtual u8 presentation_size() const = 0;
- bool is_fixed_width() const { return m_fixed_width; }
- void set_fixed_width(bool b) { m_fixed_width = b; }
+ virtual u16 weight() const = 0;
+ virtual GlyphBitmap glyph_bitmap(u32 code_point) const = 0;
- u8 glyph_spacing() const { return m_glyph_spacing; }
- void set_glyph_spacing(u8 spacing) { m_glyph_spacing = spacing; }
+ virtual u8 glyph_width(size_t ch) const = 0;
+ virtual int glyph_or_emoji_width(u32 code_point) const = 0;
+ virtual u8 glyph_height() const = 0;
+ virtual int x_height() const = 0;
- void set_glyph_width(size_t ch, u8 width)
- {
- ASSERT(m_glyph_widths);
- m_glyph_widths[ch] = width;
- }
+ virtual u8 min_glyph_width() const = 0;
+ virtual u8 max_glyph_width() const = 0;
+ virtual u8 glyph_fixed_width() const = 0;
- int glyph_count() const { return m_glyph_count; }
+ virtual u8 baseline() const = 0;
+ virtual u8 mean_line() const = 0;
- FontTypes type() { return m_type; }
- void set_type(FontTypes type);
-
- const String& family() const { return m_family; }
- void set_family(String family) { m_family = move(family); }
-
- String qualified_name() const;
-
- const Font& bold_variant() const;
-
-private:
- Font(String name, String family, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line, u8 presentation_size, u16 weight, bool owns_arrays = false);
+ virtual int width(const StringView&) const = 0;
+ virtual int width(const Utf8View&) const = 0;
+ virtual int width(const Utf32View&) const = 0;
- static RefPtr<Font> load_from_memory(const u8*);
- static size_t glyph_count_by_type(FontTypes type);
+ virtual const String& name() const = 0;
- void update_x_height() { m_x_height = m_baseline - m_mean_line; };
+ virtual bool is_fixed_width() const = 0;
- String m_name;
- String m_family;
- FontTypes m_type;
- size_t m_glyph_count { 256 };
+ virtual u8 glyph_spacing() const = 0;
- unsigned* m_rows { nullptr };
- u8* m_glyph_widths { nullptr };
- MappedFile m_mapped_file;
+ virtual int glyph_count() const = 0;
- u8 m_glyph_width { 0 };
- u8 m_glyph_height { 0 };
- u8 m_x_height { 0 };
- u8 m_min_glyph_width { 0 };
- u8 m_max_glyph_width { 0 };
- u8 m_glyph_spacing { 0 };
- u8 m_baseline { 0 };
- u8 m_mean_line { 0 };
- u8 m_presentation_size { 0 };
- u16 m_weight { 0 };
+ virtual const String& family() const = 0;
- bool m_fixed_width { false };
- bool m_owns_arrays { false };
+ virtual String qualified_name() const = 0;
- mutable RefPtr<Gfx::Font> m_bold_variant;
+ virtual const Font& bold_variant() const = 0;
};
}