/* logic/reader/nav.h — 阅读导航纯逻辑(方向语义 / tap 分区 / fit / 平移 clamp)。 * * 纯 C、无 SDK 依赖:reader.c 与宿主测试共用同一实现(logic/reader/nav.c)。 * * 方向语义(mr_reader_get_direction,默认 RTL): * - LTR(左→右读):页码沿屏幕向右递增;屏左 1/3 = 上一页,屏右 1/3 = 下一页; * 手指向右拖露出左边那页 = 上一页。 * - RTL(日漫,默认):页码沿屏幕向左递增;屏左 1/3 = **下一页**,屏右 1/3 = 上一页; * 手指向右拖露出左边那页 = 下一页。 * 图像本身不做镜像(RTL 只影响翻页语义)。 */ #ifndef MR_READER_NAV_H #define MR_READER_NAV_H #ifdef __cplusplus extern "C" { #endif /* ---- fit 三档 ---- */ #define MR_FIT_WIDTH 0 /* 适宽:撑满屏宽 */ #define MR_FIT_HEIGHT 1 /* 适高:撑满屏高 */ #define MR_FIT_ORIGINAL 2 /* 原始:1:1 像素 */ #define MR_FIT_COUNT 3 /* ---- tap 分区(按屏幕横向三分) ---- */ #define MR_ZONE_LEFT 0 #define MR_ZONE_MIDDLE 1 #define MR_ZONE_RIGHT 2 /* 屏宽三分:左/中/右。view_w<=0 返回 MIDDLE。 */ int mr_nav_tap_zone(int x, int view_w); /* tap 分区的页增量:+1=下一页 / -1=上一页 / 0=chrome 显隐(中区)。 */ int mr_nav_tap_delta(int rtl, int zone); /* 中部横向拖动的页增量。dx>0 = 手指向右(露出屏幕左侧那页)。 * 首/末页不在这里判断——调用方用 mr_nav_clamp_page 落到实际目标页。 */ int mr_nav_swipe_delta(int rtl, int dx); /* 页下标 clamp;count<=0 返回 -1。 */ int mr_nav_clamp_page(int page, int count); /* 翻页提交阈值:视口宽的 1/4,夹在 [60,160] px。 */ int mr_nav_commit_dist(int view_w); /* 松手位移是否达到翻页阈值。 */ int mr_nav_commit(int dx, int view_w); /* fit 目标尺寸(未含 zoom)。0=成功;参数非法 -1。 */ int mr_nav_fit_size(int fit, int src_w, int src_h, int vw, int vh, int *out_w, int *out_h); /* 按百分比放大(zoom_pct=100 原样;200=2×)。0=成功。 */ int mr_nav_zoom_size(int w, int h, int zoom_pct, int *out_w, int *out_h); /* 平移半幅:内容比视口每侧多出的像素(>=0)。内容不溢出该轴 → 0(该轴不可平移)。 */ void mr_nav_pan_limit(int content_w, int content_h, int vw, int vh, int *lim_x, int *lim_y); /* 把平移量夹到 ±半幅。 */ void mr_nav_pan_clamp(int content_w, int content_h, int vw, int vh, int *pan_x, int *pan_y); /* 翻页动画的进场起点(px):下一页在 RTL 从左侧进、LTR 从右侧进。delta=0 返回 0。 */ int mr_nav_slide_from(int rtl, int delta, int view_w); /* fit 档循环:适宽 → 适高 → 原始 → 适宽。 */ int mr_nav_fit_next(int fit); /* ============================================================ */ /* 条漫(M7):竖向连续滚动的排版 / 滚动窗口 / 跳页状态 */ /* ------------------------------------------------------------ * 排版用页源契约的 meta()(原始像素尺寸,不解码):每页按屏宽等比换算显示高度, * 累加成「整条」的 y 偏移表。未知尺寸的页按 2:3 竖图占位(排版稳定,解码后不改布局)。 * 全部纯整数运算、无 SDK 依赖;reader.c 与宿主测试共用(logic/reader/nav.c)。 * ============================================================ */ #define MR_STRIP_MAX_PAGE_H 200000 /* 单页显示高度上限(防坏头/极端长图撑爆累计偏移) */ typedef struct mr_strip { int count; int vw, vh; int *top; /* count+1 个:top[i]=第 i 页顶端偏移;top[count]=整条总高 */ int *height; /* count 个:每页显示高度(>=1) */ int total; } mr_strip; /* 页尺寸回调(通常是 mr_book_meta):1=已知原始尺寸,0=未知。 */ typedef int (*mr_strip_meta_fn)(void *ctx, int index, int *w, int *h); /* 建排版表。0=成功;参数非法/内存不足 -1(已清空、可安全 free)。 */ int mr_strip_build(mr_strip *s, int count, int vw, int vh, mr_strip_meta_fn meta, void *ctx); /* 释放偏移表并清零(可重复调用)。 */ void mr_strip_free(mr_strip *s); int mr_strip_page_h(const mr_strip *s, int index); /* 越界 0 */ int mr_strip_top(const mr_strip *s, int index); /* index==count 返回总高;越界 0 */ int mr_strip_total(const mr_strip *s); int mr_strip_max_offset(const mr_strip *s); /* max(0, total-vh) */ /* 视口顶端(off)落在哪一页;空册 -1。 */ int mr_strip_page_at(const mr_strip *s, int off); /* 落位到某页顶端所需的滚动量(夹到 [0,max_offset]);空册 -1。 */ int mr_strip_offset_for_page(const mr_strip *s, int page); /* 视口可见页范围 [first,last] + ±1 解码窗,条数不超过 max_pages。 * 返回窗口页数;空册 0。first/last 可 NULL。 */ int mr_strip_window(const mr_strip *s, int off, int max_pages, int *first, int *last); int mr_strip_at_end(const mr_strip *s, int off); /* 1=已到条底 */ int mr_strip_at_start(const mr_strip *s, int off); /* 1=已在条顶 */ /* ---- 跳页(chrome 滑块):目标页预解码完成后再落位,避免白屏/闪烁 ---- */ typedef struct mr_jump { int pending; /* 1=正在等目标页 */ int target; /* 目标页;pending==0 时无意义 */ unsigned long long t0; /* 开始等待的时刻(ms) */ } mr_jump; /* 开始跳页:page 夹到 [0,count);count<=0 或 page<0 时取消。 */ void mr_jump_begin(mr_jump *j, int page, int count, unsigned long long now); int mr_jump_active(const mr_jump *j); int mr_jump_target(const mr_jump *j); /* 无 pending 返回 -1 */ void mr_jump_cancel(mr_jump *j); /* 轮询:have_img=目标页是否已解码。1=可以落位(已清除 pending); * timed_out 非 NULL 时写入「是否因超时落位」(调用方据此提示降级)。 * 未就绪且未超时返回 0(继续等)。 */ int mr_jump_poll(mr_jump *j, int have_img, unsigned long long now, unsigned long long timeout_ms, int *timed_out); #ifdef __cplusplus } #endif #endif /* MR_READER_NAV_H */