Files
MeowOS-SDK/tuku/ui/reader/reader.h
T
AskaEth 62826e1d13 图库: 阅读器两级清晰度,先低档上屏、停稳再换清晰(M31)
真机 1280x2275 单页解码 392ms,首次看某页有一瞬加载感。改成:
- 大页(JPEG ≥1MP)先按显示长边一半的档位(真机页=step 4)解一版低档,
  精确落到显示框后立刻上屏(换图仍是单次原生 blit,不闪白、不重置缩放/滚动);
- 停稳 200ms 后才解目标档位(step 2),在**同一槽**原地替换低档,低档随即释放,
  常驻不翻倍;高档失败/预算跳过时保留低档,不把整页标成「内存不足」;
- 拖动/连翻/条漫滚动/跳页在途期间只解低档;高档请求复用 M22 的 gen/窗口
  stale 判据作废(只多一条 sharpen 谓词),出队前/后两条路径都计入取消;
- 日志尾部新增 tier=low|high(取消行同),真机可直接核对先糊后清。

分档只给 JPEG:step 是 JPEG 缩解概念,PNG/BMP 后端按目标逐行丢行本来就不慢,
且峰值模型对非 JPEG 按「输出=显示框」建模,多一条小图→落框路径会让模型低估
(不新增解码路径,也不改 sdk/ 与 page_source 的唯一模型)。

宿主回归:
- test_reader_membudget B10:JPEG 低档先落位(open 不阻塞)→ 高档落同槽
  (槽内字节不变、槽位全程不空)→ 拖动中强塞的高档请求被取消且不被解码;
- B8 连翻 100 页(6 类 1.3–12MP 循环)峰值增量 2714KB ≤3MB、常驻 ≤3MB,
  低档/高档都确实跑过;B3 断言小页保持单档(不付两次解码);
- test_reader_perf P11:非 JPEG 大页不分档,仍是一次原生 blit。
2026-11-06 13:10:01 +08:00

