fix(render): align text rasterization with upstream CATextLayer#214
Open
appergb wants to merge 1 commit into
Open
fix(render): align text rasterization with upstream CATextLayer#214appergb wants to merge 1 commit into
appergb wants to merge 1 commit into
Conversation
- font metrics: canvasScale=canvasHeight/1080, shadowPadding=12*2, +4px margin
(confirmed against TextLayout.swift L6/L28; rasterizer box comes from
clip.transform like upstream layer.frame L157-163, not naturalSize)
- font family: keep split('-') family + Weight/Style inference (fontdb
Family::Name rejects _Bold_/_Italic_ suffixes; no Style::Specific in 0.12);
expand weight recognition (Thin..Black) + Italic/Oblique detection
- blur: 3-pass separable box blur approximates Gaussian (matches CoreImage
shadow); radius = shadow.blur * scale (was /2), aligning shadowRadius L183
- baseline: document isGeometryFlipped equivalence (cosmic-text top-origin ==
flipped CALayer; shadow offset_y negated to image rows)
- tests: font scaling (540/1080/2160), shadow pixel spread, alignment x-centroid
ordering, word-wrap y-span, deterministic SSIM=1.0, natural_size shadow padding
- future-work TODOs: rich text (set_rich_text), emoji/CJK fallback (needs
cosmic-text 0.14+ family_emoji/family_asian), vertical text
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.
背景 (PR-8 / 痛点 4)
crates/opentake-render/src/gpu/text_engine.rs用 cosmic-text + swash + 自写 alpha-over / box-blur 栅格化文字,但从未与上游 CoreText /CATextLayer渲染结果做像素对齐验证。本 PR 对齐字体度量、字距/基线、阴影模糊,并增强测试覆盖。改动
A. 字体度量对齐 (SPEC §4.2)
CANVAS_BASIS_HEIGHT = 1080.0对齐上游referenceCanvasHeight(TextLayout.swift L7, TextLayerController.swift L150)font_px = font_size * font_scale * (canvas.h / 1080)对齐 L155/L165clip.transform(对齐上游layer.frameL157-163),不是TextLayout.naturalSize——shadow padding12*2与+4slack 属于 placement 度量,不在渲染器 box 里。在box_pixels加注释说明B. 字距/基线对齐
Style::Specific精确匹配,但 fontdb 0.16 (cosmic-text 0.12) 没有Style::Specific变体(只有 Normal/Italic/Oblique),且Family::Name文档明确要求传不带 Bold/Italic 后缀的 Typographic Family。所以保持split('-')取 family(fontdb 推荐用法),但扩展 weight 识别(Thin/ExtraLight/Light/Medium/Semibold/Bold/ExtraBold/Black)+ Italic/Oblique 检测,逼近上游NSFont(name:size:)的语义textRoot.isGeometryFlipped = true后的 Y 向下。补充注释说明 shadowoffset_y取负的等价性C. box_blur 改进
shadow.blur * scale(去掉/2),对齐上游layer.shadowRadius = max(0, blur * scale)(L183)blur_axis单 pass 辅助函数,3 次水平 + 3 次垂直D. 测试增强 (
tests/gpu_text.rs+6 测试)全部不依赖 GPU(直接测
CosmicTextRasterizer::rasterize返回的DecodedFrame),无系统字体时优雅跳过:font_size_scales_with_canvas_height— 540/1080/2160p 字号按比例缩放shadow_paints_pixels_outside_glyph_footprint— 阴影开启后非零像素多于仅文字alignment_shifts_glyph_x_centroid— left < center < right 重心 x 递增long_text_wraps_in_narrow_box— 长文字 y 跨度 > 单行rasterize_is_deterministic_ssim_one— 同输入 bytes 完全相等(SSIM=1.0 的强形式)natural_size_shadow_padding_matches_upstream—TextLayoutshadow padding = 24, REFERENCE_CANVAS_HEIGHT = 1080E. 复杂样式 TODO
模块注释加 future-work:rich text (
Buffer::set_rich_text)、emoji/CJK 回退(cosmic-text 0.12 无family_emoji/family_asian,需 0.14+)、垂直排版。验证
web (
pnpm build/pnpm test) 与本改动无关,留 CI 验证。发现的度量偏差
(blur*scale)/2偏小:上游shadowRadius = blur*scale(无 /2)。已修正——但 box-blur 的 "radius" 是半窗口,与 CA shadowRadius(Gaussian sigma 语义)不完全等价;3-pass box 近似 Gaussian 后数值上对齐,视觉上仍可能有微小差异(SPEC §6.2 已对文字区放宽到 SSIM ≥ 0.98)Style::Specific不存在:任务 spec 假设的精确匹配 API 在 cosmic-text 0.12/fontdb 0.16 不可用,已用扩展 weight 识别替代box_norm × canvas(来自clip.transform),非naturalSize——这是正确的(对齐上游layer.frame),无需在渲染器加 shadow padding文件
crates/opentake-render/src/gpu/text_engine.rs+93/-37crates/opentake-render/tests/gpu_text.rs+263/-0不合并 PR,等 review。