公开 SDK 落后主仓的一批 bugfix(主仓是固件构建源,这些修复已在设备上跑过)。 本次只做「主仓 → 公开仓」单向同步,图像栈方向由主仓侧另一单处理。 时钟 ABI(M16 第二弹,原文件自认「残余未修」): - meow_ui_time.c 147→345 行:futex 相对超时接管(__timedwait/_cp)、 timerfd_create/settime/gettime 的 itimerspec 64↔32 双向转换、 __clock_settime64 越界返 ENOTSUP,另有 4 个纯换算函数 - meow_ui_internal.h:struct meow_time32 / meow_itimerspec32 契约移入内部头 - CLOCK_ABI.md:补接管机制、验证配方与 objdump 证据 - 新增 test_meow_time64.c IME bug3(成对才有意义): - meow_ui_ime.c:IME_TAP_COOLDOWN_MS 200 冷却窗 + 打开时二次 drain - meow_ui_input.c:meow_input_touch_reset() 并在 drain 内调用(复位触摸状态机) - test_ime_fix.c:新增用例④ stray-tap 列表行高(M15,修用户可见 bug): - meow_ui_widget.c:listv_item_h() 由主题字体行高派生,不再写死 56 (两行列表 62 > 56 会让首行标题被裁剪守卫整条跳过) - include/meow_ui_widgets.h:新增 meow_listview_item_h() - 新增 test_meow_ui_listview_rowh.c 其余:meow_select.c / meow_ui_dialog.c 统一 MD3 形状 token; include/meow_ipc.h 补 MSG_KEY_PAGEUP/PAGEDOWN 枚举; meow_ui_sys.c / meow_cachegov.c 取时统一走 meow_ui_time_ms()。 测试辅助函数标定:tuku/test/test_settings_lock_host.c 的注入前等待 150ms→350ms。 该等待按修复前 IME 标定,新冷却窗下首键 dt_open≈114ms 会被当迟到抬起吞掉, 只录到 "68" 两位。仅改等待时长,断言原样保留。 验证:tuku 四套脚本全绿(run_tests 644 PASS / zip 106 / cbz 296 / webtoon PASS); 12 个源文件与主仓逐字节一致;sdk/build_sdk.sh 34 成员; tuku/build_tuku.sh 产出静态 MIPS32r2 ELF。
232 lines
10 KiB
C
232 lines
10 KiB
C
/* test_meow_ui_box.c — §12.1 meow_box 线性布局引擎宿主验证:
|
||
* 布局求解矩阵(固定/weight/wrap/嵌套/对齐)、margin/padding/gap、交叉轴对齐、view 集成。
|
||
* 纯逻辑(只创控件 + arrange + 断言矩形),不依赖 /dev/fb0/字库;不绘制。
|
||
*
|
||
* 编译(宿主 gcc,链真实 widget/draw/activity/theme/gfx + 打桩 font/global):
|
||
* gcc -o test_meow_ui_box test_meow_ui_box.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_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 \
|
||
* -I. -Iinclude -DMEOW_UI_HOST_TEST -pthread -lm
|
||
* 运行:./test_meow_ui_box
|
||
*/
|
||
#include "meow_ui.h"
|
||
#include "meow_ui_internal.h" /* meow_widget_rect:真实几何断言 */
|
||
#include "meow_ui_view.h"
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
static int g_pass = 0, g_fail = 0;
|
||
#define CHECK(cond, ...) do { \
|
||
if (cond) { g_pass++; } \
|
||
else { g_fail++; printf("FAIL %s:%d ", __FILE__, __LINE__); printf(__VA_ARGS__); printf("\n"); } \
|
||
} while (0)
|
||
|
||
static void wr(meow_widget *w, int out[4]) { meow_widget_rect(w, out); }
|
||
static void boxr(meow_box *b, int out[4]) { meow_box_rect(b, out); }
|
||
|
||
/* 创建固定尺寸按钮(既有无绝对定位;注册到绘制物注册表即可) */
|
||
static meow_widget *mk(int w, int h)
|
||
{
|
||
meow_widget *b = meow_btn_create(0, 0, w, h, "X");
|
||
return b;
|
||
}
|
||
|
||
/* ---- 竖直列:固定 + padding + gap + CROSS_START ---- */
|
||
static void test_col_fixed(void)
|
||
{
|
||
meow_box *bx = meow_box_new(MEOW_BOX_V);
|
||
CHECK(bx != NULL, "box_new V");
|
||
meow_box_set_rect(bx, 0, 0, 480, 720);
|
||
meow_box_set_padding(bx, 20, 20, 20, 20);
|
||
meow_box_set_gap(bx, 10);
|
||
meow_box_set_align(bx, MEOW_BOX_ALIGN_START, MEOW_BOX_CROSS_START);
|
||
meow_widget *a = mk(100, 50), *b = mk(120, 50), *c = mk(80, 50);
|
||
CHECK(meow_box_add(bx, a, MEOW_BOX_FIXED, 0) == 0, "add a");
|
||
CHECK(meow_box_add(bx, b, MEOW_BOX_FIXED, 0) == 0, "add b");
|
||
CHECK(meow_box_add(bx, c, MEOW_BOX_FIXED, 0) == 0, "add c");
|
||
CHECK(meow_box_count(bx) == 3, "count");
|
||
meow_box_arrange(bx);
|
||
int r[4];
|
||
wr(a, r); CHECK(r[0] == 20 && r[1] == 20 && r[2] == 100 && r[3] == 50, "A x=20 y=20 w100 h50 got %d,%d,%d,%d", r[0], r[1], r[2], r[3]);
|
||
wr(b, r); CHECK(r[0] == 20 && r[1] == 80 && r[2] == 120, "B y=80 got %d,%d,%d,%d", r[0], r[1], r[2], r[3]);
|
||
wr(c, r); CHECK(r[0] == 20 && r[1] == 140 && r[2] == 80, "C y=140 got %d,%d,%d,%d", r[0], r[1], r[2], r[3]);
|
||
meow_box_free(bx);
|
||
}
|
||
|
||
/* ---- 横向行:END 对齐 + 交叉轴中心 ---- */
|
||
static void test_row_end_center(void)
|
||
{
|
||
meow_box *bx = meow_box_new(MEOW_BOX_H);
|
||
meow_box_set_rect(bx, 10, 0, 480, 200);
|
||
meow_box_set_padding(bx, 10, 10, 10, 10);
|
||
meow_box_set_gap(bx, 5);
|
||
meow_box_set_align(bx, MEOW_BOX_ALIGN_END, MEOW_BOX_CROSS_CENTER);
|
||
meow_widget *a = mk(100, 50), *b = mk(100, 50), *c = mk(100, 50);
|
||
CHECK(meow_box_add(bx, a, MEOW_BOX_FIXED, 0) == 0, "add");
|
||
CHECK(meow_box_add(bx, b, MEOW_BOX_FIXED, 0) == 0, "addb");
|
||
CHECK(meow_box_add(bx, c, MEOW_BOX_FIXED, 0) == 0, "addc");
|
||
meow_box_arrange(bx);
|
||
/* 内容区 x∈[20,470] cw=460;foot=100*3+5*2=310;leftover=150;END → off0=150 */
|
||
int r[4];
|
||
wr(a, r);
|
||
CHECK(r[0] == 20 + 150, "END first x=170 got %d", r[0]);
|
||
/* 交叉轴中心:cy=10(pad_t);cross_size=ch=180,cross_base=50 → pad=130 → cross=65 → y=10+65=75 */
|
||
CHECK(r[1] == 75 && r[3] == 50, "center y=75 got %d,%d", r[1], r[3]);
|
||
wr(b, r); CHECK(r[0] == 20 + 150 + 100 + 5, "END second x=%d", r[0]);
|
||
wr(c, r); CHECK(r[0] == 380, "END third x=380 got %d", r[0]); /* 170+100+5+100+5+? = 380 */
|
||
meow_box_free(bx);
|
||
}
|
||
|
||
/* ---- weight 均分:竖直,两个 weight 1:3 ---- */
|
||
static void test_weight(void)
|
||
{
|
||
meow_box *bx = meow_box_new(MEOW_BOX_H);
|
||
meow_box_set_rect(bx, 0, 0, 480, 200);
|
||
/* 内容区 480 宽(无 pad/gap)。child 固定 80 + 两个权重 1:3 */
|
||
meow_widget *fixed = mk(80, 200), *w1 = mk(0, 200), *w2 = mk(0, 200);
|
||
CHECK(meow_box_add(bx, fixed, MEOW_BOX_FIXED, 0) == 0, "fixed");
|
||
CHECK(meow_box_add(bx, w1, MEOW_BOX_WEIGHT, 1) == 0, "w1");
|
||
CHECK(meow_box_add(bx, w2, MEOW_BOX_WEIGHT, 3) == 0, "w2");
|
||
meow_box_arrange(bx);
|
||
/* leftover = 480 - 80 = 400;w1=100, w2=300 */
|
||
int r[4];
|
||
wr(fixed, r); CHECK(r[0] == 0 && r[2] == 80, "fixed x=0 w80 got %d,%d", r[0], r[2]);
|
||
wr(w1, r); CHECK(r[0] == 80 && r[2] == 100, "w1 x=80 w100 got %d,%d", r[0], r[2]);
|
||
wr(w2, r); CHECK(r[0] == 180 && r[2] == 300, "w2 x=180 w300 got %d,%d", r[0], r[2]);
|
||
meow_box_free(bx);
|
||
}
|
||
|
||
/* ---- WRAP 内容测量(measure 回调给 min/preferred) ---- */
|
||
static void wrap_measure(void *ctx, int *mn, int *pf) { (void)ctx; *mn = 40; *pf = 120; }
|
||
static void test_wrap(void)
|
||
{
|
||
meow_box *bx = meow_box_new(MEOW_BOX_H);
|
||
meow_box_set_rect(bx, 0, 0, 480, 100);
|
||
meow_box_set_gap(bx, 10);
|
||
meow_box_set_align(bx, MEOW_BOX_ALIGN_START, MEOW_BOX_CROSS_START);
|
||
meow_widget *w = mk(5, 40); /* 尺寸无关,wrap 用 measure */
|
||
CHECK(meow_box_add_ex(bx, w, MEOW_BOX_WRAP, 0, 40, 120, wrap_measure, NULL) == 0, "wrap-add");
|
||
meow_box_arrange(bx);
|
||
int r[4]; wr(w, r);
|
||
/* wrap 主轴向 preferred=120;cross_start 交叉=40(widget h 落 V=40?这是 H box,交叉=h) */
|
||
CHECK(r[2] == 120, "wrap pref w=120 got %d", r[2]);
|
||
meow_box_free(bx);
|
||
}
|
||
|
||
/* ---- 嵌套:Row 内嵌 Column ---- */
|
||
static void test_nested(void)
|
||
{
|
||
meow_box *row = meow_box_new(MEOW_BOX_H);
|
||
meow_box *col = meow_box_new(MEOW_BOX_V);
|
||
meow_box_set_rect(row, 0, 0, 480, 200);
|
||
meow_box_set_rect(col, 0, 0, 200, 200);
|
||
meow_box_set_gap(row, 10);
|
||
meow_widget *a = mk(100, 50), *b = mk(100, 50), *c = mk(100, 50);
|
||
meow_box_add(row, a, MEOW_BOX_FIXED, 0);
|
||
meow_box_add_sub(row, col, MEOW_BOX_FIXED, 0);
|
||
CHECK(meow_box_add_sub(row, col, MEOW_BOX_FIXED, 0) < 0, "sub dedupe");
|
||
meow_box_add(col, b, MEOW_BOX_FIXED, 0);
|
||
meow_box_add(col, c, MEOW_BOX_FIXED, 0);
|
||
meow_box_arrange(row);
|
||
int r[4];
|
||
wr(a, r); CHECK(r[0] == 0 && r[2] == 100, "row a x0 w100 got %d,%d", r[0], r[2]);
|
||
int cr[4]; boxr(col, cr); CHECK(cr[0] == 110 && cr[1] == 0 && cr[2] == 200, "sub box x=110 got %d", cr[0]);
|
||
/* col 内 b,c 纵向:y 0,50(col y=0, gap0, cross_start) */
|
||
meow_widget_rect(b, r); CHECK(r[0] == 110 && r[1] == 0, "col b y0 got %d", r[1]);
|
||
meow_widget_rect(c, r); CHECK(r[1] == 50, "col c y50 got %d", r[1]);
|
||
meow_box_free(row); meow_box_free(col);
|
||
}
|
||
|
||
/* ---- margin(widget opts)+ 交叉轴 STRETCH ---- */
|
||
static void test_margin_stretch(void)
|
||
{
|
||
meow_box *bx = meow_box_new(MEOW_BOX_V);
|
||
meow_box_set_rect(bx, 0, 0, 480, 300);
|
||
meow_box_set_align(bx, MEOW_BOX_ALIGN_START, MEOW_BOX_CROSS_STRETCH);
|
||
meow_widget *a = mk(100, 60);
|
||
meow_widget_opts o; memset(&o, 0, sizeof o);
|
||
o.margin_x = 30; o.margin_y = 10;
|
||
CHECK(meow_widget_set_opts(a, &o) == 0, "set opts");
|
||
meow_box_add(bx, a, MEOW_BOX_FIXED, 0);
|
||
meow_box_arrange(bx);
|
||
int r[4]; wr(a, r);
|
||
/* V:交叉轴=x,STRETCH → w = cw - 2*margin_x = 480 - 60 = 420;x = margin_x = 30。
|
||
* 主轴 y:lead=margin_y=10 → y=10;ext=h=60。 */
|
||
CHECK(r[0] == 30 && r[2] == 420, "stretch w=420 x=30 got %d,%d", r[0], r[2]);
|
||
CHECK(r[1] == 10 && r[3] == 60, "y=10 h=60 got %d,%d", r[1], r[3]);
|
||
meow_box_free(bx);
|
||
}
|
||
|
||
/* ---- SPACE_BETWEEN ---- */
|
||
static void test_space_between(void)
|
||
{
|
||
meow_box *bx = meow_box_new(MEOW_BOX_H);
|
||
meow_box_set_rect(bx, 0, 0, 500, 100);
|
||
meow_box_set_align(bx, MEOW_BOX_ALIGN_SPACE_BETWEEN, MEOW_BOX_CROSS_START);
|
||
meow_widget *a = mk(100, 50), *b = mk(100, 50), *c = mk(100, 50);
|
||
meow_box_add(bx, a, MEOW_BOX_FIXED, 0);
|
||
meow_box_add(bx, b, MEOW_BOX_FIXED, 0);
|
||
meow_box_add(bx, c, MEOW_BOX_FIXED, 0);
|
||
meow_box_arrange(bx);
|
||
/* cw=500;foot=300;leftover=200;n-1=2 → 每 gap += 100 → A.x=0 B.x=200 C.x=400 */
|
||
int r[4];
|
||
wr(a, r); CHECK(r[0] == 0, "sb A x0 got %d", r[0]);
|
||
wr(b, r); CHECK(r[0] == 200, "sb B x200 got %d", r[0]);
|
||
wr(c, r); CHECK(r[0] == 400, "sb C x400 got %d", r[0]);
|
||
meow_box_free(bx);
|
||
}
|
||
|
||
/* ---- view 集成:meow_view_set_layout + relayout ---- */
|
||
static void test_view_layout(void)
|
||
{
|
||
meow_view *v = meow_view_create(900, MEOW_VIEW_ACTIVITY, NULL, NULL);
|
||
CHECK(v != NULL, "view create");
|
||
v->x = 0; v->y = 0; v->w = 480; v->h = 720;
|
||
meow_box *bx = meow_box_new(MEOW_BOX_V);
|
||
meow_box_set_gap(bx, 8);
|
||
meow_box_set_align(bx, MEOW_BOX_ALIGN_START, MEOW_BOX_CROSS_START);
|
||
meow_widget *a = mk(300, 50), *b = mk(300, 50);
|
||
meow_box_add(bx, a, MEOW_BOX_FIXED, 0);
|
||
meow_box_add(bx, b, MEOW_BOX_FIXED, 0);
|
||
meow_view_add_widget(v, a);
|
||
meow_view_add_widget(v, b);
|
||
meow_view_set_layout(v, bx); /* relayout 立即排一次 */
|
||
int r[4];
|
||
wr(a, r); CHECK(r[0] == 0 && r[1] == 0 && r[2] == 300, "view a x0 y0 w300 got %d,%d,%d", r[0], r[1], r[2]);
|
||
wr(b, r); CHECK(r[1] == 58, "view b y=58 got %d", r[1]); /* 0 + 50 + gap8 */
|
||
meow_view_free(v);
|
||
meow_box_free(bx);
|
||
}
|
||
|
||
/* ---- 越界去重 / 池满 ---- */
|
||
static void test_edge(void)
|
||
{
|
||
meow_box *bx = meow_box_new(MEOW_BOX_H);
|
||
meow_widget *a = mk(10, 10), *dup = mk(10, 10);
|
||
CHECK(meow_box_add(bx, dup, MEOW_BOX_FIXED, 0) == 0, "add dup");
|
||
CHECK(meow_box_add(bx, dup, MEOW_BOX_FIXED, 0) < 0, "dedupe");
|
||
CHECK(meow_box_add(bx, NULL, MEOW_BOX_FIXED, 0) < 0, "null add rejected");
|
||
meow_box_widget_at(bx, 0) ? 0 : 0;
|
||
CHECK(meow_box_widget_at(bx, 0) == dup, "widget_at 0");
|
||
CHECK(meow_box_sub_at(bx, 0) == NULL, "sub_at null");
|
||
meow_box_free(bx);
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
test_col_fixed();
|
||
test_row_end_center();
|
||
test_weight();
|
||
test_wrap();
|
||
test_nested();
|
||
test_margin_stretch();
|
||
test_space_between();
|
||
test_view_layout();
|
||
test_edge();
|
||
printf("box: %d pass / %d fail\n", g_pass, g_fail);
|
||
return g_fail ? 1 : 0;
|
||
}
|