Merge branch 'feat/m26-sdk-image-stack-into-main-repo'

This commit is contained in:
AskaEth committed 2026-11-06 21:35:50 +08:00
commit db672cbe8f
32 files changed
+3302 -64

No files matched your search

+1 -1
View File
@@ -44,7 +44,7 @@ FT_INCS="-I$FT_BUILD -I$FT_BUILD/include -I$FT_SRC/include"
rm -f meow_ui.a *.o rm -f meow_ui.a *.o
# -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移) # -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移)
OBJS="meow_ui_time meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_lazygrid meow_select meow_ui_str meow_ui_ft meow_net_ipc meow_cachegov" OBJS="meow_ui_time meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_jpeg meow_png_stream meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_lazygrid meow_select meow_ui_str meow_ui_ft meow_net_ipc meow_cachegov"
CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd" CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd"
for f in $OBJS; do for f in $OBJS; do
echo "== cc $f ==" echo "== cc $f =="
+2 -2
View File
@@ -7,8 +7,8 @@
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:MEOW_UI_DUMP=/tmp/demo_box.ppm ./demo_box_scroll * 运行:MEOW_UI_DUMP=/tmp/demo_box.ppm ./demo_box_scroll
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+18
View File
@@ -50,6 +50,24 @@ void meow_ui_flush_region(int x, int y, int w, int h); /* 只刷新指定区 *
/* 半透明(blend565:前景按 alpha 与背景混叠) */ /* 半透明(blend565:前景按 alpha 与背景混叠) */
void meow_ui_fill_rect_alpha(int x, int y, int w, int h, uint32_t color, int alpha); /* 0-255 */ void meow_ui_fill_rect_alpha(int x, int y, int w, int h, uint32_t color, int alpha); /* 0-255 */
/* ---- RGB565 页图(M32)----
* 页槽常驻 RGB565(2 字节/像素):真机 480×853 页 1599KB → 800KB。
* 量化与 back_buf 用同一个 565 转换(逐位截断),565 屏上最终像素与 RGBA blit
* 路径逐像素一致——不引入色偏、不会比现在多出色带。
* 命中页(页图尺寸 == 显示尺寸)走 meow_gfx_blit_rgb565:每行一次拷贝,无重采样。
*
* alpha:565 页图**按不透明**处理(alpha 被忽略)。漫画页解码后 alpha 恒为 255,
* 与旧路径等价;带透明像素的 PNG(调色板/tRNS/color type 6、或 32bpp BMP)会有可见
* 差异:旧 RGBA 路径把透明像素混合到阅读器底色,565 路径直接画它的 RGB(通常是黑)。
* 若将来要支持透明页,需要在上屏时按 alpha 混合(而不是在落槽时丢通道)。 */
uint16_t meow_gfx_rgb565(uint32_t rgb); /* 24-bit RGB → 565(与 back_buf 同式) */
void meow_gfx_rgba_to_rgb565(const uint8_t *rgba, uint16_t *out, int npx); /* 不透明像素(忽略 alpha) */
/* 原生尺寸 blit(不透明):16bpp back_buf 上是每行一次 memcpy。 */
void meow_gfx_blit_rgb565(int x, int y, int w, int h, const uint16_t *px);
/* 最近邻缩放 blit(几何不符时的兜底;采样点与 meow_img_resample 同式)。 */
void meow_gfx_blit_rgb565_scaled(int x, int y, int w, int h,
int sw, int sh, const uint16_t *px);
/* ============================================================ */ /* ============================================================ */
/* §7 动画/时间(B1 最小可用) */ /* §7 动画/时间(B1 最小可用) */
/* ============================================================ */ /* ============================================================ */
+49 -6
View File
@@ -1,7 +1,8 @@
/* /*
* meow_ui_image.h — SDK 图片层(§4,B1)。 * meow_ui_image.h — SDK 图片层(§4,B1)。
* *
* 原 meow_ui.h 拆分的一部分(image 模块)。内部 stb_image(单头文件,静态编入 meow_ui.a) * 原 meow_ui.h 拆分的一部分(image 模块)。解码后端:M23 真缩解(JPEG DCT 域 / PNG 逐行 /
* BMP 跳行,见 meow_jpeg.h)优先,回退 stb_image(单头文件,静态编入 meow_ui.a)。
* 解 PNG/JPEG/BMP,统一转 RGBA。meow_img 为不透明句柄(前向声明见 meow_ui_types.h)。 * 解 PNG/JPEG/BMP,统一转 RGBA。meow_img 为不透明句柄(前向声明见 meow_ui_types.h)。
*/ */
#ifndef MEOW_UI_IMAGE_H #ifndef MEOW_UI_IMAGE_H
@@ -26,14 +27,56 @@ void meow_img_free(meow_img *img);
* App 可用它在加载前判断「图太大」并给用户提示,而不必先撞 OOM。 */ * App 可用它在加载前判断「图太大」并给用户提示,而不必先撞 OOM。 */
int meow_img_probe_file(const char *path, int *w, int *h, int *channels); int meow_img_probe_file(const char *path, int *w, int *h, int *channels);
/* 追加(M12)预算解码:解码期受长边约束,返回图最长边 ≤ maxdim。 /* 追加(M12/M23)预算解码:解码期受长边约束,返回图最长边 ≤ maxdim,尺寸与
* JPEG:按 1/2、1/4、1/8 整数步长抽取解码(stbi_load_scaled),整幅原尺寸 RGBA 缓冲从不物化, * 「meow_img_load_file + meow_img_downscale(maxdim)」逐字节同口径(公式一致)。
* 峰值 ≈ 亮度分量平面 + 缩解输出 + 单行缓冲;随后用 meow_img_downscale 精修到 maxdim。 *
* PNG/BMP 等 stb 无解码期缩放能力的格式:整幅解码后立即降采样(峰值同旧入口,见 M12 报告)。 * 实现(M23 起):先进真缩解后端(内部 meow_jpeg.c / meow_png_stream.c),解码期只算目标分辨率:
* 小图(长边 ≤ maxdim)走旧路径,与原 API 完全一致;maxdim<=0 等价旧入口。失败返回 NULL。 */ * JPEG:DCT 域缩解(每 8×8 块只解出 N×N 像素,N 由 8·maxdim/长边 取「不欠采样」的最小值;
* N=1..7,N≥8 交回 stb),渐进式跳过精细化扫描、只解各频带首次扫描 —— 低频带已完整,
* 不整幅驻留系数阵列;
* PNG :libz 逐行 inflate + 反滤波,按步长丢行丢列直写目标尺寸(gray/gray+A/RGB/RGBA/
* 调色板/1-16bit,16bit 取高字节,tRNS 透明含 8bit 灰/RGB);
* BMP :按目标行 seek 到源行 + 行内跳列(8bpp 调色板 / 16bpp RGB555 / 24bpp / 32bpp)。
* 峰值只与输出尺寸相关,不随源图分辨率/压缩体积线性增长(2000×3000 页 ≤2.5MB 量级)。
* 不支持的特性(CMYK/YCCK 4 分量 JPEG、算术编码、过订阅 Huffman 表、16bit 量化表、Adam7
* 交错 PNG、RLE/1-4bpp BMP、几乎等尺寸)自动回退 stb 旧路径,对外语义完全不变。
* 小图(长边 ≤ maxdim)走旧路径,与原 API 完全一致;maxdim<=0 等价旧入口。失败返回 NULL。
*
* 尺寸口径说明(M23 评审 P2-2):本入口按「原图 + meow_img_downscale」公式算目标尺寸;M12 旧
* 实现经 stb 的 ceil(w/s) 缩解再精修,源尺寸不是档位整数倍时可能与本入口差 1px(实测 1999×2999:
* 旧 320×480 vs 新 319×480)。阅读器按显示框缩放,无实际影响;PNG/BMP 无此差异。 */
meow_img *meow_img_load_file_dim(const char *path, int maxdim); meow_img *meow_img_load_file_dim(const char *path, int maxdim);
meow_img *meow_img_load_mem_dim(const void *buf, int len, int maxdim); meow_img *meow_img_load_mem_dim(const void *buf, int len, int maxdim);
/* 追加(M22)缩解档位选择:取满足「长边/档位 ≥ maxdim」的最大整数档 s ∈ {1,2,4,8},
* 保证缩解结果不欠采样。meow_img_load_file_dim 内部用的就是这个函数;调用方(阅读器)
* 用它枚举候选档位做内存预算,避免两处各写一份而漂移。 */
int meow_img_pick_scale(int longside, int maxdim);
/* 追加(M22)显式档位解码:语义与 meow_img_load_file_dim 相同(结果长边 ≤ maxdim,
* 超了就再精修一次),只是缩解档位由调用方决定。内存吃紧时可以选更粗的档位——输出更小、
* 峰值更低,代价是细节变软。step <= 1 等价长边约束入口;step > 8 按 8 处理。
* M23 起:先走真缩解后端(step 折算成目标长边 ceil(长边/step),后端按该长边选 DCT 阶),
* 峰值只与输出尺寸相关;不支持的特性回退 stb(step 原样传入)。
* M27 起 PNG/BMP 也走同一后端入口(阅读器峰值模型已同步为「目标图 + 工作面」口径);
* 断言与实测见 tuku/test/test_reader_membudget.c 的 B7。 */
meow_img *meow_img_load_file_step(const char *path, int maxdim, int step);
/* 追加(M27):与 meow_img_load_file_step 相同,额外控制回退并回报**实际**路径:
* allow_stb_fallback = 1:后端不支持/失败时回退 stb(与 _step 完全一致);
* allow_stb_fallback = 0:只尝试后端,失败返回 NULL——**绝不**回落 stb。阅读器的门控
* 按「后端峰值」放行时必须用 0,否则头部判定通过、解码中途失败的文件会静默走 stb,
* 实测可放出 18–36MB(截断 12MP JPEG / 头-only BMP / 非法位深 PNG)。失败页由调用方
* 按坏图占位。
* used_backend = 1(M23 后端直出目标尺寸)/ 0(未走成后端)。NULL 时等价 _step(允许回退)。 */
meow_img *meow_img_load_file_step_ex(const char *path, int maxdim, int step,
int allow_stb_fallback, int *used_backend);
/* 追加(M22)精确重采样到 w×h(最近邻,缩小/放大都支持)。阅读器用它把「缩解档位」的
* 结果一次性落到显示框,使命中页仍是单次原生 blit(不做每帧重采样)。同尺寸返回 NULL
* (调用方保留原图);失败返回 NULL。 */
meow_img *meow_img_resample(meow_img *im, int w, int h);
int meow_img_w(const meow_img *img); int meow_img_w(const meow_img *img);
int meow_img_h(const meow_img *img); int meow_img_h(const meow_img *img);
/* 访问器:取 RGBA 像素指针(4 通道 straight alpha;供取色/直读像素)。meow_img 对外 opaque, /* 访问器:取 RGBA 像素指针(4 通道 straight alpha;供取色/直读像素)。meow_img 对外 opaque,
File diff suppressed because it is too large. Load diff
+50
View File
@@ -0,0 +1,50 @@
/*
* meow_jpeg.h — M23 真缩解后端内部接口(**不对外导出**,不在 meow_ui.h 伞头里)。
*
* 后端直接产出「目标显示尺寸」的 RGBA,不做「先整幅解、再重采样」:
* - JPEG(meow_jpeg.c):DCT 域缩解 1/8、1/4、1/2(N=1/2/4 点 IDCT),渐进式只解到
* 首个精细化扫描(首个 Ah>0)为止——低频带此时已完整,再往后只是为了更细的量化精度。
* - PNG(meow_png_stream.c):libz inflate 逐行 defilter,按步长丢行丢列直写目标尺寸。
* - BMP(meow_png_stream.c):按行 seek + 行内跳列(同一套「只碰需要的行」思路)。
* 三者峰值都只与「输出尺寸 + 目标图像」相关,不随源图分辨率线性增长——**前提是文件头
* 声明的尺寸在合理范围内**:畸形/超大声明尺寸(例如 23 字节的 SOF 声明 65535×65535)会被
* 直接拒绝(返回 0 → 回退 stb,安全失败),不会按声明尺寸分配平面。
*
* 不支持的特性一律返回 0,由 meow_ui_img.c 回退 stb(行为与 M23 之前完全一致):
* 4 分量 CMYK/YCCK、算术编码/无损/分层 JPEG、Adam7 交错 PNG、1/2/4bpp 与 RLE BMP 等。
*
* 许可证:本文件与 meow_jpeg.c / meow_png_stream.c 为 MeowOS 自写代码(MIT,随 SDK 发布)。
* 不引入第三方解码器源码——理由见 M23 报告「为什么不用 IJG libjpeg」:libjpeg 系列对
* 渐进式 JPEG 必须整幅驻留系数阵列(≈1 字节/源像素/分量),正是审计里 +23.5MB 的来源,
* 换成它也无法把渐进式峰值压到 2.5MB 以内。
*/
#ifndef MEOW_JPEG_H
#define MEOW_JPEG_H
#include <stddef.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/* 解码 path / 内存里的图,直接产出「长边 ≤ maxdim 且按 meow_img_downscale 同一公式等比缩放」
* 的 tw×th RGBA(4 通道 straight alpha,malloc 分配,调用方 free)。
* 返回 1 成功(tw/th/rgba 已填);0 = 不支持/失败/不需要(调用方回退 stb 或旧入口)。 */
int meow_img_backend_file(const char *path, int maxdim, int *tw, int *th, unsigned char **rgba);
int meow_img_backend_mem(const void *buf, size_t len, int maxdim, int *tw, int *th, unsigned char **rgba);
/* 目标尺寸:与 meow_img_downscale 同一公式(长边 = maxdim,短边按比例截断,下限 1)。 */
void meow_img_target_dims(int w, int h, int maxdim, int *tw, int *th);
/* meow_png_stream.c 提供(PNG 逐行 inflate / BMP 按行跳采样)。f 与 mem 二选一:
* f != NULL 走文件流(只读需要的行/块),否则从 mem[0..len) 读。 */
int meow_png_decode_stream(FILE *f, const unsigned char *mem, size_t len,
int maxdim, int *tw, int *th, unsigned char **rgba);
int meow_bmp_decode_stream(FILE *f, const unsigned char *mem, size_t len,
int maxdim, int *tw, int *th, unsigned char **rgba);
#ifdef __cplusplus
}
#endif
#endif /* MEOW_JPEG_H */
+544
View File
@@ -0,0 +1,544 @@
/*
* meow_png_stream.c — M23 真缩解后端(二):PNG 逐行 inflate + BMP 按行跳采样。
*
* 为什么不用 stb 的 PNG 路径:stb 先整幅 inflate + 反滤波成 raw,再展开成 RGBA 整幅,
* 最后才降采样——1600×2400 PNG 实测 +26.2MB。这里改成「按行流式」:
* - IDAT 边到边 inflate,一次只持有一行(filter 字节 + rowbytes)与上一行;
* - 反滤波后**只把需要的列**写进目标行(最近邻,与 meow_img_downscale 同口径);
* - 不需要的行整行丢弃(但仍要反滤波,filter 依赖上一行);
* - 峰值 ≈ 两行缓冲 + zlib 窗口(32KB) + 目标 RGBA,与源图分辨率无关。
* 支持:gray / gray+A / RGB / RGBA / 调色板,bit depth 1/2/4/8/16(16bit 取高字节降 8bit),
* tRNS 透明。不支持 → 返回 0 回退 stb:Adam7 交错、非 0 压缩/滤波方法、异常色型组合。
*
* BMP:文件流按目标行直接 seek 到源行(不读全图),行内跳列采样。支持 8bpp 调色板 /
* 16bpp RGB555 / 24bpp / 32bpp(BI_RGB);RLE、BITFIELDS、1/2/4bpp → 回退 stb。
*
* 许可证:MeowOS 自写(MIT,随 SDK 发布)。PNG/zlib 语义参考 RFC 2083 / zlib 手册;
* BMP 布局参考 stb_image 的解析口径(同为本仓已有依赖,行为对齐)。
*/
#include "meow_jpeg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <limits.h> /* LONG_MAX:BMP 按行 seek 的 32 位偏移上限 */
/* ---------------- zlib ABI ---------------- */
#if defined(__has_include)
# if __has_include(<zlib.h>)
# include <zlib.h>
# define MZP_HAVE_H 1
# endif
#endif
#ifndef MZP_HAVE_H
/* 设备 musl sysroot 没有 zlib.h(meow_font.c 同此口径):按 libz.a 的 ABI 声明最小 API。
* 指针/unsigned long 交给编译器定尺寸,宿主 64 位与设备 32 位都成立。 */
typedef unsigned char mzp_Bytef;
typedef unsigned int mzp_uInt;
typedef unsigned long mzp_uLong;
typedef void *mzp_voidpf;
typedef struct mzp_stream_s {
mzp_Bytef *next_in; mzp_uInt avail_in; mzp_uLong total_in;
mzp_Bytef *next_out; mzp_uInt avail_out; mzp_uLong total_out;
char *msg;
void *state;
void *zalloc;
void *zfree;
mzp_voidpf opaque;
int data_type;
mzp_uLong adler;
mzp_uLong reserved;
} mzp_stream;
extern int inflateInit_(mzp_stream *, const char *, int);
extern int inflate(mzp_stream *, int);
extern int inflateEnd(mzp_stream *);
extern const char *zlibVersion(void);
# define z_stream mzp_stream
# define Z_OK 0
# define Z_STREAM_END 1
# define Z_NO_FLUSH 0
#endif
/* ---------------- ILP32 尺寸算术守卫 ----------------
* mipsel / arm-linux-musleabi 上 long 与 size_t 都是 32 位:把「声明尺寸 × bpp」这类
* 乘积直接放在 long 里会回绕成小值或 0。实测(ARM32):54 字节 BMP 头声明 w=2^27、
* bpp=32 → w*bpp = 2^32 = 0 → rowsize = 0 → malloc(0) → 采样索引 row + sx*4 越界读
* → SIGSEGV;同一文件在 LP64 宿主返回 NULL,所以宿主测试天然看不到这类。
* 因此:凡「由文件头算出来的字节数/偏移」一律升到 unsigned long long 再验,
* 超限即返回 0,由调用方回退 stb(安全失败,与 M26 之前的行为一致)。
* 单边上限 1<<20(1,048,576):远超真实 BMP/PNG 声明尺寸,同时保证行字节数
* (≤4 MiB)、行偏移与目标 RGBA 都不会在 32 位溢出。 */
#define MZP_MAX_DIM (1u << 20)
static int mzp_bytes_ok(unsigned long long n)
{
return n > 0 && n <= (unsigned long long)(size_t)-1;
}
/* ---------------- 字节源 ---------------- */
typedef struct {
FILE *f;
const unsigned char *mem;
size_t memlen, mempos;
} png_src;
static int ps_read(png_src *s, void *dst, size_t n)
{
if (s->mem) {
if (s->mempos + n > s->memlen) return 0;
memcpy(dst, s->mem + s->mempos, n);
s->mempos += n;
return 1;
}
return fread(dst, 1, n, s->f) == n;
}
static int ps_skip(png_src *s, size_t n)
{
if (s->mem) {
if (s->mempos + n > s->memlen) return 0;
s->mempos += n;
return 1;
}
return fseek(s->f, (long)n, SEEK_CUR) == 0;
}
/* ================================================================== */
/* PNG */
/* ================================================================== */
typedef struct {
png_src src;
z_stream z;
int z_ready, z_end;
unsigned w, h;
int depth, color;
int bits; /* 每像素位数 */
size_t rowbytes;
unsigned char *line; /* 1 filter 字节 + rowbytes */
unsigned char *prev; /* 上一行的像素字节 */
unsigned char *cur; /* 本行的像素字节 */
size_t need, got;
unsigned char pal[256][3];
unsigned char trns_a[256]; /* 调色板透明度 */
int pal_n;
int have_trns;
unsigned trns[3]; /* gray / RGB 的 tRNS 值(已降到 8bit) */
unsigned char *out;
int tw, th;
int next_ty;
unsigned y;
} png_ctx;
/* 从行里取 px 列的 8bit 通道;返回通道数(写入 o[0..3] 的 RGB(A) 语义由调用方定)。 */
static void png_get_px(const png_ctx *c, const unsigned char *row, int x, unsigned char *o)
{
int d = c->depth;
if (d < 8) {
int per = 8 / d; /* 每字节像素数 */
int byte = x / per;
int shift = 8 - d * (x % per + 1);
int v = (row[byte] >> shift) & ((1 << d) - 1);
if (c->color == 3) { /* 调色板:子字节值即索引 */
o[0] = c->pal[v][0]; o[1] = c->pal[v][1]; o[2] = c->pal[v][2];
o[3] = c->trns_a[v];
} else {
unsigned char g = (unsigned char)(v * 255 / ((1 << d) - 1));
o[0] = o[1] = o[2] = g;
/* tRNS 存的是原始采样值(0..2^d-1),不是展开后的 0..255 */
o[3] = (c->color == 0 && c->have_trns && (unsigned)v == c->trns[0]) ? 0 : 255;
}
return;
}
if (d == 8) {
if (c->color == 0) { /* gray */
o[0] = o[1] = o[2] = row[x];
o[3] = (c->have_trns && row[x] == c->trns[0]) ? 0 : 255;
} else if (c->color == 2) { /* RGB */
o[0] = row[x * 3]; o[1] = row[x * 3 + 1]; o[2] = row[x * 3 + 2];
o[3] = (c->have_trns && row[x * 3] == c->trns[0] &&
row[x * 3 + 1] == c->trns[1] && row[x * 3 + 2] == c->trns[2]) ? 0 : 255;
} else if (c->color == 3) { /* palette */
int i = row[x];
o[0] = c->pal[i][0]; o[1] = c->pal[i][1]; o[2] = c->pal[i][2];
o[3] = c->trns_a[i];
} else if (c->color == 4) { /* gray + A */
o[0] = o[1] = o[2] = row[x * 2];
o[3] = row[x * 2 + 1];
} else { /* RGBA */
o[0] = row[x * 4]; o[1] = row[x * 4 + 1];
o[2] = row[x * 4 + 2]; o[3] = row[x * 4 + 3];
}
return;
}
/* 16bit:取高字节 */
if (c->color == 0) {
o[0] = o[1] = o[2] = row[x * 2];
o[3] = (c->have_trns && row[x * 2] == c->trns[0]) ? 0 : 255;
} else if (c->color == 2) {
o[0] = row[x * 6]; o[1] = row[x * 6 + 2]; o[2] = row[x * 6 + 4];
o[3] = (c->have_trns && row[x * 6] == c->trns[0] &&
row[x * 6 + 2] == c->trns[1] && row[x * 6 + 4] == c->trns[2]) ? 0 : 255;
} else if (c->color == 4) {
o[0] = o[1] = o[2] = row[x * 4];
o[3] = row[x * 4 + 2];
} else {
o[0] = row[x * 8]; o[1] = row[x * 8 + 2];
o[2] = row[x * 8 + 4]; o[3] = row[x * 8 + 6];
}
}
/* 一行反滤波完成后:按需写目标行。 */
static int png_emit_row(png_ctx *c)
{
unsigned char ft = c->line[0];
const unsigned char *src = c->line + 1;
unsigned char *dst = c->cur;
size_t x, bpp = (size_t)((c->bits + 7) / 8);
if (bpp < 1) bpp = 1;
if (ft > 4) return 0;
for (x = 0; x < c->rowbytes; x++) {
unsigned char left = (x >= bpp) ? dst[x - bpp] : 0;
unsigned char up = c->prev ? c->prev[x] : 0;
unsigned char ul = (c->prev && x >= bpp) ? c->prev[x - bpp] : 0;
unsigned char v = src[x];
switch (ft) {
case 0: dst[x] = v; break;
case 1: dst[x] = (unsigned char)(v + left); break;
case 2: dst[x] = (unsigned char)(v + up); break;
case 3: dst[x] = (unsigned char)(v + (((unsigned)left + (unsigned)up) >> 1)); break;
default: {
int p = (int)left + (int)up - (int)ul;
int pa = p - (int)left; if (pa < 0) pa = -pa;
int pb = p - (int)up; if (pb < 0) pb = -pb;
int pc = p - (int)ul; if (pc < 0) pc = -pc;
unsigned char pred = (pa <= pb && pa <= pc) ? left : (pb <= pc ? up : ul);
dst[x] = (unsigned char)(v + pred);
break;
}
}
}
if (c->next_ty < c->th) {
long long sy = (long long)c->next_ty * (long long)c->h / c->th; /* 64 位:ILP32 上 *h 会溢出 */
if (sy == (long long)c->y) {
unsigned char *o = c->out +
(size_t)((unsigned long long)c->next_ty * (unsigned long long)c->tw * 4u);
int tx;
for (tx = 0; tx < c->tw; tx++) {
long long sxl = (long long)tx * (long long)c->w / c->tw;
int sx = (int)(sxl < 0 ? 0
: (sxl >= (long long)c->w ? (long long)c->w - 1 : sxl));
unsigned char px[4];
png_get_px(c, dst, sx, px);
o[tx * 4] = px[0]; o[tx * 4 + 1] = px[1];
o[tx * 4 + 2] = px[2]; o[tx * 4 + 3] = px[3];
}
c->next_ty++;
}
}
/* 交换 prev/cur(prev 直接成为反滤波基准) */
{
unsigned char *t = c->prev;
c->prev = c->cur;
c->cur = t;
}
c->y++;
return 1;
}
#define PNG_NEED_MORE 2
static int png_pump(png_ctx *c)
{
while (c->got < c->need) {
int ret;
c->z.next_out = c->line + c->got;
c->z.avail_out = (unsigned)(c->need - c->got);
ret = inflate(&c->z, Z_NO_FLUSH);
c->got = c->need - c->z.avail_out;
if (ret == Z_STREAM_END) c->z_end = 1;
else if (ret != Z_OK) return 0;
if (c->got < c->need && (c->z.avail_in == 0 || c->z_end))
return c->z_end ? 0 : PNG_NEED_MORE;
}
if (!png_emit_row(c)) return 0;
c->got = 0;
return 1;
}
static int png_bits_of(int color, int depth)
{
switch (color) {
case 0: return depth; /* gray */
case 2: return depth * 3; /* rgb */
case 3: return depth; /* palette */
case 4: return depth * 2; /* gray + a */
case 6: return depth * 4; /* rgba */
default: return 0;
}
}
static int png_depth_ok(int color, int depth)
{
if (color == 0) return depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth == 16;
if (color == 3) return depth == 1 || depth == 2 || depth == 4 || depth == 8;
if (color == 2 || color == 4 || color == 6) return depth == 8 || depth == 16;
return 0;
}
int meow_png_decode_stream(FILE *f, const unsigned char *mem, size_t len,
int maxdim, int *tw, int *th, unsigned char **rgba)
{
png_ctx c;
unsigned char sig[8], hdr[8];
unsigned char ibuf[4096];
int have_ihdr = 0, i, ok = 0;
if (maxdim <= 0) return 0;
memset(&c, 0, sizeof c);
c.src.f = f;
c.src.mem = mem;
c.src.memlen = len;
if (!ps_read(&c.src, sig, 8)) return 0;
if (memcmp(sig, "\x89PNG\r\n\x1a\n", 8) != 0) return 0;
while (ps_read(&c.src, hdr, 8)) {
unsigned clen = ((unsigned)hdr[0] << 24) | ((unsigned)hdr[1] << 16) |
((unsigned)hdr[2] << 8) | hdr[3];
const unsigned char *type = hdr + 4;
if (clen > 0x7FFFFFFFu) return 0;
if (memcmp(type, "IHDR", 4) == 0) {
unsigned char d[13];
if (clen < 13 || have_ihdr) return 0;
if (!ps_read(&c.src, d, 13)) return 0;
c.w = ((unsigned)d[0] << 24) | ((unsigned)d[1] << 16) | ((unsigned)d[2] << 8) | d[3];
c.h = ((unsigned)d[4] << 24) | ((unsigned)d[5] << 16) | ((unsigned)d[6] << 8) | d[7];
c.depth = d[8];
c.color = d[9];
if (d[10] != 0 || d[11] != 0 || d[12] != 0) return 0; /* 只支持非交错 + 标准压缩/滤波 */
if (c.w == 0 || c.h == 0 || c.w > 65535u || c.h > 65535u) return 0;
if (!png_depth_ok(c.color, c.depth)) return 0;
c.bits = png_bits_of(c.color, c.depth);
c.rowbytes = ((size_t)c.w * c.bits + 7) / 8;
if (c.rowbytes == 0) return 0;
/* 小图不动:与 meow_img_load_file_dim 的「旧入口」判定一致 */
if ((long)(c.w > c.h ? c.w : c.h) <= maxdim) return 0;
if (clen > 13 && !ps_skip(&c.src, clen - 13)) return 0;
have_ihdr = 1;
c.need = c.rowbytes + 1;
c.line = (unsigned char *)malloc(c.need);
c.prev = (unsigned char *)malloc(c.rowbytes);
c.cur = (unsigned char *)malloc(c.rowbytes);
if (!c.line || !c.prev || !c.cur) goto done;
memset(c.prev, 0, c.rowbytes);
memset(c.cur, 0, c.rowbytes);
for (i = 0; i < 256; i++) c.trns_a[i] = 255;
meow_img_target_dims((int)c.w, (int)c.h, maxdim, &c.tw, &c.th);
{
/* ILP32 上 tw*th*4 会回绕(32768×32768×4 = 2^32 → 0 → malloc(0) 后越界写) */
unsigned long long ob = (unsigned long long)c.tw * (unsigned long long)c.th * 4u;
if (!mzp_bytes_ok(ob)) goto done;
c.out = (unsigned char *)malloc((size_t)ob);
if (!c.out) goto done;
memset(c.out, 0, (size_t)ob);
}
memset(&c.z, 0, sizeof c.z);
if (inflateInit_(&c.z, zlibVersion(), (int)sizeof c.z) != Z_OK) goto done;
c.z_ready = 1;
} else if (memcmp(type, "PLTE", 4) == 0) {
unsigned char d[256 * 3];
if (clen > sizeof d || clen % 3) return 0;
if (!ps_read(&c.src, d, clen)) return 0;
c.pal_n = (int)(clen / 3);
memcpy(c.pal, d, clen);
} else if (memcmp(type, "tRNS", 4) == 0) {
unsigned char d[256];
if (clen > sizeof d) return 0;
if (!ps_read(&c.src, d, clen)) return 0;
c.have_trns = 1;
if (c.color == 3) {
for (i = 0; i < (int)clen && i < 256; i++) c.trns_a[i] = d[i];
} else if (c.color == 0 && clen >= 2) {
/* 8bit/低位深:采样值存在低字节;16bit:与像素一样取高字节比较 */
c.trns[0] = (c.depth == 16) ? d[0] : d[1];
} else if (c.color == 2 && clen >= 6) {
if (c.depth == 16) {
c.trns[0] = d[0]; c.trns[1] = d[2]; c.trns[2] = d[4];
} else {
c.trns[0] = d[1]; c.trns[1] = d[3]; c.trns[2] = d[5];
}
}
} else if (memcmp(type, "IDAT", 4) == 0) {
unsigned remain = clen;
if (!have_ihdr || !c.out) return 0;
while (remain) {
unsigned n = remain > sizeof ibuf ? (unsigned)sizeof ibuf : remain;
if (!ps_read(&c.src, ibuf, n)) goto done;
remain -= n;
c.z.next_in = ibuf;
c.z.avail_in = n;
while (c.z.avail_in && c.next_ty < c.th) {
int r = png_pump(&c);
if (r == 0) goto done;
if (r == PNG_NEED_MORE) break;
}
}
} else if (memcmp(type, "IEND", 4) == 0) {
break;
} else {
if (clen && !ps_skip(&c.src, clen)) return 0;
}
/* 跳过 CRC */
{
unsigned char crc[4];
if (!ps_read(&c.src, crc, 4)) break;
}
if (c.out && c.next_ty >= c.th) break; /* 目标行都拿到了,不必读完 */
}
if (!have_ihdr || !c.out || c.next_ty < c.th) goto done;
if (c.color == 3 && c.pal_n <= 0) goto done;
*tw = c.tw;
*th = c.th;
*rgba = c.out;
c.out = NULL;
ok = 1;
done:
if (c.z_ready) inflateEnd(&c.z);
free(c.line);
free(c.prev);
free(c.cur);
free(c.out);
return ok;
}
/* ================================================================== */
/* BMP */
/* ================================================================== */
static unsigned le16(const unsigned char *p) { return (unsigned)p[0] | ((unsigned)p[1] << 8); }
static unsigned le32(const unsigned char *p)
{
return (unsigned)p[0] | ((unsigned)p[1] << 8) | ((unsigned)p[2] << 16) | ((unsigned)p[3] << 24);
}
int meow_bmp_decode_stream(FILE *f, const unsigned char *mem, size_t len,
int maxdim, int *tw, int *th, unsigned char **rgba)
{
png_src src;
unsigned char fh[14], dh[4];
unsigned char dib[1024];
unsigned dibsize, dataoff, bpp, compression, colors;
long w, h, rowsize;
int topdown, i;
unsigned char pal[256][3];
unsigned char *row = NULL, *out = NULL;
int tw_ = 0, th_ = 0, ok = 0;
if (maxdim <= 0) return 0;
memset(&src, 0, sizeof src);
src.f = f;
src.mem = mem;
src.memlen = len;
if (!ps_read(&src, fh, 14)) return 0;
if (fh[0] != 'B' || fh[1] != 'M') return 0;
dataoff = le32(fh + 10);
if (!ps_read(&src, dh, 4)) return 0;
dibsize = le32(dh);
if (dibsize < 40 || dibsize > sizeof dib) return 0; /* BITMAPCOREHEADER/OS2 → stb */
memcpy(dib, dh, 4);
if (!ps_read(&src, dib + 4, dibsize - 4)) return 0;
bpp = le16(dib + 14);
compression = le32(dib + 16);
colors = (dibsize >= 36) ? le32(dib + 32) : 0;
if (compression != 0) return 0; /* RLE/BITFIELDS → stb */
if (bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32) return 0;
/* 声明尺寸过 32 位算术闸(M26 r1 P1):w×bpp 与 tx×w 在 ILP32 上会回绕成小值/负数,
* 直接导致 malloc(0) + 越界读。h=INT_MIN 时 -h 同样溢出,故升到 long long 再取绝对值。 */
{
int wi = (int)le32(dib + 4);
int hi = (int)le32(dib + 8);
long long hll;
if (wi <= 0 || hi == 0) return 0;
topdown = hi < 0;
hll = topdown ? -(long long)hi : (long long)hi;
if ((unsigned long long)wi > MZP_MAX_DIM || hll <= 0 ||
(unsigned long long)hll > MZP_MAX_DIM) return 0; /* 离奇声明尺寸 → 回退 stb */
w = (long)wi;
h = (long)hll;
}
if ((long)(w > h ? w : h) <= maxdim) return 0; /* 小图走旧入口 */
if (bpp <= 8) {
unsigned n = colors ? colors : 256;
unsigned char e[4];
if (n > 256) n = 256;
for (i = 0; (unsigned)i < n; i++) {
if (!ps_read(&src, e, 4)) return 0;
pal[i][0] = e[2]; pal[i][1] = e[1]; pal[i][2] = e[0];
}
for (; i < 256; i++) pal[i][0] = pal[i][1] = pal[i][2] = 0;
}
{
/* 行字节数 64 位算(ILP32 上 w*bpp 在 w≥2^27/bpp 时回绕成 0) */
unsigned long long rb = ((unsigned long long)w * bpp + 31u) / 32u * 4u;
if (!mzp_bytes_ok(rb)) return 0;
rowsize = (long)rb; /* w ≤ MZP_MAX_DIM → ≤ 4 MiB */
}
meow_img_target_dims((int)w, (int)h, maxdim, &tw_, &th_);
row = (unsigned char *)malloc((size_t)rowsize);
{
unsigned long long ob = (unsigned long long)tw_ * (unsigned long long)th_ * 4u;
if (mzp_bytes_ok(ob)) out = (unsigned char *)malloc((size_t)ob);
}
if (!row || !out) goto done;
for (int ty = 0; ty < th_; ty++) {
long long sy = (long long)ty * h / th_;
long long file_row = topdown ? sy : ((long long)h - 1 - sy);
long long off = (long long)dataoff + file_row * (long long)rowsize;
unsigned char *o = out + (size_t)((unsigned long long)ty * (unsigned long long)tw_ * 4u);
if (src.mem) {
if (off < 0 ||
(unsigned long long)off + (unsigned long long)rowsize > (unsigned long long)src.memlen)
goto done;
memcpy(row, src.mem + (size_t)off, (size_t)rowsize);
} else {
if (off < 0 || off > (long long)LONG_MAX) goto done; /* fseek 只有 32 位偏移 */
if (fseek(src.f, (long)off, SEEK_SET) != 0) goto done;
if (fread(row, 1, (size_t)rowsize, src.f) != (size_t)rowsize) goto done;
}
for (int tx = 0; tx < tw_; tx++) {
long long sxl = (long long)tx * w / tw_;
int sx = (int)(sxl < 0 ? 0 : (sxl >= (long long)w ? (long long)w - 1 : sxl));
unsigned char *p = o + (size_t)tx * 4;
if (bpp == 24) {
const unsigned char *q = row + sx * 3;
p[0] = q[2]; p[1] = q[1]; p[2] = q[0]; p[3] = 255;
} else if (bpp == 32) {
const unsigned char *q = row + sx * 4;
p[0] = q[2]; p[1] = q[1]; p[2] = q[0]; p[3] = 255; /* BI_RGB:alpha 不作为语义 */
} else if (bpp == 16) {
unsigned v = le16(row + sx * 2);
unsigned r = (v >> 10) & 31, g = (v >> 5) & 31, b = v & 31;
p[0] = (unsigned char)((r << 3) | (r >> 2));
p[1] = (unsigned char)((g << 3) | (g >> 2));
p[2] = (unsigned char)((b << 3) | (b >> 2));
p[3] = 255;
} else {
unsigned idx = row[sx];
p[0] = pal[idx & 255][0]; p[1] = pal[idx & 255][1];
p[2] = pal[idx & 255][2]; p[3] = 255;
}
}
}
*tw = tw_;
*th = th_;
*rgba = out;
out = NULL;
ok = 1;
done:
free(row);
free(out);
return ok;
}
+103
View File
@@ -172,6 +172,9 @@ static void refresh_governor(unsigned long long cost_ms, int period)
} }
/* ---- 工具 ---- */ /* ---- 工具 ---- */
/* 时钟统一由 meow_ui_time.c 提供(meow_ui_time_ms,声明见 include/meow_ui_draw.h):
* mipsel 上 zig musl 的 time64 ABI 自相矛盾,取时必须走内核 o32 ABI 再升位,
* 故本 TU 不再保留取时实现(详见 sdk/CLOCK_ABI.md)。 */
static uint16_t rgb565(uint32_t c) static uint16_t rgb565(uint32_t c)
{ {
return (uint16_t)(((c >> 8) & 0xF800) | ((c >> 5) & 0x07E0) | ((c >> 3) & 0x001F)); return (uint16_t)(((c >> 8) & 0xF800) | ((c >> 5) & 0x07E0) | ((c >> 3) & 0x001F));
@@ -854,6 +857,106 @@ void meow_gfx_blit_rgba(int x, int y, int w, int h, const uint8_t *rgba, int alp
dirty_add(x1, y1, x2 - x1, y2 - y1); dirty_add(x1, y1, x2 - x1, y2 - y1);
} }
/* ================= RGB565 页图(M32) =================
* 阅读器页槽常驻 RGB565(2B/px)而不是 RGBA:真机 480×853 页 1599KB → 800KB。
* 量化与 back_buf 用同一个 rgb565()(逐位截断),所以 565 屏上落下的像素与旧的
* RGBA blit 路径**逐像素一致**——不引入色偏,也不会比现在多出色带。
* 命中页(解码/落框尺寸 == 显示尺寸)走 meow_gfx_blit_rgb565:每行一次 memcpy,
* 单次拷贝、没有每帧重采样。alpha 按不透明处理(页图 alpha 恒为 255;带透明像素的
* PNG/32bpp BMP 页会与旧 RGBA 路径不同——旧路径混合到底色,这里直接画 RGB)。 */
uint16_t meow_gfx_rgb565(uint32_t rgb)
{
return rgb565(rgb);
}
void meow_gfx_rgba_to_rgb565(const uint8_t *rgba, uint16_t *out, int npx)
{
if (!rgba || !out || npx <= 0) return;
for (int i = 0; i < npx; i++) {
const uint8_t *p = rgba + (size_t)i * 4;
out[i] = rgb565(((uint32_t)p[0] << 16) | ((uint32_t)p[1] << 8) | (uint32_t)p[2]);
}
}
/* 目标矩形与 clip 求交;返回 1=还有可画区域。 */
static int blit565_clip(int x, int y, int w, int h, int *x1, int *y1, int *x2, int *y2)
{
if (!g_init_ok || w <= 0 || h <= 0) return 0;
*x1 = x; *y1 = y; *x2 = x + w; *y2 = y + h;
if (*x1 < 0) *x1 = 0;
if (*y1 < 0) *y1 = 0;
if (*x2 > g_xres) *x2 = g_xres;
if (*y2 > g_yres) *y2 = g_yres;
if (g_clip_n > 0) {
int *c = g_clip_stack[g_clip_n - 1];
if (*x1 < c[0]) *x1 = c[0];
if (*y1 < c[1]) *y1 = c[1];
if (*x2 > c[2]) *x2 = c[2];
if (*y2 > c[3]) *y2 = c[3];
}
return *x2 > *x1 && *y2 > *y1;
}
void meow_gfx_blit_rgb565(int x, int y, int w, int h, const uint16_t *px)
{
if (!px) return;
int x1, y1, x2, y2;
if (!blit565_clip(x, y, w, h, &x1, &y1, &x2, &y2)) return;
int n = x2 - x1;
for (int py = y1; py < y2; py++) {
const uint16_t *src = px + (size_t)(py - y) * w + (x1 - x);
unsigned char *dst = g_fb + (size_t)py * g_line + (size_t)x1 * (size_t)(g_bpp / 8);
if (g_bpp == 16) {
memcpy(dst, src, (size_t)n * 2); /* 命中页:每行一次拷贝 */
} else {
uint32_t *d32 = (uint32_t *)dst;
for (int i = 0; i < n; i++) {
uint16_t c = src[i];
d32[i] = ((uint32_t)ex5((c >> 11) & 0x1F) << 24) |
((uint32_t)ex6((c >> 5) & 0x3F) << 16) |
((uint32_t)ex5(c & 0x1F) << 8) | 0xFFu;
}
}
}
dirty_add(x1, y1, n, y2 - y1);
}
/* 最近邻缩放(仅几何不符时的兜底路径;采样点与 meow_img_resample 同式)。
* 命中页不会走到这里——那是热路径纪律(M17/M32)。 */
void meow_gfx_blit_rgb565_scaled(int x, int y, int w, int h,
int sw, int sh, const uint16_t *px)
{
if (!px || sw <= 0 || sh <= 0) return;
int x1, y1, x2, y2;
if (!blit565_clip(x, y, w, h, &x1, &y1, &x2, &y2)) return;
int n = x2 - x1;
for (int py = y1; py < y2; py++) {
int sy = (int)((long long)(py - y) * sh / h);
if (sy >= sh) sy = sh - 1;
const uint16_t *row = px + (size_t)sy * sw;
unsigned char *dst = g_fb + (size_t)py * g_line + (size_t)x1 * (size_t)(g_bpp / 8);
if (g_bpp == 16) {
uint16_t *d16 = (uint16_t *)dst;
for (int i = 0; i < n; i++) {
int sx = (int)((long long)(x1 + i - x) * sw / w);
if (sx >= sw) sx = sw - 1;
d16[i] = row[sx];
}
} else {
uint32_t *d32 = (uint32_t *)dst;
for (int i = 0; i < n; i++) {
int sx = (int)((long long)(x1 + i - x) * sw / w);
if (sx >= sw) sx = sw - 1;
uint16_t c = row[sx];
d32[i] = ((uint32_t)ex5((c >> 11) & 0x1F) << 24) |
((uint32_t)ex6((c >> 5) & 0x3F) << 16) |
((uint32_t)ex5(c & 0x1F) << 8) | 0xFFu;
}
}
}
dirty_add(x1, y1, n, y2 - y1);
}
/* ================= present / 上屏 ================= */ /* ================= present / 上屏 ================= */
static void dump_ppm(void) static void dump_ppm(void)
{ {
+88 -5
View File
@@ -1,10 +1,11 @@
/* /*
* meow_ui_img.c — 图片层(B1.2)。基于 stb_image(单头文件、静态编入), * meow_ui_img.c — 图片层(B1.2)。解码:M23 真缩解后端(meow_jpeg.c / meow_png_stream.c)
* 解 PNG/JPEG/BMP → RGBA,统一最近邻缩放/居中裁方。 * 优先,不支持/失败回退 stb_image(单头文件、静态编入);统一输出 RGBA,最近邻缩放/居中裁方。
*/ */
#include "meow_ui.h" #include "meow_ui.h"
#include "meow_ui_internal.h" #include "meow_ui_internal.h"
#include "stb_image.h" #include "stb_image.h"
#include "meow_jpeg.h" /* M23 真缩解后端(内部头,不对外导出) */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -45,7 +46,7 @@ meow_img *meow_img_load_file(const char *path)
/* 追加(M12):预算解码。选整数缩解档位 s ∈ {1,2,4,8}——取满足「长边/s ≥ maxdim」的最大档, /* 追加(M12):预算解码。选整数缩解档位 s ∈ {1,2,4,8}——取满足「长边/s ≥ maxdim」的最大档,
* 保证缩解结果不欠采样(不丢细节),再由 meow_img_downscale 精修到 maxdim。长边 < 2*maxdim * 保证缩解结果不欠采样(不丢细节),再由 meow_img_downscale 精修到 maxdim。长边 < 2*maxdim
* 时无档可用(s=1),退回整幅解码后精修——此时本就接近目标尺寸,无需牺牲。 */ * 时无档可用(s=1),退回整幅解码后精修——此时本就接近目标尺寸,无需牺牲。 */
static int img_pick_scale(int longside, int maxdim) int meow_img_pick_scale(int longside, int maxdim)
{ {
int s = 1; int s = 1;
while (s < 8 && (longside / (s * 2)) >= maxdim) s *= 2; while (s < 8 && (longside / (s * 2)) >= maxdim) s *= 2;
@@ -79,25 +80,107 @@ meow_img *meow_img_load_file_dim(const char *path, int maxdim)
{ {
if (!path) return NULL; if (!path) return NULL;
if (maxdim <= 0) return meow_img_load_file(path); /* 不限尺寸 = 旧入口 */ if (maxdim <= 0) return meow_img_load_file(path); /* 不限尺寸 = 旧入口 */
/* 追加(M23):真缩解后端直接产出目标尺寸(JPEG 按 DCT 档位;PNG 逐行 inflate 丢行丢列;
* BMP 按行 seek 跳采样)。峰值只与输出尺寸相关。
* 不支持/失败/几乎等尺寸(4 分量 CMYK、算术编码、交错 PNG、RLE BMP、小图…)返回 0 →
* 落回下面的 stb 旧路径,对外语义与档位表现不变。 */
{
unsigned char *bp = NULL;
int bw = 0, bh = 0;
if (meow_img_backend_file(path, maxdim, &bw, &bh, &bp) && bp)
return img_finish_dim(bp, bw, bh, maxdim);
}
int w = 0, h = 0, c = 0; int w = 0, h = 0, c = 0;
if (!stbi_info(path, &w, &h, &c)) return NULL; if (!stbi_info(path, &w, &h, &c)) return NULL;
int longside = w > h ? w : h; int longside = w > h ? w : h;
if (longside <= maxdim) return meow_img_load_file(path); /* 小图不动:旧路径 */ if (longside <= maxdim) return meow_img_load_file(path); /* 小图不动:旧路径 */
unsigned char *p = stbi_load_scaled(path, &w, &h, &c, 4, img_pick_scale(longside, maxdim)); unsigned char *p = stbi_load_scaled(path, &w, &h, &c, 4, meow_img_pick_scale(longside, maxdim));
return img_finish_dim(p, w, h, maxdim); return img_finish_dim(p, w, h, maxdim);
} }
/* 追加(M22):档位由调用方指定。与 meow_img_load_file_dim 同语义(结果长边 ≤ maxdim,
* 超了再精修一次),只是档位不再由 maxdim 反推 —— 内存预算紧时可选更粗的档位。
* M27:真缩解后端优先(step 折算成目标长边 ceil(长边/step),后端按该长边选 DCT 阶,
* 峰值只与输出尺寸相关);后端不支持时回退 stbi_load_scaled(step),语义与 M22 一致。
*
* M27 r1(P1-1):allow_stb_fallback=0 时只尝试后端,**绝不回退 stb**——阅读器的门控按
* 「后端峰值」放行时必须走这里,否则「头部说支持、解码中途失败」会静默落到 stb,
* 实测可放出 18–36MB(截断 12MP JPEG / 头-only BMP / 非法位深 PNG),即 M22 的 SIGKILL 场景。
* 后端失败返回 NULL(调用方按坏图占位)。 */
meow_img *meow_img_load_file_step_ex(const char *path, int maxdim, int step,
int allow_stb_fallback, int *used_backend)
{
if (used_backend) *used_backend = 0;
if (!path) return NULL;
if (step <= 1 && maxdim <= 0)
return allow_stb_fallback ? meow_img_load_file(path) : NULL;
if (step <= 0) step = 1;
if (step > 8) step = 8;
int w = 0, h = 0, c = 0;
if (!stbi_info(path, &w, &h, &c)) return NULL;
int longside = w > h ? w : h;
if (step == 1 && maxdim <= 0)
return allow_stb_fallback ? meow_img_load_file(path) : NULL;
/* 追加(M23/M27):真缩解后端优先(JPEG/PNG/BMP 全部格式)。step 是「输出别比这个档位
* 更细」的提示:折算成目标长边 ceil(长边/step) 传给后端(后端按该长边自动选 DCT 阶),
* 与下面 stbi_load_scaled(step) 的语义一致,峰值只与输出尺寸相关;maxdim<=0 时不精修,
* 结果仍是档位尺寸。后端不支持(CMYK/算术编码/交错/RLE…)时回退 stb,行为与 M22 一致。
* M27 起阅读器的峰值模型已与后端同口径(page_source 的 reader_estimate_peak),
* 所以 PNG/BMP 也一并接后端——这正是「修好了却用不上」的最后一处缝。 */
{
int eff = maxdim > 0 ? maxdim : longside;
int step_cap = (longside + step - 1) / step;
unsigned char *bp = NULL;
int bw = 0, bh = 0;
if (step_cap > 0 && step_cap < eff) eff = step_cap;
if (eff > 0 && meow_img_backend_file(path, eff, &bw, &bh, &bp) && bp) {
if (used_backend) *used_backend = 1;
return img_finish_dim(bp, bw, bh, maxdim > 0 ? maxdim : longside);
}
}
if (!allow_stb_fallback) return NULL; /* P1-1:门控按后端放行的页,失败即坏图 */
unsigned char *p = stbi_load_scaled(path, &w, &h, &c, 4, step);
/* maxdim<=0:不精修(保留档位输出的原始尺寸)。 */
return img_finish_dim(p, w, h, maxdim > 0 ? maxdim : longside);
}
meow_img *meow_img_load_file_step(const char *path, int maxdim, int step)
{
/* 通用入口保持 M22 语义:后端失败允许回退 stb。 */
return meow_img_load_file_step_ex(path, maxdim, step, 1, NULL);
}
/* 追加(M22):精确重采样到目标尺寸(最近邻,双向)。阅读器把缩解档位的结果一次性
* 落到显示框,之后命中页就是单次原生 blit(M17 的热路径纪律不被粗档位破坏)。 */
static unsigned char *scale_buf(const meow_img *im, int dw, int dh, int cover);
meow_img *meow_img_resample(meow_img *im, int w, int h)
{
if (!im || w <= 0 || h <= 0) return NULL;
if (im->w == w && im->h == h) return NULL;
unsigned char *tmp = scale_buf(im, w, h, 0);
if (!tmp) return NULL;
return img_alloc(w, h, tmp);
}
meow_img *meow_img_load_mem_dim(const void *buf, int len, int maxdim) meow_img *meow_img_load_mem_dim(const void *buf, int len, int maxdim)
{ {
if (!buf || len <= 0) return NULL; if (!buf || len <= 0) return NULL;
if (maxdim <= 0) return meow_img_load_mem(buf, len); if (maxdim <= 0) return meow_img_load_mem(buf, len);
/* 追加(M23):同文件入口,后端直接从调用方缓冲解码(不再整幅解 + 重采样)。 */
{
unsigned char *bp = NULL;
int bw = 0, bh = 0;
if (meow_img_backend_mem(buf, (size_t)len, maxdim, &bw, &bh, &bp) && bp)
return img_finish_dim(bp, bw, bh, maxdim);
}
int w = 0, h = 0, c = 0; int w = 0, h = 0, c = 0;
if (!stbi_info_from_memory((const unsigned char *)buf, len, &w, &h, &c)) return NULL; if (!stbi_info_from_memory((const unsigned char *)buf, len, &w, &h, &c)) return NULL;
int longside = w > h ? w : h; int longside = w > h ? w : h;
if (longside <= maxdim) return meow_img_load_mem(buf, len); if (longside <= maxdim) return meow_img_load_mem(buf, len);
unsigned char *p = stbi_load_scaled_from_memory((const unsigned char *)buf, len, unsigned char *p = stbi_load_scaled_from_memory((const unsigned char *)buf, len,
&w, &h, &c, 4, &w, &h, &c, 4,
img_pick_scale(longside, maxdim)); meow_img_pick_scale(longside, maxdim));
return img_finish_dim(p, w, h, maxdim); return img_finish_dim(p, w, h, maxdim);
} }
+3 -3
View File
@@ -10,10 +10,10 @@
* gcc -Wall -Wextra -o test_ime_fix test_ime_fix.c test_host_stub.c \ * gcc -Wall -Wextra -o test_ime_fix test_ime_fix.c test_host_stub.c \
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \ * meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* meow_ui_anim.c meow_ui_media.c meow_ui_nav.c meow_pinyin.c meow_ui_box.c meow_ui_scroll.c \ * meow_ui_anim.c meow_ui_media.c meow_ui_nav.c meow_pinyin.c meow_ui_box.c meow_ui_scroll.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* (meow_ui_widget.c 新 W_LISTVIEW 引用 meow_ui_img_scaled → 需链 meow_ui_img.c+stb_image.c+-lm; * (meow_ui_widget.c 新 W_LISTVIEW 引用 meow_ui_img_scaled → 需链 meow_ui_img.c+stb_image.c+-lm -lz;
* widget/input/ime/view 后续又引入 anim/media/nav/pinyin/box/scroll 依赖,一并链接) * widget/input/ime/view 后续又引入 anim/media/nav/pinyin/box/scroll 依赖,一并链接)
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+9 -7
View File
@@ -10,13 +10,15 @@
* B6 进升级:progressive JPEG 走同一缩解路径(峰值记录 + 长边约束) * B6 进升级:progressive JPEG 走同一缩解路径(峰值记录 + 长边约束)
* B7 内存入口:meow_img_load_mem_dim 与文件入口等价(峰值 < 旧内存入口 1/2) * B7 内存入口:meow_img_load_mem_dim 与文件入口等价(峰值 < 旧内存入口 1/2)
* B8 坏图:坏 JPEG(魔数+垃圾)/ 空内存 / 不存在路径 → NULL(不崩) * B8 坏图:坏 JPEG(魔数+垃圾)/ 空内存 / 不存在路径 → NULL(不崩)
* B9 PNG/BMP:尺寸约束成立,峰值如实记录(stb 无解码期缩放 → 与旧入口同级) * B9 PNG/BMP:尺寸约束成立;M23 起 PNG/BMP 也走解码期缩解(逐行 inflate / 按行 seek),
* 峰值应显著低于旧入口(本用例只断言 ≤ maxdim + 非空,并打印峰值供报告引用)
* *
* 夹具(生成一次): * 夹具(生成一次):
* python3 test_meow_img_budget_gen.py "$PREFIX/tmp/meow_img_budget" * python3 test_meow_img_budget_gen.py "$PREFIX/tmp/meow_img_budget"
* 编译(本 sdk 目录下;--wrap 用于给 malloc/free 家族打点): * 编译(本 sdk 目录下;--wrap 用于给 malloc/free 家族打点;-lz 供 PNG 后端 inflate):
* gcc -Wall -Wextra -I. -Iinclude -DMEOW_UI_HOST_TEST -o test_meow_img_budget \ * gcc -Wall -Wextra -I. -Iinclude -DMEOW_UI_HOST_TEST -o test_meow_img_budget \
* test_meow_img_budget.c meow_ui_img.c stb_image.c -lm \ * test_meow_img_budget.c meow_ui_img.c meow_jpeg.c meow_png_stream.c stb_image.c \
* -lm -lz \
* -Wl,--wrap=malloc -Wl,--wrap=calloc -Wl,--wrap=realloc -Wl,--wrap=free * -Wl,--wrap=malloc -Wl,--wrap=calloc -Wl,--wrap=realloc -Wl,--wrap=free
* 运行:./test_meow_img_budget "$PREFIX/tmp/meow_img_budget" (exit 0=PASS / 1=FAIL) * 运行:./test_meow_img_budget "$PREFIX/tmp/meow_img_budget" (exit 0=PASS / 1=FAIL)
* 夹具目录可省略:默认 $PREFIX/tmp/meow_img_budget;缺失时自动调 gen 脚本生成。 * 夹具目录可省略:默认 $PREFIX/tmp/meow_img_budget;缺失时自动调 gen 脚本生成。
@@ -421,8 +423,8 @@ int main(int argc, char **argv)
CHECK(meow_img_load_mem_dim("x", 3, 480) == NULL, "垃圾内存 → NULL"); CHECK(meow_img_load_mem_dim("x", 3, 480) == NULL, "垃圾内存 → NULL");
} }
/* ---- B9 PNG / BMP(stb 无解码期缩放,如实记录峰值) ---- */ /* ---- B9 PNG / BMP(M23 起也走解码期缩解;只断言尺寸/非空,峰值打印) ---- */
printf("[B9] PNG / BMP:尺寸约束成立,峰值如实记录(stb 无解码期缩放)\n"); printf("[B9] PNG / BMP:尺寸约束成立,峰值记录(M23 逐行/跳行缩解,应远低于旧入口)\n");
{ {
struct { const char *tag; const char *path; } fx[] = { struct { const char *tag; const char *path; } fx[] = {
{ "PNG", p_png }, { "BMP", p_bmp }, { "PNG", p_png }, { "BMP", p_bmp },
@@ -446,8 +448,8 @@ int main(int argc, char **argv)
CHECK(nw && meow_img_w(nw) <= 480 && meow_img_h(nw) <= 480 && nonblank(nw), name); CHECK(nw && meow_img_w(nw) <= 480 && meow_img_h(nw) <= 480 && nonblank(nw), name);
peak_report(fx[i].tag, p_old); peak_report(fx[i].tag, p_old);
peak_report(" ↑ 新入口", p_new); peak_report(" ↑ 新入口", p_new);
snprintf(name, sizeof name, "%s 峰值与旧入口同级(stb 无解码期缩放)", fx[i].tag); snprintf(name, sizeof name, "%s 新入口峰值 ≤ 旧入口(不再整幅物化)", fx[i].tag);
CHECK(p_new <= p_old + p_old / 8, name); CHECK(p_new <= p_old, name);
if (old) printf(" %s 原图 %dx%d\n", fx[i].tag, meow_img_w(old), meow_img_h(old)); if (old) printf(" %s 原图 %dx%d\n", fx[i].tag, meow_img_w(old), meow_img_h(old));
meow_img_free(nw); meow_img_free(nw);
} }
+2 -2
View File
@@ -16,8 +16,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_img_color * 运行:./test_meow_img_color
*/ */
#include "meow_ui.h" #include "meow_ui.h"
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -8,8 +8,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_lyric_view * 运行:./test_meow_lyric_view
* *
* 覆盖矩阵(对齐任务批2:活动行纯白/灰阶、翻译行占位不叠行、偏上锚定、折行中西文、点行 seek 命中、 * 覆盖矩阵(对齐任务批2:活动行纯白/灰阶、翻译行占位不叠行、偏上锚定、折行中西文、点行 seek 命中、
+2 -2
View File
@@ -9,8 +9,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_md3 * 运行:./test_meow_md3
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -7,8 +7,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_anim * 运行:./test_meow_ui_anim
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -7,8 +7,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_box * 运行:./test_meow_ui_box
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -16,8 +16,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_dispatch (无设备,纯宿主) * 运行:./test_meow_ui_dispatch (无设备,纯宿主)
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -19,8 +19,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_home_gesture * 运行:./test_meow_ui_home_gesture
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -12,8 +12,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_iconbtn * 运行:./test_meow_ui_iconbtn
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -11,8 +11,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_lazygrid.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_lazygrid.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_lazygrid * 运行:./test_meow_ui_lazygrid
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -20,8 +20,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_ui_nav.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c meow_ui_nav.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz \
* -Wl,--wrap=meow_ui_text_height * -Wl,--wrap=meow_ui_text_height
* 运行:./test_meow_ui_listview_rowh * 运行:./test_meow_ui_listview_rowh
*/ */
+2 -2
View File
@@ -13,8 +13,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_listvirt * 运行:./test_meow_ui_listvirt
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -7,8 +7,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_ui_nav.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c meow_ui_nav.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_scroll * 运行:./test_meow_ui_scroll
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -9,8 +9,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_select.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_select.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_select * 运行:./test_meow_ui_select
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -11,8 +11,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_swipe * 运行:./test_meow_ui_swipe
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -10,8 +10,8 @@
* gcc -o test_meow_ui_theme test_meow_ui_theme.c test_host_stub.c \ * gcc -o test_meow_ui_theme test_meow_ui_theme.c test_host_stub.c \
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \ * meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* *
* 验证要点:四套主题 primary/radius 各不相同(MD3 蓝 / MIUIx 橙 + 更大圆角), * 验证要点:四套主题 primary/radius 各不相同(MD3 蓝 / MIUIx 橙 + 更大圆角),
* 同 style 下 light/dark 的 surface 成对切换;图形用 MEOW_UI_DUMP 导出 PPM 目检。 * 同 style 下 light/dark 的 surface 成对切换;图形用 MEOW_UI_DUMP 导出 PPM 目检。
+2 -2
View File
@@ -14,8 +14,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_theme_export * 运行:./test_meow_ui_theme_export
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -11,8 +11,8 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:./test_meow_ui_view_event * 运行:./test_meow_ui_view_event
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+3 -3
View File
@@ -5,11 +5,11 @@
* gcc -o test_meow_ui_widgets test_meow_ui_widgets.c test_host_stub.c \ * gcc -o test_meow_ui_widgets test_meow_ui_widgets.c test_host_stub.c \
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \ * meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
* 运行:MEOW_UI_DUMP=/tmp/b2.ppm ./test_meow_ui_widgets (可选,dump 屏幕) * 运行:MEOW_UI_DUMP=/tmp/b2.ppm ./test_meow_ui_widgets (可选,dump 屏幕)
* *
* 注:W_LISTVIEW 的 MEOW_LIST_ICON_IMG 分支调用 meow_ui_img_scaled → 宿主链 meow_ui_img.c+stb_image.c+-lm。 * 注:W_LISTVIEW 的 MEOW_LIST_ICON_IMG 分支调用 meow_ui_img_scaled → 宿主链 meow_ui_img.c+stb_image.c+-lm -lz。
* 结构化列表断言用 back_buf 像素(region_has/px_near),画完即读,非目检。 * 结构化列表断言用 back_buf 像素(region_has/px_near),画完即读,非目检。
*/ */
#include "meow_ui.h" #include "meow_ui.h"
+2 -2
View File
@@ -25,11 +25,11 @@
* test_host_stub.c meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * test_host_stub.c meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_ui_img.c meow_ui_config.c meow_ui_notify.c meow_notify_ipc.c meow_ui_draw.c \ * meow_ui_img.c meow_ui_config.c meow_ui_notify.c meow_notify_ipc.c meow_ui_draw.c \
* meow_ui_view.c meow_ui_nav.c meow_ui_media.c stb_image.c \ * meow_ui_view.c meow_ui_nav.c meow_ui_media.c stb_image.c meow_jpeg.c meow_png_stream.c \
* ../hello_app/ui/home/home.c ../hello_app/ui/full.c ../hello_app/ui/demo/demo.c \ * ../hello_app/ui/home/home.c ../hello_app/ui/full.c ../hello_app/ui/demo/demo.c \
* ../hello_app/ui/demo/list/list.c ../hello_app/ui/common/chrome.c \ * ../hello_app/ui/demo/list/list.c ../hello_app/ui/common/chrome.c \
* ../hello_app/logic/notify.c ../hello_app/logic/state.c \ * ../hello_app/logic/notify.c ../hello_app/logic/state.c \
* -I. -I../hello_app -I../meow_launcherd -pthread -lm * -I. -I../hello_app -I../meow_launcherd -pthread -lm -lz
* 运行:MEOW_UI_DUMP=/tmp/repro.ppm ./test_p1p2p3_repro (optional,dump 最终屏幕) * 运行:MEOW_UI_DUMP=/tmp/repro.ppm ./test_p1p2p3_repro (optional,dump 最终屏幕)
* *
* 预期 RESULT: ALL PASS(P1c/P2/P3 断言真实有效,未弱化)。 * 预期 RESULT: ALL PASS(P1c/P2/P3 断言真实有效,未弱化)。
+1 -1
View File
@@ -11,7 +11,7 @@
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_ui_media.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_ui_media.c \
* meow_notify_ipc.c stb_image.c -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
*/ */
#include "meow_ui.h" #include "meow_ui.h"
#include "meow_ui_internal.h" #include "meow_ui_internal.h"