Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ jobs:
key: ${{github.event.repository.name}}-${{github.job}}-${{matrix.os}}-${{matrix.type}}

- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DTOMATO_ASAN=${{matrix.type == 'asan' && 'ON' || 'OFF'}}
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DTOMATO_ASAN=${{matrix.type == 'asan' && 'ON' || 'OFF'}} -DBUILD_TESTING=ON

- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato test_font_loaders

- name: Test
working-directory: ${{github.workspace}}/build
run: ctest -V -C ${{env.BUILD_TYPE}}

linux-debian12:
timeout-minutes: 10
Expand Down Expand Up @@ -190,7 +194,11 @@ jobs:
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache

- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato test_font_loaders

- name: Test
working-directory: ${{github.workspace}}/build
run: ctest -V -C ${{env.BUILD_TYPE}}

windows:
timeout-minutes: 15
Expand Down Expand Up @@ -248,5 +256,9 @@ jobs:
-DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe

- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato test_font_loaders

- name: Test
working-directory: ${{github.workspace}}/build
run: ctest -V -C ${{env.BUILD_TYPE}}

4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ message(STATUS "${tomato_VERSION_MAJOR}.${tomato_VERSION_MINOR}.${tomato_VERSION

# cmake setup end

if (BUILD_TESTING)
include(CTest)
endif()

add_subdirectory(./src)

# TODO: move to src
Expand Down
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.9...3.24 FATAL_ERROR)

add_subdirectory(./font_loading)

########################################

if (TOMATO_MAIN_SO)
Expand Down Expand Up @@ -205,6 +207,8 @@ target_link_libraries(tomato PUBLIC

solanaceae_object_store

font_loading

SDL3::SDL3

imgui
Expand Down
49 changes: 49 additions & 0 deletions src/font_loading/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
cmake_minimum_required(VERSION 3.9...3.24 FATAL_ERROR)

########################################

add_library(font_loading STATIC)

target_sources(font_loading PUBLIC
./font_finder.hpp
./font_finder.cpp
./font_finder_i.hpp
./font_finder_fs.hpp
./font_finder_fs.cpp
./font_finder_fc_sdl.hpp
./font_finder_fc_sdl.cpp
)

# TODO: conditionally compile fontconfig
#if (TOMATO_BREAKPAD)
# target_sources(tomato PUBLIC
# ./breakpad_client.hpp
# ./breakpad_client.cpp
# )

# target_link_libraries(tomato PUBLIC breakpad_client)
# target_compile_definitions(tomato PUBLIC TOMATO_BREAKPAD)
#endif()

target_compile_features(font_loading PUBLIC cxx_std_17)
target_link_libraries(font_loading PUBLIC
SDL3::SDL3
imgui
)

set_target_properties(font_loading PROPERTIES POSITION_INDEPENDENT_CODE ON)

########################################

if (BUILD_TESTING)
add_executable(test_font_loaders
./test_ff.cpp
)

target_link_libraries(test_font_loaders
font_loading
)

add_test(NAME test_font_loaders COMMAND test_font_loaders)
endif()

126 changes: 126 additions & 0 deletions src/font_loading/font_finder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include "./font_finder.hpp"

#include "./font_finder_fc_sdl.hpp"
#include "./font_finder_fs.hpp"

#include <stdexcept>

#include <iostream>

std::vector<std::string_view> getPlatformDefaultUIFamilies(void) {
#if defined(_WIN32) || defined(WIN32)
return {
"Segoe UI",
"sans-serif",
"Noto Sans",
"Helvetica",
"serif",
};
#elif __ANDROID__
return {
"Noto Sans",
"sans-serif",
"Droid Sans",
"Roboto",
"serif",
};
#elif __APPLE__
return {
"Helvetica",
"sans-serif",
"Noto Sans",
"serif",
};
#else // assume linux, prs welcome
return {
"sans-serif",
"Noto Sans",
"Ubuntu",
"serif",
};
#endif
}

std::vector<std::string_view> getPlatformDefaultColorEmojiFamilies(void) {
#if defined(_WIN32) || defined(WIN32)
return {
"Seguiemj", // Segoe UI Emoji
"Color Emoji",
"Emoji",
};
#elif __ANDROID__
return {
"Noto Color Emoji",
"Color Emoji",
"Emoji",
};
#elif __APPLE__
return {
"Apple Color Emoji",
"Color Emoji",
"Emoji",
};
#else // assume linux, other platform prs welcome
return {
"Color Emoji",
"Emoji",
};
#endif
}

template<typename FF, typename... Args>
void constructFF(std::vector<std::unique_ptr<FontFinderInterface>>& list, Args&&... args) {
try {
std::unique_ptr<FontFinderInterface> ff = std::make_unique<FF>(std::forward<Args>(args)...);
list.push_back(std::move(ff));
} catch (const std::runtime_error& e) {
std::cerr << "caught runtime_error exception '" << e.what() << "'\n";
} catch (...) {
std::cerr << "caught exception\n";
}
}

std::vector<std::unique_ptr<FontFinderInterface>> constructPlatformDefaultFinderBackends(void) {
std::vector<std::unique_ptr<FontFinderInterface>> list;

constructFF<FontFinder_FontConfigSDL>(list);


#if defined(_WIN32) || defined(WIN32)
constructFF<FontFinder_FileSystem>(list, "C:\\Windows\\Fonts");
#elif __ANDROID__
constructFF<FontFinder_FileSystem>(list, "/system/fonts");
#elif __APPLE__
// TODO: macos only
constructFF<FontFinder_FileSystem>(list, "/Library/Fonts");
constructFF<FontFinder_FileSystem>(list, "/System/Library/Fonts");
#else
constructFF<FontFinder_FileSystem>(list, "/usr/share/fonts");
constructFF<FontFinder_FileSystem>(list, "/usr/local/share/fonts");
#endif

return list;
}

std::string getBestMatch(
const std::vector<std::unique_ptr<FontFinderInterface>>& backends,
std::string_view family,
std::string_view lang,
bool color
) {
for (const auto& backend : backends) {
try {
auto res = backend->findBest(family, lang, color);
if (!res.empty()) {
return res;
}
} catch (const std::runtime_error& e) {
std::cerr << "caught runtime_error exception '" << e.what() << "'\n";
} catch (...) {
std::cerr << "caught exception\n";
}
}

return ""; // none found
}

28 changes: 28 additions & 0 deletions src/font_loading/font_finder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include "./font_finder_i.hpp"

#include <string_view>
#include <vector>
#include <memory>

// for typical usage, you want to:
// 1. construct finder backends once
// 2. have a desired font family or get the family list eg. getPlatformDefaultUIFamilies()
// 3. pass it to the getBestMatch() function


// returns a list of "family" names, that when put into the backends
// on current platform, will likely yield a match.
std::vector<std::string_view> getPlatformDefaultUIFamilies(void);
std::vector<std::string_view> getPlatformDefaultColorEmojiFamilies(void);

std::vector<std::unique_ptr<FontFinderInterface>> constructPlatformDefaultFinderBackends(void);

std::string getBestMatch(
const std::vector<std::unique_ptr<FontFinderInterface>>& backends,
std::string_view family,
std::string_view lang = "",
bool color = false
);

Loading
Loading