1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 14:48:14 +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:
Andreas Kling 2019-02-02 23:13:12 +01:00
parent 655753c557
commit 7f91aec25c
7 changed files with 170 additions and 10 deletions

View file

@ -2,6 +2,15 @@
#include "Peanut8x10.h"
#include "Liza8x10.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
@ -29,8 +38,15 @@ void Font::initialize()
Font& Font::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();
if (!s_default_font) {
#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;
}
@ -47,11 +63,12 @@ RetainPtr<Font> Font::clone() const
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)
: m_glyphs(glyphs)
Font::Font(const String& name, const char* const* glyphs, byte glyph_width, byte glyph_height, byte first_glyph, byte last_glyph)
: m_name(name)
, m_glyphs(glyphs)
, m_glyph_width(glyph_width)
, m_glyph_height(glyph_height)
, m_first_glyph(first_glyph)
@ -73,3 +90,108 @@ Font::Font(const char* const* glyphs, byte glyph_width, byte glyph_height, byte
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