Create Emboss::Font as unique ptr not optional

Reason: Job need pointer on font until finished
This commit is contained in:
Filip Sykala 2022-01-06 15:41:03 +01:00
parent b1b8eee3c9
commit 4ec4bafe19
6 changed files with 110 additions and 74 deletions

View File

@ -23,6 +23,7 @@ public:
Private() = delete; Private() = delete;
static std::optional<stbtt_fontinfo> load_font_info(const Emboss::Font &font); static std::optional<stbtt_fontinfo> load_font_info(const Emboss::Font &font);
static std::optional<stbtt_fontinfo> load_font_info(const unsigned char *data, unsigned int index = 0);
static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness); static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness);
static std::optional<Emboss::Glyph> get_glyph(int unicode, const Emboss::Font &font, const FontProp &font_prop, static std::optional<Emboss::Glyph> get_glyph(int unicode, const Emboss::Font &font, const FontProp &font_prop,
Emboss::Glyphs &cache, std::optional<stbtt_fontinfo> &font_info_opt); Emboss::Glyphs &cache, std::optional<stbtt_fontinfo> &font_info_opt);
@ -43,13 +44,19 @@ public:
std::optional<stbtt_fontinfo> Private::load_font_info(const Emboss::Font &font) std::optional<stbtt_fontinfo> Private::load_font_info(const Emboss::Font &font)
{ {
int font_offset = stbtt_GetFontOffsetForIndex(font.buffer.data(), font.index); return load_font_info(font.buffer.data(), font.index);
}
std::optional<stbtt_fontinfo> Private::load_font_info(
const unsigned char *data, unsigned int index)
{
int font_offset = stbtt_GetFontOffsetForIndex(data, index);
if (font_offset < 0) { if (font_offset < 0) {
std::cerr << "Font index("<<font.index<<") doesn't exist." << std::endl; std::cerr << "Font index(" << index << ") doesn't exist." << std::endl;
return {}; return {};
} }
stbtt_fontinfo font_info; stbtt_fontinfo font_info;
if (stbtt_InitFont(&font_info, font.buffer.data(), font_offset) == 0) { if (stbtt_InitFont(&font_info, data, font_offset) == 0) {
std::cerr << "Can't initialize font." << std::endl; std::cerr << "Can't initialize font." << std::endl;
return {}; return {};
} }
@ -424,52 +431,47 @@ std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_
} }
#endif #endif
std::optional<Emboss::Font> Emboss::load_font(std::vector<unsigned char> data) std::unique_ptr<Emboss::Font> Emboss::load_font(const std::vector<unsigned char>&& data)
{ {
Font res; unsigned int collection_size = 0;
res.buffer = std::move(data);
unsigned int index = 0;
int font_offset = 0; int font_offset = 0;
while (font_offset >= 0) { while (font_offset >= 0) {
font_offset = stbtt_GetFontOffsetForIndex(res.buffer.data(), index++); font_offset = stbtt_GetFontOffsetForIndex(data.data(), collection_size++);
} }
--index; // last one is bad --collection_size; // last one is bad
// at least one font must be inside collection // at least one font must be inside collection
if (index < 1) { if (collection_size < 1) {
std::cerr << "There is no font collection inside data." << std::endl; std::cerr << "There is no font collection inside data." << std::endl;
return {}; return nullptr;
} }
// select default font on index 0 auto font_info = Private::load_font_info(data.data());
res.index = 0; if (!font_info.has_value()) return nullptr;
res.count = index;
auto font_info = Private::load_font_info(res);
if (!font_info.has_value()) return {};
const stbtt_fontinfo *info = &(*font_info); const stbtt_fontinfo *info = &(*font_info);
// load information about line gap // load information about line gap
stbtt_GetFontVMetrics(info, &res.ascent, &res.descent, &res.linegap); int ascent, descent, linegap;
stbtt_GetFontVMetrics(info, &ascent, &descent, &linegap);
return res; return std::make_unique<Emboss::Font>(
std::move(data), collection_size, ascent, descent, linegap);
} }
std::optional<Emboss::Font> Emboss::load_font(const char *file_path) std::unique_ptr<Emboss::Font> Emboss::load_font(const char *file_path)
{ {
FILE *file = fopen(file_path, "rb"); FILE *file = fopen(file_path, "rb");
if (file == nullptr) { if (file == nullptr) {
std::cerr << "Couldn't open " << file_path << " for reading." << std::endl; std::cerr << "Couldn't open " << file_path << " for reading." << std::endl;
return {}; return nullptr;
} }
// find size of file // find size of file
if (fseek(file, 0L, SEEK_END) != 0) { if (fseek(file, 0L, SEEK_END) != 0) {
std::cerr << "Couldn't fseek file " << file_path << " for size measure." << std::endl; std::cerr << "Couldn't fseek file " << file_path << " for size measure." << std::endl;
return {}; return nullptr;
} }
size_t size = ftell(file); size_t size = ftell(file);
if (size == 0) { if (size == 0) {
std::cerr << "Size of font file is zero. Can't read." << std::endl; std::cerr << "Size of font file is zero. Can't read." << std::endl;
return {}; return nullptr;
} }
rewind(file); rewind(file);
@ -477,19 +479,19 @@ std::optional<Emboss::Font> Emboss::load_font(const char *file_path)
size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file); size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file);
if (count_loaded_bytes != size) { if (count_loaded_bytes != size) {
std::cerr << "Different loaded(from file) data size." << std::endl; std::cerr << "Different loaded(from file) data size." << std::endl;
return {}; return nullptr;
} }
return load_font(std::move(buffer)); return load_font(std::move(buffer));
} }
#ifdef _WIN32 #ifdef _WIN32
std::optional<Emboss::Font> Emboss::load_font(HFONT hfont) std::unique_ptr<Emboss::Font> Emboss::load_font(HFONT hfont)
{ {
HDC hdc = ::CreateCompatibleDC(NULL); HDC hdc = ::CreateCompatibleDC(NULL);
if (hdc == NULL) { if (hdc == NULL) {
std::cerr << "Can't create HDC by CreateCompatibleDC(NULL)." << std::endl; std::cerr << "Can't create HDC by CreateCompatibleDC(NULL)." << std::endl;
return {}; return nullptr;
} }
// To retrieve the data from the beginning of the file for TrueType // To retrieve the data from the beginning of the file for TrueType
@ -508,7 +510,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
if (size == 0 || size == GDI_ERROR) { if (size == 0 || size == GDI_ERROR) {
std::cerr << "HFONT doesn't have size." << std::endl; std::cerr << "HFONT doesn't have size." << std::endl;
::DeleteDC(hdc); ::DeleteDC(hdc);
return {}; return nullptr;
} }
std::vector<unsigned char> buffer(size); std::vector<unsigned char> buffer(size);
@ -516,7 +518,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
::DeleteDC(hdc); ::DeleteDC(hdc);
if (size != loaded_size) { if (size != loaded_size) {
std::cerr << "Different loaded(from HFONT) data size." << std::endl; std::cerr << "Different loaded(from HFONT) data size." << std::endl;
return {}; return nullptr;
} }
return load_font(std::move(buffer)); return load_font(std::move(buffer));

View File

@ -57,15 +57,28 @@ public:
struct Font struct Font
{ {
// loaded data from font file // loaded data from font file
std::vector<unsigned char> buffer; const std::vector<unsigned char> buffer;
unsigned int index = 0; // index of actual file info in collection unsigned int index; // index of actual file info in collection
unsigned int count = 0; // count of fonts in file collection const unsigned int count; // count of fonts in file collection
// vertical position is "scale*(ascent - descent + lineGap)" // vertical position is "scale*(ascent - descent + lineGap)"
int ascent = 0, descent = 0, linegap = 0; const int ascent, descent, linegap;
Emboss::Glyphs cache; // cache of glyphs Emboss::Glyphs cache; // cache of glyphs
Font(const std::vector<unsigned char> &&buffer,
unsigned int count,
int ascent,
int descent,
int linegap)
: buffer(std::move(buffer))
, index(0) // select default font on index 0
, count(count)
, ascent(ascent)
, descent(descent)
, linegap(linegap)
{}
}; };
/// <summary> /// <summary>
@ -73,13 +86,13 @@ public:
/// </summary> /// </summary>
/// <param name="file_path">Location of .ttf or .ttc font file</param> /// <param name="file_path">Location of .ttf or .ttc font file</param>
/// <returns>Font object when loaded.</returns> /// <returns>Font object when loaded.</returns>
static std::optional<Font> load_font(const char *file_path); static std::unique_ptr<Font> load_font(const char *file_path);
// data = raw file data // data = raw file data
static std::optional<Font> load_font(std::vector<unsigned char> data); static std::unique_ptr<Font> load_font(const std::vector<unsigned char>&& data);
#ifdef _WIN32 #ifdef _WIN32
// fix for unknown pointer HFONT // fix for unknown pointer HFONT
using HFONT = void*; using HFONT = void*;
static std::optional<Font> load_font(HFONT hfont); static std::unique_ptr<Font> load_font(HFONT hfont);
#endif // _WIN32 #endif // _WIN32
/// <summary> /// <summary>

View File

@ -839,11 +839,9 @@ bool GLGizmoEmboss::load_font()
// fill font name after load from .3mf // fill font name after load from .3mf
if (fi.name.empty()) if (fi.name.empty())
fi.name = Slic3r::GUI::GLGizmoEmboss::get_file_name(fi.path); fi.name = Slic3r::GUI::GLGizmoEmboss::get_file_name(fi.path);
std::optional<Emboss::Font> font_opt = Emboss::load_font( std::unique_ptr<Emboss::Font> font_ptr = Emboss::load_font(fi.path.c_str());
fi.path.c_str()); if (font_ptr == nullptr) return false;
if (!font_opt.has_value()) return false; m_font = std::move(font_ptr);
// TODO: fix copy of font data
m_font = std::make_shared<Emboss::Font>(std::move(*font_opt));
load_imgui_font(); load_imgui_font();
return true; return true;
} }
@ -859,12 +857,17 @@ bool GLGizmoEmboss::load_font()
bool GLGizmoEmboss::load_font(const wxFont &font) bool GLGizmoEmboss::load_font(const wxFont &font)
{ {
auto font_opt = WxFontUtils::load_font(font); auto font_ptr = WxFontUtils::load_font(font);
if (!font_opt.has_value()) return false; if (font_ptr == nullptr) return false;
// TODO: fix copy of font data m_font = std::move(font_ptr);
m_font = std::make_shared<Emboss::Font>(std::move(*font_opt));
WxFontUtils::update_property(m_font_prop, font); WxFontUtils::update_property(m_font_prop, font);
// TODO: fix dynamic creation of italic
// TODO: decide when rewrite emboss depth
m_font_prop.emboss = m_font_prop.size_in_mm / 2.f; m_font_prop.emboss = m_font_prop.size_in_mm / 2.f;
load_imgui_font(); load_imgui_font();
return true; return true;
} }

