From 831bd00620dcae368c3fa176902be3b2f9b0379a Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 2 Nov 2026 04:10:05 +0800 Subject: [PATCH] =?UTF-8?q?docs(app-iced):=20SIM=20=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E5=8F=A3=E5=BE=84=E7=B2=BE=E7=A1=AE=E5=8C=96=EF=BC=88=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E6=9C=80=E5=A4=9A=E8=A1=8C=20402=20/=20=E5=85=A8?= =?UTF-8?q?=E6=AE=B5=E6=9C=80=E5=AE=BD=E8=A1=8C=20411=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 视觉 r3 的不计入裁决的精度提醒:`SIM_SAFE_MAX_INK = 402` 其实是**字符最多**那一行的 ink, 全段**墨迹最宽**的行是 411px(渲染 410),所以「余量 22px」实际是 13px。 - 拆成两个常量并分别断言:`SIM_SAFE_MAX_CHARS_INK = 402`(67 字符那行)、 `SIM_SAFE_WIDEST_INK = 411`(墨迹最宽那行,新加断言 `cap >= 411`,并在失败信息里打印余量); - 文档写明「两者不是同一行:402 那行字符多但字形窄」。 证据:`cargo test -p unlucky-app-iced --no-default-features` → `test result: ok. 86 passed; 0 failed` / `test result: ok. 6 passed; 0 failed`。 --- crates/app-iced/src/pages/layout/tests.rs | 33 +++++++++++++++-------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/crates/app-iced/src/pages/layout/tests.rs b/crates/app-iced/src/pages/layout/tests.rs index 48e6965..c795876 100644 --- a/crates/app-iced/src/pages/layout/tests.rs +++ b/crates/app-iced/src/pages/layout/tests.rs @@ -152,11 +152,15 @@ fn chars_per_line(width: f32) -> f32 { /// **逐行**折行模拟结果(FreeType `getlength` 量宽 + 贪心词折行,脚本见模块文档 §3)。 /// -/// 这两组数是外部实测:在同一段正文(361 字符)上扫列宽得到—— -/// `SAFE` 是交付宽度下的最长一行,`BREAK` 是第一档会冒出 73 字符行的宽度。 -/// 有了它,Rust 侧不用字体引擎也能把「上限必须夹在这两者之间」写成断言。 +/// 四个数都是外部实测,口径要分清(视觉 r3 提醒过这里容易写糊): +/// - `SAFE_MAX_CHARS` / `SAFE_MAX_CHARS_INK`:cap=424 时**字符最多**的那一行 —— 67 字符,ink **402px**; +/// - `SAFE_WIDEST_INK`:cap=424 时**墨迹最宽**的那一行 —— **411px**(不是同一行!402 那行字符多但字形窄); +/// - `BREAK_INK` / `BREAK_CHARS`:第一档会冒出 73 字符行的宽度 428px(那行 ink 428px)。 +/// +/// 有了它,Rust 侧不用字体引擎也能把「上限必须夹在这些数之间」写成断言。 const SIM_SAFE_MAX_CHARS: f32 = 67.0; -const SIM_SAFE_MAX_INK: f32 = 402.0; +const SIM_SAFE_MAX_CHARS_INK: f32 = 402.0; +const SIM_SAFE_WIDEST_INK: f32 = 411.0; const SIM_BREAK_INK: f32 = 428.0; const SIM_BREAK_CHARS: f32 = 73.0; @@ -185,13 +189,20 @@ fn line_length_is_capped_at_72_characters() { "平均口径上界必须比逐行安全宽**更宽**——这说明 cap 不是拿平均算出来的" ); - // ③ 交付宽度下,模拟出来的最长一行装得下,且字符数 ≤72 + // ③ 交付宽度下两条实测线都装得下:字符最多那行(402px)与墨迹最宽那行(411px) assert!( - SIM_SAFE_MAX_INK <= measure_cap_px(), - "模拟最长行 {}px 超过上限 {}px", - SIM_SAFE_MAX_INK, + SIM_SAFE_MAX_CHARS_INK <= measure_cap_px(), + "字符最多那行 {}px 超过上限 {}px", + SIM_SAFE_MAX_CHARS_INK, measure_cap_px() ); + assert!( + SIM_SAFE_WIDEST_INK <= measure_cap_px(), + "墨迹最宽那行 {}px 超过上限 {}px(余量只有 {}px)", + SIM_SAFE_WIDEST_INK, + measure_cap_px(), + measure_cap_px() - SIM_SAFE_WIDEST_INK + ); const { assert!(SIM_SAFE_MAX_CHARS <= MAX_MEASURE_CHARS) }; // ④ **两侧夹逼**:这是本条真正的护栏。 @@ -202,10 +213,10 @@ fn line_length_is_capped_at_72_characters() { "上限 ≥{SIM_BREAK_INK}px 时逐行模拟会再次出现 {SIM_BREAK_CHARS} 字符行——请重跑折行模拟" ); assert!( - measure_cap_px() >= SIM_SAFE_MAX_INK, - "上限 {}px 比模拟出来的最长行 {}px 还窄,白丢宽度", + measure_cap_px() >= SIM_SAFE_WIDEST_INK, + "上限 {}px 比模拟出来的最宽行 {}px 还窄,白丢宽度", measure_cap_px(), - SIM_SAFE_MAX_INK + SIM_SAFE_WIDEST_INK ); // ⑤ 平均口径的回归护栏:旧 0.5em 的 504px 在实测步进下能放 83 字符