84 lines
5.1 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.
/* ui/reader/reader.h — 阅读页给 app.c 的事件接缝(跟手拖动/平移)。
*
* app.c 只做最小路由:ACT_READER 时的 on_touch_down/move 转给这里(镜像 library 分支)。
* 其余入口(on_tap / view on_event / mr_reader_open_dir)仍走 tuku_internal.h 的既有声明。
*/
#ifndef TUKU_UI_READER_READER_H
#define TUKU_UI_READER_READER_H
#ifdef __cplusplus
extern "C" {
#endif
/* 两级清晰度档位(M31):低档=先上屏的过渡图,高档=停稳后替换的目标档位。
* 同时供宿主测试断言槽内档位用(mr_reader_ui_slot_tier / mr_reader_ui_focus_tier)。 */
#define MR_TIER_LOW 0
#define MR_TIER_HIGH 1
void reader_on_touch_down(int x, int y);
void reader_on_touch_move(int x, int y);
/* 书库 → 阅读器(文件管理器模式用):按目录内图片自然序从 start_index 开始。
* - start_index >= 册页数:钳到末页;其它负数按 0 处理;
* - start_index == MR_READER_START_RESUME(-1):沿用该册续读记录(= mr_reader_open_dir)。
* 显式下标优先于续读记录:用户在列表里点了某张图,就不该被上次的页码带走。 */
#define MR_READER_START_RESUME (-1)
void mr_reader_open_dir_at(const char *dir, int start_index);
/* 书库 → 阅读器(按文件名定位起始页;M18 评审 P1-1 的首选入口):
* 打开 dir 后,由阅读器自己的目录册枚举(logic/reader/page_source.c: mr_dir_book_init,
* 与翻页用的是同一份全量枚举)按 basename 找起始页(先大小写敏感,再大小写不敏感兜底)。
* 找不到则退回续读记录/首页。这样书库不需要(也不能)从可能被 MR_LIB_SCAN_MAX 截断的
* 列表里推导下标——目录条目超过 2000 时也不会「点 A 开 B」。name 为 NULL/空则等价续读。 */
void mr_reader_open_dir_at_name(const char *dir, const char *name);
/* 保留旧入口:等价于 mr_reader_open_dir_at(dir, MR_READER_START_RESUME)。 */
void mr_reader_open_dir(const char *dir);
#ifdef MR_READER_HOST_TEST
/* 宿主集成测试专用:只读观察本页状态(不参与产品逻辑)。 */
int mr_reader_ui_mode(void); /* MR_MODE_PAGED / MR_MODE_WEBTOON */
int mr_reader_ui_page(void); /* 当前页(条漫=视口顶端所在页) */
int mr_reader_ui_count(void); /* 当前册页数 */
int mr_reader_ui_jump_open(void); /* 1=跳页滑块已展开 */
int mr_reader_ui_jump_pending(void);/* 1=跳页目标等待解码 */
long mr_reader_ui_resident_kb(void);/* 驻留页图字节(KB) */
int mr_reader_ui_failed_pages(void);/* 解码失败(坏图)页数 */
int mr_reader_ui_skipped_pages(void);/* 被内存预算跳过(可重试)的页数 */
/* 注入 /proc/meminfo 读数(kB);-1 = 恢复真实读取。用于确定性验证内存门控与放宽档。 */
void mr_reader_ui_test_set_mem(long free_kb, long avail_kb);
/* 峰值模型自检:用产品代码里的同一个模型算预估峰值(kB),供宿主测试与 --wrap malloc
* 实测对照。0=探测失败。 */
long long mr_reader_ui_decode_peak_kb(const char *path, int step, int box_w, int box_h);
long mr_reader_ui_peak_cap_kb(void); /* 常态峰值上限(kB) */
long mr_reader_ui_peak_budget_kb(void); /* 当前 MemFree 下的实际预算(kB) */
long mr_reader_ui_resident_cap_kb(void); /* 常驻上限(kB) */
int mr_reader_ui_blit_draws(void); /* 累计原生 blit 绘页次数(热路径应为纯 blit) */
int mr_reader_ui_scaled_draws(void);/* 累计重采样绘页次数(每帧重采样=卡顿) */
int mr_reader_ui_decode_count(void);/* 累计解码次数(查重解抖动/活锁) */
/* ---- M31 两级清晰度(先低档秒出,停稳再换档)---- */
int mr_reader_ui_focus_tier(void); /* 焦点页档位:-1=无图,0=低档过渡图,1=目标档位 */
int mr_reader_ui_slot_tier(int idx);/* 指定页档位:-1=不在槽内,否则同上 */
long mr_reader_ui_slot_kb(int idx); /* 指定槽内页图的常驻字节(KB);0=不在槽内 */
int mr_reader_ui_low_decodes(void); /* 低档解码次数 */
int mr_reader_ui_high_decodes(void);/* 目标档位解码次数 */
int mr_reader_ui_high_canceled(void);/* 被取消(拖动/换页/未停稳)的高档请求数 */
int mr_reader_ui_sharpen_idx(void); /* 当前允许升级的页;-1=拖动/未停稳/无需升级 */
/* 改写「停稳」窗口(默认 MR_SHARPEN_MS=200ms):0=立刻允许高档,很大=冻结高档。 */
void mr_reader_ui_test_set_sharpen_ms(int ms);
/* 绕过停稳判定强排一个「换清晰」请求(验证拖动中会被 M22 的取消通道作废)。 */
void mr_reader_ui_test_queue_high(int idx);
int mr_reader_ui_fit(void); /* 当前 fit 档(MR_FIT_*) */
int mr_reader_ui_chrome(void); /* 1=顶栏可见 */
/* 直接切模式(绕过顶栏 tap 的命中时序;测试用,产品路径仍走顶栏动作)。 */
void mr_reader_test_toggle_mode(void);
/* 浏览根(生产=MR_ROOT_DIR):册间衔接不得越过它。测试可指向合成夹具根。 */
void mr_reader_test_set_root(const char *root);
const char *mr_reader_test_root(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* TUKU_UI_READER_READER_H */