mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-29 16:21:29 +00:00
Support font files.
This only works with the userspace build of SharedGraphics so far. It's also very slow at loading fonts, but that's easy to fix. Let's put fonts in /res/fonts/.
This commit is contained in:
parent
655753c557
commit
7f91aec25c
Notes:
sideshowbarker
2024-07-19 15:53:54 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/7f91aec25cd
|
@ -16,6 +16,11 @@ public:
|
||||||
m_buffer[m_offset++] = value & 0xffu;
|
m_buffer[m_offset++] = value & 0xffu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void operator<<(char value)
|
||||||
|
{
|
||||||
|
m_buffer[m_offset++] = (byte)value;
|
||||||
|
}
|
||||||
|
|
||||||
void operator<<(word value)
|
void operator<<(word value)
|
||||||
{
|
{
|
||||||
m_buffer[m_offset++] = value & 0xffu;
|
m_buffer[m_offset++] = value & 0xffu;
|
||||||
|
@ -43,9 +48,20 @@ public:
|
||||||
m_buffer[m_offset++] = value[i];
|
m_buffer[m_offset++] = value[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void operator<<(const ByteBuffer& value)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < value.size(); ++i)
|
||||||
|
m_buffer[m_offset++] = value[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool at_end() const
|
||||||
|
{
|
||||||
|
return m_offset == m_buffer.size();
|
||||||
|
}
|
||||||
|
|
||||||
void fill_to_end(byte ch)
|
void fill_to_end(byte ch)
|
||||||
{
|
{
|
||||||
while (m_offset < m_buffer.size())
|
while (!at_end())
|
||||||
m_buffer[m_offset++] = ch;
|
m_buffer[m_offset++] = ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
Base/res/fonts/Liza8x10.font
Normal file
BIN
Base/res/fonts/Liza8x10.font
Normal file
Binary file not shown.
|
@ -1,18 +1,28 @@
|
||||||
#include "FontEditor.h"
|
#include "FontEditor.h"
|
||||||
#include <SharedGraphics/Painter.h>
|
#include <SharedGraphics/Painter.h>
|
||||||
|
#include <LibGUI/GButton.h>
|
||||||
#include <LibGUI/GLabel.h>
|
#include <LibGUI/GLabel.h>
|
||||||
|
|
||||||
FontEditorWidget::FontEditorWidget(GWidget* parent)
|
FontEditorWidget::FontEditorWidget(GWidget* parent)
|
||||||
: GWidget(parent)
|
: GWidget(parent)
|
||||||
{
|
{
|
||||||
auto mutable_font = Font::default_font().clone();
|
m_edited_font = Font::load_from_file("/saved.font");
|
||||||
|
if (!m_edited_font)
|
||||||
|
m_edited_font = Font::default_font().clone();
|
||||||
|
|
||||||
m_glyph_map_widget = new GlyphMapWidget(*mutable_font, this);
|
m_glyph_map_widget = new GlyphMapWidget(*m_edited_font, this);
|
||||||
m_glyph_map_widget->move_to({ 90, 5 });
|
m_glyph_map_widget->move_to({ 90, 5 });
|
||||||
|
|
||||||
m_glyph_editor_widget = new GlyphEditorWidget(*mutable_font, this);
|
m_glyph_editor_widget = new GlyphEditorWidget(*m_edited_font, this);
|
||||||
m_glyph_editor_widget->move_to({ 5, 5 });
|
m_glyph_editor_widget->move_to({ 5, 5 });
|
||||||
|
|
||||||
|
auto* save_button = new GButton(this);
|
||||||
|
save_button->set_caption("Save");
|
||||||
|
save_button->set_relative_rect({ 5, 135, 140, 20 });
|
||||||
|
save_button->on_click = [this] (GButton&) {
|
||||||
|
m_edited_font->write_to_file("/saved.font");
|
||||||
|
};
|
||||||
|
|
||||||
auto* label = new GLabel(this);
|
auto* label = new GLabel(this);
|
||||||
label->set_relative_rect({ 5, 110, 140, 20 });
|
label->set_relative_rect({ 5, 110, 140, 20 });
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ public:
|
||||||
virtual ~FontEditorWidget() override;
|
virtual ~FontEditorWidget() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
RetainPtr<Font> m_edited_font;
|
||||||
|
|
||||||
GlyphMapWidget* m_glyph_map_widget { nullptr };
|
GlyphMapWidget* m_glyph_map_widget { nullptr };
|
||||||
GlyphEditorWidget* m_glyph_editor_widget { nullptr };
|
GlyphEditorWidget* m_glyph_editor_widget { nullptr };
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,15 @@
|
||||||
#include "Peanut8x10.h"
|
#include "Peanut8x10.h"
|
||||||
#include "Liza8x10.h"
|
#include "Liza8x10.h"
|
||||||
#include <AK/kmalloc.h>
|
#include <AK/kmalloc.h>
|
||||||
|
#include <AK/BufferStream.h>
|
||||||
|
#include <AK/StdLibExtras.h>
|
||||||
|
|
||||||
|
#ifdef USERLAND
|
||||||
|
#include <LibC/unistd.h>
|
||||||
|
#include <LibC/stdio.h>
|
||||||
|
#include <LibC/fcntl.h>
|
||||||
|
#include <LibC/errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEFAULT_FONT_NAME Liza8x10
|
#define DEFAULT_FONT_NAME Liza8x10
|
||||||
|
|
||||||
|
@ -29,8 +38,15 @@ void Font::initialize()
|
||||||
|
|
||||||
Font& Font::default_font()
|
Font& Font::default_font()
|
||||||
{
|
{
|
||||||
if (!s_default_font)
|
if (!s_default_font) {
|
||||||
s_default_font = adopt(*new Font(DEFAULT_FONT_NAME::glyphs, DEFAULT_FONT_NAME::glyph_width, DEFAULT_FONT_NAME::glyph_height, DEFAULT_FONT_NAME::first_glyph, DEFAULT_FONT_NAME::last_glyph)).leak_ref();
|
#ifdef USERLAND
|
||||||
|
s_default_font = Font::load_from_file("/res/fonts/Liza8x10.font").leak_ref();
|
||||||
|
ASSERT(s_default_font);
|
||||||
|
#else
|
||||||
|
|
||||||
|
s_default_font = adopt(*new Font(DEFAULT_FONT_NAME::name, DEFAULT_FONT_NAME::glyphs, DEFAULT_FONT_NAME::glyph_width, DEFAULT_FONT_NAME::glyph_height, DEFAULT_FONT_NAME::first_glyph, DEFAULT_FONT_NAME::last_glyph)).leak_ref();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
return *s_default_font;
|
return *s_default_font;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,11 +63,12 @@ RetainPtr<Font> Font::clone() const
|
||||||
memset(new_glyphs[i], ' ', bytes_per_glyph);
|
memset(new_glyphs[i], ' ', bytes_per_glyph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return adopt(*new Font(new_glyphs, m_glyph_width, m_glyph_height, 0, 255));
|
return adopt(*new Font(m_name, new_glyphs, m_glyph_width, m_glyph_height, 0, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Font(const char* const* glyphs, byte glyph_width, byte glyph_height, byte first_glyph, byte last_glyph)
|
Font::Font(const String& name, const char* const* glyphs, byte glyph_width, byte glyph_height, byte first_glyph, byte last_glyph)
|
||||||
: m_glyphs(glyphs)
|
: m_name(name)
|
||||||
|
, m_glyphs(glyphs)
|
||||||
, m_glyph_width(glyph_width)
|
, m_glyph_width(glyph_width)
|
||||||
, m_glyph_height(glyph_height)
|
, m_glyph_height(glyph_height)
|
||||||
, m_first_glyph(first_glyph)
|
, m_first_glyph(first_glyph)
|
||||||
|
@ -73,3 +90,108 @@ Font::Font(const char* const* glyphs, byte glyph_width, byte glyph_height, byte
|
||||||
Font::~Font()
|
Font::~Font()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USERLAND
|
||||||
|
struct FontFileHeader {
|
||||||
|
char magic[4];
|
||||||
|
byte glyph_width;
|
||||||
|
byte glyph_height;
|
||||||
|
byte type;
|
||||||
|
byte unused[7];
|
||||||
|
char name[64];
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
RetainPtr<Font> Font::load_from_file(const String& path)
|
||||||
|
{
|
||||||
|
int fd = open(path.characters(), O_RDONLY, 0644);
|
||||||
|
if (fd < 0) {
|
||||||
|
dbgprintf("open(%s) got fd=%d, failed: %s\n", path.characters(), fd, strerror(errno));
|
||||||
|
perror("open");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FontFileHeader header;
|
||||||
|
ssize_t nread = read(fd, &header, sizeof(FontFileHeader));
|
||||||
|
if (nread != sizeof(FontFileHeader)) {
|
||||||
|
dbgprintf("nread != sizeof(FontFileHeader)=%u\n", sizeof(FontFileHeader));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(header.magic, "!Fnt", 4)) {
|
||||||
|
dbgprintf("header.magic != '!Fnt'\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.name[63] != '\0') {
|
||||||
|
dbgprintf("Font name not fully null-terminated\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char** new_glyphs = static_cast<char**>(kmalloc(sizeof(char*) * 256));
|
||||||
|
for (unsigned glyph_index = 0; glyph_index < 256; ++glyph_index) {
|
||||||
|
new_glyphs[glyph_index] = static_cast<char*>(kmalloc(header.glyph_width * header.glyph_height));
|
||||||
|
char* bitptr = new_glyphs[glyph_index];
|
||||||
|
for (unsigned y = 0; y < header.glyph_height; ++y) {
|
||||||
|
unsigned pattern;
|
||||||
|
ssize_t nread = read(fd, &pattern, sizeof(unsigned));
|
||||||
|
if (nread != sizeof(unsigned)) {
|
||||||
|
// FIXME: free() things and return nullptr.
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
for (unsigned x = 0; x < header.glyph_width; ++x) {
|
||||||
|
if (pattern & (1u << x)) {
|
||||||
|
*(bitptr++) = '#';
|
||||||
|
} else {
|
||||||
|
*(bitptr++) = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return adopt(*new Font(String(header.name), new_glyphs, header.glyph_width, header.glyph_height, 0, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Font::write_to_file(const String& path)
|
||||||
|
{
|
||||||
|
int fd = open(path.characters(), O_WRONLY | O_CREAT, 0644);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("open");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 0;
|
||||||
|
memcpy(header.name, m_name.characters(), min(m_name.length(), 63u));
|
||||||
|
|
||||||
|
size_t bytes_per_glyph = sizeof(unsigned) * m_glyph_height;
|
||||||
|
|
||||||
|
auto buffer = ByteBuffer::create_uninitialized(sizeof(FontFileHeader) + (256 * bytes_per_glyph));
|
||||||
|
BufferStream stream(buffer);
|
||||||
|
|
||||||
|
stream << ByteBuffer::wrap((byte*)&header, sizeof(FontFileHeader));
|
||||||
|
|
||||||
|
for (unsigned glyph_index = 0; glyph_index < 256; ++glyph_index) {
|
||||||
|
auto* glyph_bits = (byte*)m_glyphs[glyph_index];
|
||||||
|
for (unsigned y = 0; y < m_glyph_height; ++y) {
|
||||||
|
unsigned pattern = 0;
|
||||||
|
for (unsigned x = 0; x < m_glyph_width; ++x) {
|
||||||
|
if (glyph_bits[y * m_glyph_width + x] == '#') {
|
||||||
|
pattern |= 1 << x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream << pattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(stream.at_end());
|
||||||
|
ssize_t nwritten = write(fd, buffer.pointer(), buffer.size());
|
||||||
|
ASSERT(nwritten == (ssize_t)buffer.size());
|
||||||
|
int rc = close(fd);
|
||||||
|
ASSERT(rc == 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "CharacterBitmap.h"
|
#include "CharacterBitmap.h"
|
||||||
#include <AK/Retainable.h>
|
#include <AK/Retainable.h>
|
||||||
#include <AK/RetainPtr.h>
|
#include <AK/RetainPtr.h>
|
||||||
|
#include <AK/AKString.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
|
|
||||||
class Font : public Retainable<Font> {
|
class Font : public Retainable<Font> {
|
||||||
|
@ -11,6 +12,11 @@ public:
|
||||||
|
|
||||||
RetainPtr<Font> clone() const;
|
RetainPtr<Font> clone() const;
|
||||||
|
|
||||||
|
#ifdef USERLAND
|
||||||
|
static RetainPtr<Font> load_from_file(const String& path);
|
||||||
|
bool write_to_file(const String& path);
|
||||||
|
#endif
|
||||||
|
|
||||||
~Font();
|
~Font();
|
||||||
|
|
||||||
const CharacterBitmap& glyph_bitmap(char ch) const { return *m_bitmaps[(byte)ch]; }
|
const CharacterBitmap& glyph_bitmap(char ch) const { return *m_bitmaps[(byte)ch]; }
|
||||||
|
@ -21,7 +27,9 @@ public:
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Font(const char* const* glyphs, byte glyph_width, byte glyph_height, byte first_glyph, byte last_glyph);
|
Font(const String& name, const char* const* glyphs, byte glyph_width, byte glyph_height, byte first_glyph, byte last_glyph);
|
||||||
|
|
||||||
|
String m_name;
|
||||||
|
|
||||||
const char* const* m_glyphs { nullptr };
|
const char* const* m_glyphs { nullptr };
|
||||||
mutable RetainPtr<CharacterBitmap> m_bitmaps[256];
|
mutable RetainPtr<CharacterBitmap> m_bitmaps[256];
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Liza8x10 {
|
namespace Liza8x10 {
|
||||||
|
|
||||||
|
static constexpr char name[64] = "Old Liza";
|
||||||
|
|
||||||
static constexpr char first_glyph = '!';
|
static constexpr char first_glyph = '!';
|
||||||
static constexpr char last_glyph = '~';
|
static constexpr char last_glyph = '~';
|
||||||
static constexpr byte glyph_width = 8;
|
static constexpr byte glyph_width = 8;
|
||||||
|
|
Loading…
Reference in a new issue