build 配置

字体的 build 配置有三个基本层:

  1. 通用基础架构和元数据
  2. 可重复使用的字体包
  3. 产品专属配置

背景

将一系列字体添加到 Fuchsia build 的设置 非常困难。这是因为

  • Fuchsia 的开发者指南倾向于将预构建的二进制文件保留在 CIPD 中, 不在 Git 代码库中
  • Fuchsia 的字体文件来自各种来源。
  • 在运行的 Fuchsia 系统上,仅仅为客户提供 目录中包含 .ttf 个文件。
    • 字体文件不能完全进行自描述;还有一些重要的元数据 (例如名称、别名和样式属性), 外部。
    • 其他元数据片段 码位,可以通过 但从每个字体文件开始运行时,其效率要高得多 在构建时预计算它们。
    • 客户端应用可能不知道具体要查找哪种字体 用于:他们可能想请求获取 通用字体系列 样式和语言,但实际上并没有特定的 字体文件。
  • 字体元数据冗长、经常重复,并且容易维护。它 最好为每个常用字体仅定义一次此元数据 而非询问产品定位和 单独的组件来管理自己的副本。

通用基础架构和元数据

第一层为资产和元数据建立目录, 可用于 Fuchsia 产品 build。

字体数据存储区

字体文件的元数据和外部源列表保存在 字体数据代码库。对于 Fuchsia 的开源字体,您可以在以下位置找到该字体: //fontdata

每当字体数据代码库的内容发生变化时,Furchsia 的 自动化基础架构会自动对其进行检查, 代码库描述的字体文件,并将它们捆绑到 CIPD 软件包中 并上传到 Fuchsia 的 CIPD 服务器。

字体数据存储区包含以下文件:

manifest.xml

这是一个 Jiri 清单文件。 在本示例中,它由 Git 代码库和修订版本 ID 列表组成,其中包含 所需的字体文件

每个导入的代码库都列在 <project> 元素中。

示例条目:

<project
    name="github.com/googlefonts/noto-cjk"
    path="github.com/googlefonts/noto-cjk"
    remote="https://fuchsia.googlesource.com/third_party/github.com/googlefonts/noto-cjk"
    remotebranch="upstream/master"
    revision="be6c059ac1587e556e2412b27f5155c8eb3ddbe6"/>
  • name:任意名称(不会影响任何内容)
  • path:确定代码库相对于根的检出位置 checkout 目录
  • remote:远程代码库的 Git 网址
  • remotebranch:远程代码库中的分支名称
  • revision:用于固定检出的 Git 提交哈希值

contents.json

这些是供 Fuchsia 的基础架构从 checkout 目录进入暂存目录 (staging directory)。{destination, files} 的每个条目都定义了暂存目录中的顶级文件夹,并且 文件。

示例条目:

{
    "destination": "material",
    "files": [
      "github.com/google/material-design-icons/iconfont/MaterialIcons-Regular.ttf",
      "github.com/google/material-design-icons/LICENSE"
    ]
}

${catalog_name}.font_catalog.json

字体目录文件是人工编写的,包含所有字体的元数据, 系列、资源和字体。

为便于修改,我们提供了 .font_catalog.json 文件的 JSON 架构 在 /src/fonts/tools/schemas/font_catalog.schema.json. 规范架构为 在 Rust 中定义

packing_script.py

Fuchsia 的基础架构会在填充预演条件后调用此脚本 目录

脚本:

  • 将暂存目录中的所有字体和许可文件复制到输出中 目录。
  • 在以下文件中生成 ${catalog_name}.font_pkgs.json 文件: 输出目录中。

此脚本通常不需要修改。

基础架构配方

如上所述,无论何时,只要 fontdata 的修改。这个食谱:

  1. 使用 jiri initjiri update 检出引用的代码库。
  2. 根据 contents.json 暂存已签出的文件。
  3. 调用打包脚本以将文件写入输出 目录。
  4. 将输出目录的内容上传到 CIPD

CIPD 软件包

系统会将开放源代码字体包上传到 fuchsia/third_party/fonts CIPD 软件包

Jiri 预构建

CIPD 软件包的内容通过 prebuilts jiri 清单

    <!--   Fonts -->
    <package name="fuchsia/third_party/fonts"
             version="git_revision:a10ce51e308f48c5e6d70ab5777434af46a5ddb8"
             path="prebuilt/third_party/fonts"/>

可以获取 fuchsia/third_party/fonts 软件包的 version ID 通过“代码”菜单集群上的最新实例 “CIPD 软件包”页面

fuchsia/third_party/fonts CIPD 软件包的屏幕截图,其中突出显示了以前缀“git_revision:”开头的实例的标记

全局 GN 参数

//src/fonts/build/font_args.gni 进行声明 几个与字体相关的构建参数。其中最重要的两个选项是

