# 機能設計書 84-FontManager

## 概要

本ドキュメントは、Avaloniaフレームワークにおけるフォント管理機能「FontManager」の設計仕様を記述する。FontManagerクラスは、システムフォントの列挙、フォントコレクションの管理、GlyphTypefaceの取得、フォントフォールバック処理を担当する中核的なフォント管理システムである。

### 本機能の処理概要

FontManagerは、アプリケーション全体のフォントを統合管理するシングルトンサービスである。システムにインストールされたフォント、埋め込みフォント、カスタムフォントコレクションを管理し、Typefaceからの要求に応じて適切なGlyphTypefaceを提供する。また、文字に対応するフォントが見つからない場合のフォールバック処理も担当する。

**業務上の目的・背景**：クロスプラットフォームアプリケーションでは、プラットフォームごとに異なるフォント環境に対応する必要がある。FontManagerは、プラットフォーム固有のフォント実装（IFontManagerImpl）を抽象化し、統一的なフォントアクセスAPIを提供する。また、アプリケーション固有のフォントリソースを動的に追加・削除する機能も提供する。

**機能の利用シーン**：テキスト描画時のフォント解決、カスタムフォントの登録、Unicode文字に対するフォールバックフォントの検索、フォントファミリー一覧の取得で利用される。

**主要な処理内容**：
1. システムフォントコレクション（SystemFonts）の管理
2. 埋め込みフォントコレクション（EmbeddedFontCollection）の管理
3. TypefaceからGlyphTypefaceへの解決
4. 文字に対するフォントマッチング（TryMatchCharacter）
5. フォントファミリーマッピングとフォールバック処理
6. フォントコレクションの動的追加・削除

**関連システム・外部連携**：IFontManagerImpl（プラットフォーム実装）、IFontCollection、Typeface、GlyphTypefaceと連携する。

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 全テキスト表示画面 | 補助機能 | フォント解決で使用される |

## 機能種別

サービス / ファクトリ / キャッシュ管理

## 入力仕様

### 入力パラメータ

**TryGetGlyphTypeface**:
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| typeface | Typeface | Yes | 解決対象のTypeface | - |
| glyphTypeface | out GlyphTypeface? | - | 出力パラメータ | - |

**TryMatchCharacter**:
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| codepoint | int | Yes | Unicode コードポイント | - |
| fontStyle | FontStyle | Yes | フォントスタイル | - |
| fontWeight | FontWeight | Yes | フォント太さ | - |
| fontStretch | FontStretch | Yes | フォント伸縮 | - |
| fontFamily | FontFamily? | No | 優先フォントファミリー | - |
| culture | CultureInfo? | No | カルチャ情報 | - |

### 入力データソース

Typeface、テキストレンダリングコンポーネントからの呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| glyphTypeface | GlyphTypeface | 解決されたグリフタイプフェース |
| DefaultFontFamily | FontFamily | デフォルトフォントファミリー |
| SystemFonts | IFontCollection | システムフォントコレクション |

### 出力先

Typeface、GlyphRun、テキストレンダリングパイプライン

## 処理フロー

### 処理シーケンス

```
1. FontManager.Currentでシングルトン取得
   └─ AvaloniaLocatorからサービス取得
   └─ 未登録の場合、IFontManagerImplを使用して新規作成

2. TryGetGlyphTypeface呼び出し
   └─ フォントファミリーマッピングを確認
   └─ DefaultFontFamilyNameの場合、デフォルトフォントにフォールバック
   └─ FontFamilyKeyがある場合、対応するフォントコレクションから検索
   └─ キーがない場合、SystemFontsから検索
   └─ 見つからない場合、DefaultFontFamilyで再試行

3. TryMatchCharacter呼び出し（フォントフォールバック）
   └─ FontManagerOptions.FontFallbacksを確認
   └─ UnicodeRangeに基づいてフォールバックフォントを選択
   └─ CompositeFontFamilyKeyの場合、各キーを順番に試行
   └─ 最終的にSystemFonts.TryMatchCharacterにフォールバック

4. フォントコレクション管理
   └─ AddFontCollection: フォントコレクションを追加
   └─ RemoveFontCollection: フォントコレクションを削除
```

