Add a display server and graphical user interface #38
6
.gitignore
vendored
6
.gitignore
vendored
@ -4,7 +4,11 @@ build/
|
||||
initrd/boot/moon
|
||||
env-local.sh
|
||||
initrd/bin/**
|
||||
base/usr/**
|
||||
base/usr/bin/**
|
||||
base/usr/include/**
|
||||
base/usr/lib/**
|
||||
base/usr/share/pkgdb/**
|
||||
!base/usr/share/fonts/*
|
||||
base/etc/skel/LICENSE
|
||||
.fakeroot
|
||||
kernel/config.cmake
|
||||
|
BIN
base/usr/share/fonts/Tamsyn-Bold.psf
Normal file
BIN
base/usr/share/fonts/Tamsyn-Bold.psf
Normal file
Binary file not shown.
BIN
base/usr/share/fonts/Tamsyn-Regular.psf
Normal file
BIN
base/usr/share/fonts/Tamsyn-Regular.psf
Normal file
Binary file not shown.
@ -6,9 +6,11 @@ set(SOURCES
|
||||
${HEADERS}
|
||||
src/Canvas.cpp
|
||||
src/Rect.cpp
|
||||
src/Font.cpp
|
||||
)
|
||||
|
||||
add_library(ui ${SOURCES})
|
||||
target_compile_options(ui PRIVATE ${COMMON_FLAGS})
|
||||
target_include_directories(ui PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/)
|
||||
target_include_directories(ui PUBLIC ${LUNA_BASE}/usr/include)
|
||||
target_link_libraries(ui PUBLIC os)
|
||||
|
55
libui/include/ui/Font.h
Normal file
55
libui/include/ui/Font.h
Normal file
@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#include <luna/Buffer.h>
|
||||
#include <luna/SharedPtr.h>
|
||||
#include <os/Path.h>
|
||||
#include <ui/Canvas.h>
|
||||
|
||||
#define PSF_FONT_MAGIC 0x864ab572
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class Font : public Shareable
|
||||
{
|
||||
public:
|
||||
enum FontWeight
|
||||
{
|
||||
Regular,
|
||||
Bold,
|
||||
};
|
||||
|
||||
static Result<SharedPtr<Font>> load(const os::Path& path);
|
||||
static Result<SharedPtr<Font>> load_builtin(StringView name, FontWeight weight);
|
||||
|
||||
static SharedPtr<Font> default_font();
|
||||
static SharedPtr<Font> default_bold_font();
|
||||
|
||||
void render(wchar_t codepoint, ui::Color color, ui::Canvas& canvas);
|
||||
void render(const wchar_t* text, ui::Color color, ui::Canvas& canvas);
|
||||
|
||||
int width() const
|
||||
{
|
||||
return m_psf_header.width;
|
||||
}
|
||||
|
||||
int height() const
|
||||
{
|
||||
return m_psf_header.height;
|
||||
}
|
||||
|
||||
private:
|
||||
struct PSFHeader
|
||||
{
|
||||
u32 magic;
|
||||
u32 version; // zero
|
||||
u32 headersize;
|
||||
u32 flags; // 0 if there's no unicode table
|
||||
u32 numglyph;
|
||||
u32 bytesperglyph;
|
||||
int height;
|
||||
int width;
|
||||
};
|
||||
|
||||
PSFHeader m_psf_header;
|
||||
Buffer m_font_data;
|
||||
};
|
||||
};
|
117
libui/src/Font.cpp
Normal file
117
libui/src/Font.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include <luna/String.h>
|
||||
#include <os/File.h>
|
||||
#include <ui/Font.h>
|
||||
|
||||
SharedPtr<ui::Font> s_default_font = {};
|
||||
SharedPtr<ui::Font> s_default_bold_font = {};
|
||||
|
||||
constexpr static int BYTES_PER_PIXEL = (int)sizeof(ui::Color);
|
||||
|
||||
namespace ui
|
||||
{
|
||||
Result<SharedPtr<Font>> Font::load(const os::Path& path)
|
||||
{
|
||||
auto font = TRY(make_shared<Font>());
|
||||
|
||||
auto file = TRY(os::File::open(path, os::File::ReadOnly));
|
||||
|
||||
TRY(file->read_typed(font->m_psf_header));
|
||||
|
||||
if (font->m_psf_header.magic != PSF_FONT_MAGIC)
|
||||
{
|
||||
os::eprintln("ui::Font::load(%s) failed: font magic does not match PSF2 magic", path.name().chars());
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
if (font->m_psf_header.version != 0)
|
||||
{
|
||||
os::eprintln("ui::Font::load(%s) failed: font version is unsupported", path.name().chars());
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
if (font->m_psf_header.flags)
|
||||
{
|
||||
os::eprintln("ui::Font::load(%s) warning: font has a unicode table, which we're ignoring",
|
||||
path.name().chars());
|
||||
// todo(); // Font has a unicode table, oh no!
|
||||
}
|
||||
|
||||
font->m_font_data = TRY(file->read_all()); // Read the rest of the file into the font data buffer.
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
Result<SharedPtr<Font>> Font::load_builtin(StringView name, FontWeight weight)
|
||||
{
|
||||
auto path = TRY(String::format("/usr/share/fonts/%s-%s.psf"_sv, name.chars(),
|
||||
weight == FontWeight::Bold ? "Bold" : "Regular"));
|
||||
|
||||
return load(path.view());
|
||||
}
|
||||
|
||||
SharedPtr<Font> Font::default_font()
|
||||
{
|
||||
if (s_default_font) return s_default_font;
|
||||
s_default_font = load("/usr/share/fonts/Tamsyn-Regular.psf").release_value();
|
||||
return s_default_font;
|
||||
}
|
||||
|
||||
SharedPtr<Font> Font::default_bold_font()
|
||||
{
|
||||
if (s_default_bold_font) return s_default_bold_font;
|
||||
s_default_bold_font = load("/usr/share/fonts/Tamsyn-Bold.psf").release_value();
|
||||
return s_default_bold_font;
|
||||
}
|
||||
|
||||
void Font::render(wchar_t codepoint, ui::Color color, ui::Canvas& canvas)
|
||||
{
|
||||
check(canvas.width == m_psf_header.width && canvas.height == m_psf_header.height);
|
||||
|
||||
const wchar_t str[] = { codepoint, 0 };
|
||||
render(str, color, canvas);
|
||||
}
|
||||
|
||||
void Font::render(const wchar_t* text, ui::Color color, ui::Canvas& canvas)
|
||||
{
|
||||
usize len = wcslen(text);
|
||||
|
||||
int height = m_psf_header.height;
|
||||
int width = m_psf_header.width;
|
||||
int last_char_width = width;
|
||||
|
||||
if (canvas.width < (m_psf_header.width * static_cast<int>(len)))
|
||||
{
|
||||
len = (canvas.width / width) + 1;
|
||||
last_char_width = canvas.width % width;
|
||||
}
|
||||
|
||||
if (canvas.height < height) height = canvas.height;
|
||||
|
||||
const int bytes_per_line = (m_psf_header.width + 7) / 8;
|
||||
|
||||
for (usize i = 0; i < len; i++)
|
||||
{
|
||||
if (i + 1 == len) width = last_char_width;
|
||||
wchar_t codepoint = text[i];
|
||||
|
||||
u8* glyph =
|
||||
m_font_data.data() + (codepoint > 0 && codepoint < (wchar_t)m_psf_header.numglyph ? codepoint : 0) *
|
||||
m_psf_header.bytesperglyph;
|
||||
|
||||
u32 offset = (u32)i * (m_psf_header.width + 1) * BYTES_PER_PIXEL;
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
u32 line = offset;
|
||||
int mask = 1 << (m_psf_header.width - 1);
|
||||
for (int x = 0; x < m_psf_header.width; x++)
|
||||
{
|
||||
if (*((u32*)glyph) & mask) *(u32*)(canvas.ptr + line) = color.raw;
|
||||
mask >>= 1;
|
||||
line += BYTES_PER_PIXEL;
|
||||
}
|
||||
glyph += bytes_per_line;
|
||||
offset += canvas.stride * BYTES_PER_PIXEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user