建構設定

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

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

背景

將一系列字型納入 Fuchsia 版本設定有點複雜。這是因為

  • Fuchsia 的開發人員指南偏好將預先建構的二進位檔案保存在 CIPD,而非 Git 存放區中。
  • Fuchsia 的字型檔案的來源很多,
  • 在運作中的 Fuchsia 系統上,只為客戶提供充滿 .ttf 檔案的目錄並不足夠,
    • 字型檔案並不完全自述,還必須從外部取得重要的中繼資料 (例如名稱、別名和樣式屬性)。
    • 其他中繼資料片段 (例如字型支援的碼點清單) 可在執行階段從每個字型檔案取得,但在建構時預先運算會更有效率。
    • 用戶端應用程式可能無法確切知道他們需要的字型,因此可能會想要求使用特定的通用字型系列樣式和語言,但實際上沒有特定的字型檔案。
  • 字型中繼資料詳細、經常重複,且容易維護。與其要求產品目標和個別元件的維護人員自行管理副本,建議您針對 Fuchsia 提供的每個常見字型,只定義一次中繼資料。

通用基礎架構和中繼資料

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

字型資料存放區

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

只要字型資料存放區的內容有所變更,Fusia 的自動化基礎架構就會自動檢查、擷取存放區描述的所有字型檔案,並將這些檔案組合成上傳至 Fuchsia CIPD 伺服器的 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:決定存放區要檢查的位置 (相對於根結帳目錄)。
  • remote:遠端存放區的 Git 網址
  • remotebranch:遠端存放區中的分支版本名稱
  • 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

字型目錄檔案是人工撰寫的中繼資料套裝組合,適用於這個字型資料存放區中所有的字型系列、資產和字體。

為方便編輯,/src/fonts/tools/schemas/font_catalog.schema.json 會提供 .font_catalog.json 檔案的 JSON 結構定義。標準結構定義是 Rust 中定義

packing_script.py

Fuchsia 的基礎架構填入暫存目錄後會叫用這個指令碼。

指令碼:

指令碼通常不需要修改。

基礎架構方案

如上所述,每次修改 fontdata 時,都會自動觸發基礎架構方案。這份食譜:

  1. 使用 jiri initjiri 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"/>

您可以從 CIPD 套件頁面上的最新執行個體「標記」取得 fuchsia/third_party/fonts 套件的 version ID。

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:轉換後的檔案名稱版本:轉換為小寫,所有特殊字元都會替換為連字號。可用來為 Fuuchsia 套件命名。
  • path_prefix:資產父項目錄的位置 (相對於 //prebuilt/third_party/fonts)。

//src/fonts/build/fonts.gni 中,.font_pkgs.json 檔案的內容會合併為單一 GN 範圍,可做為對照表使用。

字型套件

除了直接將字型資產直接提供給字型提供者的命名空間之外,您也可以選擇建立單一字型 Fuchsia 套件。看起來就是這樣:packageresources 中只包含單一字型,沒有任何其他內容。

此屬性可用於暫時傳送字型,搭配 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 指令碼專屬字型都有 ASCII 範圍的字符,但 Noto Sans Latin 變體會先優先採用。
  • 如果有重疊的涵蓋範圍,請將較小的字型檔案放在清單中較高的位置。這樣可以減少載入備用字型時 UI 資源浪費的情形。

font_collection

定義於 fonts.gni

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

輸入

(完整說明文件請參閱 Font.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 目標。

如果產品只使用「local」字型,只要將 font_collection 目標新增至產品的依附元件標籤 (通常為 base_package_labels),就夠了。

如果產品也使用 package 字型,則必須根據套件是否屬於臨時性質,將這些目標明確新增至 base_package_labelsuniverse_package_labels