### フローチャート

```mermaid
flowchart TD
    A[TryGetGlyphTypeface] --> B{マッピング確認}
    B -->|あり| C[マップされたFontFamily使用]
    B -->|なし| D{DefaultFontFamilyName?}
    D -->|Yes| E[DefaultFontFamilyで再帰呼び出し]
    D -->|No| F{FontFamilyKeyあり?}
    F -->|Yes| G{CompositeFontFamilyKey?}
    G -->|Yes| H[各キーを順番に試行]
    G -->|No| I[単一キーで検索]
    F -->|No| J[SystemFontsから検索]
    H --> K{見つかった?}
    I --> K
    J --> K
    K -->|Yes| L[GlyphTypeface返却]
    K -->|No| M{DefaultFontFamily?}
    M -->|No| E
    M -->|Yes| N[false返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | シングルトン | FontManager.Currentで唯一のインスタンスを取得 | アプリケーション全体 |
| BR-002 | フォールバック順序 | FontFallbacks → 指定FontFamily → SystemFonts → DefaultFontFamily | フォント検索時 |
| BR-003 | フォントコレクションキー | フォントコレクションのキーはfonts:スキームに従う | AddFontCollection時 |
| BR-004 | デフォルトフォント禁止 | "$Default"をDefaultFontFamilyNameとして使用不可 | FontManager初期化時 |

### 計算ロジック

**フォントコレクションソース解決**:
```csharp
source = key.Source.EnsureAbsolute(key.BaseUri)
```

**システムフォントキー**:
```csharp
SystemFontsKey = new Uri("fonts:SystemFonts", UriKind.Absolute)
```

## データベース操作仕様

該当なし（メモリ上での処理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ArgumentException | AddFontCollectionでキーがfonts:スキームでない場合 | 正しいキー形式を使用 |
| - | InvalidOperationException | DefaultFontFamilyNameが空またはnullの場合 | FontManagerOptionsで設定 |
| - | InvalidOperationException | DefaultFontFamilyNameが"$Default"の場合 | 具体的なフォント名を設定 |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- フォントコレクションはConcurrentDictionaryでスレッドセーフに管理
- フォントコレクションの取得結果は内部的にキャッシュされる
- システムフォントは遅延ロードされる

## セキュリティ考慮事項

- 埋め込みフォントはavares://またはresm://スキームからのみ読み込み可能
- 外部URLからのフォント読み込みは制限される

## 備考

FontManagerはIDisposableを実装しており、アプリケーション終了時にフォントコレクションのリソースを解放する。

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | フィールド定義（20-28行目）: SystemFontsKey, _fontCollections, _fontFallbacks等 |
| 1-2 | IFontCollection.cs | `src/Avalonia.Base/Media/Fonts/IFontCollection.cs` | フォントコレクションインターフェース |
| 1-3 | FontManagerOptions.cs | `src/Avalonia.Base/Media/Fonts/FontManagerOptions.cs` | 設定オプション |

**読解のコツ**: _fontCollectionsはConcurrentDictionary<Uri, IFontCollection>型で、Uriをキーにフォントコレクションを管理する。

#### Step 2: シングルトンとコンストラクタを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | Currentプロパティ（45-64行目）: シングルトンパターン |
| 2-2 | FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | コンストラクタ（30-40行目）: 初期化処理 |

**主要処理フロー**:
1. **49-53行目**: AvaloniaLocatorから既存インスタンスを取得
2. **56-60行目**: 未登録の場合、IFontManagerImplから新規作成してバインド
3. **34行目**: FontManagerOptionsからFontFallbacksを取得
4. **38-39行目**: デフォルトフォントファミリーを決定

#### Step 3: GlyphTypeface解決処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | TryGetGlyphTypeface（101-188行目）: メイン解決ロジック |
| 3-2 | FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | TryGetGlyphTypefaceByKeyAndName（190-213行目）: キーベース検索 |

**主要処理フロー**:
- **105行目**: フォントファミリーマッピングを取得
- **107-110行目**: DefaultFontFamilyNameの場合、デフォルトで再試行
- **115-159行目**: CompositeFontFamilyKeyの場合、各キーを順番に試行
- **163-168行目**: SystemFontsから検索
- **177行目**: 見つからない場合、DefaultFontFamilyで再試行

#### Step 4: フォントマッチング処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | TryMatchCharacter（263-328行目）: 文字に対するフォントマッチング |

**主要処理フロー**:
- **266-280行目**: FontFallbacksから優先的にマッチング
- **283-323行目**: FontFamilyKeyがある場合、コレクションから検索
- **326-327行目**: 最終的にSystemFonts.TryMatchCharacterにフォールバック

#### Step 5: フォントコレクション管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | AddFontCollection（221-236行目）: コレクション追加 |
| 5-2 | FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | RemoveFontCollection（242-248行目）: コレクション削除 |
| 5-3 | FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | TryGetFontCollection（354-384行目）: コレクション取得 |

### プログラム呼び出し階層図

```
FontManager.Current (シングルトン)
    │
    ├─ TryGetGlyphTypeface
    │      ├─ GetMappedFontFamily
    │      ├─ TryGetGlyphTypefaceByKeyAndName
    │      │      └─ TryGetFontCollection
    │      │             └─ IFontCollection.TryGetGlyphTypeface
    │      └─ SystemFonts.TryGetGlyphTypeface
    │
    ├─ TryMatchCharacter
    │      ├─ FontFallbacks ループ
    │      │      └─ UnicodeRange.IsInRange
    │      ├─ TryGetFontCollection
    │      │      └─ IFontCollection.TryMatchCharacter
    │      └─ SystemFonts.TryMatchCharacter
    │
    ├─ AddFontCollection
    │      └─ _fontCollections.AddOrUpdate
    │
    └─ RemoveFontCollection
           └─ _fontCollections.TryRemove
