Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add callback to get missing fonts #188

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
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
45 changes: 45 additions & 0 deletions include/lunasvg.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <memory>
#include <string>
#include <vector>
#include <functional>

#if !defined(LUNASVG_BUILD_STATIC) && (defined(_WIN32) || defined(__CYGWIN__))
#define LUNASVG_EXPORT __declspec(dllexport)
Expand Down Expand Up @@ -129,6 +130,50 @@ LUNASVG_API bool lunasvg_add_font_face_from_data(const char* family, bool bold,

namespace lunasvg {

/**
* @brief A callback function type to handle missing fonts.
* @param family The name of the font family.
* @param bold Use `true` for bold, `false` otherwise.
* @param italic Use `true` for italic, `false` otherwise.
* @return The path to the font file or an empty string if the font is not found.
*/
typedef std::function<const std::string(const std::string& family, bool bold, bool italic)> MissingFontCallback;

/**
* @brief Allows to user to load custom fonts.
*/
namespace LUNASVG_API FontManager {
/**
* @brief Add a font face from a file to the cache.
* @param family The name of the font family. If an empty string is provided, the font will act as a fallback.
* @param bold Use `true` for bold, `false` otherwise.
* @param italic Use `true` for italic, `false` otherwise.
* @param filename The path to the font file.
* @return `true` if the font face was successfully added to the cache, `false` otherwise.
*/
bool addFromFile(const std::string& family, bool bold, bool italic, const std::string& filename);

/**
* @brief Add a font face from memory to the cache.
* @param family The name of the font family. If an empty string is provided, the font will act as a fallback.
* @param bold Use `true` for bold, `false` otherwise.
* @param italic Use `true` for italic, `false` otherwise.
* @param data A pointer to the memory buffer containing the font data.
* @param length The size of the memory buffer in bytes.
* @param destroy_func Callback function to free the memory buffer when it is no longer needed.
* @param closure User-defined pointer passed to the `destroy_func` callback.
* @return `true` if the font face was successfully added to the cache, `false` otherwise.
*/
bool addFromData(const std::string& family, bool bold, bool italic, const void* data, size_t length, lunasvg_destroy_func_t destroy_func, void* closure);


/**
* @brief Registers a callback function to handle missing fonts.
* @param callback The callback function to register.
*/
void registerMissingFontCalback(MissingFontCallback callback);
}

/**
* @note Bitmap pixel format is ARGB32_Premultiplied.
*/
Expand Down
31 changes: 30 additions & 1 deletion source/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,11 +417,35 @@ bool FontFaceCache::addFontFace(const std::string& family, bool bold, bool itali
return !face.isNull();
}

void FontFaceCache::registerMissingFontCallback(const std::function<const std::string(const std::string&, bool, bool)>& callback)
{
m_callback = callback;
}

FontFace FontFaceCache::tryRequestFontFace(const std::string_view& family, bool bold, bool italic)
{
if (m_callback == nullptr) {
return FontFace();
}
std::string filename = m_callback(std::string(family), bold, italic);
if (filename.empty()) {
return FontFace();
}
auto face = FontFace(filename.c_str());
if(!face.isNull()) {
addFontFace(std::string(family), bold, italic, face);
return face;
}
else {
return FontFace();
}
}

FontFace FontFaceCache::getFontFace(const std::string_view& family, bool bold, bool italic)
{
auto it = m_table.find(family);
if(it == m_table.end()) {
return FontFace();
return tryRequestFontFace(family, bold, italic);
}

auto select = [bold, italic](const FontFaceEntry& a, const FontFaceEntry& b) {
Expand All @@ -439,6 +463,11 @@ FontFace FontFaceCache::getFontFace(const std::string_view& family, bool bold, b
entry = select(entry, item);
}

if(bold != std::get<0>(entry) || italic != std::get<1>(entry)) {
return tryRequestFontFace(family, bold, italic);
}


return std::get<2>(entry);
}

Expand Down
5 changes: 5 additions & 0 deletions source/graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <array>
#include <string>
#include <map>
#include <functional>

namespace lunasvg {

Expand Down Expand Up @@ -421,12 +422,16 @@ class FontFaceCache {
public:
bool addFontFace(const std::string& family, bool bold, bool italic, const FontFace& face);
FontFace getFontFace(const std::string_view& family, bool bold, bool italic);
void registerMissingFontCallback(const std::function<const std::string(const std::string&, bool, bool)>& callback);

private:
FontFaceCache();
using FontFaceEntry = std::tuple<bool, bool, FontFace>;
std::map<std::string, std::vector<FontFaceEntry>, std::less<>> m_table;
std::function<const std::string(const std::string&, bool, bool)> m_callback = nullptr;
friend FontFaceCache* fontFaceCache();

FontFace tryRequestFontFace(const std::string_view& family, bool bold, bool italic);
};

FontFaceCache* fontFaceCache();
Expand Down
12 changes: 12 additions & 0 deletions source/lunasvg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ bool lunasvg_add_font_face_from_data(const char* family, bool bold, bool italic,

namespace lunasvg {

bool FontManager::addFromFile(const std::string& family, bool bold, bool italic, const std::string& filename) {
return lunasvg_add_font_face_from_file(family.c_str(), bold, italic, filename.c_str());
}

bool FontManager::addFromData(const std::string& family, bool bold, bool italic, const void* data, size_t length, lunasvg_destroy_func_t destroy_func, void* closure) {
return lunasvg_add_font_face_from_data(family.c_str(), bold, italic, data, length, destroy_func, closure);
}

void FontManager::registerMissingFontCalback(std::function<const std::string(const std::string& family, bool bold, bool italic)> callback) {
fontFaceCache()->registerMissingFontCallback(callback);
}

Bitmap::Bitmap(int width, int height)
: m_surface(plutovg_surface_create(width, height))
{
Expand Down