View File

@ -12,36 +12,36 @@
using namespace Slic3r; using namespace Slic3r;
using namespace Slic3r::GUI; using namespace Slic3r::GUI;
std::optional<Emboss::Font> WxFontUtils::load_font(const wxFont &font) std::unique_ptr<Emboss::Font> WxFontUtils::load_font(const wxFont &font)
{ {
if (!font.IsOk()) return {}; if (!font.IsOk()) return nullptr;
#ifdef _WIN32 #ifdef _WIN32
return Emboss::load_font(font.GetHFONT()); return Emboss::load_font(font.GetHFONT());
#elif defined(__APPLE__) #elif defined(__APPLE__)
// use file path // use file path
const wxNativeFontInfo *info = font.GetNativeFontInfo(); const wxNativeFontInfo *info = font.GetNativeFontInfo();
if (info == nullptr) return {}; if (info == nullptr) return nullptr;
CTFontDescriptorRef descriptor = info->GetCTFontDescriptor(); CTFontDescriptorRef descriptor = info->GetCTFontDescriptor();
CFURLRef typeref = (CFURLRef) CFURLRef typeref = (CFURLRef)
CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute); CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute);
CFStringRef url = CFURLGetString(typeref); CFStringRef url = CFURLGetString(typeref);
if (url == NULL) return {}; if (url == NULL) return nullptr;
wxString file_uri; wxString file_uri;
wxCFTypeRef(url).GetValue(file_uri); wxCFTypeRef(url).GetValue(file_uri);
std::string file_path(wxURI::Unescape(file_uri).c_str()); std::string file_path(wxURI::Unescape(file_uri).c_str());
size_t start = std::string("file://").size(); size_t start = std::string("file://").size();
if (file_path.empty() || file_path.size() <= start) return {}; if (file_path.empty() || file_path.size() <= start) return nullptr;
file_path = file_path.substr(start, file_path.size() - start); file_path = file_path.substr(start, file_path.size() - start);
return Emboss::load_font(file_path.c_str()); return Emboss::load_font(file_path.c_str());
#elif defined(__linux__) #elif defined(__linux__)
static FontConfigHelp help; static FontConfigHelp help;
std::string font_path = help.get_font_path(font); std::string font_path = help.get_font_path(font);
if (font_path.empty()) return {}; if (font_path.empty()) return nullptr;
return Emboss::load_font(font_path.c_str()); return Emboss::load_font(font_path.c_str());
#else #else
// HERE is place to add implementation for another platform // HERE is place to add implementation for another platform
// to convert wxFont to font data as windows or font file path as linux // to convert wxFont to font data as windows or font file path as linux
return {}; return nullptr;
#endif #endif
} }
@ -205,4 +205,6 @@ void WxFontUtils::update_property(FontProp &font_prop, const wxFont &font)
auto it = from_weight.find(wx_weight); auto it = from_weight.find(wx_weight);
if (it != from_weight.end()) font_prop.weight = it->second; if (it != from_weight.end()) font_prop.weight = it->second;
} }
} }

