☰
Skia 与 Chromium 协同落地:Blink 布局测试重基线(Rebaseline)操作指南
2026/9/25 4:57:42 网站建设 项目流程
  • 图形学
  • 图像处理

【免费下载链接】skia

Skia is a complete 2D graphic library for drawing Text, Geometries, and Images.

项目地址:https://gitcode.com/gh_mirrors/skia1/skia
点击查看免费下载

本篇指南基于 Skia 官方开发者文档,系统讲解“如何让一个会改变 Blink 布局测试结果的 Skia 变更安全落地”。读完本文,你将掌握两条落地路径——小范围测试改动(少于约 20 个用例)的免协调重基线流程,以及大范围渲染改动所依赖的SK_IGNORE_xxx_FIX代码抑制(code suppression)机制,并理解 Skia 自动滚入(roll)Chromium 这一底层协作模型的来龙去脉。

背景:Skia 变更为什么会“炸”到 Blink 布局测试

Skia 是 Chromium 的 2D 渲染引擎,二者通过自动滚动(roll)机制保持同步:

  • Skia 仓库的提交会由Auto Roll Bot(即skia-deps-roller)每天多次自动滚入 Chromium 的DEPS,也可以手动触发。因此 Skia 侧的每一个像素级渲染差异,最终都会在 Chromium 侧的 Blink 布局测试(third_party/blink/web_tests/TestExpectations所管理的那套 WebKit 布局测试)上体现出来;
  • 布局测试的核心产物是截图比对:只要 Skia 的绘制行为变化(抗锯齿、抖动、光栅化策略等),大量布局测试的期望图像就会失配,Chromium.WebKit树随之变红;
  • 文档给出的关键决策阈值是约 20 个测试用例:影响更少可以自行重基线,影响更多则必须引入代码抑制并通知 Blink gardener。

这一阈值划分是整个流程的骨架,下面分别展开。相关上游文档见 Skia 变更如何同步到 Chromium 与 Skia 在 Chrome 中的分支与滚动。

路径 A:影响少于约 20 个布局测试——免协调重基线

原文档明确指出:影响少于约 20 个布局测试结果的变更,无需与 Blink gardener 特别协调,按以下五步操作即可:

  1. 准备 Skia 变更,并记录哪些布局测试会转红。Skia 本地可通过自身的 GM 测试与 SkiaGold 比对预判,Chromium 侧的布局测试运行细节属于 Blink 仓库范畴,文档在此只给出“先预判红名单”这一要求。

  2. 把代码提交到 Skia 仓库。

  3. 在包含该变更的 Skia 自动 roll 之前,手动向 Blink 的LayoutTests/TestExpectations文件推送一个变更,把因你的改动而预期失败的测试标记出来。标记语法为:

    foo/bar/test-name.html [ Failure Pass ] # Needs rebaseline

    这条期望行的含义是:该测试当前会失败(Failure),在重基线完成后应当通过(Pass),尾部注释说明这是“待重基线”条目。

  4. 等待 Skia roll 成功落地。此时 Blink 树不会因你的变更而变红,因为期望文件已经声明了这些失败是预期内的。

  5. 再提交一个 BlinkTestExpectations变更,移除你在第 3 步添加的所有跳过的测试期望,并运行:

    git cl rebaseline

    该命令会触发自动重基线机器人,由它自动把新的期望图像 check in,完成图像基线更新。

整条路径的精髓在于时序控制:TestExpectations 的声明必须先于(或恰好在)Skia roll 落地前生效,让 roll 通过 CQ 时布局测试不会大面积变红;roll 落地后再撤销期望并交给 rebase bot 自动更新图像。

路径 B:影响超过约 20 个测试——代码抑制 + 重基线 + 清理三段式

当“大范围”指超过约 20 个测试时,直接改图会导致Chromium.WebKit树在较长时间内大面积变红,必须走更严谨的三段式流程:Setup(设置代码抑制)→ Rebaseline(重基线)→ Cleanup(清理)。

基本概念

  • 代码抑制(code suppression):即一个编译开关(build flag,又称 define),用来在 Chromium 侧暂时屏蔽新渲染路径、保留旧行为;
  • 命名规范:抑制开关必须命名为SK_IGNORE_xxx_FIX形式(FIX后缀提示该开关是临时性的,重基线后必须移除);
  • roll 的含义:更新 Chromium 中 Skia 版本的动作称为 roll,由 Auto Roll Bot 每天自动执行多次,也可手动执行(对应skia-deps-roller的 DEPS 变更)。

代码抑制在 Skia 源码中的真实形态

