test(app-iced): M75 复审 P1-B —— 渲层断言收紧到 2px 级(变异实测会红)
- 高度断言改 assert_eq!(true_height, 40):变异成 42 实测变红(证据 target/m75/evidence.sh) - 补「带图标左内边距 16」断言:墨迹 ≈21(16→21 / 24→29 / 8→13 三档互不重叠) - 分隔线:行数 2..=4 + 单条墨量覆盖率 0.8..=1.3(1.5dp 会到 ~1.5), 只统计「连续非底色 > 900」的长横线行,避免把文字墨量算进去 - 两条判据都踩过误报:白色与浅色页面底色在容差内(padding 量出 3)、 圆角透出的底色被当成满档 OnPrimary;已改成「内带 + nearer 判定」并注明原因
This commit is contained in:
1 parent
e905fa3922
commit
d075feb77d
1 file changed
+68
-31
@@ -36,20 +36,32 @@ fn ui(flavor: SchemeFlavor) -> Ui {
|
||||
|
||||
/// `ULL_GALLERY_SHOT` → 截图路径(相对路径按**工作区根**解释:`cargo test` 的 cwd 是 crate 目录)。
|
||||
/// 一条 1dp 细线在竖直方向的「墨量覆盖率」:各行相对底色的不透明度之和(1dp ⇒ ≈1.0)。
|
||||
///
|
||||
/// **只统计「长横线行」**(连续非底色像素 > 900):标题/正文那些行也有几百个零散墨迹像素,
|
||||
/// 按「任意非底色像素数」筛会把文字算进墨量(首版实测 57.9,明显是文字被算进去了)。
|
||||
fn line_coverage(shot: &Shot, surface: [u8; 3], line: [u8; 3]) -> f32 {
|
||||
let mut total = 0.0;
|
||||
for y in 0..shot.height {
|
||||
let mut longest = 0;
|
||||
let mut current = 0;
|
||||
let mut sum = 0.0f32;
|
||||
let mut count = 0usize;
|
||||
let mut run_sum = 0.0f32;
|
||||
for x in 0..shot.width {
|
||||
let pixel = shot.at(x, y);
|
||||
if !matches(pixel, surface) {
|
||||
count += 1;
|
||||
sum += delta_ratio(pixel, surface, line);
|
||||
current += 1;
|
||||
run_sum += delta_ratio(pixel, surface, line);
|
||||
if current > longest {
|
||||
longest = current;
|
||||
sum = run_sum;
|
||||
}
|
||||
} else {
|
||||
current = 0;
|
||||
run_sum = 0.0;
|
||||
}
|
||||
}
|
||||
if count > 300 {
|
||||
total += sum / count as f32;
|
||||
if longest > 900 {
|
||||
total += sum / longest as f32;
|
||||
}
|
||||
}
|
||||
total
|
||||
@@ -171,6 +183,13 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
}
|
||||
let true_height = true_bottom - true_top + 1;
|
||||
|
||||
// **精确 40**:变异成 42 必须红。上一版写的是 `(39..=41).contains(..)`,
|
||||
// reviewer 把高度改成 42 重新出图后断言照样绿 —— 那就是「渲层断言等于没有」。
|
||||
assert_eq!(
|
||||
true_height, 40,
|
||||
"可见高必须精确 40(12b 1.1);变异成 42 这里就会红"
|
||||
);
|
||||
|
||||
// 圆角档位:量**顶部那一行的左内缩**。药丸(r = 高/2 = 20)在离顶端 1px 处内缩
|
||||
// ≈ r − √(2r−1) = 13.8;r=8 只有 ≈4.1;直角为 0。比「数圆角行数」抗锯齿得多。
|
||||
let top_row_left = (label_button.left..=label_button.right)
|
||||
@@ -182,31 +201,45 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
"药丸圆角应 = 20(12b 1.2):顶部行左内缩应 ≈14,实测 {top_inset}(8 圆角 ≈4,直角 0)"
|
||||
);
|
||||
|
||||
// ---- 12b 1.4 / 1.6:内边距 16、图标↔文字 8(用带前置图标的 Filled 格量)----
|
||||
let ink = shot.ink_inside(&label_button, [255, 255, 255]);
|
||||
if let Some(ink) = ink {
|
||||
let icon_pad = ink.left - label_button.left;
|
||||
// 图标盒左缘 = 16;字形在 24 viewBox 里自带 ≈5.3 的左边距 ⇒ 墨迹落在 21 附近
|
||||
assert!(
|
||||
(19..=23).contains(&icon_pad),
|
||||
"12b 1.4:带图标左内边距应 16(墨迹 ≈21),实测 {icon_pad}"
|
||||
);
|
||||
} else {
|
||||
panic!("Filled 格应带前置图标(量内边距用)");
|
||||
// ---- 12b 1.4:带前置图标的左内边距 = 16(用 Filled 格量,避开圆角只扫中间带)----
|
||||
// 判「墨迹」的方式:比容器色更接近 OnPrimary。不要用字面量白——浅色页面底色 (246,250,255)
|
||||
// 与白在容差内,会把圆角外的底色当成墨迹(首次实现就踩了,量出 3)。
|
||||
let on_primary = rgb(ui.color(Role::OnPrimary));
|
||||
let mut left_ink: Option<usize> = None;
|
||||
for y in (label_button.top + 12)..=(label_button.bottom - 12) {
|
||||
for x in (label_button.left + 4)..=label_button.right {
|
||||
if nearer(shot.at(x, y), on_primary, fill) {
|
||||
left_ink = Some(left_ink.map_or(x, |best: usize| best.min(x)));
|
||||
}
|
||||
}
|
||||
}
|
||||
let icon_pad = left_ink.expect("Filled 格应带前置图标(量内边距用)") - label_button.left;
|
||||
// 图标盒左缘 = 16;字形在 24 viewBox 里自带 ≈5.3 左边距 ⇒ 墨迹落在 21 附近
|
||||
// (16 → 21;24 → 29;8 → 13,三档互不重叠)
|
||||
assert!(
|
||||
(18..=24).contains(&icon_pad),
|
||||
"12b 1.4:带图标左内边距应 16(墨迹 ≈21),实测 {icon_pad}"
|
||||
);
|
||||
|
||||
// ---- Q9:IconButton 的字形不许撑满 40 盒 --- // ---- 12b 1.4 / 1.6:内边距 16、图标↔文字 8(用带前置图标的 Filled 格量)----
|
||||
let ink = shot.ink_inside(&label_button, [255, 255, 255]);
|
||||
if let Some(ink) = ink {
|
||||
let icon_pad = ink.left - label_button.left;
|
||||
// 图标盒左缘 = 16;字形在 24 viewBox 里自带 ≈5.3 的左边距 ⇒ 墨迹落在 21 附近
|
||||
assert!(
|
||||
(19..=23).contains(&icon_pad),
|
||||
"12b 1.4:带图标左内边距应 16(墨迹 ≈21),实测 {icon_pad}"
|
||||
);
|
||||
} else {
|
||||
panic!("Filled 格应带前置图标(量内边距用)");
|
||||
// ---- Q9:IconButton 的字形不许撑满 40 盒 --- // ---- 12b 1.4:带前置图标的左内边距 = 16(用 Filled 格量,避开圆角只扫中间带)----
|
||||
// 判「墨迹」的方式:比容器色更接近 OnPrimary。不要用字面量白——浅色页面底色 (246,250,255)
|
||||
// 与白在容差内,会把圆角外的底色当成墨迹(首次实现就踩了,量出 3)。
|
||||
let on_primary = rgb(ui.color(Role::OnPrimary));
|
||||
let mut left_ink: Option<usize> = None;
|
||||
for y in (label_button.top + 12)..=(label_button.bottom - 12) {
|
||||
for x in (label_button.left + 4)..=label_button.right {
|
||||
if nearer(shot.at(x, y), on_primary, fill) {
|
||||
left_ink = Some(left_ink.map_or(x, |best: usize| best.min(x)));
|
||||
}
|
||||
}
|
||||
}
|
||||
let icon_pad = left_ink.expect("Filled 格应带前置图标(量内边距用)") - label_button.left;
|
||||
// 图标盒左缘 = 16;字形在 24 viewBox 里自带 ≈5.3 左边距 ⇒ 墨迹落在 21 附近
|
||||
// (16 → 21;24 → 29;8 → 13,三档互不重叠)
|
||||
assert!(
|
||||
(18..=24).contains(&icon_pad),
|
||||
"12b 1.4:带图标左内边距应 16(墨迹 ≈21),实测 {icon_pad}"
|
||||
);
|
||||
|
||||
// ---- Q9:IconButton 的字形不许撑满 40 盒 -----------------------------------
|
||||
let tonal = rgb(ui.color(Role::SecondaryContainer));
|
||||
@@ -269,10 +302,11 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
// **墨量覆盖率**:一条 1dp 的线,其各行相对底色的不透明覆盖率之和应 ≈1.0。
|
||||
// 1.5dp 的线会到 ≈1.5,2dp 会到 ≈2.0 —— 这是「容忍 1.5 倍粗」的补丁。
|
||||
let full = rgb(ui.color(Role::OutlineVariant));
|
||||
let coverage = line_coverage(&shot, surface, full);
|
||||
// 屏上正好 2 条线(通栏 + 列表内缩),所以把总墨量除以 2 得到「单条线的覆盖率」
|
||||
let coverage = line_coverage(&shot, surface, full) / 2.0;
|
||||
assert!(
|
||||
(0.8..=1.3).contains(&coverage),
|
||||
"分隔线墨量覆盖率应 ≈1.0(= 1dp),实测 {coverage:.2}(1.5dp 会到 ~1.5)"
|
||||
"单条分隔线墨量覆盖率应 ≈1.0(= 1dp),实测 {coverage:.2}(1.5dp 会到 ~1.5)"
|
||||
);
|
||||
|
||||
// ---- 12b 1.8:禁用格必须与静息格不同 ------------------------------------
|
||||
@@ -300,8 +334,10 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
if bbox.width() < 60 {
|
||||
continue;
|
||||
}
|
||||
for y in (bbox.top + 2)..=(bbox.bottom - 2) {
|
||||
for x in (bbox.left + 2)..=(bbox.right - 2) {
|
||||
// 只扫**内带**:圆角外的页面底色 (246,250,255) 与 OnPrimary(255,255,255) 在容差内,
|
||||
// 贴边扫描会把圆角透出的底色当成「满档内容」(首版就在 (866,162) 误报)。
|
||||
for y in (bbox.top + 12)..=(bbox.bottom - 12) {
|
||||
for x in (bbox.left + 12)..=(bbox.right - 12) {
|
||||
assert!(
|
||||
!matches(shot.at(x, y), full_content),
|
||||
"禁用容器内出现满档 OnPrimary @({x},{y}):禁用标签没降到 38%"
|
||||
@@ -324,6 +360,7 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
true_height,
|
||||
top_inset,
|
||||
primary.len(),
|
||||
runs,
|
||||
ink_px,
|
||||
coverage,
|
||||
glyph_width
|
||||
|
||||
Reference in new issue
Block a user