Files
MeowOS-For-R3P2/patch_v2/reader_app/app/book.h
T
AskaEth 7c7d891570 feat: M6.44+M6.45 收编 — 真机 0.8.45 现场保全(reader章节/key_router按键路由/WiFi连接修复/ncm bench+IME修复)
脏工作区现场收编:devdocs/local/m6_44_45_dirty_tracked.patch(46 个已跟踪文本文件,
+3090/-585, 已对 M6.43 基线干净适配) + m6_44_45_untracked_src.tar.gz 中 patch_v2/ 下
13 个新增源文件, 合成单个提交, 内容与容器工作树(R3ProII/patch_v2)逐字节一致。

- reader 章节: 新增 core/rdchapter.{h,c} — TXT 章节规范解析器, 扫描 512KB 码位对齐段文件
  逐段流式识别标题行(行首缩进≤4/显示宽≤40/行内标点≤1 三重约束防误判), 输出标题+全书字符
  偏移+段号/段内偏移+阿拉伯章号(中文数字归一), 首章前内容归"卷首"; book/reader/rdenc/
  rdlayout/settings 接入章节跳转与进度锚点, 附 chapter_smoke/turn_repro/build_turn_repro.sh
- key_router 按键路由: 新增 meow_launcherd/key_router.{h,c} — launcher-UI 页物理键统一路由
  (P1 仅音量键), 把读取边沿+防抖+长按 held+ramp 推进从 5 个会话收敛为进程内单开;
  各页每圈 key_router_pump() 取防抖后边沿, 动作(调音量/光标导航)仍由调用页决定,
  保留 run_menu 的 meow_mode 分支; App 前台 volume_page 武装时边沿抑制;
  main_menu/now_playing/notif_center/settings_page/subpage 接入, 附 test_key_router_vol/test_np_keys
- WiFi 连接修复: meow_netmgrd connect 有界等待 wpa_state=COMPLETED(普通 10s/隐藏网络 15s,
  env 可调)修设置页连接无响应; list_networks/scan_results 的 \xNN 转义还原始字节, 修中文 SSID
  永不命中致新建同名 open 记录顶影; launcher netmgr_ipc 配读超时; 附 test_wifi_connect(桩
  wpa_cli 驱动 static wifi_connect_ex), test_netmgrd.sh 补用例; wifi_page 同步
- ncm bench: 新增 bench/lyric_sim.c、bench/plpage_sim.c, vol_sync_sim 与 ncm core/app 同步
- SDK IME 修复: shift 大小写、K_ENTER 只提交不关、阻塞 IME 循环喂 on_tick 不被遮挡、
  IME 打开 ~200ms TAP 冷却窗吞 stray-TAP; 附 sdk/test_ime_fix.c
- 同期: meow_audiod 音量异步 ACK 线程(代际防 fd/槽复用竞态)、watchdog 音量收编(首选 audiod
  权威, settings.conf 覆盖路径)、panel 文件搜索(F1-④)与蓝牙只读详情(F1-③)、各类 build 脚本同步

范围红线: third_party/legado-E-main 原开发者未跟踪, 本次不入库(保留 devdocs/local tar 参考);
二进制不入库(后续重编); devdocs/ 不入库。59 文件全部在 patch_v2/ 下, 无 third_party/devdocs。
验证: git apply --check 干净; 59 文件 md5 与容器 patch_v2 逐一比对 59/59 一致(含
key_router.c/rdchapter.c/meow_ui_ime.c/test_wifi_connect.c 抽查); 可执行位保守
(check_lgpl_release.sh 100755, build_turn_repro.sh 100644 与容器一致)。
2026-11-04 20:02:28 +08:00

106 lines
6.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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; /* 段内字符偏移(页首) */
uint8_t flags; /* bit0 = 首页行是否段首行(缩进/段距判定;Phase 2A/2C) */
} 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] */
int rd_book_set_page(rd_book *b, int page); /* 跳到绝对页;clamp;返回实际页(段刮擦用) */
int rd_book_prefetch(rd_book *b); /* 空闲预取下一段(reader_on_tick 调);0=已备/无需 */
int rd_book_is_image(rd_book *b); /* 1=CBZ 图片页书 */
/* 目录:0=无;i 项标题写到 title,目标段/字符偏移填 *seg 与 *ch。 */
int rd_book_toc_n(const rd_book *b);
int rd_book_toc(const rd_book *b, int i, char *title, int tsz, int *seg, int32_t *ch);
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);
rd_enc_t rd_book_enc_get(const rd_book *b); /* TXT 有效编码(非 TXT = RD_ENC_UTF8) */
const char *rd_book_path(const rd_book *b); /* 原始路径 */
/* R3:TXT 编码切换:重开 src(覆盖编码)+ 重建索引 + 回锚。返回目标页;非 TXT/CBZ 或失败负值。
* 用于「编码」菜单(Big5 繁体书手动选定)。 */
int rd_book_set_enc(rd_book *b, rd_enc_t enc);
/* R3.1:页索引持久化缓存目录(MeowData/os.meow.reader/index)。dir 为空 → 禁持久化(直排,不落盘)。
* 由 reader.c 在 open 前建目录并注入;书/字号/行距/版面/编码/字体任一变化时缓存自动失效重排。 */
void rd_book_set_index_dir(const char *dir);
/* R3.2:TXT 分段流式缓存根(MeowData/os.meow.reader,与 index 同父)。base 为空 → 禁分段(退回全量直排)。
* 由 reader.c 在 open 前注入;book.c 据此派生 <base>/seg/<path哈希> 段目录,开书时把 txt 切 512KB
* 码位对齐段文件,渲染只加载当前页所在段(不全量读整书)——治大书开书 CPU100%/返回无效。 */
void rd_book_set_seg_base(const char *base);
/* R3.3(TXT 章节):章节规范解析(core/rdchapter.c)+ 章节→页映射。
* 只对 TXT(seg_mode 分段流式路径)生效;其它格式返回「无章节」,不破坏既有路径。
* rd_book_chapter_n 触发解析(首次读全部段文件解码扫行,或命中章节缓存秒回),
* 解析/缓存后就绪;顶栏章节名与「当前页属于哪章」据此工作。 */
int rd_book_chapter_n(rd_book *b); /* 章节数;-1=非 TXT/CBZ(不可用) */
int rd_book_chapter_ready(rd_book *b); /* 1=章节已解析(含无章节=0 但已确认) */
int rd_book_reparse_chapters(rd_book *b); /* 手动重解析:清除缓存+重扫+落盘;见 book.c */
int rd_book_chapter(rd_book *b, int i, char *title, int tsz,
int64_t *char_off, int *seg, int32_t *seg_char, int *number);
int rd_book_chapter_for_page(rd_book *b, int page, int *idx); /* 当前页所属章节下标;-1=无 */
int rd_book_page_for_char(rd_book *b, int64_t char_off); /* 全书字符偏移 → 页号;-1=不可用 */
int64_t rd_book_page_char_off(rd_book *b, int page); /* 页首全书字符偏移;-1=不可用 */
/* 段(文件/段模式跳转用)。非段模式返回 -1。 */
int rd_book_seg_n(rd_book *b); /* 段数 */
int rd_book_seg_page(rd_book *b, int seg); /* 段首页(ensure built);-1 */
int rd_book_seg_page_count(rd_book *b, int seg); /* 段页数;-1 */
int rd_book_seg_of_page(rd_book *b, int page); /* 页所属段;-1 */
/* 字体/几何 */
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 */