```

### データフロー図

```
[入力]                    [処理]                         [出力]

Typeface ──────────────▶ FontManager ────────────────▶ GlyphTypeface
                              │
                              ├─ _fontCollections
                              │      ├─ SystemFontCollection
                              │      └─ EmbeddedFontCollection
                              │
                              └─ _fontFallbacks
                                     └─ FontFallback[]

Codepoint ─────────────▶ TryMatchCharacter ───────────▶ Typeface
FontStyle                      │                          (fallback result)
FontWeight                     └─ UnicodeRange判定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| FontManager.cs | `src/Avalonia.Base/Media/FontManager.cs` | ソース | メインクラス実装 |
| IFontManagerImpl.cs | `src/Avalonia.Base/Platform/IFontManagerImpl.cs` | ソース | プラットフォーム抽象化 |
| IFontCollection.cs | `src/Avalonia.Base/Media/Fonts/IFontCollection.cs` | ソース | フォントコレクションインターフェース |
| SystemFontCollection.cs | `src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs` | ソース | システムフォントコレクション |
| EmbeddedFontCollection.cs | `src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs` | ソース | 埋め込みフォントコレクション |
| FontManagerOptions.cs | `src/Avalonia.Base/Media/Fonts/FontManagerOptions.cs` | ソース | 設定オプション |
| FontFallback.cs | `src/Avalonia.Base/Media/Fonts/FontFallback.cs` | ソース | フォールバック定義 |
| FontFamilyKey.cs | `src/Avalonia.Base/Media/Fonts/FontFamilyKey.cs` | ソース | フォントファミリーキー |
| CompositeFontFamilyKey.cs | `src/Avalonia.Base/Media/Fonts/CompositeFontFamilyKey.cs` | ソース | 複合フォントファミリーキー |
