BuildSystem: Move all userpace libraries under the userspace directory
As the number of libraries is increasing, root directory starts to expand. This adds better organization for libraries
This commit is contained in:
25
userspace/libraries/LibFont/CMakeLists.txt
Normal file
25
userspace/libraries/LibFont/CMakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
project(libfont CXX)
|
||||
|
||||
set(LIBGUI_SOURCES
|
||||
Font.cpp
|
||||
PSF.cpp
|
||||
)
|
||||
|
||||
add_custom_target(libfont-headers
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
||||
DEPENDS sysroot
|
||||
)
|
||||
|
||||
add_library(libfont ${LIBGUI_SOURCES})
|
||||
add_dependencies(libfont headers libc-install)
|
||||
target_link_libraries(libfont PUBLIC libc)
|
||||
|
||||
add_custom_target(libfont-install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libfont.a ${BANAN_LIB}/
|
||||
DEPENDS libfont
|
||||
BYPRODUCTS ${BANAN_LIB}/libfont.a
|
||||
)
|
||||
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||
77
userspace/libraries/LibFont/Font.cpp
Normal file
77
userspace/libraries/LibFont/Font.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include <BAN/ScopeGuard.h>
|
||||
|
||||
#include <LibFont/Font.h>
|
||||
#include <LibFont/PSF.h>
|
||||
|
||||
#if __is_kernel
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#if __is_kernel
|
||||
extern uint8_t _binary_font_prefs_psf_start[];
|
||||
extern uint8_t _binary_font_prefs_psf_end[];
|
||||
#endif
|
||||
|
||||
namespace LibFont
|
||||
{
|
||||
|
||||
#if __is_kernel
|
||||
BAN::ErrorOr<Font> Font::prefs()
|
||||
{
|
||||
size_t font_data_size = _binary_font_prefs_psf_end - _binary_font_prefs_psf_start;
|
||||
return load(BAN::ConstByteSpan(_binary_font_prefs_psf_start, font_data_size));
|
||||
}
|
||||
#endif
|
||||
|
||||
BAN::ErrorOr<Font> Font::load(BAN::StringView path)
|
||||
{
|
||||
BAN::Vector<uint8_t> file_data;
|
||||
|
||||
#if __is_kernel
|
||||
{
|
||||
auto inode = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
|
||||
TRY(file_data.resize(inode->size()));
|
||||
TRY(inode->read(0, BAN::ByteSpan(file_data.span())));
|
||||
}
|
||||
#else
|
||||
{
|
||||
char path_buffer[PATH_MAX];
|
||||
strncpy(path_buffer, path.data(), path.size());
|
||||
path_buffer[path.size()] = '\0';
|
||||
|
||||
int fd = open(path_buffer, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
BAN::ScopeGuard file_closer([fd] { close(fd); });
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
TRY(file_data.resize(st.st_size));
|
||||
|
||||
ssize_t total_read = 0;
|
||||
while (total_read < st.st_size)
|
||||
{
|
||||
ssize_t nread = read(fd, file_data.data() + total_read, st.st_size - total_read);
|
||||
if (nread == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
total_read += nread;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return load(BAN::ConstByteSpan(file_data.span()));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Font> Font::load(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
if (is_psf1(font_data))
|
||||
return TRY(parse_psf1(font_data));
|
||||
if (is_psf2(font_data))
|
||||
return TRY(parse_psf2(font_data));
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
}
|
||||
214
userspace/libraries/LibFont/PSF.cpp
Normal file
214
userspace/libraries/LibFont/PSF.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
#include <BAN/Debug.h>
|
||||
#include <BAN/Endianness.h>
|
||||
#include <BAN/UTF8.h>
|
||||
|
||||
#include <LibFont/PSF.h>
|
||||
|
||||
#define PSF1_MAGIC0 0x36
|
||||
#define PSF1_MAGIC1 0x04
|
||||
#define PSF1_MODE512 0x01
|
||||
#define PSF1_MODEHASTAB 0x02
|
||||
#define PSF1_MODEHASSEQ 0x04
|
||||
#define PSF1_STARTSEQ 0xFFFE
|
||||
#define PSF1_SEPARATOR 0xFFFF
|
||||
|
||||
#define PSF2_MAGIC0 0x72
|
||||
#define PSF2_MAGIC1 0xB5
|
||||
#define PSF2_MAGIC2 0x4A
|
||||
#define PSF2_MAGIC3 0x86
|
||||
#define PSF2_HAS_UNICODE_TABLE 0x01
|
||||
#define PSF2_STARTSEQ 0xFE
|
||||
#define PSF2_SEPARATOR 0xFF
|
||||
|
||||
namespace LibFont
|
||||
{
|
||||
|
||||
bool is_psf1(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
if (font_data.size() < 2)
|
||||
return false;
|
||||
return font_data[0] == PSF1_MAGIC0 && font_data[1] == PSF1_MAGIC1;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Font> parse_psf1(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
struct PSF1Header
|
||||
{
|
||||
uint8_t magic[2];
|
||||
uint8_t mode;
|
||||
uint8_t char_size;
|
||||
};
|
||||
|
||||
if (font_data.size() < sizeof(PSF1Header))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
const auto& header = font_data.as<const PSF1Header>();
|
||||
|
||||
uint32_t glyph_count = header.mode & PSF1_MODE512 ? 512 : 256;
|
||||
uint32_t glyph_size = header.char_size;
|
||||
uint32_t glyph_data_size = glyph_size * glyph_count;
|
||||
|
||||
if (font_data.size() < sizeof(PSF1Header) + glyph_data_size)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
BAN::Vector<uint8_t> glyph_data;
|
||||
TRY(glyph_data.resize(glyph_data_size));
|
||||
memcpy(glyph_data.data(), font_data.data() + sizeof(PSF1Header), glyph_data_size);
|
||||
|
||||
BAN::HashMap<uint32_t, uint32_t> glyph_offsets;
|
||||
TRY(glyph_offsets.reserve(glyph_count));
|
||||
|
||||
bool codepoint_redef = false;
|
||||
bool codepoint_sequence = false;
|
||||
|
||||
if (header.mode & (PSF1_MODEHASTAB | PSF1_MODEHASSEQ))
|
||||
{
|
||||
uint32_t current_index = sizeof(PSF1Header) + glyph_data_size;
|
||||
|
||||
uint32_t glyph_index = 0;
|
||||
while (current_index < font_data.size())
|
||||
{
|
||||
uint16_t lo = font_data[current_index];
|
||||
uint16_t hi = font_data[current_index + 1];
|
||||
uint16_t codepoint = (hi << 8) | lo;
|
||||
|
||||
if (codepoint == PSF1_STARTSEQ)
|
||||
{
|
||||
codepoint_sequence = true;
|
||||
break;
|
||||
}
|
||||
else if (codepoint == PSF1_SEPARATOR)
|
||||
{
|
||||
glyph_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (glyph_offsets.contains(codepoint))
|
||||
codepoint_redef = true;
|
||||
else
|
||||
TRY(glyph_offsets.insert(codepoint, glyph_index * glyph_size));
|
||||
}
|
||||
|
||||
current_index += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < glyph_count; i++)
|
||||
TRY(glyph_offsets.insert(i, i * glyph_size));
|
||||
}
|
||||
|
||||
if (codepoint_redef)
|
||||
dwarnln("Font contains multiple definitions for same codepoint(s)");
|
||||
if (codepoint_sequence)
|
||||
dwarnln("Font contains codepoint sequences (not supported)");
|
||||
|
||||
return Font(BAN::move(glyph_offsets), BAN::move(glyph_data), 8, header.char_size, 1);
|
||||
}
|
||||
|
||||
bool is_psf2(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
if (font_data.size() < 4)
|
||||
return false;
|
||||
return font_data[0] == PSF2_MAGIC0 && font_data[1] == PSF2_MAGIC1 && font_data[2] == PSF2_MAGIC2 && font_data[3] == PSF2_MAGIC3;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Font> parse_psf2(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
struct PSF2Header
|
||||
{
|
||||
uint8_t magic[4];
|
||||
BAN::LittleEndian<uint32_t> version;
|
||||
BAN::LittleEndian<uint32_t> header_size;
|
||||
BAN::LittleEndian<uint32_t> flags;
|
||||
BAN::LittleEndian<uint32_t> glyph_count;
|
||||
BAN::LittleEndian<uint32_t> glyph_size;
|
||||
BAN::LittleEndian<uint32_t> height;
|
||||
BAN::LittleEndian<uint32_t> width;
|
||||
};
|
||||
|
||||
if (font_data.size() < sizeof(PSF2Header))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
const auto& header = font_data.as<const PSF2Header>();
|
||||
|
||||
uint32_t glyph_data_size = header.glyph_count * header.glyph_size;
|
||||
|
||||
if (font_data.size() < glyph_data_size + header.header_size)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
BAN::Vector<uint8_t> glyph_data;
|
||||
TRY(glyph_data.resize(glyph_data_size));
|
||||
memcpy(glyph_data.data(), font_data.data() + header.header_size, glyph_data_size);
|
||||
|
||||
BAN::HashMap<uint32_t, uint32_t> glyph_offsets;
|
||||
TRY(glyph_offsets.reserve(400));
|
||||
|
||||
bool invalid_utf = false;
|
||||
bool codepoint_redef = false;
|
||||
bool codepoint_sequence = false;
|
||||
|
||||
uint8_t bytes[4] {};
|
||||
uint32_t byte_index = 0;
|
||||
if (header.flags & PSF2_HAS_UNICODE_TABLE)
|
||||
{
|
||||
uint32_t glyph_index = 0;
|
||||
for (uint32_t i = glyph_data_size + header.header_size; i < font_data.size(); i++)
|
||||
{
|
||||
uint8_t byte = font_data[i];
|
||||
|
||||
if (byte == PSF2_STARTSEQ)
|
||||
{
|
||||
codepoint_sequence = true;
|
||||
break;
|
||||
}
|
||||
else if (byte == PSF2_SEPARATOR)
|
||||
{
|
||||
if (byte_index)
|
||||
{
|
||||
invalid_utf = true;
|
||||
byte_index = 0;
|
||||
}
|
||||
glyph_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(byte_index < 4);
|
||||
bytes[byte_index++] = byte;
|
||||
|
||||
uint32_t len = BAN::UTF8::byte_length(bytes[0]);
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
invalid_utf = true;
|
||||
byte_index = 0;
|
||||
}
|
||||
else if (len == byte_index)
|
||||
{
|
||||
uint32_t codepoint = BAN::UTF8::to_codepoint(bytes);
|
||||
if (codepoint == BAN::UTF8::invalid)
|
||||
invalid_utf = true;
|
||||
else if (glyph_offsets.contains(codepoint))
|
||||
codepoint_redef = true;
|
||||
else
|
||||
TRY(glyph_offsets.insert(codepoint, glyph_index * header.glyph_size));
|
||||
byte_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < header.glyph_count; i++)
|
||||
TRY(glyph_offsets.insert(i, i * header.glyph_size));
|
||||
}
|
||||
|
||||
if (invalid_utf)
|
||||
dwarnln("Font contains invalid UTF-8 codepoint(s)");
|
||||
if (codepoint_redef)
|
||||
dwarnln("Font contains multiple definitions for same codepoint(s)");
|
||||
if (codepoint_sequence)
|
||||
dwarnln("Font contains codepoint sequences (not supported)");
|
||||
|
||||
return Font(BAN::move(glyph_offsets), BAN::move(glyph_data), header.width, header.height, header.glyph_size / header.height);
|
||||
}
|
||||
|
||||
}
|
||||
50
userspace/libraries/LibFont/include/LibFont/Font.h
Normal file
50
userspace/libraries/LibFont/include/LibFont/Font.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/HashMap.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace LibFont
|
||||
{
|
||||
|
||||
class Font
|
||||
{
|
||||
public:
|
||||
Font() = default;
|
||||
Font(BAN::HashMap<uint32_t, uint32_t>&& glyph_offsets, BAN::Vector<uint8_t>&& glyph_data, uint32_t width, uint32_t height, uint32_t pitch)
|
||||
: m_glyph_offsets(BAN::move(glyph_offsets))
|
||||
, m_glyph_data(BAN::move(glyph_data))
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
, m_pitch(pitch)
|
||||
{ }
|
||||
|
||||
static BAN::ErrorOr<Font> load(BAN::StringView path);
|
||||
static BAN::ErrorOr<Font> load(BAN::ConstByteSpan font_data);
|
||||
#if __is_kernel
|
||||
static BAN::ErrorOr<Font> prefs();
|
||||
#endif
|
||||
|
||||
uint32_t width() const { return m_width; }
|
||||
uint32_t height() const { return m_height; }
|
||||
uint32_t pitch() const { return m_pitch; }
|
||||
|
||||
bool has_glyph(uint32_t codepoint) const { return glyph(codepoint) != nullptr; }
|
||||
const uint8_t* glyph(uint32_t codepoint) const
|
||||
{
|
||||
auto it = m_glyph_offsets.find(codepoint);
|
||||
if (it == m_glyph_offsets.end())
|
||||
return nullptr;
|
||||
return m_glyph_data.data() + it->value;
|
||||
}
|
||||
|
||||
private:
|
||||
BAN::HashMap<uint32_t, uint32_t> m_glyph_offsets;
|
||||
BAN::Vector<uint8_t> m_glyph_data;
|
||||
uint32_t m_width = 0;
|
||||
uint32_t m_height = 0;
|
||||
uint32_t m_pitch = 0;
|
||||
};
|
||||
|
||||
}
|
||||
14
userspace/libraries/LibFont/include/LibFont/PSF.h
Normal file
14
userspace/libraries/LibFont/include/LibFont/PSF.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <LibFont/Font.h>
|
||||
|
||||
namespace LibFont
|
||||
{
|
||||
|
||||
bool is_psf1(BAN::ConstByteSpan);
|
||||
BAN::ErrorOr<Font> parse_psf1(BAN::ConstByteSpan);
|
||||
|
||||
bool is_psf2(BAN::ConstByteSpan);
|
||||
BAN::ErrorOr<Font> parse_psf2(BAN::ConstByteSpan);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user