*.font_pkgs.json 个文件

按照设计,这些文件可以通过 GN 的简单 JSON 解析器解析, read_file。 它们包含以下形式的条目列表:

    {
      "file_name": "AlphaSans-Regular.ttf",
      "safe_name": "alphasans-regular-ttf",
      "path_prefix": "alpha"
    },
  • file_name:字体文件资源文件的名称。这是规范的 的标识符,从而获取此对照表中的键。
  • safe_name:文件名的转换版本:转换为小写形式。 并将所有特殊字符替换为连字符。它可用于命名 Fuchsia 软件包。
  • path_prefix:素材资源父级目录的位置(相对于该目录) //prebuilt/third_party/fonts

//src/fonts/build/fonts.gni 中, .font_pkgs.json 文件合并为单个 GN 作用域, 用作对照表

字体包

除了直接向字体提供程序的命名空间提供字体资源之外, 还可以选择创建单字体的 Fuchsia 软件包。这是 顾名思义,就是一个 package,它只包含一种字体, 仅 resources,不执行任何其他操作。

这可用于结合临时字体传递 fuchsia.pkg.FontResolver。(待办事项:链接到更多文档。)

所有可能的字体包都已在 //src/fonts/packages/BUILD.gn

  • 每个软件包名称均采用 font-package-<font-safe-name> 格式(请参阅 safe_name),例如 font-package-roboto-regular-ttf
  • 因此,软件包的 GN 目标为 //src/fonts/packages:<package-name>,例如 //src/fonts/packages:font-package-roboto-regular.ttf
  • 每个包的网址都采用以下格式 fuchsia-pkg://fuchsia.com/<package-name>,例如 fuchsia-pkg://fuchsia.com/font-package-roboto-regular-ttf

local_font_bundle

fonts.gni 中定义

本地字体包是一组直接放置在 使用 config_data()

大多数本地字体包都是在 //src/fonts/collections/BUILD.gn

示例:

