建構設定

字型建構設定有三個基本層:

  1. 通用基礎架構和中繼資料
  2. 可重複使用的字型組合
  3. 產品專屬設定

背景

將字型集合加入 Fuchsia 建構作業的設定程序有點複雜。這是因為

  • Fuchsia 的開發人員指南建議將預先建構的二進位檔案保留在 CIPD 中,而非 Git 存放區。
  • Fuchsia 的字型檔案來自多種來源。
  • 在執行中的 Fuchsia 系統上,只提供用戶端一個充滿 .ttf 檔案的目錄是不夠的。
    • 字型檔案並非完全自我描述;有些重要中繼資料 (例如名稱、別名和樣式屬性) 必須從外部取得。
    • 其他中繼資料 (例如字型支援的碼點清單) 可以在執行階段從每個字型檔案取得,但在建構時預先計算會更有效率。
    • 用戶端應用程式可能不清楚要尋找哪種字型,而是要求特定的一般字型系列、樣式和語言,但實際上並未指定字型檔案。
  • 字型中繼資料冗長、經常重複,且容易出錯。建議您為 Fuchsia 提供的每個通用字型定義一次這項中繼資料,而不是要求產品目標和個別元件的維護人員管理自己的副本。

通用基礎架構和中繼資料

第一層會建立資產和中繼資料目錄,可用於 Fuchsia 產品建構作業。

字型資料存放區

字型檔案的中繼資料和外部來源清單會保存在字型資料存放區中。如果是 Fuchsia 的開放原始碼字型,請前往 //fontdata。

每當字型資料存放區的內容變更時,Fuchsia 的自動化基礎架構會自動檢查、擷取存放區描述的所有字型檔案,並將這些檔案彙整至 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"
    revision="be6c059ac1587e556e2412b27f5155c8eb3ddbe6"/>
  • name:任意名稱 (不會影響任何項目)
  • path:決定存放區相對於根檢出目錄的檢出位置。
  • remote:遠端存放區的 Git 網址
  • revision:要固定檢出的 Git 修訂版本雜湊

contents.json

這些指令會指示 Fuchsia 基礎架構將檔案從檢出目錄複製到暫存目錄。{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 的基礎架構會在填入測試目錄後叫用這個指令碼。

指令碼:

指令碼通常不需要修改。

基礎架構配方

如上所述,每當 fontdata 修改時,系統就會自動觸發基礎架構配方。這項配方:

  1. 使用 jiri init 和 jiri update 簽出參照的存放區。
  2. 根據 contents.json 暫存已簽出的檔案。
  3. 叫用封裝指令碼,將檔案寫入輸出目錄。
  4. 將輸出目錄的內容上傳至 CIPD。

CIPD 套件

開放原始碼字型套件會上傳至 fuchsia/third_party/fonts CIPD 套件。

Jiri 預先建構項目

CIPD 套件的內容會透過 prebuilts jiri 資訊清單進入 Fuchsia 檢出:

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

如要取得 fuchsia/third_party/fonts 套件的 version ID,請前往 CIPD 套件頁面,查看最新執行個體的「Tags」。

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:字型檔案素材資源檔案的名稱。這是每個字型素材資源的標準 ID,因此也是這個對照表中的鍵。
  • 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 中宣告。

範例:

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-serif、serif 和 monospace 字型系列。
  • 如果涵蓋範圍重疊,請將更具體的素材資源放在清單中較高的位置。舉例來說,所有 Noto Sans 指令碼專用字型都有 ASCII 範圍的字元,但 Noto Sans Latin 變體應排在最前面。
  • 如果涵蓋範圍重疊,請將較小的字型檔案放在清單上方。這可減少載入備用字型時的 UI 資源浪費。

font_collection

定義於 fonts.gni

宣告任何必要的 local_font_bundle 和/或字型 packages 後,系統會將這些項目組合成 font_collection。

輸入

(如需完整說明文件,請參閱 fonts.gni)。

  • font_packages:目標產品 universe_package_labels 中字型 package 的 GN 標籤。
  • 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 目標包含上述兩個 JSON 檔案的 config_data,以及本機字型素材資源的 config_data 目標。

如果產品只使用本機字型,只要將 font_collection 目標新增至產品的依附元件標籤 (通常是 base_package_labels) 即可。

如果產品也使用字型 package,則必須明確將這些目標新增至 base_package_labels 或 universe_package_labels,具體取決於套件是否為暫時性。