文档要求“把变更放在代码抑制后面”,即新代码路径用#ifdef / #ifndef包裹,Chromium 侧不定义该宏时行为与旧版本完全一致。当前 Skia 仓库中就有多个这样的存量开关,可作为写代码时的直接参照:

  • src/core/SkBitmapDevice.cpp 中SK_IGNORE_BLURRED_RRECT_OPT包裹了drawRRect的优化路径——定义该宏则回退到通用的drawPath分支:

    void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) { #ifdef SK_IGNORE_BLURRED_RRECT_OPT // call the VIRTUAL version, so any subclasses who do handle drawPath aren't // required to override drawRRect. this->drawPath(SkPath::RRect(rrect), paint, true); #else LOOP_TILER( drawRRect(rrect, paint), Bounder(rrect.getBounds(), paint)) #endif }
  • src/gpu/DitherUtils.h 用#ifndef SK_IGNORE_GPU_DITHER把 GPU 抖动相关的整组声明(DitherRangeForConfig、MakeDitherLUT)包裹起来,对应的实现侧 src/gpu/DitherUtils.cpp、src/gpu/ganesh/SkGr.cpp 以及 Graphite 侧的 src/gpu/graphite/PaintParams.cpp、src/gpu/graphite/precompile/PaintOption.cpp 也以同样的#ifndef对称包裹。

    这种“头文件与实现同时用相同宏包裹”的写法保证了:Chromium 定义SK_IGNORE_GPU_DITHER后,新路径的声明与实现一起消失,旧版 Chromium 代码不会因链接缺失或符号冲突而出错。编写自己的SK_IGNORE_xxx_FIX时,应对齐这一模式。

Setup:三种情形下的初始化步骤

情形一:抑制尚不存在——直接法(Direct method)

  1. 在 Skia 中做出会改变大量 Blink 布局测试的变更;
  2. 将该变更放在代码抑制(SK_IGNORE_xxx_FIX)之后;
  3. 把变更 check in 到 Skia 仓库;
  4. 手动 roll Skia,或给 autoroll 追加代码抑制——即把它写进 Chromium 的skia/chromium_skia_defines.gypi。

情形二:抑制尚不存在——替代法(Alternate method)

  1. 先在 Chromium 的skia/chromium_skia_defines.gypi中加上代码抑制,再动 Skia 代码;
  2. 在 Skia 中做出会改变大量布局测试的变更;
  3. 把变更放在代码抑制后面;
  4. 把变更 check in 到 Skia 仓库;
  5. 等待 Skia roll 进 Chromium。

两种写法的差异只在时序:直接法让 Skia 先落地、roll 时带上 define;替代法让 define 先落地,roll 到 Chromium 后新代码自然被抑制。两者终态相同。

情形三:抑制已存在于头文件中

  1. 从 Chromium 的头文件中移除该代码抑制,同时把它加入skia/chromium_skia_defines.gypi;
  2. 原文档特别警告:代码抑制不能同时存在于头文件和 gyp 文件的 define 中,否则会产生“多重定义”警告,而在 Chromium 构建中这类警告会被当作错误,直接打断整个 Chromium 构建。

这一约束与 Skia 与 Chromium 的 API 同步策略 中关于“code suppression cannot exist in both the header file and the gyp file, it should only reside in one location”的描述完全一致,说明 define 的存放位置是全局唯一归属问题,而非简单便利问题。

Rebaseline:重基线窗口期的操作

  1. 选择 Blink 树安静的时段操作,尤其避开 PST 下午;改动越大,这一点越重要。无论如何,都要确认当值 Blink gardener 是谁并事先通知——你会让Chromium.WebKit树变红一段时间,gardener 需要知道这不是他要修的故障。
  2. 提交一个同时做两件事的 CL:从 Chromium 的skia/chromium_skia_defines.gypi中移除代码抑制,同时向 Blink 的LayoutTests/TestExpectations添加[ NeedsRebaseline ]期望行。之后自动重基线机器人会负责把新图像 check in。原文档给出的规模指引是:大约600 张以内需要重基线的图像走这套自动化流程是普遍可接受的;超过 600 张时仍可用[ NeedsRebaseline ],但最好与 gardener 协调。该 CL 应当能干净地通过 CQ。
  3. 小心本来就失败或不稳定(flaky)的测试:它们是否需要重基线是不确定的;而 flaky 测试无论如何都不应从 TestExpectations 中移除。遇到这类情况,在提交前先回退(revert)你对 TestExpectations 的改动。
  4. 如果清理步骤不由你负责,请按以下模板开一个 Skia Issue 交给负责人:
    • 标题:Remove code suppression SK_IGNORE_xxx_FIX.
    • 描述:Code suppression SK_IGNORE_xxx_FIX rebaselined with Blink revision 123456.
    • 并 assign 给负责清理的那个人。

Cleanup:清理

  1. 从 Skia 中删除已经不再使用的旧代码,以及当初为抑制新代码而引入的所有 define;
  2. 把清理变更 check in 到 Skia 仓库;
  3. 等待 Skia roll 进 Chromium。

至此SK_IGNORE_xxx_FIX从“临时脚手架”完成它的生命周期。可以推断,正是这个“Issue 跟踪 + 最终移除”的闭环,使得仓库里存活的SK_IGNORE_*宏数量有限且都可追溯到具体变更(如上文SK_IGNORE_BLURRED_RRECT_OPT、SK_IGNORE_GPU_DITHER即为其产物)。

配套能力:在 trybot 上联调 Skia + Chromium/Blink 改动

上述流程的前提是“能在提交前验证 Skia 变更在 Chromium 中的表现”。多仓库 Chromium trybot 指南 提供了配套的验证手段:

  • 只有 Skia 改动:Skia 补丁已在 Gerrit 上时,直接跑 Chromium trybot 即可,机器人会应用该 Skia 补丁;
  • Skia + Chromium 改动:在 Chromium CL 的<chromium>/src/DEPS的hooks数组中加fetch_custom_patch+apply_custom_patch两个钩子,从 Gerrit 的refs/changes/XX/YYYY/ZZfetch 并 cherry-pick Skia 补丁,让 trybot 在 Skia 补丁之上跑测试;
  • 本地验证时运行gclient runhooks拉取 Skia 源码;若third_party/skia工作区不干净(已打过补丁),需先在该目录执行git reset --hard再运行gclient runhooks;
  • 上传 Chromium CL 时用常规git cl upload,但要在 issue 描述中加COMMIT=false,避免误提交。

对于无法走 DEPS 钩子的任意文件改动,文档还给出了把文件拷入<chromium>/src/patch/并按 Chromium 目录结构覆盖的兜底方案。

出问题时:roll 失败、回滚与树管理

重基线流程发生在 Skia roll 与 Chromium 树的交汇处,失败时的处置方式在 Skia 文档体系中有明确对应:

  • Skia 在 Chrome 的分支与滚动 说明:roll 出问题时应到 autoroll 页面暂停新 roll、revert 有问题的 DEPS roll,找不到 owner 时指派给 Skia Gardener(列于 status.skia.org 的 gardeners 组件中);

  • Skia 日常维护(gardening)文档 明确指出:DEPS roll 落地失败的常见原因就是布局测试——检查 DEPS roll 的 commit 哈希区间找到肇事的 Skia CL 并 revert(或联系作者);如果 Skia CL 改变了布局测试但新图像看起来正确,则测试需要重基线,并给出了两条操作路径:编辑 Chromium 侧的skia/skia_test_expectations.txt(较快、但文档标注为不推荐),或提交单独的 Blink 补丁编辑LayoutTests/TestExpectations(推荐但更慢)。此外还给出了创建 “Skia image rebaseline” Chromium bug 的完整模板(标签需包含OS-All与Cr-Blink-LayoutTests,滤镜相关改动需 cc 特定同学)。

    注意这两条路径与本文主线文档的关系:gardening 文档面向“roll 已经红了、需要灭火”的场景,而blink.md面向“我要主动发起一个已知会改变渲染的变更”的场景——后者通过代码抑制和[ NeedsRebaseline ]预期行,本质上就是为了避免进入前者的救火状态。

决策速查

变更规模是否需要通知 gardener核心机制关键动作
少于约 20 个布局测试否TestExpectations期望行roll 前加foo/bar/test.html [ Failure Pass ] # Needs rebaseline,roll 后移除并git cl rebaseline
超过约 20 个布局测试是SK_IGNORE_xxx_FIX代码抑制Setup(define 写入skia/chromium_skia_defines.gypi,且不得与头文件重复)→ Rebaseline(移除 define + 加[ NeedsRebaseline ],约 600 张以内自动化可接受)→ Cleanup(删旧码与 define,开 Skia Issue 跟踪)

无论哪条路径,时序纪律都是成败关键:期望声明要跑在 roll 变红之前,define 的增删要成对出现,清理必须闭环。按这套流程操作,一个像素级的 Skia 变更就能在 Chromium 庞大的布局测试体系下平稳落地。

  • 图形学
  • 图像处理

【免费下载链接】skia

Skia is a complete 2D graphic library for drawing Text, Geometries, and Images.

项目地址:https://gitcode.com/gh_mirrors/skia1/skia
点击查看免费下载
上一篇:猫抓插件实战上手:网页视频音频一网打尽的零门槛攻略
下一篇:MobileIMSDK即时通讯场景扩展:从单聊到群聊的完整实现指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询