View File

@ -1,6 +1,7 @@
#ifndef slic3r_WxFontUtils_hpp_ #ifndef slic3r_WxFontUtils_hpp_
#define slic3r_WxFontUtils_hpp_ #define slic3r_WxFontUtils_hpp_
#include <memory>
#include <optional> #include <optional>
#include <wx/font.h> #include <wx/font.h>
#include "libslic3r/Emboss.hpp" #include "libslic3r/Emboss.hpp"
@ -15,7 +16,7 @@ public:
WxFontUtils() = delete; WxFontUtils() = delete;
// os specific load of wxFont // os specific load of wxFont
static std::optional<Slic3r::Emboss::Font> load_font(const wxFont &font); static std::unique_ptr<Slic3r::Emboss::Font> load_font(const wxFont &font);
static FontItem::Type get_actual_type(); static FontItem::Type get_actual_type();
static FontItem get_font_item(const wxFont &font); static FontItem get_font_item(const wxFont &font);

View File

@ -101,8 +101,8 @@ TEST_CASE("Emboss text", "[Emboss]")
char letter = '%'; char letter = '%';
float flatness = 2.; float flatness = 2.;
std::optional<Emboss::Font> font = Emboss::load_font(font_path.c_str()); auto font = Emboss::load_font(font_path.c_str());
REQUIRE(font.has_value()); REQUIRE(font != nullptr);
std::optional<Emboss::Glyph> glyph = Emboss::letter2glyph(*font, letter, flatness); std::optional<Emboss::Glyph> glyph = Emboss::letter2glyph(*font, letter, flatness);
REQUIRE(glyph.has_value()); REQUIRE(glyph.has_value());
@ -185,23 +185,38 @@ TEST_CASE("triangle intersection", "[]")
namespace fs = std::filesystem; namespace fs = std::filesystem;
TEST_CASE("Italic check", "[]") TEST_CASE("Italic check", "[]")
{ {
//std::string s1 = "italic"; std::queue<std::string> dir_paths;
//std::string s2 = "italic"; #ifdef _WIN32
//auto pos = s1.find(s2); dir_paths.push("C:/Windows/Fonts");
//std::cout << ((pos != std::string::npos) ? "good" : "bad"); #elif defined(__APPLE__)
#elif defined(__linux__)
std::string dir_path = "C:/Windows/Fonts"; dir_paths.push("/usr/share/fonts");
#endif
bool exist_italic = false;
bool exist_non_italic = false;
while (!dir_paths.empty()) {
std::string dir_path = dir_paths.front();
dir_paths.pop();
for (const auto &entry : fs::directory_iterator(dir_path)) { for (const auto &entry : fs::directory_iterator(dir_path)) {
if (entry.is_directory()) continue;
const fs::path &act_path = entry.path(); const fs::path &act_path = entry.path();
if (entry.is_directory()) {
dir_paths.push(act_path.u8string());
continue;
}
std::string ext = act_path.extension().u8string(); std::string ext = act_path.extension().u8string();
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) { return std::tolower(c); }); std::transform(ext.begin(), ext.end(), ext.begin(),
[](unsigned char c) { return std::tolower(c); });
if (ext != ".ttf") continue; if (ext != ".ttf") continue;
std::string path_str = act_path.u8string(); std::string path_str = act_path.u8string();
auto font_opt = Emboss::load_font(path_str.c_str()); auto font_opt = Emboss::load_font(path_str.c_str());
if (!font_opt.has_value()) continue; if (font_opt == nullptr) continue;
if (Emboss::is_italic(*font_opt))
std::cout << ((Emboss::is_italic(*font_opt)) ? "[yes] " : "[no ] ") exist_italic = true;
<< entry.path() << std::endl; else
exist_non_italic = true;
//std::cout << ((Emboss::is_italic(*font_opt)) ? "[yes] " : "[no ] ") << entry.path() << std::endl;
} }
} }
CHECK(exist_italic);
CHECK(exist_non_italic);
}