fix(capture): Linux headless 截图中 ASCII 字母被裁成上半部分#53
Merged
Conversation
The headless renderer derived each glyph's baseline offset from `ascent_unscaled / units_per_em`, but ab_glyph's `PxScale.y` maps the font's full `height_unscaled` (ascent − descent) — not units_per_em — to pixels. For CJK-capable fonts (Noto CJK on Linux, Arial Unicode) whose ascent−descent exceeds 1em, the offset was too large and pushed the baseline below the cell. Because rows are painted top-to-bottom, the next row's background fill then erased the lower half of every tall glyph — on Linux screenshots every ASCII letter showed only its top half. Use `as_scaled(scale).ascent()`, which divides by height_unscaled and so matches the outline rasterization. Add a regression test asserting a tall glyph reaches into the top of its cell (fails at y=9 on the old code, passes after the fix). Root-caused via systematic-debugging: per-row ink in the Linux screenshot only occupied rel=[10,17] of each 18px cell; a metrics probe confirmed the ab_glyph scale semantics (Arial Unicode: 19.24px offset > 18px cell with the bug, 14.36px correct). Co-Authored-By: Claude <noreply@anthropic.com>
🔒 门禁检查结果
Rust 测试覆盖率
前端测试覆盖率
✅ 所有检查通过,可以合入
|
…atin fonts Code review (#53) noted the regression test would silently pass for the wrong reason on a host whose `load_font()` resolves a Latin-only font (height≈upem), where the clipping bug never manifests — so it couldn't actually guard the regression there. Resolve by computing the *buggy* baseline offset (ascent_unscaled/upem*18) up front and skipping loudly (with a clear reason) when it does not exceed the cell height, rather than false-passing. On Arial Unicode / Noto CJK the offset is 19.24 > 18, so the test still runs and discriminates bug vs fix. Co-Authored-By: Claude <noreply@anthropic.com>
5 tasks
Shadow-Azure
added a commit
that referenced
this pull request
Jul 19, 2026
Patch release for the Linux headless screenshot glyph-clipping fix (#53): ASCII letters were rendered at half height because the baseline offset divided by units_per_em instead of height_unscaled. Also resyncs Cargo.lock (was stale at 0.3.0). Co-authored-by: ZN-Ice <zn-ice@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Linux headless 沙箱的截图里,所有 ASCII 字母都被裁成只剩上半部分,标点/制表符正常,与 macOS 体验差距很大(见
release_test/2026-07-19-19-40-45/claude-07-after-trust.png)。根因在
crates/cli-box-core/src/capture/headless.rs的render_png():ab_glyph 的
PxScale.y映射的是字体的height_unscaled(= ascent − descent),不是units_per_em(文档明说的"非标准 scale")。代码用upem做分母,对任何ascent − descent > 1em的字体(所有 CJK 字体:Linux 的 Noto CJK、Arial Unicode)都会高估基线偏移,把基线推到 cell 底边以下。又因为渲染是自上而下的,下一行的背景填充会覆盖上一行溢出的像素,于是每个高字母的下半部分被擦除。Solution
一行修复(
0048e2d):用与光栅化器一致的as_scaled(scale).ascent()推导基线偏移——它内部除以height_unscaled,任意字体下字形都落在 cell 内:根因定位(systematic-debugging 四阶段,无猜测):
rel=[10,17](cell 底部 8px),顶部 10px 全空 → 基线被推到 cell 下方。19.24px> cell18px(裁剪),正确值14.36px。回归测试
render_png_tall_glyphs_span_cell_height:断言高字形墨迹到达 cell 顶部——旧代码y=9失败(字形挤在 cell 底部),修复后通过。修复后实测:墨迹从
rel=[10,17](8px 残缺)→rel=[4,14](10px 全高),与 macOS 参考渲染(~14px/19px 行)一致。Test Plan
render_png_tall_glyphs_span_cell_height:旧代码 FAIL(y=9),修复后 PASScargo test -p cli-box-core -p cli-box-cli:core 166 + cli 33 + 7 个集成套件全过cargo clippy -p cli-box-core --all-targets -- -D warnings:无警告cargo fmt --all -- --check:通过PxScale.y⇒height_unscaled(非 upem),Arial Unicode 偏移 19.24→14.36🤖 Generated with Claude Code