From 5daf8818c97366d5ad1da68f039331f1b768f11f Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 4 Nov 2022 10:01:32 +0100 Subject: [PATCH] Add checking of new installed font into list on each open combo box --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 122 +++++++++++------------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 14 ++- src/slic3r/Utils/WxFontUtils.cpp | 2 + 3 files changed, 66 insertions(+), 72 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 6bc837e843..976f442a0f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -1226,58 +1226,13 @@ void GLGizmoEmboss::draw_text_input() } } -/// -/// Keep list of loadable OS fonts -/// Filtrate which can be loaded. -/// Sort alphanumerical. -/// -class MyFontEnumerator : public wxFontEnumerator +#include +#include "wx/hashmap.h" +std::size_t hash_value(wxString const &s) { - wxFontEncoding m_encoding; - bool m_fixed_width_only = false; - std::vector m_facenames; - std::vector m_facenames_bad; -public: - MyFontEnumerator(wxFontEncoding encoding) : m_encoding(encoding) {} - void enumerate() { - m_facenames.clear(); - m_facenames_bad.clear(); - EnumerateFacenames(m_encoding, m_fixed_width_only); - std::sort(m_facenames.begin(), m_facenames.end()); - } - - const std::vector &get_face_names() const { return m_facenames; } - const std::vector &get_bad_face_names() const { return m_facenames_bad; } -protected: - /// - /// Called by wxFontEnumerator::EnumerateFacenames() for each match. - /// - /// name identificator to load face by wxFont - /// True to continue enumeration or false to stop it. - virtual bool OnFacename(const wxString& facename) wxOVERRIDE { - // vertical font start with @, we will filter it out - if (facename.empty() || facename[0] == '@') return true; - wxFont wx_font(wxFontInfo().FaceName(facename).Encoding(m_encoding)); - - //* - // Faster chech if wx_font is loadable but not 100% - // names could contain not loadable font - if (!WxFontUtils::can_load(wx_font)) { - m_facenames_bad.emplace_back(facename); - return true; // can't load - } - /*/ - // Slow copy of font files to try load font - // After this all files are loadable - auto font_file = WxFontUtils::create_font_file(wx_font); - if (font_file == nullptr) { - m_facenames_bad.emplace_back(facename.c_str()); - return true; // can't create font file - } // */ - m_facenames.push_back(facename); - return true; - } -}; + boost::hash hasher; + return hasher(s.ToStdString()); +} bool GLGizmoEmboss::select_facename(const wxString &facename) { if (!wxFontEnumerator::IsValidFacename(facename)) return false; @@ -1303,27 +1258,57 @@ static std::string concat(std::vector data) { void GLGizmoEmboss::init_face_names() { Timer t("enumerate_fonts"); if (m_face_names.is_init) return; - m_face_names.is_init = true; - MyFontEnumerator font_enumerator(m_face_names.encoding); + m_face_names.is_init = true; - { using namespace std::chrono; + using namespace std::chrono; steady_clock::time_point enumerate_start = steady_clock::now(); - ScopeGuard sg([&enumerate_start, &font_enumerator]() { + ScopeGuard sg([&enumerate_start, &face_names = m_face_names]() { steady_clock::time_point enumerate_end = steady_clock::now(); long long enumerate_duration = duration_cast(enumerate_end - enumerate_start).count(); - BOOST_LOG_TRIVIAL(info) << "OS enumerate " << font_enumerator.get_face_names().size() << " fonts " - << "(+ " << font_enumerator.get_bad_face_names().size() << " can't load " - << "= " << font_enumerator.get_face_names().size() + font_enumerator.get_bad_face_names().size() << " fonts) " - << "in " << enumerate_duration << " ms\n" << concat(font_enumerator.get_bad_face_names()); + BOOST_LOG_TRIVIAL(info) << "OS enumerate " << face_names.faces.size() << " fonts " + << "(+ " << face_names.bad.size() << " can't load " + << "= " << face_names.faces.size() + face_names.bad.size() << " fonts) " + << "in " << enumerate_duration << " ms\n" << concat(face_names.bad); }); - - font_enumerator.enumerate(); - }// End Time measures + wxArrayString facenames = wxFontEnumerator::GetFacenames(m_face_names.encoding); + size_t hash = boost::hash_range(facenames.begin(), facenames.end()); + // check if it is same as last time + if (m_face_names.hash == hash) return; // no new installed font + m_face_names.hash = hash; - const std::vector &names = font_enumerator.get_face_names(); + // validation lambda + auto is_valid_font = [encoding = m_face_names.encoding](const wxString &name) { + if (name.empty()) return false; + + // vertical font start with @, we will filter it out + // Not sure if it is only in Windows so filtering is on all platforms + if (name[0] == '@') return false; + + wxFont wx_font(wxFontInfo().FaceName(name).Encoding(encoding)); + + //* + // Faster chech if wx_font is loadable but not 100% + // names could contain not loadable font + if (!WxFontUtils::can_load(wx_font)) return false; + + /*/ + // Slow copy of font files to try load font + // After this all files are loadable + auto font_file = WxFontUtils::create_font_file(wx_font); + if (font_file == nullptr) + return false; // can't create font file + // */ + return true; + }; + const float &width = m_gui_cfg->face_name_max_width; - m_face_names.faces.reserve(names.size()); - for (const wxString &name : names) { + m_face_names.faces.reserve(facenames.size()); + for (const wxString &name : facenames) { + if (!is_valid_font(name)) { + m_face_names.bad.push_back(name); + continue; + } + FaceName face_name = {name}; std::string name_str(name.ToUTF8().data()); face_name.name_truncated = ImGuiWrapper::trunc(name_str, width); @@ -1482,10 +1467,11 @@ void GLGizmoEmboss::draw_font_list() static_cast(m_face_names.names.size())); #endif // SHOW_FONT_COUNT ImGui::EndCombo(); - allow_update_rendered_font = true; - } else if (allow_update_rendered_font) { + } else if (m_face_names.is_init) { + // Just one after close combo box // free texture and set id to zero - allow_update_rendered_font = false; + + m_face_names.is_init = false; // cancel all process for generation of texture for (FaceName &face : m_face_names.faces) if (face.cancel != nullptr) face.cancel->store(true); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 5b9674e478..71fdbf4d83 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -244,8 +244,13 @@ private: { // flag if face names was enumerated from OS bool is_init = false; - + // data of can_load() faces std::vector faces = {}; + // Not valid face names + std::vector bad = {}; + + // Configuration of font encoding + const wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM; // Identify if preview texture exists GLuint texture_id = 0; @@ -254,14 +259,15 @@ private: // Gtk:ERROR:../../../../gtk/gtkiconhelper.c:494:ensure_surface_for_gicon: assertion failed (error == NULL): Failed to load /usr/share/icons/Yaru/48x48/status/image-missing.png: Error opening file /usr/share/icons/Yaru/48x48/status/image-missing.png: Too many open files (g-io-error-quark, 31) unsigned int count_opened_font_files = 0; - // Configuration of font encoding - const wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM; - // Configuration for texture height const int count_cached_textures = 32; // index for new generated texture index(must be lower than count_cached_textures) size_t texture_index = 0; + + // hash created from enumerated font from OS + // check when new font was installed + size_t hash = 0; } m_face_names; // Text to emboss diff --git a/src/slic3r/Utils/WxFontUtils.cpp b/src/slic3r/Utils/WxFontUtils.cpp index 67b6077903..b7bd97091c 100644 --- a/src/slic3r/Utils/WxFontUtils.cpp +++ b/src/slic3r/Utils/WxFontUtils.cpp @@ -73,6 +73,8 @@ bool WxFontUtils::can_load(const wxFont &font) #elif defined(__APPLE__) return is_valid_ttf(get_file_path(font)); #elif defined(__linux__) + return true; + // font config check file path take about 4000ms for chech them all std::string font_path = Slic3r::GUI::get_font_path(font); return !font_path.empty(); #endif