diff --git a/patch_v2/reader_app/engine/rdft.c b/patch_v2/reader_app/engine/rdft.c index 73b1a3f..7b4ad54 100644 --- a/patch_v2/reader_app/engine/rdft.c +++ b/patch_v2/reader_app/engine/rdft.c @@ -15,6 +15,13 @@ typedef struct { int bw, bh, pitch, left, top; } glyph_slot; +/* advance 测量缓存:rdft_advance 逐字测量是排版索引用热路径(大书每次开/重排全量逐字测), + * 同一码点在全书反复出现(中文常用字 ~几千)。独立的小型开放寻址表缓存 (px,cp)→advance, + * 避免对重复码点反复 FT_Load_Glyph,把测量成本从 O(全书字符) 摊到 O(唯一码点)。 + * 与 glyph_slot 缓存分离:glyph 缓存存「已光栅化位图」,此处只存 advance(不栅格化、不占位图)。 */ +#define RD_ADV_SLOTS 4096 /* 幂 2;开放寻址线性探测 */ +typedef struct { uint64_t key; int adv; } adv_slot; + struct rdft { FT_Library lib; FT_Face face; @@ -23,6 +30,7 @@ struct rdft { int nslots; /* 容量 */ int used; /* 在线条目数 */ uint64_t clock; /* 单调戳 */ + adv_slot *adv; /* advance 缓存(排版测量) */ int has_font; }; @@ -36,6 +44,8 @@ int rdft_init(rdft **r) x->nslots = 512; x->slots = (glyph_slot *)calloc((size_t)x->nslots, sizeof(glyph_slot)); if (!x->slots) { FT_Done_FreeType(x->lib); free(x); return -6; } + x->adv = (adv_slot *)calloc(RD_ADV_SLOTS, sizeof(adv_slot)); + if (!x->adv) { free(x->slots); FT_Done_FreeType(x->lib); free(x); return -6; } x->used = 0; x->clock = 1; *r = x; @@ -48,6 +58,7 @@ int rdft_load_font(rdft *r, const char *path) if (r->face) { FT_Done_Face(r->face); r->face = NULL; } if (r->slots) { for (int i = 0; i < r->nslots; i++) free(r->slots[i].bmp); } if (r->slots) memset(r->slots, 0, (size_t)r->nslots * sizeof(glyph_slot)); + if (r->adv) memset(r->adv, 0, (size_t)RD_ADV_SLOTS * sizeof(adv_slot)); r->used = 0; if (FT_New_Face(r->lib, path, 0, &r->face) != 0) { r->has_font = 0; return -1; } r->has_font = 1; @@ -61,8 +72,9 @@ void rdft_set_px(rdft *r, int px) if (px <= 0) px = r->px; r->px = px; if (r->face) FT_Set_Pixel_Sizes(r->face, 0, (FT_UInt)px); - /* key 含字号,清缓存防旧字号位图残留 */ + /* key 含字号,清缓存防旧字号位图残留(glyph + advance 同清,key 同含 px) */ if (r->slots) { for (int i = 0; i < r->nslots; i++) free(r->slots[i].bmp); memset(r->slots, 0, (size_t)r->nslots * sizeof(glyph_slot)); } + if (r->adv) memset(r->adv, 0, (size_t)RD_ADV_SLOTS * sizeof(adv_slot)); r->used = 0; } @@ -147,18 +159,53 @@ int rdft_glyph(rdft *r, uint32_t cp, int *adv_x, return 0; } +/* (px,cp)→advance 缓存:开放寻址线性探测;key==0 为空槽哨兵(key=(px<<32)|cp,px≥1 恒非 0)。 */ +static uint32_t adv_hash(uint64_t key) +{ + /* 乘法散列取高位,把 64 位 key(px 在高位、cp 在低位)散布到 12 位表。 */ + return (uint32_t)((key * 2654435761ULL) >> 22) & (RD_ADV_SLOTS - 1); +} +static int adv_find(const rdft *r, uint64_t key, int *adv) +{ + uint32_t h = adv_hash(key); + for (uint32_t i = 0; i < RD_ADV_SLOTS; i++) { + uint32_t idx = (h + i) & (RD_ADV_SLOTS - 1); + uint64_t k = r->adv[idx].key; + if (k == 0) return 0; + if (k == key) { *adv = r->adv[idx].adv; return 1; } + } + return 0; +} +static void adv_put(rdft *r, uint64_t key, int adv) +{ + uint32_t h = adv_hash(key); + for (uint32_t i = 0; i < RD_ADV_SLOTS; i++) { + uint32_t idx = (h + i) & (RD_ADV_SLOTS - 1); + if (r->adv[idx].key == 0 || r->adv[idx].key == key) { + r->adv[idx].key = key; r->adv[idx].adv = adv; return; + } + } + /* 表满:丢弃(下次未命中直接算) */ +} + int rdft_advance(rdft *r, uint32_t cp, int *adv_x) { if (!r || !r->face || !adv_x) return -1; + uint64_t key = ((uint64_t)(uint32_t)r->px << 32) | cp; + if (adv_find(r, key, adv_x)) return 0; FT_UInt gi = FT_Get_Char_Index(r->face, cp); if (r->px <= 0) FT_Set_Pixel_Sizes(r->face, 0, (FT_UInt)r->px); if (FT_Load_Glyph(r->face, gi, FT_LOAD_NO_HINTING | FT_LOAD_TARGET_LIGHT) != 0) { - *adv_x = r->face->glyph->advance.x >> 6; + int a = r->face->glyph->advance.x >> 6; + *adv_x = a; + adv_put(r, key, a); return 0; } int a = (int)((r->face->glyph->advance.x >= 0 ? r->face->glyph->advance.x + 0x20 : r->face->glyph->advance.x - 0x20) >> 6); - *adv_x = a < 0 ? 0 : a; + a = a < 0 ? 0 : a; + *adv_x = a; + adv_put(r, key, a); return 0; } @@ -209,6 +256,7 @@ void rdft_free(rdft *r) if (!r) return; if (r->slots) { for (int i = 0; i < r->nslots; i++) free(r->slots[i].bmp); } free(r->slots); + free(r->adv); if (r->face) FT_Done_Face(r->face); if (r->lib) FT_Done_FreeType(r->lib); free(r);