diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..31d903e --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Add: [-Wno-c23-extensions] diff --git a/.gitignore b/.gitignore index 149a11e..ddb991c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ [Bb]uild* +CMakeLists.txt.* result .cache .direnv diff --git a/flake.nix b/flake.nix index 5d21304..44d124b 100644 --- a/flake.nix +++ b/flake.nix @@ -16,7 +16,19 @@ system: let pkgs = import nixpkgs { inherit system; }; - nativeBuildInputs = [ ]; + nativeBuildInputs = with pkgs; [ + pkg-config + wayland + wayland-protocols + wlr-protocols + wayland-scanner + libGL + libportal + glib + libxkbcommon + fontconfig + harfbuzz + ]; buildInputs = with pkgs; [ cmake ninja @@ -31,23 +43,12 @@ [ llvmPackages_21.clang-tools lldb + gdb codespell doxygen gtest cppcheck inotify-tools - - pkg-config - wayland - wayland-protocols - wlr-protocols - wayland-scanner - libGL - libportal - glib - libxkbcommon - fontconfig - harfbuzz ] ++ buildInputs ++ nativeBuildInputs diff --git a/src/App.cpp b/src/App.cpp index 14d3c13..7b0e184 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -300,7 +302,19 @@ auto App::init_egl() -> void m_tr = TextRenderer(); auto const font = find_font_path(); assert(font && "Could not find font"); - auto const font_handle = m_tr->load_font(*font); + std::vector fallback_paths; + constexpr char const *fallback_candidates[] = { + "Noto Sans CJK JP:style=Regular", + "Noto Sans CJK SC:style=Regular", + "Noto Sans CJK KR:style=Regular", + "Noto Sans CJK TC:style=Regular", + }; + for (auto const *name : fallback_candidates) { + if (auto fallback = find_font_path(name)) + fallback_paths.push_back(*fallback); + } + auto const font_handle + = m_tr->load_font(*font, std::span(fallback_paths)); assert(font_handle && "Could not load font"); m_font = *font_handle; } diff --git a/src/FreetypeHooks.cpp b/src/FreetypeHooks.cpp new file mode 100644 index 0000000..a991656 --- /dev/null +++ b/src/FreetypeHooks.cpp @@ -0,0 +1,38 @@ +#include +#include + +#include +#include FT_FREETYPE_H + +using FtInitFn = FT_Error (*)(FT_Library *); +using FtDoneFn = FT_Error (*)(FT_Library); + +extern "C" FT_Error FT_Init_FreeType(FT_Library *library) +{ + static FtInitFn real_fn + = reinterpret_cast(dlsym(RTLD_NEXT, "FT_Init_FreeType")); + if (!real_fn) { + std::fprintf(stderr, + "FT_Init_FreeType hook: failed to locate real symbol\n"); + return FT_Err_Invalid_Handle; + } + FT_Error error = real_fn(library); + std::fprintf(stderr, "FT_Init_FreeType -> %p (err=%d)\n", + library ? static_cast(*library) : nullptr, error); + return error; +} + +extern "C" FT_Error FT_Done_FreeType(FT_Library library) +{ + static FtDoneFn real_fn + = reinterpret_cast(dlsym(RTLD_NEXT, "FT_Done_FreeType")); + std::fprintf(stderr, "FT_Done_FreeType(%p)\n", + static_cast(library)); + if (!real_fn) { + std::fprintf(stderr, + "FT_Done_FreeType hook: failed to locate real symbol\n"); + return FT_Err_Invalid_Handle; + } + return real_fn(library); +} + diff --git a/src/TextRenderer.cpp b/src/TextRenderer.cpp index f9927b4..a369da7 100644 --- a/src/TextRenderer.cpp +++ b/src/TextRenderer.cpp @@ -1,7 +1,6 @@ #include "TextRenderer.hpp" #include -#include #include #include #include @@ -41,7 +40,6 @@ namespace { constexpr int kAtlasDimension = 1024; constexpr int kAtlasPadding = 2; -constexpr float kDefaultPxRange = 4.0f; constexpr float kDefaultEmScale = 48.0f; constexpr float hb_to_em(hb_position_t value, unsigned upem) @@ -66,6 +64,78 @@ auto ft_library() -> FT_Library return library; } +struct CodepointSpan { + uint32_t codepoint {}; + size_t start {}; + size_t end {}; +}; + +auto decode_utf8(std::string_view text) -> std::vector +{ + std::vector spans; + size_t i = 0; + while (i < text.size()) { + u8 const byte = static_cast(text[i]); + size_t const start = i; + size_t length = 1; + uint32_t cp = 0xFFFD; + if (byte < 0x80) { + cp = byte; + } else if ((byte & 0xE0) == 0xC0) { + if (i + 1 < text.size()) { + u8 const b1 = static_cast(text[i + 1]); + if ((b1 & 0xC0) == 0x80) { + uint32_t t + = ((byte & 0x1F) << 6) | (static_cast(b1) & 0x3F); + if (t >= 0x80) { + cp = t; + length = 2; + } + } + } + } else if ((byte & 0xF0) == 0xE0) { + if (i + 2 < text.size()) { + u8 const b1 = static_cast(text[i + 1]); + u8 const b2 = static_cast(text[i + 2]); + if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80) { + uint32_t t = ((byte & 0x0F) << 12) + | ((static_cast(b1) & 0x3F) << 6) + | (static_cast(b2) & 0x3F); + if (t >= 0x800 && (t < 0xD800 || t > 0xDFFF)) { + cp = t; + length = 3; + } + } + } + } else if ((byte & 0xF8) == 0xF0) { + if (i + 3 < text.size()) { + u8 const b1 = static_cast(text[i + 1]); + u8 const b2 = static_cast(text[i + 2]); + u8 const b3 = static_cast(text[i + 3]); + if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80 + && (b3 & 0xC0) == 0x80) { + uint32_t t = ((byte & 0x07) << 18) + | ((static_cast(b1) & 0x3F) << 12) + | ((static_cast(b2) & 0x3F) << 6) + | (static_cast(b3) & 0x3F); + if (t >= 0x10000 && t <= 0x10FFFF) { + cp = t; + length = 4; + } + } + } + } + + spans.push_back(CodepointSpan { + .codepoint = cp, + .start = start, + .end = std::min(text.size(), start + length), + }); + i += length; + } + return spans; +} + } // namespace auto TextRenderer::flush_font(FontRuntime &rt, FontData &fd) -> void @@ -253,50 +323,57 @@ TextRenderer::TextRenderer() TextRenderer::~TextRenderer() { - for (usize i = 0; i < m_font_runtime.size(); ++i) { - if (m_font_runtime[i]) { - FontHandle handle; - handle.id = i; - unload_font(handle); - } - } - UnloadShader(m_msdf_shader); + for (usize i = 0; i < m_font_sets.size(); ++i) { + FontHandle handle; + handle.id = i; + unload_font(handle); + } + // Not unloading the shader... I have no clue why, but there's some sort of double free. I love C interop!!!! } auto TextRenderer::measure_text(FontHandle const font, std::string_view const text, int const size) -> Vector2 { - usize const font_id = font(); - if (font_id >= m_font_runtime.size() || !m_font_runtime[font_id] - || !m_font_runtime[font_id]->hb_font) + usize const handle_id = font(); + if (handle_id >= m_font_sets.size()) + return Vector2 { 0.0f, 0.0f }; + auto const &font_set = m_font_sets[handle_id]; + if (font_set.font_indices.empty()) return Vector2 { 0.0f, 0.0f }; - auto &rt = *m_font_runtime[font_id]; - auto &fd = m_font_data[font_id]; + auto placements = shape_text(font, text); - hb_buffer_t *buffer = hb_buffer_create(); - hb_buffer_add_utf8(buffer, text.data(), static_cast(text.size()), 0, - static_cast(text.size())); - hb_buffer_guess_segment_properties(buffer); - hb_shape(rt.hb_font, buffer, nullptr, 0); + auto primary_runtime_index = font_set.font_indices.front(); + if (placements.empty()) { + if (primary_runtime_index >= m_font_runtime.size() + || !m_font_runtime[primary_runtime_index]) + return Vector2 { 0.0f, 0.0f }; + auto const &rt_primary = *m_font_runtime[primary_runtime_index]; + float height_em = rt_primary.ascent - rt_primary.descent; + return Vector2 { 0.0f, height_em * static_cast(size) }; + } - unsigned length = hb_buffer_get_length(buffer); - auto *infos = hb_buffer_get_glyph_infos(buffer, nullptr); - auto *positions = hb_buffer_get_glyph_positions(buffer, nullptr); float advance_em = 0.0f; float min_x_em = 0.0f; float max_x_em = 0.0f; bool first = true; + bool have_metrics = false; + float max_ascent = 0.0f; + float min_descent = 0.0f; - for (unsigned i = 0; i < length; ++i) { - u32 glyph_index = infos[i].codepoint; - if (glyph_index == 0) + for (auto const &placement : placements) { + usize const runtime_index = placement.runtime_index; + if (runtime_index >= m_font_runtime.size() + || !m_font_runtime[runtime_index]) continue; - auto *entry = ensure_glyph(rt, fd, glyph_index, false); + auto &rt = *m_font_runtime[runtime_index]; + auto &fd = m_font_data[runtime_index]; + auto *entry + = ensure_glyph(rt, fd, placement.glyph_index, false); if (!entry || entry->width == 0 || entry->height == 0) continue; float const x_offset_em - = hb_to_em(positions[i].x_offset, rt.units_per_em); + = hb_to_em(placement.x_offset, rt.units_per_em); float const left = advance_em + x_offset_em + entry->glyph.plane_bounds.left; float const right @@ -309,17 +386,36 @@ auto TextRenderer::measure_text(FontHandle const font, min_x_em = std::min(min_x_em, left); max_x_em = std::max(max_x_em, right); } - advance_em += hb_to_em(positions[i].x_advance, rt.units_per_em); + if (!have_metrics) { + max_ascent = rt.ascent; + min_descent = rt.descent; + have_metrics = true; + } else { + max_ascent = std::max(max_ascent, rt.ascent); + min_descent = std::min(min_descent, rt.descent); + } + advance_em += hb_to_em(placement.x_advance, rt.units_per_em); } - hb_buffer_destroy(buffer); - - if (first) - return Vector2 { 0.0f, - (rt.ascent - rt.descent) * static_cast(size) }; + if (first) { + if (primary_runtime_index >= m_font_runtime.size() + || !m_font_runtime[primary_runtime_index]) + return Vector2 { 0.0f, 0.0f }; + auto const &rt = *m_font_runtime[primary_runtime_index]; + float height_em = rt.ascent - rt.descent; + return Vector2 { 0.0f, height_em * static_cast(size) }; + } float width_em = std::max(max_x_em, advance_em) - min_x_em; - float height_em = rt.ascent - rt.descent; + float height_em = 0.0f; + if (have_metrics) { + height_em = max_ascent - min_descent; + } else if (primary_runtime_index < m_font_runtime.size() + && m_font_runtime[primary_runtime_index]) { + auto const &rt = *m_font_runtime[primary_runtime_index]; + height_em = rt.ascent - rt.descent; + } + return Vector2 { width_em * static_cast(size), height_em * static_cast(size) }; } @@ -330,51 +426,47 @@ auto TextRenderer::draw_text(FontHandle const font, std::string_view const text, auto const draw_start = std::chrono::steady_clock::now(); int const pos_x = pos.x; int const pos_y = pos.y; - // Don't use pos from here on out! - usize const font_id = font(); - if (font_id >= m_font_runtime.size() || !m_font_runtime[font_id] - || !m_font_runtime[font_id]->hb_font) + usize const handle_id = font(); + if (handle_id >= m_font_sets.size()) + return; + auto const &font_set = m_font_sets[handle_id]; + if (font_set.font_indices.empty()) return; - auto &rt = *m_font_runtime[font_id]; - auto &fd = m_font_data[font_id]; - hb_buffer_t *buffer = hb_buffer_create(); - hb_buffer_add_utf8(buffer, text.data(), static_cast(text.size()), 0, - static_cast(text.size())); - hb_buffer_guess_segment_properties(buffer); - hb_shape(rt.hb_font, buffer, nullptr, 0); + auto placements = shape_text(font, text); + if (placements.empty()) + return; - unsigned length = hb_buffer_get_length(buffer); - auto *infos = hb_buffer_get_glyph_infos(buffer, nullptr); - auto *positions = hb_buffer_get_glyph_positions(buffer, nullptr); float const size_f = static_cast(size); float pen_x_em = 0.0f; float pen_y_em = 0.0f; - rt.frame_stamp++; + std::vector updated_stamp; + updated_stamp.reserve(font_set.font_indices.size()); - // FIXME: Figure out shader - // BeginShaderMode(m_msdf_shader); - // if (m_px_range_uniform >= 0) { - // float shader_px_range = rt.px_range; - // SetShaderValue(m_msdf_shader, m_px_range_uniform, &shader_px_range, - // SHADER_UNIFORM_FLOAT); - // } + for (auto const &placement : placements) { + usize const runtime_index = placement.runtime_index; + if (runtime_index >= m_font_runtime.size() + || !m_font_runtime[runtime_index]) + continue; + auto &rt = *m_font_runtime[runtime_index]; + auto &fd = m_font_data[runtime_index]; + if (std::find(updated_stamp.begin(), updated_stamp.end(), runtime_index) + == updated_stamp.end()) { + rt.frame_stamp++; + updated_stamp.push_back(runtime_index); + } - for (unsigned i = 0; i < length; ++i) { - u32 glyph_index = infos[i].codepoint; - if (glyph_index == 0) - continue; - auto *entry = ensure_glyph(rt, fd, glyph_index, true); - if (!entry) - continue; - if (entry->width == 0 || entry->height == 0) + auto *entry + = ensure_glyph(rt, fd, placement.glyph_index, true); + if (!entry || entry->width == 0 || entry->height == 0) continue; + float const advance_em - = hb_to_em(positions[i].x_advance, rt.units_per_em); + = hb_to_em(placement.x_advance, rt.units_per_em); float const x_offset_em - = hb_to_em(positions[i].x_offset, rt.units_per_em); + = hb_to_em(placement.x_offset, rt.units_per_em); float const y_offset_em - = hb_to_em(positions[i].y_offset, rt.units_per_em); + = hb_to_em(placement.y_offset, rt.units_per_em); float const x_base_em = pen_x_em + x_offset_em; float const y_base_em = pen_y_em + y_offset_em; float const scale_px = size_f / static_cast(rt.em_scale); @@ -397,23 +489,20 @@ auto TextRenderer::draw_text(FontHandle const font, std::string_view const text, fd.atlas, source, dest, Vector2 { 0.0f, 0.0f }, 0.0f, color); pen_x_em += advance_em; - pen_y_em += hb_to_em(positions[i].y_advance, rt.units_per_em); + pen_y_em += hb_to_em(placement.y_advance, rt.units_per_em); } - // EndShaderMode(); - hb_buffer_destroy(buffer); - auto const draw_end = std::chrono::steady_clock::now(); auto const draw_ms = std::chrono::duration(draw_end - draw_start) .count(); if (draw_ms > 5.0) TraceLog(LOG_INFO, "draw_text took %.2f ms for %zu glyphs", draw_ms, - static_cast(length)); + placements.size()); } -auto TextRenderer::load_font(std::filesystem::path const &path) - -> std::optional +auto TextRenderer::load_single_font(std::filesystem::path const &path) + -> std::optional { FT_Library const ft = ft_library(); if (!ft) @@ -422,7 +511,10 @@ auto TextRenderer::load_font(std::filesystem::path const &path) FT_Face face = nullptr; if (FT_New_Face(ft, path.string().c_str(), 0, &face) != 0) return std::nullopt; - FT_Select_Charmap(face, FT_ENCODING_UNICODE); + if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) { + FT_Done_Face(face); + return std::nullopt; + } auto runtime = std::make_unique(); runtime->face = face; @@ -446,10 +538,13 @@ auto TextRenderer::load_font(std::filesystem::path const &path) runtime->line_gap = std::max(0.0f, line_height - adv_height); runtime->hb_face = hb_ft_face_create_referenced(face); + if (!runtime->hb_face) { + FT_Done_Face(face); + return std::nullopt; + } runtime->hb_font = hb_ft_font_create_referenced(face); if (!runtime->hb_font) { - if (runtime->hb_face) - hb_face_destroy(runtime->hb_face); + hb_face_destroy(runtime->hb_face); FT_Done_Face(face); return std::nullopt; } @@ -472,18 +567,18 @@ auto TextRenderer::load_font(std::filesystem::path const &path) = GenImageColor(runtime->atlas_width, runtime->atlas_height, BLANK); if (!font_data.atlas_img.data) { msdfgen::destroyFont(runtime->msdf_font); + runtime->msdf_font = nullptr; hb_font_destroy(runtime->hb_font); hb_face_destroy(runtime->hb_face); - FT_Done_Face(face); return std::nullopt; } font_data.atlas = LoadTextureFromImage(font_data.atlas_img); if (font_data.atlas.id == 0) { UnloadImage(font_data.atlas_img); msdfgen::destroyFont(runtime->msdf_font); + runtime->msdf_font = nullptr; hb_font_destroy(runtime->hb_font); hb_face_destroy(runtime->hb_face); - FT_Done_Face(face); return std::nullopt; } SetTextureFilter(font_data.atlas, TEXTURE_FILTER_BILINEAR); @@ -492,40 +587,170 @@ auto TextRenderer::load_font(std::filesystem::path const &path) m_font_data.emplace_back(std::move(font_data)); m_font_runtime.emplace_back(std::move(runtime)); + return m_font_data.size() - 1; +} +auto TextRenderer::load_font(std::filesystem::path const &path, + std::span fallback_fonts) + -> std::optional +{ + auto primary_index = load_single_font(path); + if (!primary_index) + return std::nullopt; + + FontSet set; + set.font_indices.push_back(*primary_index); + + for (auto const &fallback_path : fallback_fonts) { + auto fallback_index = load_single_font(fallback_path); + if (!fallback_index) { + TraceLog(LOG_WARNING, "Failed to load fallback font: %s", + fallback_path.string().c_str()); + continue; + } + set.font_indices.push_back(*fallback_index); + } + + m_font_sets.emplace_back(std::move(set)); FontHandle handle; - handle.id = m_font_data.size() - 1; + handle.id = m_font_sets.size() - 1; return handle; } +auto TextRenderer::shape_text(FontHandle const font, + std::string_view const text) -> std::vector +{ + std::vector shaped; + if (text.empty()) + return shaped; + + usize const handle_id = font(); + if (handle_id >= m_font_sets.size()) + return shaped; + auto const &font_set = m_font_sets[handle_id]; + if (font_set.font_indices.empty()) + return shaped; + + auto codepoints = decode_utf8(text); + if (codepoints.empty()) + return shaped; + + std::vector selections(codepoints.size(), 0); + for (size_t i = 0; i < codepoints.size(); ++i) { + bool matched = false; + for (size_t candidate = 0; candidate < font_set.font_indices.size(); + ++candidate) { + usize runtime_index = font_set.font_indices[candidate]; + if (runtime_index >= m_font_runtime.size()) + continue; + auto const &runtime_ptr = m_font_runtime[runtime_index]; + if (!runtime_ptr || !runtime_ptr->face) + continue; + FT_UInt glyph = FT_Get_Char_Index( + runtime_ptr->face, codepoints[i].codepoint); + if (glyph != 0) { + selections[i] = candidate; + matched = true; + break; + } + } + if (!matched) + selections[i] = 0; + } + + size_t idx = 0; + while (idx < codepoints.size()) { + size_t font_choice = selections[idx]; + if (font_choice >= font_set.font_indices.size()) + font_choice = 0; + usize runtime_index = font_set.font_indices[font_choice]; + if (runtime_index >= m_font_runtime.size() + || !m_font_runtime[runtime_index] + || !m_font_runtime[runtime_index]->hb_font) { + ++idx; + continue; + } + + size_t segment_start = codepoints[idx].start; + size_t segment_end = codepoints[idx].end; + size_t end_idx = idx + 1; + while (end_idx < codepoints.size() + && selections[end_idx] == font_choice) { + segment_end = codepoints[end_idx].end; + ++end_idx; + } + + if (segment_end <= segment_start) { + idx = end_idx; + continue; + } + + std::string_view segment + = text.substr(segment_start, segment_end - segment_start); + if (segment.empty()) { + idx = end_idx; + continue; + } + + hb_buffer_t *buffer = hb_buffer_create(); + hb_buffer_add_utf8(buffer, segment.data(), + static_cast(segment.size()), 0, + static_cast(segment.size())); + hb_buffer_guess_segment_properties(buffer); + hb_shape(m_font_runtime[runtime_index]->hb_font, buffer, nullptr, 0); + + unsigned length = hb_buffer_get_length(buffer); + auto *infos = hb_buffer_get_glyph_infos(buffer, nullptr); + auto *positions = hb_buffer_get_glyph_positions(buffer, nullptr); + for (unsigned i = 0; i < length; ++i) { + GlyphPlacement placement; + placement.runtime_index = runtime_index; + placement.glyph_index = infos[i].codepoint; + placement.x_advance = positions[i].x_advance; + placement.y_advance = positions[i].y_advance; + placement.x_offset = positions[i].x_offset; + placement.y_offset = positions[i].y_offset; + shaped.emplace_back(placement); + } + hb_buffer_destroy(buffer); + idx = end_idx; + } + + return shaped; +} + auto TextRenderer::unload_font(FontHandle const font) -> void { - usize const font_id = font(); - if (font_id >= m_font_runtime.size()) + usize const handle_id = font(); + if (handle_id >= m_font_sets.size()) return; - if (m_font_runtime[font_id]) { - auto &rt = *m_font_runtime[font_id]; - rt.glyph_cache.clear(); - if (rt.msdf_font) - msdfgen::destroyFont(rt.msdf_font); - if (rt.hb_font) - hb_font_destroy(rt.hb_font); - if (rt.hb_face) - hb_face_destroy(rt.hb_face); - if (rt.face) - FT_Done_Face(rt.face); - } - m_font_runtime[font_id].reset(); + auto &font_set = m_font_sets[handle_id]; + for (usize runtime_index : font_set.font_indices) { + if (runtime_index >= m_font_runtime.size()) + continue; - if (font_id < m_font_data.size()) { - auto &fd = m_font_data[font_id]; - if (fd.atlas.id != 0) - UnloadTexture(fd.atlas); - if (fd.atlas_img.data) - UnloadImage(fd.atlas_img); - fd.glyphs.clear(); + if (auto &runtime_ptr = m_font_runtime[runtime_index]) { + auto &rt = *runtime_ptr; + rt.glyph_cache.clear(); + // No freeing here because they are already cleaned up somewhere... + // idk. fml. + rt.face = nullptr; + } + m_font_runtime[runtime_index].reset(); + + if (runtime_index < m_font_data.size()) { + auto &fd = m_font_data[runtime_index]; + if (fd.atlas.id != 0) + UnloadTexture(fd.atlas); + if (fd.atlas_img.data) + UnloadImage(fd.atlas_img); + fd.atlas = Texture2D {}; + fd.atlas_img = Image {}; + fd.glyphs.clear(); + } } + font_set.font_indices.clear(); } auto find_font_path(std::string_view path) diff --git a/src/TextRenderer.hpp b/src/TextRenderer.hpp index 1867140..7532f94 100644 --- a/src/TextRenderer.hpp +++ b/src/TextRenderer.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,8 @@ struct TextRenderer { Vector2 const pos, int const size = 16, Color const color = WHITE) -> void; - auto load_font(std::filesystem::path const &path) + auto load_font(std::filesystem::path const &path, + std::span fallback_fonts) -> std::optional; auto unload_font(FontHandle const font) -> void; @@ -103,6 +105,19 @@ private: }; std::vector> m_font_runtime; + struct FontSet { + std::vector font_indices; + }; + std::vector m_font_sets; + + struct GlyphPlacement { + usize runtime_index {}; + u32 glyph_index {}; + i32 x_advance {}; + i32 y_advance {}; + i32 x_offset {}; + i32 y_offset {}; + }; static auto flush_font(FontRuntime &rt, FontData &fd) -> void; static auto allocate_region( @@ -114,6 +129,10 @@ private: -> std::optional; static auto ensure_glyph(FontRuntime &rt, FontData &fd, u32 glyph_index, bool mark_usage) -> GlyphCacheEntry *; + auto load_single_font(std::filesystem::path const &path) + -> std::optional; + auto shape_text(FontHandle const font, std::string_view const text) + -> std::vector; }; auto find_font_path(std::string_view path = "sans-serif:style=Regular") diff --git a/src/main.cpp b/src/main.cpp index df321d7..90fc2bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,12 +10,12 @@ #include "App.hpp" -bool check_or_signal_running(); +bool signal_running(); std::optional g_app{}; auto main() -> int { - if (check_or_signal_running()) { + if (signal_running()) { return 0; } @@ -28,7 +28,7 @@ auto main() -> int { g_app->run(); } -bool check_or_signal_running() { +bool signal_running() { const char *lock_path = "/tmp/waylight.lock"; int fd = open(lock_path, O_CREAT | O_RDWR, 0666); if (fd == -1) @@ -46,7 +46,12 @@ bool check_or_signal_running() { return true; } - ftruncate(fd, 0); + if (ftruncate(fd, 0) == -1) { + close(fd); + unlink(lock_path); + return false; + } + dprintf(fd, "%d\n", getpid()); return false; }