From 18d269506a689e37746c87aa03bc4a19a69c63da Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Mon, 28 Feb 2022 18:32:50 +0100 Subject: [PATCH] add index of font inside of collection to FontProp(font property) + serialization/deserialization (3mf + appConfig) separate glyph cache from FontFile --- src/libslic3r/Emboss.cpp | 62 +++++++++----------- src/libslic3r/Emboss.hpp | 71 ++++++++++++++--------- src/libslic3r/Format/3mf.cpp | 6 +- src/libslic3r/TextConfiguration.hpp | 4 ++ src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 39 ++++++++----- src/slic3r/GUI/Jobs/EmbossJob.cpp | 28 +++++---- src/slic3r/GUI/Jobs/EmbossJob.hpp | 28 ++++----- src/slic3r/Utils/FontListSerializable.cpp | 4 ++ src/slic3r/Utils/FontListSerializable.hpp | 1 + src/slic3r/Utils/FontManager.cpp | 67 +++++++++++---------- src/slic3r/Utils/FontManager.hpp | 5 +- src/slic3r/Utils/WxFontUtils.cpp | 6 +- tests/libslic3r/test_emboss.cpp | 4 +- 13 files changed, 189 insertions(+), 136 deletions(-) diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index 556d11d8a..9f0291138 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -21,8 +21,6 @@ class Private { public: Private() = delete; - - static std::optional load_font_info(const Emboss::FontFile &font); static std::optional load_font_info(const unsigned char *data, unsigned int index = 0); static std::optional get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness); static std::optional 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 Private::load_font_info(const Emboss::FontFile &font) -{ - return load_font_info(font.buffer.data(), font.index); -} - std::optional Private::load_font_info( const unsigned char *data, unsigned int index) { @@ -137,7 +130,10 @@ std::optional 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 Emboss::get_font_path(const std::wstring &font_face_ } #endif -std::unique_ptr Emboss::load_font( - std::vector &&data) +std::unique_ptr Emboss::create_font_file( + std::unique_ptr> 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::load_font( std::move(data), collection_size, ascent, descent, linegap, units_per_em); } -std::unique_ptr Emboss::load_font(const char *file_path) +std::unique_ptr 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::load_font(const char *file_path) return nullptr; } rewind(file); - - std::vector buffer(size); - size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file); + auto buffer = std::make_unique>(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::load_font(HFONT hfont) +std::unique_ptr Emboss::create_font_file(HFONT hfont) { HDC hdc = ::CreateCompatibleDC(NULL); if (hdc == NULL) { @@ -571,16 +566,14 @@ std::unique_ptr Emboss::load_font(HFONT hfont) ::DeleteDC(hdc); return nullptr; } - - std::vector buffer(size); - size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer.data(), size); + auto buffer = std::make_unique>(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::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 font_info_opt; - + assert(font_with_cache.has_value()); + + std::optional 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 space_opt = Private::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt); + std::optional 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(wc); - std::optional glyph_opt = Private::get_glyph(unicode, font, font_prop, font.cache, font_info_opt); + std::optional 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 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 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); diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index 69c2893a6..fd3b8c8aa 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -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) /// struct FontFile { // loaded data from font file - const std::vector 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> 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 &&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> 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; + } + }; + + /// + /// Add caching for shape of glyphs + /// + struct FontFileWithCache + { + std::shared_ptr font_file; + // cache for glyph shape + std::shared_ptr cache; + + FontFileWithCache() : font_file(nullptr), cache(nullptr) {} + FontFileWithCache(std::unique_ptr font_file) + : font_file(std::move(font_file)) + , cache(std::make_shared()) + {} + bool has_value() const { return font_file != nullptr && cache != nullptr; } }; /// @@ -104,14 +122,14 @@ public: /// /// Location of .ttf or .ttc font file /// Font object when loaded. - static std::unique_ptr load_font(const char *file_path); + static std::unique_ptr create_font_file(const char *file_path); // data = raw file data - static std::unique_ptr load_font(std::vector&& data); + static std::unique_ptr create_font_file(std::unique_ptr> data); #ifdef _WIN32 // fix for unknown pointer HFONT using HFONT = void*; static void * can_load(HFONT hfont); - static std::unique_ptr load_font(HFONT hfont); + static std::unique_ptr create_font_file(HFONT hfont); #endif // _WIN32 /// @@ -130,7 +148,7 @@ public: /// Characters to convert /// User defined property of the font /// Inner polygon cw(outer ccw) - 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) /// /// Selector of font + /// Index of font in collection /// True when the font description contains italic/obligue otherwise False - static bool is_italic(FontFile &font); + static bool is_italic(FontFile &font, int font_index = 0); /// /// Project 2d point into space diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 8e7b402cd..bea038a35 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -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 TextConfigurationSerialization::read(const char float angle = get_attribute_value_float(attributes, num_attributes, ANGLE_ATTR); if (std::fabs(angle) > std::numeric_limits::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); diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp index b0549c860..160493453 100644 --- a/src/libslic3r/TextConfiguration.hpp +++ b/src/libslic3r/TextConfiguration.hpp @@ -43,6 +43,10 @@ struct FontProp // When not set value is zero and is not stored std::optional angle; // [in radians] + // Parameter for True Type Font collections + // Select index of font in collection + std::optional collection_number; + //enum class Align { // left, // right, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index d543825c2..4f4069fd3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -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( - 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& font_file = m_font_manager.get_font_file(); - if (font_file == nullptr) return false; - auto data = std::make_unique(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(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 diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index a2edc1581..7e8c50645 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -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(depth); Emboss::ProjectScale project(std::move(projectZ), scale); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index 37dd757a6..67fc7823a 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -47,7 +47,7 @@ public: /// Control for job, check of cancelation /// Triangle mesh model static TriangleMesh create_mesh(const char * text, - Emboss::FontFile &font, + Emboss::FontFileWithCache &font, const FontProp & font_prop, Ctl & ctl); @@ -61,16 +61,16 @@ private: /// struct EmbossDataBase { - // Pointer on Data of font (glyph shapes) - std::shared_ptr 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 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 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 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 & 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) diff --git a/src/slic3r/Utils/FontListSerializable.cpp b/src/slic3r/Utils/FontListSerializable.cpp index 0ccbae344..920b91ad3 100644 --- a/src/slic3r/Utils/FontListSerializable.cpp +++ b/src/slic3r/Utils/FontListSerializable.cpp @@ -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 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()) diff --git a/src/slic3r/Utils/FontListSerializable.hpp b/src/slic3r/Utils/FontListSerializable.hpp index 692d9de0a..a47ef149c 100644 --- a/src/slic3r/Utils/FontListSerializable.hpp +++ b/src/slic3r/Utils/FontListSerializable.hpp @@ -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: diff --git a/src/slic3r/Utils/FontManager.cpp b/src/slic3r/Utils/FontManager.cpp index b056b62c9..d3751f048 100644 --- a/src/slic3r/Utils/FontManager.cpp +++ b/src/slic3r/Utils/FontManager.cpp @@ -72,13 +72,12 @@ bool FontManager::wx_font_changed(std::unique_ptr 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 &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 &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(); +} + 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 font_ptr = Emboss::load_font( - fi.path.c_str()); + std::unique_ptr 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 &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 &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 &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 &buffer = font_file.buffer; + const std::vector &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(); diff --git a/src/slic3r/Utils/FontManager.hpp b/src/slic3r/Utils/FontManager.hpp index a0b75c51f..4e9944912 100644 --- a/src/slic3r/Utils/FontManager.hpp +++ b/src/slic3r/Utils/FontManager.hpp @@ -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 font_file = nullptr; + Emboss::FontFileWithCache font_file_with_cache; std::optional imgui_font_index; diff --git a/src/slic3r/Utils/WxFontUtils.cpp b/src/slic3r/Utils/WxFontUtils.cpp index d9e42742f..a8ddf7193 100644 --- a/src/slic3r/Utils/WxFontUtils.cpp +++ b/src/slic3r/Utils/WxFontUtils.cpp @@ -45,7 +45,7 @@ bool WxFontUtils::can_load(const wxFont &font) std::unique_ptr 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 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 diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp index 7f7045ffe..7b222543f 100644 --- a/tests/libslic3r/test_emboss.cpp +++ b/tests/libslic3r/test_emboss.cpp @@ -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 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;