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;
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(int unicode, const Emboss::Font &font, const FontProp &font_prop,
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)
{
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) {
std::cerr << "Font index("<<font.index<<") doesn't exist." << std::endl;
std::cerr << "Font index(" << index << ") doesn't exist." << std::endl;
return {};
}
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;
return {};
}
@ -424,52 +431,47 @@ std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_
}
#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;
res.buffer = std::move(data);
unsigned int index = 0;
int font_offset = 0;
unsigned int collection_size = 0;
int 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
if (index < 1) {
if (collection_size < 1) {
std::cerr << "There is no font collection inside data." << std::endl;
return {};
return nullptr;
}
// select default font on index 0
res.index = 0;
res.count = index;
auto font_info = Private::load_font_info(data.data());
if (!font_info.has_value()) return nullptr;
auto font_info = Private::load_font_info(res);
if (!font_info.has_value()) return {};
const stbtt_fontinfo *info = &(*font_info);
// load information about line gap
stbtt_GetFontVMetrics(info, &res.ascent, &res.descent, &res.linegap);
return res;
int ascent, descent, linegap;
stbtt_GetFontVMetrics(info, &ascent, &descent, &linegap);
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");
if (file == nullptr) {
std::cerr << "Couldn't open " << file_path << " for reading." << std::endl;
return {};
return nullptr;
}
// find size of file
if (fseek(file, 0L, SEEK_END) != 0) {
std::cerr << "Couldn't fseek file " << file_path << " for size measure." << std::endl;
return {};
return nullptr;
}
size_t size = ftell(file);
if (size == 0) {
std::cerr << "Size of font file is zero. Can't read." << std::endl;
return {};
return nullptr;
}
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);
if (count_loaded_bytes != size) {
std::cerr << "Different loaded(from file) data size." << std::endl;
return {};
return nullptr;
}
return load_font(std::move(buffer));
}
#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);
if (hdc == NULL) {
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
@ -508,7 +510,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
if (size == 0 || size == GDI_ERROR) {
std::cerr << "HFONT doesn't have size." << std::endl;
::DeleteDC(hdc);
return {};
return nullptr;
}
std::vector<unsigned char> buffer(size);
@ -516,7 +518,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
::DeleteDC(hdc);
if (size != loaded_size) {
std::cerr << "Different loaded(from HFONT) data size." << std::endl;
return {};
return nullptr;
}
return load_font(std::move(buffer));

View File

@ -57,15 +57,28 @@ public:
struct Font
{
// 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 count = 0; // count of fonts in file collection
unsigned int index; // index of actual file info in collection
const unsigned int count; // count of fonts in file collection
// 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
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>
@ -73,13 +86,13 @@ public:
/// </summary>
/// <param name="file_path">Location of .ttf or .ttc font file</param>
/// <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
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
// fix for unknown pointer HFONT
using HFONT = void*;
static std::optional<Font> load_font(HFONT hfont);
static std::unique_ptr<Font> load_font(HFONT hfont);
#endif // _WIN32
/// <summary>

View File

@ -839,11 +839,9 @@ bool GLGizmoEmboss::load_font()
// fill font name after load from .3mf
if (fi.name.empty())
fi.name = Slic3r::GUI::GLGizmoEmboss::get_file_name(fi.path);
std::optional<Emboss::Font> font_opt = Emboss::load_font(
fi.path.c_str());
if (!font_opt.has_value()) return false;
// TODO: fix copy of font data
m_font = std::make_shared<Emboss::Font>(std::move(*font_opt));
std::unique_ptr<Emboss::Font> font_ptr = Emboss::load_font(fi.path.c_str());
if (font_ptr == nullptr) return false;
m_font = std::move(font_ptr);
load_imgui_font();
return true;
}
@ -859,12 +857,17 @@ bool GLGizmoEmboss::load_font()
bool GLGizmoEmboss::load_font(const wxFont &font)
{
auto font_opt = WxFontUtils::load_font(font);
if (!font_opt.has_value()) return false;
// TODO: fix copy of font data
m_font = std::make_shared<Emboss::Font>(std::move(*font_opt));
auto font_ptr = WxFontUtils::load_font(font);
if (font_ptr == nullptr) return false;
m_font = std::move(font_ptr);
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;
load_imgui_font();
return true;
}

View File

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

View File

@ -1,6 +1,7 @@
#ifndef slic3r_WxFontUtils_hpp_
#define slic3r_WxFontUtils_hpp_
#include <memory>
#include <optional>
#include <wx/font.h>
#include "libslic3r/Emboss.hpp"
@ -15,7 +16,7 @@ public:
WxFontUtils() = delete;
// 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 get_font_item(const wxFont &font);

View File

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