Files
MeowOS-For-R3P2/patch_v2/sdk/test_meow_ui_scroll.c
T
AskaEth 38be5e78bc fix(sdk): 时钟 ABI 根因修复 — meow_ui_time 按 o32 time32 取时并链接期接管
真机 meow_ui_time_ms() 返回「低 32=秒×1000、高 32 随机」的根因不是 SDK 写法,
而是 zig 0.17 自带 musl 在 mipsel 上的 time64 ABI 自相矛盾:
- zig 头(mips-linux-musl/bits/alltypes.h)无条件 64 位 time_t、struct timespec 16 字节;
- zig 的 clang 给 32 位 mips 预定义 __ILP32__,musl 的 time64 回退分支
  `#if defined(SYS_x_time64) && !defined(__ILP32__)`(本意只排除 x32)被编译掉;
- 于是 libc 的 __clock_gettime64 实为 o32 time32 实现(SYS_clock_gettime 4263),
  只写 8 字节 {int32 sec; int32 nsec},与头的 16 字节布局错配。

修复(patch_v2/sdk/meow_ui_time.c):
- meow_ui_time_ms() 直接按内核 o32 ABI 取 8 字节 time32,再升 64 位毫秒;
- 同 TU 强定义 __clock_gettime/__clock_gettime64(归档先于 -lc,链接期接管,
  time()/gettimeofday()/pthread 定时等待的内部取时随之修正);
- 同源缺陷一并修:__nanosleep_time64/__clock_nanosleep(_time64) 转换 time32 后重发
  (修复前 usleep(16000) 等亚秒睡眠立即返回、变忙等空转);
- gfx/sys/input/cachegov 四处重复 now_ms 收敛到 meow_ui_time_ms;
- build_sdk.sh OBJS 增加 meow_ui_time;新增 test_meow_time 宿主单测、
  tools/clock_abi_probe.c 探针、CLOCK_ABI.md 根因/验证/影响面文档;
- 26 个宿主测试的编译注释补 meow_ui_time.c(cachegov 测试补时钟源)。

验证:宿主单测 PASS;anim(32)/view_event 宿主用例全过;build_sdk_host.sh --verify
76 成员全 MIPS32r2、0 warning;探针链接后无 libc cgt_init/__vdsosym,
__time64/__timedwait_cp 的取时指向本 TU,睡眠走 4166/4265 且用本地 8 字节结构。
2026-11-05 13:41:52 +08:00

