全屏滑条统一路径+对比色(112/115) + 字体索引+查列表+丢失降级(113) + 文档刷新(114) + svcd CLI文档+mips-repo拆bins/mpk(116)

This commit is contained in:
MeowOS Dev committed 2026-08-30 14:14:30 +08:00
1 parent b75ecce5de
commit 19a001f007
22 files changed
+666 -129

No files matched your search

+194
View File
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* access():字库缺失判定用 */
/* ---------------- 最小 zlib ABI 声明(与 libz.a 匹配,mipsel 32-bit unsigned long=4B) ------- */
typedef unsigned char mzf_Bytef;
@@ -721,3 +722,196 @@ int meow_font_config_multifont(int on,
if (distinct) *distinct = d_n;
return 0;
}
/* ================================================================== */
/* M2.58 字体索引 + 应用字库查询(规格 §5.7:索引文件 / 查列表 / 丢失降级默认) */
/* ================================================================== */
/* SDK 可选日志:SDK 链 meow_log 强符号(→app 日志);launcher 无 meow_log(弱符号 → NULL,
* 静默跳过)——避免 meow_font.o 依赖 SDK,launcher 链接不至于为未定义 meow_log 而失败。 */
extern void meow_log(int lvl, const char *fmt, ...) __attribute__((weak));
#define MEOW_FONT_INDEX_MAX 32 /* index 条数上限(实际 ≤17,留余量) */
#define MEOW_FONT_DEF_PNG "/usr/data/mnt/sd_0/MeowOS/fonts/default/regular/font.png"
#define MEOW_FONT_DEF_IDX "/usr/data/mnt/sd_0/MeowOS/fonts/default/regular/font.idx"
#define MEOW_FONT_SYS_PNG "/usr/share/meowos/font/font.png"
#define MEOW_FONT_SYS_IDX "/usr/share/meowos/font/font.idx"
const char *meow_font_card_root(void)
{
const char *e = getenv("MEOW_CARD_ROOT");
return (e && e[0]) ? e : "/usr/data/mnt/sd_0";
}
int meow_font_index_path(char *out, int olen)
{
if (!out || olen <= 0) return -1;
snprintf(out, (size_t)olen, "%s/%s", meow_font_card_root(), MEOW_FONT_INDEX_REL);
return 0;
}
/* 合成「板载默认」条目(index0;无卡/无 index 时唯一项)。 */
static void meow_font_default_entry(meow_font_info *out)
{
if (!out) return;
memset(out, 0, sizeof *out);
snprintf(out->family, sizeof out->family, "default");
snprintf(out->name, sizeof out->name, "默认字体");
snprintf(out->weight, sizeof out->weight, "regular");
snprintf(out->tier, sizeof out->tier, "common");
out->glyph_count = 0;
snprintf(out->label, sizeof out->label, "默认字体 Regular(common)");
snprintf(out->path_png, sizeof out->path_png, "MeowOS/fonts/default/regular/font.png");
}
/* CSV 单字段读取(支持双引号包裹 + 内嵌双引号转义)。p 走到下一字段/行尾。 */
static int csv_field(const char **pp, char *out, int olen)
{
const char *p = *pp;
if (!out || olen <= 0) return 0;
int o = 0;
if (*p == '"') {
p++;
while (*p && o < olen - 1) {
if (*p == '"') {
if (p[1] == '"') { out[o++] = '"'; p += 2; continue; }
p++; /* 结束引号 */
break;
}
out[o++] = *p++;
}
if (*p == ',') p++;
else if (*p == '\r' || *p == '\n') { /* 行尾,由外层清理 */ }
} else {
while (*p && *p != ',' && *p != '\r' && *p != '\n' && o < olen - 1)
out[o++] = *p++;
if (*p == ',') p++;
}
out[o] = 0;
*pp = p;
return 1;
}
/* 有界复制(字符串入 dst≤dlen 且保证 NUL;避免 -Wformat-truncation 之类告警)。 */
static void fcpy(char *dst, int dlen, const char *src)
{
if (dlen <= 0) return;
size_t n = src ? strlen(src) : 0;
if (n >= (size_t)dlen) n = (size_t)dlen - 1;
memcpy(dst, src, n);
dst[n] = 0;
}
/* 解析一行 index(CSV 6 字段)。成功填 info 并返回 1;path 为空 → 0(跳过)。 */
static int meow_font_parse_index_line(char *line, meow_font_info *info)
{
if (!line || !info) return 0;
const char *p = line;
char f[6][360];
for (int i = 0; i < 6; i++) {
if (!csv_field(&p, f[i], (int)sizeof f[i])) return 0;
if (!f[i][0]) return 0;
}
memset(info, 0, sizeof *info);
fcpy(info->family, sizeof info->family, f[0]);
fcpy(info->name, sizeof info->name, f[0]); /* index 无单列 name → 回退 family */
fcpy(info->weight, sizeof info->weight, f[1]);
fcpy(info->path_png, sizeof info->path_png, f[2]);
fcpy(info->label, sizeof info->label, f[3]);
fcpy(info->tier, sizeof info->tier, f[4]);
info->glyph_count = atoi(f[5]);
return info->path_png[0] ? 1 : 0;
}
int meow_font_index_load(meow_font_info *out, int max)
{
if (!out || max <= 0) return 0;
char path[450];
if (meow_font_index_path(path, sizeof path) != 0) return 0;
FILE *f = fopen(path, "r");
if (!f) { meow_font_default_entry(&out[0]); return 1; } /* 无卡/无 index → 仅板载默认 */
int n = 0, total = 0;
char line[1024];
while (fgets(line, sizeof line, f)) {
char *s = line;
while (*s == ' ' || *s == '\t') s++;
if (!*s || *s == '\n' || *s == '\r' || *s == '#') continue; /* 忽略空行/注释 */
meow_font_info tmp;
if (!meow_font_parse_index_line(s, &tmp)) continue;
total++;
if (n < max) { out[n] = tmp; n++; }
}
fclose(f);
if (total == 0) { meow_font_default_entry(&out[0]); return 1; }
return total;
}
int meow_font_get_available_count(void)
{
meow_font_info buf[1];
return meow_font_index_load(buf, 1); /* max=1:只统计总数,不要求全填 */
}
int meow_font_enumerate(int idx, meow_font_info *out)
{
if (!out || idx < 0) return 0;
meow_font_info buf[MEOW_FONT_INDEX_MAX];
int n = meow_font_index_load(buf, MEOW_FONT_INDEX_MAX);
if (idx >= n) return 0;
memcpy(out, &buf[idx], sizeof *out);
return 1;
}
/* 相对路径按卡根解析为绝对路径(绝对路径原样返回)。 */
static void font_abs_path(const char *rel, char *out, int olen)
{
if (!rel || !rel[0]) { if (olen > 0) out[0] = 0; return; }
if (rel[0] == '/') { snprintf(out, (size_t)olen, "%s", rel); return; }
snprintf(out, (size_t)olen, "%s/%s", meow_font_card_root(), rel);
}
/* 由 png 绝对路径派生同目录 font.idx(.png → .idx)。0=成功。 */
static int font_idx_from_png(const char *png, char *out, int olen)
{
if (!png || olen <= 0) return -1;
snprintf(out, (size_t)olen, "%s", png);
size_t n = strlen(out);
if (n > 4 && !strcmp(out + n - 4, ".png")) {
out[n-4]='.'; out[n-3]='i'; out[n-2]='d'; out[n-1]='x'; out[n]=0;
return 0;
}
return -1;
}
/* 装载系统默认字体(跟随 font.file,经 env MEOW_FONT_PNG/IDX → 卡默认 → 固件)。
* 与 SDK meow_ui_gfx load_font 的优先级一致;app 经 select_by_id(0) 或任何降级回退时走此路径。 */
static int meow_font_load_system_default(void)
{
const char *ep = getenv("MEOW_FONT_PNG");
const char *ei = getenv("MEOW_FONT_IDX");
char idxbuf[400];
if (ep && ep[0]) {
if (!ei || !ei[0]) {
if (font_idx_from_png(ep, idxbuf, sizeof idxbuf) != 0) ei = NULL;
else ei = idxbuf;
}
if (ei && meow_font_load(ep, ei) == 0) return 0;
}
if (meow_font_load(MEOW_FONT_DEF_PNG, MEOW_FONT_DEF_IDX) == 0) return 0;
if (meow_font_load(MEOW_FONT_SYS_PNG, MEOW_FONT_SYS_IDX) == 0) return 0;
return -1;
}
int meow_font_select_by_id(int id)
{
if (id == 0) return meow_font_load_system_default(); /* 跟随系统默认(font.file) */
meow_font_info info;
if (!meow_font_enumerate(id, &info)) return -1; /* 越界 → 负值 */
if (!info.path_png[0]) return -1;
char png[400], idx[400];
font_abs_path(info.path_png, png, sizeof png);
if (font_idx_from_png(png, idx, sizeof idx) != 0) return -1;
if (access(png, R_OK) == 0 && meow_font_load(png, idx) == 0) return 0;
/* 字库缺失 → 降级默认(不丢请求)+ WARN(app 日志;meow_log 为 SDK 统一日志) */
if (meow_log) meow_log(2 /* MEOW_LOG_WARN */, "font %s missing, fallback default", png);
return meow_font_load_system_default();
}
+48
View File
@@ -117,6 +117,54 @@ int meow_font_config_multifont(int on,
int meow_font_import_zip(const char *zip_path); /* TODO:MeowPanel */
int meow_font_export_zip(const char *family, const char *out_zip); /* TODO:MeowPanel */
/* ================================================================== */
/* M2.58 字体索引 + 应用字库查询(规格 §5.7:索引文件 / 查列表 / 丢失降级默认) */
/* ================================================================== */
/* 系统字体列表的持久化快照 = TF 卡 <card_root>/MeowOS/config/fonts/index(CSV,每套一条:
* "family","weight","path","label","tier",glyph_count
* path = 卡根相对 font.png(如 MeowOS/fonts/misans/regular/font.png)
* label = 显示名(含字重 + 尺寸标记,如 `MiSans Regular(common≈4k)`)
* tier = common|gbk|full(档位,信息用 + 驱动按需加载)
* launcher 扫描 MeowOS/fonts/<family>/<weight>/ 后写该文件(覆盖,含默认行 index0);
* SDK 侧 meow_font_get_available_count()/enumerate() 只从这个文件读,不依赖 launcher 内存数组;
* 无卡/无 index → 仅 1 项板载默认(family=default)。 */
#define MEOW_FONT_INDEX_REL "MeowOS/config/fonts/index"
/* 权威列表数据模型(SDK 侧快照,枚举时填充;规格 §5.7.1)。 */
#ifndef MEOW_FONT_INFO_DEFINED
#define MEOW_FONT_INFO_DEFINED
typedef struct meow_font_info {
char family[64]; /* family slug = MeowOS/fonts/<family>/ 一级目录名 */
char name[64]; /* 显示名(index 无单列 → 回退 family) */
char weight[32]; /* weight slug(regular|bold|…,缺省 regular) */
char tier[8]; /* 档位 common|gbk|full(info 用) */
int glyph_count; /* font.json glyph_count(info 用) */
char label[128]; /* index 显示名(含字重 + 尺寸标记) */
int size_list[16]; /* 原生字号表(index 无 → 空) */
int size_count; /* 有效字号数 */
int bit_depth; /* 4|8(index 无 → 0) */
char path_png[320]; /* 卡根相对 MeowOS/fonts/<family>/<weight>/font.png */
} meow_font_info;
#endif
/* 卡根:env MEOW_CARD_ROOT 优先,否则默认 /usr/data/mnt/sd_0。 */
const char *meow_font_card_root(void);
/* <card_root>/MeowOS/config/fonts/index 绝对路径写入 out;0=成功。 */
int meow_font_index_path(char *out, int olen);
/* 读 index → 填充 out 数组(最多 max 条),返回「总条数」(无 index/不可读/空 → 1=合成默认行)。
* 注意 out[i].path_png 为「卡根相对」路径,需经卡根解析为绝对路径再使用。 */
int meow_font_index_load(meow_font_info *out, int max);
/* 应用可读 TF 卡字体列表(规格 §5.7.2):
* - get_available_count():可用字库数(含默认;无卡 → 1)。
* - enumerate(idx, out):按序号取,越界返回 0;idx=0=默认行(family=default)。
* - select_by_id(id):id=0 跟随系统默认(font.file,经 env MEOW_FONT_PNG/IDX);
* id>0 会话内固定用该套;该套字库缺失 → 降级默认(不丢请求)+ WARN 日志
* (meow_log→app 日志)。成功 0,越界负值。 */
int meow_font_get_available_count(void);
int meow_font_enumerate(int idx, meow_font_info *out);
int meow_font_select_by_id(int id);
#ifdef __cplusplus
}
#endif