- core: 编码检测(BOM→UTF-8严格→GB18030/Big5统计, Big5与GB重叠按GB18030兜底, §3.5风险注明) + GB18030双字节码表(uint16[126][190]=47880B, tools/gen_gb18030_table.py 生成, 生成物入仓) + 流式排版器(贪心断行+Kinsoku避头尾+分页+重排锚定, rd_meas_fn 测量回调替 FreeType, 宿主可测) + TXT 流式加载器(按段读, 不整文件入内存, \n 恒独立换行可安全分段) - engine: FreeType 封装(FT_New_Face 按需读文件, NO_HINTING/LIGHT 灰阶, LRU 512 key=码点+字号, blend565, rdft_advance 只测宽不栅格化) - app: 书架(扫 Books/ 识别 5 后缀, 最近读置顶, 空态提示) + 阅读页(W_CUSTOM 画布 3 栏翻页 +中央菜单占位(字号±/行距±/返回) +顶栏进度%/章节名) + 书桥(段表+flat 页索引, 渲染, 重排回锚) + 进度持久化(MeowData/os.meow.reader/progress/, path hash→seg/ch/fs/ls/ts) - 取舍: 正文字体 FreeType 直读 TF MeowOS/fonts/ TTF/OTF; 无字体回退 SDK 位图字库(meow_ui_text, 未打包字体(许可/体积), 全 glyph 兜底 R2); 页位图缓存当前+前后各1页(3×691KB), 翻页动画默认无 - 内存实测(宿主 --wrap malloc, 73页书): 书结构 130KB + 当前段刮擦~1.6MB(行/页容量按 n 偏高,R2 收紧) + 字形缓存~650KB + 3页位图 2.07MB ≈ 4.45MB 动态, 在 ≤8MB 阅读态预算内 - 测试: 宿主 core 58/58(enc/gb18030金标准/kinsoku/page/reflow/txt); qemu-mipsel ft_smoke PASS + book_smoke(12页/渲染有墨/翻页/重排回锚) PASS; reader 交叉 -Wall -Wextra 0 warning - 产物: reader(mipsel 静态1.2MB)+build_reader.sh(vendor FreeType 可复现); vendor/二进制 gitignore
65 lines
3.2 KiB
C
65 lines
3.2 KiB
C
/* app/book.h — 书桥:把 core(TXT/排版) + engine(FreeType) 串成「一本 TXT 书」。
|
||
*
|
||
* 打开一本书:探测编码 → 逐段 rdtxt 流式读 → 每段 utf8→码点 → rd_layout(测量=rdft_advance)
|
||
* → 页索引(flat:每页=段+段内字符偏移)+ 段表(file_off/file_len/page_start/page_count)。
|
||
* 渲染页:定位段 → 重读该段 → 重排 → 取该页行 → 逐字 rdft_glyph → blend565 到全屏缓冲。
|
||
* 锚定/进度:(段,字符偏移),与字号无关;改字号/行距触发后台重排并回锚(§6.3)。
|
||
*
|
||
* 内存纪律:单段(文本+cps+布局)≈ 320KB 冲击,随段释放;页索引 flat ~每页 12B;3 页位图由
|
||
* 阅读 view 持有(本模块只填一个渲染目标缓冲,不缓存整页)。
|
||
*/
|
||
#ifndef RDBOOK_H
|
||
#define RDBOOK_H
|
||
|
||
#include "rdenc.h"
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
typedef struct rd_book rd_book;
|
||
|
||
typedef struct rd_book_page {
|
||
int32_t seg; /* 段下标 */
|
||
int32_t seg_char; /* 段内字符偏移(页首) */
|
||
} rd_book_page;
|
||
|
||
/* 打开书:path=TXT;font_path=FreeType 字体;geom=版面(fs 字号 / ls 行距% / pw,ph 全屏 /
|
||
* mx,my 左右/上下边距 / top 顶部 inset(状态栏+顶条))。0=成功。 */
|
||
int rd_book_open(rd_book **b, const char *path, const char *font_path,
|
||
int fs, int ls, int pw, int ph, int mx, int my, int top);
|
||
void rd_book_close(rd_book *b);
|
||
|
||
int rd_book_pages(rd_book *b);
|
||
int rd_book_current(rd_book *b); /* 当前页 */
|
||
int rd_book_turn(rd_book *b, int delta); /* +1/-1;clamp 到 [0,npages-1] */
|
||
void rd_book_anchor(rd_book *b, int *seg, int32_t *ch);/* 当前页锚(段,字符偏移) */
|
||
int rd_book_jump_to_anchor(rd_book *b, int seg, int32_t ch, int fs, int ls); /* 重排 + 回锚 */
|
||
int rd_book_set_size(rd_book *b, int fs, int ls); /* 重排 + 回锚(anchor=当前页) */
|
||
|
||
/* 渲染页到全屏缓冲:out 为 pw*ph RGB565(每行 pitch 字节);先填 bg565 再画正文。
|
||
* 0=成功;1=该页为空(无正文,如末页空白)。 */
|
||
int rd_book_render(rd_book *b, int page_no, uint16_t *out, int pitch, uint16_t bg565, uint16_t fg565);
|
||
|
||
/* SDK 字库兜底:逐行回调(每行一个 utf8 文本串,屏幕坐标 x,y 已含 inset/边距)。
|
||
* 用于「无 TTF/OTF → 用 meow_ui_text 位图字库渲染正文」的降级路径(见 reader 视图取舍)。 */
|
||
typedef void (*rd_book_line_fn)(int x, int y, const char *utf8, int len, void *ctx);
|
||
int rd_book_render_text(rd_book *b, int page_no, rd_book_line_fn fn, void *ctx);
|
||
|
||
/* 书名/信息(章节名:TXT 无章节=文件名;enc 可读名)。调用方 strcpy 到自己的缓冲。 */
|
||
const char *rd_book_basename(const rd_book *b); /* 文件名(路径尾分量) */
|
||
const char *rd_book_encname(const rd_book *b);
|
||
const char *rd_book_path(const rd_book *b); /* 原始路径 */
|
||
|
||
/* 字体/几何 */
|
||
int rd_book_font(rd_book *b); /* 当前字号 */
|
||
int rd_book_ls(rd_book *b); /* 行距% */
|
||
void rd_book_geom(rd_book *b, int *fs, int *ls, int *pw, int *ph, int *mx, int *my, int *top);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif /* RDBOOK_H */
|