185 lines
6.6 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.
/* test_meow_ui_scroll.c — §12.3 meow_scroll 滚动物理宿主验证:
* 跟手拖动(track 跟随与 clamp)、速度跟踪→松手 fling(位移序列/停止位置/单调/不越界)、
* 边界过冲 clamp + 简单回弹、snap。时间推进用真实 usleep(meow_anim_tick 驱动 fling)。
*
* 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/draw/activity/ime + 打桩 font/global):
* gcc -o test_meow_ui_scroll test_meow_ui_scroll.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 \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
* 运行:./test_meow_ui_scroll
*/
#include "meow_ui.h"
#include "meow_ui_internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.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)
#define LIST_H 400
#define ITEM_H 44
#define COUNT 50
/* max_scroll = COUNT*ITEM_H - LIST_H = 2200 - 400 = 1800 */
#define MAXS (COUNT * ITEM_H - LIST_H)
static int src(int idx, char *label, int len, void *ctx)
{
(void)ctx;
if (idx < 0 || idx >= COUNT) return 0;
snprintf(label, (size_t)len, "row %d", idx);
return 1;
}
static meow_widget *make_list(void)
{
meow_widget *lv = meow_list_create(0, 0, 480, LIST_H, COUNT, src, NULL);
meow_list_set_item_h(lv, ITEM_H);
return lv;
}
/* 喂一串向下(正)速度采样,模拟快速下划 */
static void feed_drag(meow_scroll *s, int step, int n)
{
uint64_t now = meow_ui_time_ms();
for (int i = 0; i < n; i++) {
meow_scroll_track(s, step, now + (uint64_t)i * 16);
}
/* 最后用一个真实稍晚时刻的 track 让采样时间戳真实(保持一致钟) */
meow_scroll_track(s, 0, meow_ui_time_ms());
}
static void pump_until_idle(meow_scroll *s, int *max_off, int *mono_ok)
{
int prev = meow_scroll_offset(s);
int guard = 0;
while (meow_scroll_active(s) && guard++ < 300) {
meow_anim_tick();
int cur = meow_scroll_offset(s);
if (*max_off < cur) *max_off = cur;
if (cur < prev) *mono_ok = 0; /* 下划 fling 应单调不减(回弹段除外:此处只测无回弹) */
prev = cur;
usleep(10000);
}
meow_anim_tick();
}
static void test_track_follow(void)
{
meow_widget *lv = make_list();
meow_scroll *s = meow_scroll_wrap(lv, 0);
CHECK(s != NULL, "wrap");
CHECK(meow_scroll_offset(s) == 0, "init offset 0");
meow_scroll_track(s, 10, meow_ui_time_ms());
CHECK(meow_scroll_offset(s) == 10, "follow +10 got %d", meow_scroll_offset(s));
/* 超量拖到底:clamp 到 max */
meow_scroll_track(s, 100000, meow_ui_time_ms());
CHECK(meow_scroll_offset(s) == MAXS, "clamp to max got %d", meow_scroll_offset(s));
meow_scroll_free(s);
meow_widget_free(lv);
}
static void test_fling_no_boundary(void)
{
meow_widget *lv = make_list();
meow_scroll *s = meow_scroll_wrap(lv, 0);
/* 从 0 起拖 ~300px,建正初速 */
uint64_t t = meow_ui_time_ms();
for (int i = 0; i < 12; i++) meow_scroll_track(s, 25, t + (uint64_t)i * 16);
int start = meow_scroll_offset(s);
CHECK(start > 0, "dragged start>0 got %d", start);
meow_scroll_fling(s);
CHECK(meow_scroll_active(s) == 1, "fling active");
int max_off = start, mono = 1, prev = start;
int guard = 0;
while (meow_scroll_active(s) && guard++ < 300) {
meow_anim_tick();
int cur = meow_scroll_offset(s);
if (max_off < cur) max_off = cur;
if (cur < prev) mono = 0;
prev = cur;
usleep(10000);
}
meow_anim_tick();
int end = meow_scroll_offset(s);
CHECK(mono == 1, "monotonic non-decreasing during fling");
CHECK(end >= start, "fling advances end=%d start=%d", end, start);
CHECK(end <= MAXS, "no overflow end=%d max=%d", end, MAXS);
CHECK(meow_scroll_active(s) == 0, "settles idle");
meow_scroll_free(s);
meow_widget_free(lv);
}
static void test_fling_boundary_bounce(void)
{
meow_widget *lv = make_list();
meow_scroll *s = meow_scroll_wrap(lv, 0);
/* 先拖到近底(~1700) */
meow_list_set_scroll(lv, 1700);
/* 快速下划,冲过底界 */
uint64_t t = meow_ui_time_ms();
for (int i = 0; i < 8; i++) meow_scroll_track(s, 40, t + (uint64_t)i * 16);
meow_scroll_fling(s);
int max_off = 0, mono = 1;
pump_until_idle(s, &max_off, &mono);
int end = meow_scroll_offset(s);
CHECK(max_off <= MAXS, "never exceed max, max_off=%d max=%d", max_off, MAXS);
CHECK(end == MAXS, "bounce settles at bottom end=%d", end); /* 回弹后回到底 */
CHECK(meow_scroll_active(s) == 0, "idle after bounce");
meow_scroll_free(s);
meow_widget_free(lv);
}
static void test_snap(void)
{
meow_widget *lv = make_list();
meow_scroll *s = meow_scroll_wrap(lv, 0);
meow_scroll_set_snap(s, ITEM_H); /* 吸附到行边界 */
/* 慢拖到某非边界位置并给 small velocity → fling 结束 snap 到行倍数 */
uint64_t t = meow_ui_time_ms();
for (int i = 0; i < 6; i++) meow_scroll_track(s, 20, t + (uint64_t)i * 16);
meow_scroll_fling(s);
int max_off = 0, mono = 1;
pump_until_idle(s, &max_off, &mono);
int end = meow_scroll_offset(s);
CHECK((end % ITEM_H) == 0, "snap to item multiple got %d", end);
CHECK(end <= MAXS, "snap in range %d", end);
meow_scroll_free(s);
meow_widget_free(lv);
}
static void test_stop(void)
{
meow_widget *lv = make_list();
meow_scroll *s = meow_scroll_wrap(lv, 0);
uint64_t t = meow_ui_time_ms();
for (int i = 0; i < 6; i++) meow_scroll_track(s, 20, t + (uint64_t)i * 16);
meow_scroll_fling(s);
CHECK(meow_scroll_active(s) == 1, "fling active (stop test)");
meow_scroll_stop(s);
CHECK(meow_scroll_active(s) == 0, "stopped immediately");
meow_scroll_free(s);
meow_widget_free(lv);
}
int main(void)
{
meow_ui_opts o = { 480, 720 };
if (meow_ui_init(&o) != 0) { printf("init failed\n"); return 1; }
test_track_follow();
test_fling_no_boundary();
test_fling_boundary_bounce();
test_snap();
test_stop();
meow_ui_shutdown();
printf("scroll: %d pass / %d fail\n", g_pass, g_fail);
return g_fail ? 1 : 0;
}