```gn
local_font_bundle("small-open-fonts-local") {
  asset_names = [
    "MaterialIcons-Regular.ttf",
    "Roboto-Regular.ttf",
    "Roboto-Light.ttf",
    "Roboto-Medium.ttf",
    "RobotoMono-Regular.ttf",
    "RobotoSlab-Regular.ttf",
  ]
}

产品特定的字体配置

最后,每个 主推产品组 需要配置特定的字体资源, 元数据。

字体产品配置文件

.fontcfg.json(或 .fontcfg.json5)文件包含一组人工编写的 产品特定的字体设置。这里有 JSON 架构适用于 更好的编辑器体验

目前,此文件的主要用途是定义一种 链,即在与 客户端的字体请求不可用。

以下是一个后备广告链的基本示例, //src/fonts/collections/open-fonts-collection.fontcfg.json5:

fallback_chain: [
        ///
        ///
        /// SANS SERIF LATIN
        "Roboto-Regular.ttf",
        "Roboto-Black.ttf",
        "Roboto-BlackItalic.ttf",
        "Roboto-Bold.ttf",
        "Roboto-BoldItalic.ttf",
        "Roboto-Italic.ttf",
        "Roboto-Light.ttf",
        "Roboto-LightItalic.ttf",
        "Roboto-Medium.ttf",
        "Roboto-MediumItalic.ttf",
        "Roboto-Thin.ttf",
        "Roboto-ThinItalic.ttf",
        "RobotoCondensed-Regular.ttf",
        "RobotoCondensed-Bold.ttf",
        "RobotoCondensed-BoldItalic.ttf",
        "RobotoCondensed-Italic.ttf",
        "RobotoCondensed-Light.ttf",
        "RobotoCondensed-LightItalic.ttf",
        "DroidSans-Regular.ttf",
        "DroidSans-Bold.ttf",

        ///
        ///
        /// SANS-SERIF NON-LATIN
        "NotoNaskhArabicUI-Regular.ttf",
        "NotoSansArmenian-Regular.ttf",
        "NotoSansEthiopic-Regular.ttf",
        "NotoSansGeorgian-Regular.ttf",
        "NotoSansHebrew-Regular.ttf",
        "NotoSansThaiUI-Regular.ttf",

        // All Indian scripts should come after Devanagari, due to shared danda characters.
        "NotoSansDevanagariUI-Regular.ttf",
        "NotoSansBengaliUI-Regular.ttf",
        "NotoSansGujaratiUI-Regular.ttf",
        "NotoSansKannada-Regular.ttf",
        "NotoSansMalayalamUI-Regular.ttf",
        "NotoSansTamilUI-Regular.ttf",
        "NotoSansTelugu-Regular.ttf",

        ///
        ///
        /// SANS SERIF CJK
        {
            full_name: "Noto Sans CJK SC",
        },
        {
            full_name: "Noto Sans CJK TC",
        },
        {
            full_name: "Noto Sans CJK HK",
        },
        {
            full_name: "Noto Sans CJK KR",
        },
        {
            full_name: "Noto Sans CJK JP",
        },
        {
            full_name: "Noto Sans CJK SC Bold",
        },
        {
            full_name: "Noto Sans CJK TC Bold",
        },
        {
            full_name: "Noto Sans CJK HK Bold",
        },
        {
            full_name: "Noto Sans CJK KR Bold",
        },
        {
            full_name: "Noto Sans CJK JP Bold",
        },
        {
            full_name: "Noto Sans CJK SC Black",
        },
        {
            full_name: "Noto Sans CJK TC Black",
        },
        {
            full_name: "Noto Sans CJK HK Black",
        },
        {
            full_name: "Noto Sans CJK KR Black",
        },
        {
            full_name: "Noto Sans CJK JP Black",
        },
        {
            full_name: "Noto Sans CJK SC DemiLight",
        },
        {
            full_name: "Noto Sans CJK TC DemiLight",
        },
        {
            full_name: "Noto Sans CJK HK DemiLight",
        },
        {
            full_name: "Noto Sans CJK KR DemiLight",
        },
        {
            full_name: "Noto Sans CJK JP DemiLight",
        },
        {
            full_name: "Noto Sans CJK SC Light",
        },
        {
            full_name: "Noto Sans CJK TC Light",
        },
        {
            full_name: "Noto Sans CJK HK Light",
        },
        {
            full_name: "Noto Sans CJK KR Light",
        },
        {
            full_name: "Noto Sans CJK JP Light",
        },
        {
            full_name: "Noto Sans CJK SC Medium",
        },
        {
            full_name: "Noto Sans CJK TC Medium",
        },
        {
            full_name: "Noto Sans CJK HK Medium",
        },
        {
            full_name: "Noto Sans CJK KR Medium",
        },
        {
            full_name: "Noto Sans CJK JP Medium",
        },
        {
            full_name: "Noto Sans CJK SC Thin",
        },
        {
            full_name: "Noto Sans CJK TC Thin",
        },
        {
            full_name: "Noto Sans CJK HK Thin",
        },
        {
            full_name: "Noto Sans CJK KR Thin",
        },
        {
            full_name: "Noto Sans CJK JP Thin",
        },

        ///
        ///
        /// SERIF LATIN
        "RobotoSlab-Regular.ttf",
        "RobotoSlab-Bold.ttf",
        "RobotoSlab-Light.ttf",
        "RobotoSlab-Thin.ttf",
        "DroidSerif-Regular.ttf",
        "DroidSerif-Bold.ttf",
        "DroidSerif-BoldItalic.ttf",
        "DroidSerif-Italic.ttf",

        ///
        ///
        /// SERIF CJK
        {
            full_name: "Noto Serif CJK SC",
        },
        {
            full_name: "Noto Serif CJK TC",
        },
        {
            full_name: "Noto Serif CJK KR",
        },
        {
            full_name: "Noto Serif CJK JP",
        },
        {
            full_name: "Noto Serif CJK SC Bold",
        },
        {
            full_name: "Noto Serif CJK TC Bold",
        },
        {
            full_name: "Noto Serif CJK KR Bold",
        },
        {
            full_name: "Noto Serif CJK JP Bold",
        },
        {
            full_name: "Noto Serif CJK SC Black",
        },
        {
            full_name: "Noto Serif CJK TC Black",
        },
        {
            full_name: "Noto Serif CJK KR Black",
        },
        {
            full_name: "Noto Serif CJK JP Black",
        },
        {
            full_name: "Noto Serif CJK SC ExtraLight",
        },
        {
            full_name: "Noto Serif CJK TC ExtraLight",
        },
        {
            full_name: "Noto Serif CJK KR ExtraLight",
        },
        {
            full_name: "Noto Serif CJK JP ExtraLight",
        },
        {
            full_name: "Noto Serif CJK SC Light",
        },
        {
            full_name: "Noto Serif CJK TC Light",
        },
        {
            full_name: "Noto Serif CJK KR Light",
        },
        {
            full_name: "Noto Serif CJK JP Light",
        },
        {
            full_name: "Noto Serif CJK SC Medium",
        },
        {
            full_name: "Noto Serif CJK TC Medium",
        },
        {
            full_name: "Noto Serif CJK KR Medium",
        },
        {
            full_name: "Noto Serif CJK JP Medium",
        },
        {
            full_name: "Noto Serif CJK SC SemiBold",
        },
        {
            full_name: "Noto Serif CJK TC SemiBold",
        },
        {
            full_name: "Noto Serif CJK KR SemiBold",
        },
        {
            full_name: "Noto Serif CJK JP SemiBold",
        },

        ///
        ///
        /// MONOSPACE LATIN
        "RobotoMono-Bold.ttf",
        "RobotoMono-BoldItalic.ttf",
        "RobotoMono-Italic.ttf",
        "RobotoMono-Light.ttf",
        "RobotoMono-LightItalic.ttf",
        "RobotoMono-Regular.ttf",
        "RobotoMono-Medium.ttf",
        "RobotoMono-MediumItalic.ttf",
        "RobotoMono-Thin.ttf",
        "RobotoMono-ThinItalic.ttf",
        "DroidSansMono-Regular.ttf",

        ///
        ///
        /// MONOSPACE CJK
        {
            full_name: "Noto Sans Mono CJK SC",
        },
        {
            full_name: "Noto Sans Mono CJK TC",
        },
        {
            full_name: "Noto Sans Mono CJK HK",
        },
        {
            full_name: "Noto Sans Mono CJK KR",
        },
        {
            full_name: "Noto Sans Mono CJK JP",
        },
        {
            full_name: "Noto Sans Mono CJK SC Bold",
        },
        {
            full_name: "Noto Sans Mono CJK TC Bold",
        },
        {
            full_name: "Noto Sans Mono CJK HK Bold",
        },
        {
            full_name: "Noto Sans Mono CJK KR Bold",
        },
        {
            full_name: "Noto Sans Mono CJK JP Bold",
        },

        ///
        ///
        /// CURSIVE LATIN
        "Quintessential-Regular.ttf",

        ///
        ///
        /// EMOJI
        "NotoColorEmoji.ttf",

        ///
        ///
        /// SYMBOLS
        "NotoSansSymbols-Regular.ttf",
        "NotoSansSymbols2-Regular.ttf",
    ]

如果资源文件包含多个字型,则同一种字型 使用 JSON 对象(而不仅仅是文件名)进行引用:

fallback_chain: [
    "SomeCompleteFont-Bold.ttf",
    { file_name: "NotoSansCJK-Regular.ttc", index: 1},
]

后备链是由手动定义的。请遵循以下准则:

  • 为每种受支持的脚本添加至少一种字体。(支持的 脚本因产品而异)。
  • 尽量至少覆盖 sans-serifserifmonospace 字体 。
  • 当覆盖范围重叠时,将更具体的素材资源放在 列表。例如,所有 Noto Sans 脚本专用字体都有字形 ,但应首先显示 Noto Sans Latin 变体。
  • 当有重叠的覆盖区域时,将较小的字体文件放在 列表。这可以减少加载后备字体时的界面卡顿。

font_collection

fonts.gni 中定义

在完成任何所需的 local_font_bundle 和/或字体 packages 之后 它们会汇编到 font_collection 中。

输入

(如需查看完整文档,请参阅 fonts.gni。)

  • font_packages:字体为 package 的 GN 标签 位于目标商品的universe_package_labels中。
  • local_font_bundles:目标的 local_font_bundle 的 GN 标签 产品。这些内容将包含在字体提供程序的配置数据中。
  • local_asset_names:本地字体素材资源名称列表(用于创建临时 local_font_bundle)。
  • product_config_path:包含以下内容的 JSON 文件的路径 产品专用的字体配置,包括后备字体 。
  • manifest_prefix:生成的字体清单文件名称的前缀。 默认设置为 "all"

内部原理

font_collection 会遍历所有字体资源和传递闭包, 其中包含的所有软件包它会收集其 GN 元数据 构建映射到本地文件中字体包的字体列表。

模板会将此信息传递给字体清单生成器 (GN 模板Rust 源代码)以及 字体目录和所有字体资产。

清单生成器从字体目录中选择预定义的元数据 。font_collection它还读了 从每个包含的字体文件中提取 码位(字符集)。

所有这些数据都会汇聚到一个 .font_manifest.json 文件中, 使用 config_data 规则提供给字体提供程序服务。

输出

font_collection 会生成以下工件:

  • <manifest-prefix>.font_manifest.json:这是元数据的集合 。它通过使用 config_data 规则。
  • font_packages.json。此文件列出了包含的所有单字体 Fuchsia 软件包,并使用 config_data 规则提供给 pkg-resolver。这个 用于确定通过 fuchsia.pkg.FontResolver 公开的字体包。

font_collection 创建的 GN 目标包含config_data 上述两个 JSON 文件,以及本地字体资源的 config_data 目标。

如果商品仅使用本地字体,则添加本地字体就足够了。 font_collection 定位到产品的依赖项标签(通常 base_package_labels)。

如果产品还使用字体 package,则必须明确添加这些目标 更改为 base_package_labelsuniverse_package_labels, 具体取决于软件包是否为临时资源