add index of font inside of collection to FontProp(font property) + serialization/deserialization (3mf + appConfig)

separate glyph cache from FontFile
This commit is contained in:
Filip Sykala 2022-02-28 18:32:50 +01:00
parent 8022c64209
commit 18d269506a
13 changed files with 189 additions and 136 deletions

View File

@ -21,8 +21,6 @@ class Private
{
public:
Private() = delete;
static std::optional<stbtt_fontinfo> load_font_info(const Emboss::FontFile &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::FontFile &font, const FontProp &font_prop,
@ -42,11 +40,6 @@ public:
static Point to_point(const stbtt__point &point);
};
std::optional<stbtt_fontinfo> Private::load_font_info(const Emboss::FontFile &font)
{
return load_font_info(font.buffer.data(), font.index);
}
std::optional<stbtt_fontinfo> Private::load_font_info(
const unsigned char *data, unsigned int index)
{
@ -137,7 +130,10 @@ std::optional<Emboss::Glyph> Private::get_glyph(
return glyph_item->second;
if (!font_info_opt.has_value()) {
font_info_opt = Private::load_font_info(font);
int font_index = font_prop.collection_number.has_value()?
*font_prop.collection_number : 0;
if (font_index >= font.count) return {};
font_info_opt = Private::load_font_info(font.data->data(), font_index);
// can load font info?
if (!font_info_opt.has_value()) return {};
}
@ -466,16 +462,16 @@ std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_
}
#endif
std::unique_ptr<Emboss::FontFile> Emboss::load_font(
std::vector<unsigned char> &&data)
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(
std::unique_ptr<std::vector<unsigned char>> data)
{
int collection_size = stbtt_GetNumberOfFonts(data.data());
int collection_size = stbtt_GetNumberOfFonts(data->data());
// at least one font must be inside collection
if (collection_size < 1) {
std::cerr << "There is no font collection inside data." << std::endl;
return nullptr;
}
auto font_info = Private::load_font_info(data.data());
auto font_info = Private::load_font_info(data->data());
if (!font_info.has_value()) return nullptr;
const stbtt_fontinfo *info = &(*font_info);
@ -490,7 +486,7 @@ std::unique_ptr<Emboss::FontFile> Emboss::load_font(
std::move(data), collection_size, ascent, descent, linegap, units_per_em);
}
std::unique_ptr<Emboss::FontFile> Emboss::load_font(const char *file_path)
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(const char *file_path)
{
FILE *file = fopen(file_path, "rb");
if (file == nullptr) {
@ -509,14 +505,13 @@ std::unique_ptr<Emboss::FontFile> Emboss::load_font(const char *file_path)
return nullptr;
}
rewind(file);
std::vector<unsigned char> buffer(size);
size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file);
auto buffer = std::make_unique<std::vector<unsigned char>>(size);
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 nullptr;
}
return load_font(std::move(buffer));
return create_font_file(std::move(buffer));
}
@ -557,7 +552,7 @@ void * Emboss::can_load(HFONT hfont)
return hfont;
}
std::unique_ptr<Emboss::FontFile> Emboss::load_font(HFONT hfont)
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont)
{
HDC hdc = ::CreateCompatibleDC(NULL);
if (hdc == NULL) {
@ -571,16 +566,14 @@ std::unique_ptr<Emboss::FontFile> Emboss::load_font(HFONT hfont)
::DeleteDC(hdc);
return nullptr;
}
std::vector<unsigned char> buffer(size);
size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer.data(), size);
auto buffer = std::make_unique<std::vector<unsigned char>>(size);
size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer->data(), size);
::DeleteDC(hdc);
if (size != loaded_size) {
std::cerr << "Different loaded(from HFONT) data size." << std::endl;
return nullptr;
}
return load_font(std::move(buffer));
return create_font_file(std::move(buffer));
}
#endif // _WIN32
@ -588,20 +581,22 @@ std::optional<Emboss::Glyph> Emboss::letter2glyph(const FontFile &font,
int letter,
float flatness)
{
auto font_info_opt = Private::load_font_info(font);
auto font_info_opt = Private::load_font_info(font.data->data(), 0);
if (!font_info_opt.has_value()) return {};
return Private::get_glyph(*font_info_opt, letter, flatness);
}
ExPolygons Emboss::text2shapes(FontFile & font,
ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
const char * text,
const FontProp &font_prop)
{
std::optional<stbtt_fontinfo> font_info_opt;
assert(font_with_cache.has_value());
std::optional<stbtt_fontinfo> font_info_opt;
Point cursor(0, 0);
ExPolygons result;
const FontFile& font = *font_with_cache.font_file;
Emboss::Glyphs& cache = *font_with_cache.cache;
std::wstring ws = boost::nowide::widen(text);
for (wchar_t wc: ws){
if (wc == '\n') {
@ -617,14 +612,14 @@ ExPolygons Emboss::text2shapes(FontFile & font,
if (wc == '\t') {
// '\t' = 4*space => same as imgui
const int count_spaces = 4;
std::optional<Glyph> space_opt = Private::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt);
std::optional<Glyph> space_opt = Private::get_glyph(int(' '), font, font_prop, cache, font_info_opt);
if (!space_opt.has_value()) continue;
cursor.x() += count_spaces * space_opt->advance_width;
continue;
}
int unicode = static_cast<int>(wc);
std::optional<Glyph> glyph_opt = Private::get_glyph(unicode, font, font_prop, font.cache, font_info_opt);
std::optional<Glyph> glyph_opt = Private::get_glyph(unicode, font, font_prop, cache, font_info_opt);
if (!glyph_opt.has_value()) continue;
// move glyph to cursor position
@ -652,9 +647,10 @@ void Emboss::apply_transformation(const FontProp &font_prop,
}
}
bool Emboss::is_italic(FontFile &font) {
std::optional<stbtt_fontinfo> font_info_opt =
Private::load_font_info(font);
bool Emboss::is_italic(FontFile &font, int font_index)
{
if (font_index >= font.count) return false;
std::optional<stbtt_fontinfo> font_info_opt = Private::load_font_info(font.data->data(), font_index);
if (!font_info_opt.has_value()) return false;
stbtt_fontinfo *info = &(*font_info_opt);

View File

@ -59,44 +59,62 @@ public:
/// keep information from file about font
/// (store file data itself)
/// + cache data readed from buffer
/// + cache shape of glyphs (optionaly modified)
/// </summary>
struct FontFile
{
// loaded data from font file
const std::vector<unsigned char> buffer;
// must store data size for imgui rasterization
// To not store data on heap and To prevent unneccesary copy
// data are stored inside unique_ptr
std::unique_ptr<std::vector<unsigned char>> data;
unsigned int index; // index of actual file info in collection
const unsigned int count; // count of fonts in file collection
// count of fonts when data are collection of fonts
unsigned int count;
// vertical position is "scale*(ascent - descent + lineGap)"
const int ascent, descent, linegap;
int ascent, descent, linegap;
// for convert font units to pixel
int unit_per_em;
Emboss::Glyphs cache; // cache of glyphs
FontFile(std::vector<unsigned char> &&buffer,
unsigned int count,
int ascent,
int descent,
int linegap,
int unit_per_em
)
: buffer(std::move(buffer))
, index(0) // select default font on index 0
FontFile(std::unique_ptr<std::vector<unsigned char>> data,
unsigned int count,
int ascent,
int descent,
int linegap,
int unit_per_em)
: data(std::move(data))
, count(count)
, ascent(ascent)
, descent(descent)
, linegap(linegap)
, unit_per_em(unit_per_em)
{}
bool operator==(const FontFile &other) const {
return index == other.index &&
buffer.size() == other.buffer.size() &&
buffer == other.buffer;
{
assert(this->data != nullptr);
}
bool operator==(const FontFile &other) const {
return count == other.count && ascent == other.ascent &&
descent == other.descent && linegap == other.linegap &&
data->size() == other.data->size();
//&& *data == *other.data;
}
};
/// <summary>
/// Add caching for shape of glyphs
/// </summary>
struct FontFileWithCache
{
std::shared_ptr<FontFile> font_file;
// cache for glyph shape
std::shared_ptr<Emboss::Glyphs> cache;
FontFileWithCache() : font_file(nullptr), cache(nullptr) {}
FontFileWithCache(std::unique_ptr<FontFile> font_file)
: font_file(std::move(font_file))
, cache(std::make_shared<Emboss::Glyphs>())
{}
bool has_value() const { return font_file != nullptr && cache != nullptr; }
};
/// <summary>
@ -104,14 +122,14 @@ public:
/// </summary>
/// <param name="file_path">Location of .ttf or .ttc font file</param>
/// <returns>Font object when loaded.</returns>
static std::unique_ptr<FontFile> load_font(const char *file_path);
static std::unique_ptr<FontFile> create_font_file(const char *file_path);
// data = raw file data
static std::unique_ptr<FontFile> load_font(std::vector<unsigned char>&& data);
static std::unique_ptr<FontFile> create_font_file(std::unique_ptr<std::vector<unsigned char>> data);
#ifdef _WIN32
// fix for unknown pointer HFONT
using HFONT = void*;
static void * can_load(HFONT hfont);
static std::unique_ptr<FontFile> load_font(HFONT hfont);
static std::unique_ptr<FontFile> create_font_file(HFONT hfont);
#endif // _WIN32
/// <summary>
@ -130,7 +148,7 @@ public:
/// <param name="text">Characters to convert</param>
/// <param name="font_prop">User defined property of the font</param>
/// <returns>Inner polygon cw(outer ccw)</returns>
static ExPolygons text2shapes(FontFile & font,
static ExPolygons text2shapes(FontFileWithCache &font,
const char * text,
const FontProp &font_prop);
@ -148,8 +166,9 @@ public:
/// search for italic (or oblique), bold italic (or bold oblique)
/// </summary>
/// <param name="font">Selector of font</param>
/// <param name="font_index">Index of font in collection</param>
/// <returns>True when the font description contains italic/obligue otherwise False</returns>
static bool is_italic(FontFile &font);
static bool is_italic(FontFile &font, int font_index = 0);
/// <summary>
/// Project 2d point into space

View File

@ -163,6 +163,7 @@ static constexpr const char *BOLDNESS_ATTR = "boldness";
static constexpr const char *SKEW_ATTR = "skew";
static constexpr const char *DISTANCE_ATTR = "distance";
static constexpr const char *ANGLE_ATTR = "angle";
static constexpr const char *COLLECTION_NUMBER_ATTR = "collection";
static constexpr const char *FONT_FAMILY_ATTR = "family";
static constexpr const char *FONT_FACE_NAME_ATTR = "face_name";
@ -3329,7 +3330,8 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex
stream << DISTANCE_ATTR << "=\"" << *fp.distance << "\" ";
if (fp.angle.has_value())
stream << ANGLE_ATTR << "=\"" << *fp.angle << "\" ";
if (fp.collection_number.has_value())
stream << COLLECTION_NUMBER_ATTR << "=\"" << *fp.collection_number << "\" ";
// font descriptor
if (fp.family.has_value())
stream << FONT_FAMILY_ATTR << "=\"" << *fp.family << "\" ";
@ -3361,6 +3363,8 @@ std::optional<TextConfiguration> TextConfigurationSerialization::read(const char
float angle = get_attribute_value_float(attributes, num_attributes, ANGLE_ATTR);
if (std::fabs(angle) > std::numeric_limits<float>::epsilon())
fp.angle = angle;
int collection_number = get_attribute_value_int(attributes, num_attributes, COLLECTION_NUMBER_ATTR);
if (collection_number > 0) fp.collection_number = collection_number;
fp.size_in_mm = get_attribute_value_float(attributes, num_attributes, LINE_HEIGHT_ATTR);
fp.emboss = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);

View File

@ -43,6 +43,10 @@ struct FontProp
// When not set value is zero and is not stored
std::optional<float> angle; // [in radians]
// Parameter for True Type Font collections
// Select index of font in collection
std::optional<int> collection_number;
//enum class Align {
// left,
// right,

View File

@ -78,7 +78,7 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
void GLGizmoEmboss::set_fine_position()
{
const Selection & selection = m_parent.get_selection();
const Selection &selection = m_parent.get_selection();
const Selection::IndicesList indices = selection.get_volume_idxs();
// no selected volume
if (indices.empty()) return;
@ -157,7 +157,7 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
Plater* plater = wxGetApp().plater();
const Camera &camera = plater->get_camera();
auto data = std::make_unique<EmbossDataCreate>(
m_font_manager.get_font_file(),
m_font_manager.get_font().font_file_with_cache,
create_configuration(),
create_volume_name(), volume_type, screen_coor, object_idx,
hit_vol_tr, camera,
@ -662,9 +662,9 @@ bool GLGizmoEmboss::process()
if (m_volume == nullptr) return false;
// exist loaded font?
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
if (font_file == nullptr) return false;
auto data = std::make_unique<EmbossDataUpdate>(font_file,
Emboss::FontFileWithCache font = m_font_manager.get_font().font_file_with_cache;
if (!font.has_value()) return false;
auto data = std::make_unique<EmbossDataUpdate>(font,
create_configuration(),
create_volume_name(), m_volume);
@ -1401,6 +1401,7 @@ void GLGizmoEmboss::draw_style_edit() {
if (exist_change) {
m_font_manager.free_style_images();
m_font_manager.clear_glyphs_cache();
process();
}
@ -1581,21 +1582,27 @@ void GLGizmoEmboss::draw_advanced()
ImGui::Text("%s", _u8L("Advanced font options could be change only for corect font.\nStart with select correct font.").c_str());
return;
}
FontProp &font_prop = m_font_manager.get_font_item().prop;
#ifdef SHOW_FONT_FILE_PROPERTY
ImGui::SameLine();
auto& ff = m_font_manager.get_font().font_file_with_cache;
int cache_size = ff.has_value()? (int)ff.cache->size() : 0;
std::string ff_property =
"ascent=" + std::to_string(font_file->ascent) +
", descent=" + std::to_string(font_file->descent) +
", lineGap=" + std::to_string(font_file->linegap) +
", unitPerEm=" + std::to_string(font_file->unit_per_em) +
", cache(" + std::to_string(font_file->cache.size()) + " glyphs)";
if (font_file->count > 1) ff_property +=
", collect=" + std::to_string(font_file->index + 1) + "/" + std::to_string(font_file->count);
", unitPerEm=" + std::to_string(font_file->unit_per_em) +
", cache(" + std::to_string(cache_size) + " glyphs)";
if (font_file->count > 1) {
int collection = font_prop.collection_number.has_value() ?
*font_prop.collection_number : 0;
ff_property += ", collect=" + std::to_string(collection+1) + "/" + std::to_string(font_file->count);
}
m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property);
#endif // SHOW_FONT_FILE_PROPERTY
FontProp &font_prop = m_font_manager.get_font_item().prop;
bool exist_change = false;
auto &tr = m_gui_cfg->translations;
@ -1693,12 +1700,15 @@ void GLGizmoEmboss::draw_advanced()
ImGui::Text("%s", tr.collection.c_str());
ImGui::SameLine(m_gui_cfg->advanced_input_offset);
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
if (ImGui::BeginCombo("## Font collection", std::to_string(font_file->index).c_str())) {
unsigned int selected = font_prop.collection_number.has_value() ?
*font_prop.collection_number : 0;
if (ImGui::BeginCombo("## Font collection", std::to_string(selected).c_str())) {
for (unsigned int i = 0; i < font_file->count; ++i) {
ImGui::PushID(1 << (10 + i));
bool is_selected = i == font_file->index;
bool is_selected = (i == selected);
if (ImGui::Selectable(std::to_string(i).c_str(), is_selected)) {
font_file->index = i;
if (i == 0) font_prop.collection_number.reset();
else font_prop.collection_number = i;
exist_change = true;
}
ImGui::PopID();
@ -1711,6 +1721,7 @@ void GLGizmoEmboss::draw_advanced()
if (exist_change) {
m_font_manager.free_style_images();
m_font_manager.clear_glyphs_cache();
process();
}
#ifdef ALLOW_DEBUG_MODE

View File

@ -22,11 +22,11 @@ using namespace GUI;
void EmbossUpdateJob::process(Ctl &ctl)
{
// check if exist valid font
if (m_input->font_file == nullptr) return;
if (!m_input->font_file.has_value()) return;
const TextConfiguration &cfg = m_input->text_configuration;
m_result = EmbossCreateJob::create_mesh(
cfg.text.c_str(), *m_input->font_file, cfg.font_item.prop, ctl);
cfg.text.c_str(), m_input->font_file, cfg.font_item.prop, ctl);
if (m_result.its.empty()) return;
if (ctl.was_canceled()) return;
@ -98,11 +98,11 @@ void EmbossUpdateJob::finalize(bool canceled, std::exception_ptr &)
void EmbossCreateJob::process(Ctl &ctl) {
// It is neccessary to create some shape
// Emboss text window is opened by creation new emboss text object
m_result = (m_input->font_file == nullptr) ?
create_default_mesh() :
create_mesh(m_input->text_configuration.text.c_str(),
*m_input->font_file,
m_input->text_configuration.font_item.prop, ctl);
const char *text = m_input->text_configuration.text.c_str();
FontProp &prop = m_input->text_configuration.font_item.prop;
m_result = (m_input->font_file.has_value()) ?
create_mesh(text, m_input->font_file, prop, ctl):
create_default_mesh();
if (m_result.its.empty()) m_result = create_default_mesh();
if (ctl.was_canceled()) return;
@ -240,16 +240,20 @@ TriangleMesh EmbossCreateJob::create_default_mesh()
return triangle_mesh;
}
TriangleMesh EmbossCreateJob::create_mesh(const char * text,
Emboss::FontFile &font,
const FontProp & font_prop,
Ctl & ctl)
TriangleMesh EmbossCreateJob::create_mesh(const char *text,
Emboss::FontFileWithCache &font,
const FontProp &font_prop,
Ctl &ctl)
{
assert(font.has_value());
if (!font.has_value()) return {};
ExPolygons shapes = Emboss::text2shapes(font, text, font_prop);
if (shapes.empty()) return {};
if (ctl.was_canceled()) return {};
float scale = font_prop.size_in_mm / font.unit_per_em;
int unit_per_em = font.font_file->unit_per_em;
float scale = font_prop.size_in_mm / unit_per_em;
float depth = font_prop.emboss / scale;
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
Emboss::ProjectScale project(std::move(projectZ), scale);

View File

@ -47,7 +47,7 @@ public:
/// <param name="ctl">Control for job, check of cancelation</param>
/// <returns>Triangle mesh model</returns>
static TriangleMesh create_mesh(const char * text,
Emboss::FontFile &font,
Emboss::FontFileWithCache &font,
const FontProp & font_prop,
Ctl & ctl);
@ -61,16 +61,16 @@ private:
/// </summary>
struct EmbossDataBase
{
// Pointer on Data of font (glyph shapes)
std::shared_ptr<Emboss::FontFile> font_file;
// Keep pointer on Data of font (glyph shapes)
Emboss::FontFileWithCache font_file;
// font item is not used for create object
TextConfiguration text_configuration;
// new volume name created from text
std::string volume_name;
EmbossDataBase(std::shared_ptr<Emboss::FontFile> font_file,
TextConfiguration text_configuration,
std::string volume_name)
: font_file(std::move(font_file))
EmbossDataBase(Emboss::FontFileWithCache font_file,
TextConfiguration text_configuration,
std::string volume_name)
: font_file(font_file)
, text_configuration(text_configuration)
, volume_name(volume_name)
{}
@ -88,11 +88,11 @@ struct EmbossDataUpdate : public EmbossDataBase
// unique identifier of volume to change
// Change of volume change id, last change could disapear
// ObjectID volume_id;
EmbossDataUpdate(std::shared_ptr<Emboss::FontFile> font_file,
TextConfiguration text_configuration,
std::string volume_name,
ModelVolume * volume)
: EmbossDataBase(std::move(font_file), text_configuration, volume_name)
EmbossDataUpdate(Emboss::FontFileWithCache font_file,
TextConfiguration text_configuration,
std::string volume_name,
ModelVolume *volume)
: EmbossDataBase(font_file, text_configuration, volume_name)
, volume(volume)
{}
};
@ -125,7 +125,7 @@ struct EmbossDataCreate: public EmbossDataBase
// It is inside of GLGizmoEmboss object,
// so I hope it will survive
EmbossDataCreate(std::shared_ptr<Emboss::FontFile> font_file,
EmbossDataCreate(Emboss::FontFileWithCache font_file,
const TextConfiguration & text_configuration,
const std::string & volume_name,
ModelVolumeType volume_type,
@ -135,7 +135,7 @@ struct EmbossDataCreate: public EmbossDataBase
const Camera& camera,
const std::vector<Vec2d> & bed_shape,
RaycastManager * raycast_manager)
: EmbossDataBase(std::move(font_file), text_configuration, volume_name)
: EmbossDataBase(font_file, text_configuration, volume_name)
, volume_type(volume_type)
, screen_coor(screen_coor)
, object_idx(object_idx)

View File

@ -14,6 +14,7 @@ const std::string FontListSerializable::APP_CONFIG_FONT_BOLDNESS = "boldness"
const std::string FontListSerializable::APP_CONFIG_FONT_SKEW = "skew";
const std::string FontListSerializable::APP_CONFIG_FONT_DISTANCE = "distance";
const std::string FontListSerializable::APP_CONFIG_FONT_ANGLE = "angle";
const std::string FontListSerializable::APP_CONFIG_FONT_COLLECTION = "collection";
const std::string FontListSerializable::APP_CONFIG_FONT_CHAR_GAP = "char_gap";
const std::string FontListSerializable::APP_CONFIG_FONT_LINE_GAP = "line_gap";
@ -83,6 +84,7 @@ std::optional<FontItem> FontListSerializable::load_font_item(
read(app_cfg_section, APP_CONFIG_FONT_SKEW, fp.skew);
read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, fp.distance);
read(app_cfg_section, APP_CONFIG_FONT_ANGLE, fp.angle);
read(app_cfg_section, APP_CONFIG_FONT_COLLECTION, fp.collection_number);
read(app_cfg_section, APP_CONFIG_FONT_CHAR_GAP, fp.char_gap);
read(app_cfg_section, APP_CONFIG_FONT_LINE_GAP, fp.line_gap);
@ -109,6 +111,8 @@ void FontListSerializable::store_font_item(AppConfig & cfg,
cfg.set(section_name, APP_CONFIG_FONT_DISTANCE, std::to_string(*fp.distance));
if (fp.angle.has_value())
cfg.set(section_name, APP_CONFIG_FONT_ANGLE, std::to_string(*fp.angle));
if (fp.collection_number.has_value())
cfg.set(section_name, APP_CONFIG_FONT_COLLECTION, std::to_string(*fp.collection_number));
if (fp.char_gap.has_value())
cfg.set(section_name, APP_CONFIG_FONT_CHAR_GAP, std::to_string(*fp.char_gap));
if (fp.line_gap.has_value())

View File

@ -25,6 +25,7 @@ class FontListSerializable
static const std::string APP_CONFIG_FONT_SKEW;
static const std::string APP_CONFIG_FONT_DISTANCE;
static const std::string APP_CONFIG_FONT_ANGLE;
static const std::string APP_CONFIG_FONT_COLLECTION;
static const std::string APP_CONFIG_FONT_CHAR_GAP;
static const std::string APP_CONFIG_FONT_LINE_GAP;
public:

View File

@ -72,13 +72,12 @@ bool FontManager::wx_font_changed(std::unique_ptr<Emboss::FontFile> font_file)
if (!wx_font.has_value()) return false;
if (font_file == nullptr) {
auto new_font_file = WxFontUtils::create_font_file(*wx_font);
if (new_font_file == nullptr) return false;
m_font_list[m_font_selected].font_file = std::move(new_font_file);
} else {
m_font_list[m_font_selected].font_file = std::move(font_file);
font_file = WxFontUtils::create_font_file(*wx_font);
if (font_file == nullptr) return false;
}
m_font_list[m_font_selected].font_file_with_cache =
Emboss::FontFileWithCache(std::move(font_file));
auto &fi = get_font_item();
fi.type = WxFontUtils::get_actual_type();
fi.path = WxFontUtils::store_wxFont(*wx_font);
@ -150,7 +149,7 @@ std::shared_ptr<Emboss::FontFile> &FontManager::get_font_file()
{
// TODO: fix not selected font
//if (!is_activ_font()) return nullptr;
return m_font_list[m_font_selected].font_file;
return m_font_list[m_font_selected].font_file_with_cache.font_file;
}
const FontItem &FontManager::get_font_item() const
@ -209,8 +208,17 @@ const std::optional<wxFont> &FontManager::get_wx_font() const
return m_font_list[m_font_selected].wx_font;
}
void FontManager::clear_glyphs_cache()
{
if (!is_activ_font()) return;
Emboss::FontFileWithCache &ff = m_font_list[m_font_selected].font_file_with_cache;
if (!ff.has_value()) return;
ff.cache = std::make_shared<Emboss::Glyphs>();
}
void FontManager::clear_imgui_font() {
// TODO: improove to clear only actual font
if (!is_activ_font()) return;
free_imgui_fonts();
return;
ImFont *imgui_font = get_imgui_font(m_font_selected);
@ -255,7 +263,7 @@ void FontManager::free_except_active_font() {
const Item &act_item = m_font_list[m_font_selected];
for (auto &item : m_font_list) {
if (&item == &act_item) continue; // keep alive actual font file
item.font_file = nullptr;
item.font_file_with_cache = {};
}
}
@ -301,10 +309,11 @@ bool FontManager::set_up_font_file(size_t item_index)
if (fi.type == FontItem::Type::file_path) {
// fill font name after load from .3mf
if (fi.name.empty()) fi.name = get_file_name(fi.path);
std::unique_ptr<Emboss::FontFile> font_ptr = Emboss::load_font(
fi.path.c_str());
std::unique_ptr<Emboss::FontFile> font_ptr =
Emboss::create_font_file(fi.path.c_str());
if (font_ptr == nullptr) return false;
item.font_file = std::move(font_ptr);
item.font_file_with_cache =
Emboss::FontFileWithCache(std::move(font_ptr));
return true;
}
if (fi.type != WxFontUtils::get_actual_type()) return false;
@ -366,10 +375,12 @@ void FontManager::create_texture(size_t index, const std::string &text, GLuint&
{
if (index >= m_font_list.size()) return;
Item &item = m_font_list[index];
if (!item.font_file_with_cache.has_value() && !set_up_font_file(index))
return;
const FontProp &font_prop = item.font_item.prop;
std::shared_ptr<Emboss::FontFile> &font_file = item.font_file;
if (font_file == nullptr && !set_up_font_file(index)) return;
ExPolygons shapes = Emboss::text2shapes(*font_file, text.c_str(), font_prop);
ExPolygons shapes = Emboss::text2shapes(item.font_file_with_cache,
text.c_str(), font_prop);
BoundingBox bb;
for (ExPolygon &shape : shapes) bb.merge(BoundingBox(shape.contour.points));
@ -415,13 +426,12 @@ void FontManager::init_style_images(int max_width) {
for (Item &item : m_font_list) {
FontItem & font_item = item.font_item;
const FontProp & font_prop = font_item.prop;
std::shared_ptr<Emboss::FontFile> &font_file = item.font_file;
size_t index = &item - &m_font_list.front();
if (font_file == nullptr && !set_up_font_file(index)) continue;
if (font_file == nullptr) continue;
if (!item.font_file_with_cache.has_value() && !set_up_font_file(index))
continue;
ExPolygons &shapes = name_shapes[index];
shapes = Emboss::text2shapes(*font_file, font_item.name.c_str(), font_prop);
shapes = Emboss::text2shapes(item.font_file_with_cache, font_item.name.c_str(), font_prop);
// create image description
item.image = StyleImage();
@ -437,7 +447,8 @@ void FontManager::init_style_images(int max_width) {
// dot per inch for monitor
int dpi = get_dpi_for_window(mf);
double ppm = dpi / 25.4; // pixel per milimeter
double scale = font_prop.size_in_mm / font_file->unit_per_em * Emboss::SHAPE_SCALE * ppm;
double unit_per_em = item.font_file_with_cache.font_file->unit_per_em;
double scale = font_prop.size_in_mm / unit_per_em * Emboss::SHAPE_SCALE * ppm;
scales[index] = scale;
//double scale = font_prop.size_in_mm * SCALING_FACTOR;
@ -520,11 +531,6 @@ void FontManager::init_style_images(int max_width) {
void FontManager::free_style_images() {
if (!is_activ_font()) return;
std::shared_ptr<Emboss::FontFile> &font_file =
m_font_list[m_font_selected].font_file;
if(font_file != nullptr)
font_file->cache.clear();
if (!m_exist_style_images) return;
GLuint tex_id = (GLuint) (intptr_t) m_font_list.front().image->texture_id;
for (Item &it : m_font_list) it.image.reset();
@ -560,8 +566,8 @@ ImFont * FontManager::load_imgui_font(size_t index, const std::string &text)
if (index >= m_font_list.size()) return nullptr;
Item &item = m_font_list[index];
if (item.font_file == nullptr) return nullptr;
const Emboss::FontFile &font_file = *item.font_file;
if (!item.font_file_with_cache.has_value()) return nullptr;
const Emboss::FontFile &font_file = *item.font_file_with_cache.font_file;
// TODO: Create glyph range
ImFontGlyphRangesBuilder builder;
@ -596,7 +602,7 @@ ImFont * FontManager::load_imgui_font(size_t index, const std::string &text)
font_config.FontDataOwnedByAtlas = false;
const std::vector<unsigned char> &buffer = font_file.buffer;
const std::vector<unsigned char> &buffer = *font_file.data;
m_imgui_font_atlas.AddFontFromMemoryTTF(
(void *) buffer.data(), buffer.size(), font_size, &font_config, item.font_ranges.Data);
@ -633,9 +639,10 @@ bool FontManager::set_wx_font(size_t item_index, const wxFont &wx_font) {
WxFontUtils::create_font_file(wx_font);
if (font_file == nullptr) return false;
Item &item = m_font_list[item_index];
item.font_file = std::move(font_file);
item.wx_font = wx_font;
Item &item = m_font_list[item_index];
item.font_file_with_cache =
Emboss::FontFileWithCache(std::move(font_file));
item.wx_font = wx_font;
FontItem &fi = item.font_item;
fi.type = WxFontUtils::get_actual_type();

View File

@ -59,6 +59,9 @@ public:
// fastering load font on index by wxFont, ignore type and descriptor
bool load_font(size_t font_index, const wxFont &font);
// clear actual selected glyphs cache
void clear_glyphs_cache();
// remove cached imgui font for actual selected font
void clear_imgui_font();
@ -137,7 +140,7 @@ public:
std::string truncated_name;
// share font file data with emboss job thread
std::shared_ptr<Emboss::FontFile> font_file = nullptr;
Emboss::FontFileWithCache font_file_with_cache;
std::optional<size_t> imgui_font_index;

View File

@ -45,7 +45,7 @@ bool WxFontUtils::can_load(const wxFont &font)
std::unique_ptr<Emboss::FontFile> WxFontUtils::create_font_file(const wxFont &font)
{
#ifdef _WIN32
return Emboss::load_font(font.GetHFONT());
return Emboss::create_font_file(font.GetHFONT());
#elif defined(__APPLE__)
// use file path
const wxNativeFontInfo *info = font.GetNativeFontInfo();
@ -61,12 +61,12 @@ std::unique_ptr<Emboss::FontFile> WxFontUtils::create_font_file(const wxFont &fo
size_t start = std::string("file://").size();
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());
return Emboss::create_font_file(file_path.c_str());
#elif defined(__linux__)
static FontConfigHelp help;
std::string font_path = help.get_font_path(font);
if (font_path.empty()) return nullptr;
return Emboss::load_font(font_path.c_str());
return Emboss::create_font_file(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

View File

@ -130,7 +130,7 @@ TEST_CASE("Emboss text", "[Emboss]")
char letter = '%';
float flatness = 2.;
auto font = Emboss::load_font(font_path.c_str());
auto font = Emboss::create_font_file(font_path.c_str());
REQUIRE(font != nullptr);
std::optional<Emboss::Glyph> glyph = Emboss::letter2glyph(*font, letter, flatness);
@ -237,7 +237,7 @@ TEST_CASE("Italic check", "[]")
[](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());
auto font_opt = Emboss::create_font_file(path_str.c_str());
if (font_opt == nullptr) continue;
if (Emboss::is_italic(*font_opt))
exist_italic = true;