修复文本缓存失效

This commit is contained in:
Nanako 2025-04-04 23:48:47 +08:00
parent e9909e1c77
commit 0ac8367b43
10 changed files with 162 additions and 128 deletions

View File

@ -2,24 +2,17 @@
#include "interface/image_interface.h"
glyph_atlas_result_t bitmap_glyph_atlas::get_or_create_glyph(int32_t in_glyph_index,
const std::shared_ptr<font_face_interface>& in_font, float in_font_size) {
glyph_atlas_result_t bitmap_glyph_atlas::create_glyph(const char_key_t& in_key) {
const auto& glyph_index = in_key.glyph_index;
const auto& font = in_key.font_face;
const auto& font_size = in_key.font_size;
glyph_atlas_result_t result{};
// 创建缓存键
const auto& cache_key = create_cache_key(in_glyph_index, in_font->get_font_family(), in_font_size);
// 检查缓存,如果已存在则直接返回
auto cached_result = find_in_cache(cache_key);
if (cached_result.reason == glyph_atlas_reason_t::success) {
return cached_result;
}
in_font->set_font_size(in_font_size);
font->set_font_size(font_size);
// 获取字形的位图数据
auto bitmap = in_font->get_glyph_image(in_glyph_index);
auto bitmap = font->get_glyph_image(glyph_index);
if (!bitmap) {
result.reason = glyph_atlas_reason_t::glyph_not_found;
return result;
@ -36,7 +29,7 @@ glyph_atlas_result_t bitmap_glyph_atlas::get_or_create_glyph(int32_t in_glyph_in
atlas_->update_region(bitmap->data, bitmap->get_data_size(), region->rect);
// 缓存结果以便未来复用
add_to_cache(cache_key, *region);
add_to_cache(in_key, *region);
result.reason = glyph_atlas_reason_t::success;
result.region = *region;

View File

@ -26,13 +26,8 @@ public:
*
*
*
* @param in_glyph_index Unicode码点或字体特定索引
* @param in_font
* @param in_font_size
* @param in_key
* @return /
*/
glyph_atlas_result_t get_or_create_glyph(
int32_t in_glyph_index,
const std::shared_ptr<font_face_interface>& in_font,
float in_font_size);
glyph_atlas_result_t create_glyph(const char_key_t& in_key) override;
};

View File

@ -2,24 +2,19 @@
#include "interface/image_interface.h"
glyph_atlas_result_t color_emoji_atlas::get_or_create_emoji(int32_t in_glyph_index,
const std::shared_ptr<font_face_interface>& in_font, float in_font_size) {
glyph_atlas_result_t color_emoji_atlas::create_glyph(const char_key_t& in_key) {
const auto& glyph_index = in_key.glyph_index;
const auto& font = in_key.font_face;
const auto& font_size = in_key.font_size;
glyph_atlas_result_t result{};
if (!font->supports_color_emoji())
return result;
// 创建缓存键
const auto& cache_key = create_cache_key(in_glyph_index, in_font->get_font_family(), in_font_size);
// 检查缓存
auto cached_result = find_in_cache(cache_key);
if (cached_result.reason == glyph_atlas_reason_t::success) {
return cached_result;
}
in_font->set_font_size(in_font_size);
font->set_font_size(font_size);
// 获取彩色表情位图
auto bitmap = in_font->get_emoji_image(in_glyph_index);
auto bitmap = font->get_emoji_image(glyph_index);
if (!bitmap) {
result.reason = glyph_atlas_reason_t::glyph_not_found;
return result;
@ -36,7 +31,7 @@ glyph_atlas_result_t color_emoji_atlas::get_or_create_emoji(int32_t in_glyph_ind
atlas_->update_region(bitmap->data, bitmap->get_data_size(), region->rect);
// 缓存结果以便未来复用
add_to_cache(cache_key, *region);
add_to_cache(in_key, *region);
result.reason = glyph_atlas_reason_t::success;
result.region = *region;

View File

@ -22,17 +22,12 @@ public:
}
/**
* @brief
* @brief
*
*
*
*
* @param in_glyph_index
* @param in_font
* @param in_font_size
* @param in_key
* @return /
*/
glyph_atlas_result_t get_or_create_emoji(
int32_t in_glyph_index,
const std::shared_ptr<font_face_interface>& in_font,
float in_font_size);
glyph_atlas_result_t create_glyph(const char_key_t& in_key) override;
};

View File

@ -0,0 +1,9 @@
#include "font_atlas.h"
#include "interface/font_interface.h"
char_key_t::char_key_t(uint32_t in_glyph_index, const std::shared_ptr<font_face_interface>& in_font_face,
float in_font_size):
glyph_index(in_glyph_index),
font_face(in_font_face),
font_size(in_font_size) {}

View File

@ -1,14 +1,10 @@
#pragma once
#include <Eigen/Eigen>
#include <memory>
#include <string>
#include <sstream>
#include <iomanip>
#include <unordered_map>
#include "texture/atlas/texture2d_atlas.h"
class font_face_interface;
/**
* @enum glyph_atlas_reason_t
* @brief
@ -33,6 +29,34 @@ struct glyph_atlas_result_t {
atlas_region_t region; ///< 分配的区域信息(仅当操作成功时有效)
};
struct char_key_t {
uint32_t glyph_index;
std::shared_ptr<font_face_interface> font_face;
float font_size;
char_key_t(uint32_t in_glyph_index, const std::shared_ptr<font_face_interface>& in_font_face, float in_font_size);
bool operator==(const char_key_t& other) const {
// Implement comparison logic. Might involve comparing font pointers
// or font identifiers, glyph_id, and font_size.
// Be careful comparing floats directly.
return glyph_index == other.glyph_index &&
font_face == other.font_face && // Simple pointer comparison, might need deeper check
std::abs(font_size - other.font_size) < 1e-6; // Epsilon comparison for float
}
};
template<>
struct std::hash<char_key_t> {
size_t operator()(const char_key_t& in_key) const {
std::hash<uint32_t> hash_fn;
size_t hash = hash_fn(in_key.glyph_index);
hash ^= (uint64_t)in_key.font_face.get();
hash ^= std::hash<float>{}(in_key.font_size);
return hash;
}
};
/**
* @class atlas_base
* @brief
@ -43,22 +67,7 @@ struct glyph_atlas_result_t {
class atlas_base {
protected:
std::shared_ptr<texture2d_atlas> atlas_; ///< 底层纹理图集对象
std::unordered_map<std::string, atlas_region_t> cached_regions_; ///< 已缓存的区域映射表
/**
* @brief
*
* @param in_glyph_index Unicode码点或字体特定索引
* @param in_font_name
* @param in_font_size
* @return
*/
static std::string create_cache_key(uint32_t in_glyph_index, const std::string& in_font_name, float in_font_size) {
std::stringstream ss;
ss << std::hex << in_glyph_index << "_" << in_font_name << "_" << std::fixed
<< std::setprecision(1) << in_font_size;
return ss.str();
}
std::unordered_map<char_key_t, atlas_region_t> cached_regions_; ///< 已缓存的区域映射表
/**
* @brief
@ -77,31 +86,13 @@ protected:
return atlas_ != nullptr;
}
/**
* @brief
*
* @param in_cache_key
* @return /
*/
glyph_atlas_result_t find_in_cache(const std::string& in_cache_key) {
glyph_atlas_result_t result{};
auto it = cached_regions_.find(in_cache_key);
if (it != cached_regions_.end()) {
result.reason = glyph_atlas_reason_t::success;
result.region = it->second;
}
return result;
}
/**
* @brief
*
* @param in_cache_key
* @param in_region
*/
void add_to_cache(const std::string& in_cache_key, const atlas_region_t& in_region) {
void add_to_cache(const char_key_t& in_cache_key, const atlas_region_t& in_region) {
cached_regions_[in_cache_key] = in_region;
}
@ -145,4 +136,32 @@ public:
void clear_cache() {
cached_regions_.clear();
}
/**
* @brief
*
* @param in_cache_key
* @return /
*/
glyph_atlas_result_t find_in_cache(const char_key_t& in_cache_key) {
glyph_atlas_result_t result{};
auto it = cached_regions_.find(in_cache_key);
if (it != cached_regions_.end()) {
result.reason = glyph_atlas_reason_t::success;
result.region = it->second;
}
return result;
}
/**
* @brief
*
*
*
* @param in_key
* @return /
*/
virtual glyph_atlas_result_t create_glyph(const char_key_t& in_key) = 0;
};

View File

@ -1,54 +1,91 @@
#include "font_atlas_manager.h"
std::optional<atlas_region_t> font_atlas_manager::get_or_create_glyph(
int32_t in_glyph_id,
const std::shared_ptr<font_face_interface>& in_font,
float in_font_size,
bool is_emoji)
{
int32_t in_glyph_id,
const std::shared_ptr<font_face_interface>& in_font,
float in_font_size,
bool is_emoji) {
glyph_atlas_result_t result{};
result.reason = glyph_atlas_reason_t::atlas_full;
// 初始化原因,循环/创建尝试会更新它
result.reason = glyph_atlas_reason_t::unknown; // 默认为失败
char_key_t key(in_glyph_id, in_font, in_font_size);
// **处理表情符号**
if (is_emoji) {
// 尝试从现有表情图集中获取
// **1. 尝试在现有表情符号图集中查找**
for (auto& atlas : emoji_atlases_) {
result = atlas.get_or_create_emoji(in_glyph_id, in_font, in_font_size);
if (result.reason == glyph_atlas_reason_t::success) {
return result.region;
glyph_atlas_result_t find_result = atlas.find_in_cache(key);
if (find_result.reason == glyph_atlas_reason_t::success) {
return find_result.region; // 找到了!
}
}
// 如果所有现有图集都已满,创建新的表情图集
// **2. 尝试在当前表情符号图集中创建**
if (!emoji_atlases_.empty() && current_emoji_atlas_ < emoji_atlases_.size()) {
result = emoji_atlases_[current_emoji_atlas_].create_glyph(key);
if (result.reason == glyph_atlas_reason_t::success) {
return result.region;
}
} else {
result.reason = glyph_atlas_reason_t::atlas_full; // 模拟已满以触发创建
}
// **3. 如果当前表情符号图集已满(或不存在),创建一个新图集**
if (result.reason == glyph_atlas_reason_t::atlas_full) {
auto& atlas = create_new_emoji_atlas();
result = atlas.get_or_create_emoji(in_glyph_id, in_font, in_font_size);
const Eigen::Vector2i new_atlas_size = { 2048, 2048 }; // 示例大小
// 创建新的表情符号图集
create_new_emoji_atlas(new_atlas_size);
// 更新当前表情符号图集索引为新创建的图集
current_emoji_atlas_ = emoji_atlases_.size() - 1;
// 尝试在新图集中创建字形
result = emoji_atlases_[current_emoji_atlas_].create_glyph(key);
if (result.reason == glyph_atlas_reason_t::success) {
return result.region;
}
}
}
// **处理普通字形**
else {
// 尝试从现有字形图集中获取
} else { // 普通字形(非表情符号)
// **1. 尝试在现有字形图集中查找**
for (auto& atlas : glyph_atlases_) {
result = atlas.get_or_create_glyph(in_glyph_id, in_font, in_font_size);
if (result.reason == glyph_atlas_reason_t::success) {
return result.region;
glyph_atlas_result_t find_result = atlas.find_in_cache(key);
if (find_result.reason == glyph_atlas_reason_t::success) {
return find_result.region; // 找到了!
}
}
// 如果所有现有图集都已满,创建新的字形图集
// **2. 尝试在当前字形图集中创建**
if (!glyph_atlases_.empty() && current_glyph_atlas_ < glyph_atlases_.size()) {
result = glyph_atlases_[current_glyph_atlas_].create_glyph(key);
if (result.reason == glyph_atlas_reason_t::success) {
return result.region;
}
} else {
result.reason = glyph_atlas_reason_t::atlas_full; // 模拟已满以触发创建
}
// **3. 如果当前字形图集已满(或不存在),创建一个新图集**
if (result.reason == glyph_atlas_reason_t::atlas_full) {
auto& atlas = create_new_glyph_atlas();
result = atlas.get_or_create_glyph(in_glyph_id, in_font, in_font_size);
const Eigen::Vector2i new_atlas_size = { 2048, 2048}; // 示例大小
// 创建新的字形图集
create_new_glyph_atlas(new_atlas_size);
// 更新当前字形图集索引为新创建的图集
current_glyph_atlas_ = glyph_atlases_.size() - 1;
// 尝试在新图集中创建字形
result = glyph_atlases_[current_glyph_atlas_].create_glyph(key);
if (result.reason == glyph_atlas_reason_t::success) {
return result.region;
}
}
}
// 如果所有尝试都失败,返回空
// **4. 如果所有尝试都失败返回nullopt**
return std::nullopt;
}

View File

@ -59,8 +59,10 @@ public:
}
private:
std::vector<bitmap_glyph_atlas> glyph_atlases_; ///< 普通字形图集列表
std::vector<color_emoji_atlas> emoji_atlases_; ///< 表情符号图集列表
std::vector<bitmap_glyph_atlas> glyph_atlases_; ///< 普通字形图集列表
std::vector<color_emoji_atlas> emoji_atlases_; ///< 表情符号图集列表
int32_t current_glyph_atlas_ = 0; ///< 当前字形图集索引
int32_t current_emoji_atlas_ = 0; ///< 当前表情图集索引
/**
* @brief

View File

@ -40,6 +40,7 @@ public:
[[nodiscard]] virtual std::string get_font_family() const = 0;
[[nodiscard]] virtual std::string get_font_style() const = 0;
[[nodiscard]] uint64_t get_key() const { return reinterpret_cast<uint64_t>(this); }
[[nodiscard]] virtual bool supports_color_emoji() const = 0;

View File

@ -6,7 +6,7 @@
#include "widget/panel_widget/mbox.h"
mbutton::mbutton() {
color_ = {0.1, 0.1, 0.1, 1};
color_ = {0.2, 0.2, 0.2, 1};
slot_.h_alignment(horizontal_alignment_t::center);
slot_.v_alignment(vertical_alignment_t::center);
}
@ -30,32 +30,20 @@ void mbutton::on_paint(mirage_paint_context& in_context) {
void mbutton::on_click(const Eigen::Vector2f& in_position, mouse_button in_button) {
mborder::on_click(in_position, in_button);
std::cout << this << ": Button clicked!" << in_position.x() << ", " << in_position.y() << std::endl;
color_ = {0, 0, 1, 1};
// const auto& parent = get_parent();
// if (std::shared_ptr<mh_box> hbox = std::dynamic_pointer_cast<mh_box>(parent)) {
// hbox->add_child<mbutton>()
// .stretch()
// .margin({ 5 });
// }
// if (std::shared_ptr<mv_box> vbox = std::dynamic_pointer_cast<mv_box>(parent)) {
// vbox->add_child<mbutton>()
// .stretch()
// .margin({ 5 });
// }
color_ = {0.2, 0.2, 0.2, 1};
invalidate(invalidate_reason::paint);
}
void mbutton::on_double_click(const Eigen::Vector2f& in_position, mouse_button in_button) {
mborder::on_double_click(in_position, in_button);
std::cout << this << ": Button double clicked!" << in_position.x() << ", " << in_position.y() << std::endl;
color_ = {1, 1, 1, 1};
invalidate(invalidate_reason::paint);
}
void mbutton::on_mouse_enter() {
mborder::on_mouse_enter();
std::cout << this << ": Mouse entered!" << std::endl;
color_ = {0, 1, 0, 1};
color_ = {0.2, 0.2, 0.2, 1};
invalidate(invalidate_reason::paint);
}
@ -69,7 +57,7 @@ void mbutton::on_mouse_leave() {
hit_test_handle mbutton::on_mouse_button_down(const Eigen::Vector2f& in_position, mouse_button in_button) {
mborder::on_mouse_button_down(in_position, in_button);
std::cout << this << ": Mouse pressed!" << in_position.x() << ", " << in_position.y() << std::endl;
color_ = {0, 0, 1, 1};
color_ = {0.1, 0.1, 0.1, 1};
invalidate(invalidate_reason::paint);
return hit_test_handle::handled();
}
@ -77,7 +65,7 @@ hit_test_handle mbutton::on_mouse_button_down(const Eigen::Vector2f& in_position
hit_test_handle mbutton::on_mouse_button_up(const Eigen::Vector2f& in_position, mouse_button in_button) {
mborder::on_mouse_button_up(in_position, in_button);
std::cout << this << ": Mouse released!" << in_position.x() << ", " << in_position.y() << std::endl;
color_ = {1, 0, 0, 1};
color_ = {0.2, 0.2, 0.2, 1};
invalidate(invalidate_reason::paint);
return hit_test_handle::handled();
}