Improve performance loading list of fonts using an app::Task

We list the fonts in a background thread to fill the list of fonts in
the UI. And now we are inserting the fonts in alphabetical order.
This commit is contained in:
David Capello 2025-04-18 19:56:56 -03:00
parent 943c3b28df
commit 8a8ddbc630
2 changed files with 115 additions and 66 deletions

View File

@ -39,6 +39,7 @@
#include "ui/message.h"
#include "ui/paint_event.h"
#include "ui/size_hint_event.h"
#include "ui/system.h"
#include "ui/theme.h"
#include "ui/view.h"
@ -175,7 +176,6 @@ private:
if (m_thumbnail.surface)
return;
const auto* theme = app::skin::SkinTheme::get(this);
try {
Fonts* fonts = Fonts::instance();
const FontInfo fontInfoDefSize(m_fontInfo,
@ -312,75 +312,17 @@ FontPopup::FontPopup(const FontInfo& fontInfo)
}
// Create one FontItem for each font
m_listBox.addChild(new SeparatorInView(Strings::font_popup_system_fonts()));
bool empty = true;
m_systemFontsSeparator = new SeparatorInView(Strings::font_popup_system_fonts());
m_listBox.addChild(m_systemFontsSeparator);
// Get system fonts from laf-text module
const text::FontMgrRef fontMgr = fonts->fontMgr();
const int n = fontMgr->countFamilies();
if (n > 0) {
for (int i = 0; i < n; ++i) {
std::string name = fontMgr->familyName(i);
text::FontStyleSetRef set = fontMgr->familyStyleSet(i);
if (set && set->count() > 0) {
// Match the typeface with the default FontStyle (Normal
// weight, Upright slant, etc.)
auto typeface = set->matchStyle(text::FontStyle());
if (typeface) {
auto* item = new FontItem(name, typeface->fontStyle(), set);
item->ThumbnailGenerated.connect([this] { onThumbnailGenerated(); });
m_listBox.addChild(item);
empty = false;
}
}
}
}
// Get fonts listing .ttf files TODO we should be able to remove
// this code in the future (probably after DirectWrite API is always
// available).
else {
base::paths fontDirs;
get_font_dirs(fontDirs);
// Create a list of fullpaths to every font found in all font
// directories (fontDirs)
base::paths files;
for (const auto& fontDir : fontDirs) {
for (const auto& file : base::list_files(fontDir, base::ItemType::Files)) {
files.push_back(base::join_path(fontDir, file));
}
}
// Sort all files by "file title"
std::sort(files.begin(), files.end(), [](const std::string& a, const std::string& b) {
return base::utf8_icmp(base::get_file_title(a), base::get_file_title(b)) < 0;
});
for (auto& file : files) {
std::string ext = base::string_to_lower(base::get_file_extension(file));
if (ext == "ttf" || ext == "ttc" || ext == "otf" || ext == "dfont") {
m_listBox.addChild(new FontItem(file));
empty = false;
}
}
}
if (empty)
m_listBox.addChild(new ListItem(Strings::font_popup_empty_fonts()));
for (auto* child : m_listBox.children()) {
if (auto* childItem = dynamic_cast<FontItem*>(child)) {
if (childItem->fontInfo().title() == childItem->text()) {
m_listBox.selectChild(childItem);
break;
}
}
}
m_listFontsTask.run([this](base::task_token& token) { listSystemFonts(token); });
}
FontPopup::~FontPopup()
{
m_timer.stop();
m_listFontsTask.cancel();
m_listFontsTask.wait();
}
void FontPopup::setSearchText(const std::string& searchText)
@ -486,7 +428,8 @@ void FontPopup::onThumbnailGenerated()
void FontPopup::onTickRelayout()
{
m_popup->view()->updateView();
m_timer.stop();
if (!m_listFontsTask.running())
m_timer.stop();
}
bool FontPopup::onProcessMessage(ui::Message* msg)
@ -507,4 +450,105 @@ bool FontPopup::onProcessMessage(ui::Message* msg)
return ui::PopupWindow::onProcessMessage(msg);
}
void FontPopup::listSystemFonts(base::task_token& token)
{
Fonts* fonts = Fonts::instance();
bool empty = true;
// Get system fonts from laf-text module
const text::FontMgrRef fontMgr = fonts->fontMgr();
const int n = fontMgr->countFamilies();
if (n > 0) {
for (int i = 0; i < n; ++i) {
std::string name = fontMgr->familyName(i);
text::FontStyleSetRef set = fontMgr->familyStyleSet(i);
if (set && set->count() > 0) {
// Match the typeface with the default FontStyle (Normal
// weight, Upright slant, etc.)
auto typeface = set->matchStyle(text::FontStyle());
if (typeface) {
ui::execute_from_ui_thread([=, &token] {
if (token.canceled())
return;
auto* item = new FontItem(name, typeface->fontStyle(), set);
item->ThumbnailGenerated.connect([this] { onThumbnailGenerated(); });
int j = m_listBox.getChildIndex(m_systemFontsSeparator) + 1;
for (; j < m_listBox.getItemsCount(); ++j) {
if (name < m_listBox.at(j)->text())
break;
}
m_listBox.insertChild(j, item);
layout();
});
empty = false;
}
}
if (token.canceled())
goto done;
}
}
// Get fonts listing .ttf files TODO we should be able to remove
// this code in the future (probably after DirectWrite API is always
// available).
else {
base::paths fontDirs;
get_font_dirs(fontDirs);
// Create a list of fullpaths to every font found in all font
// directories (fontDirs)
base::paths files;
for (const auto& fontDir : fontDirs) {
for (const auto& file : base::list_files(fontDir, base::ItemType::Files)) {
files.push_back(base::join_path(fontDir, file));
if (token.canceled())
goto done;
}
}
// Sort all files by "file title"
std::sort(files.begin(), files.end(), [](const std::string& a, const std::string& b) {
return base::utf8_icmp(base::get_file_title(a), base::get_file_title(b)) < 0;
});
for (auto& file : files) {
std::string ext = base::string_to_lower(base::get_file_extension(file));
if (ext == "ttf" || ext == "ttc" || ext == "otf" || ext == "dfont") {
ui::execute_from_ui_thread([this, file, &token] {
if (token.canceled())
return;
m_listBox.addChild(new FontItem(file));
});
empty = false;
}
}
}
done:;
if (token.canceled())
return;
if (empty) {
ui::execute_from_ui_thread([this, &token] {
if (token.canceled())
return;
m_listBox.addChild(new ListItem(Strings::font_popup_empty_fonts()));
layout();
});
}
ui::execute_from_ui_thread([this, &token] {
if (token.canceled())
return;
// Stop the view relayout
onTickRelayout();
m_timer.stop();
});
}
} // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2021-2024 Igara Studio S.A.
// Copyright (C) 2021-2025 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -9,6 +9,7 @@
#define APP_UI_FONT_POPUP_H_INCLUDED
#pragma once
#include "app/task.h"
#include "ui/listbox.h"
#include "ui/popup_window.h"
#include "ui/timer.h"
@ -57,10 +58,14 @@ protected:
bool onProcessMessage(ui::Message* msg) override;
private:
void listSystemFonts(base::task_token& token);
gen::FontPopup* m_popup;
Widget* m_systemFontsSeparator;
FontListBox m_listBox;
ui::Timer m_timer;
ui::Widget* m_pinnedSeparator = nullptr;
app::Task m_listFontsTask;
};
} // namespace app