# 画面設計書 74-SkCanvas

## 概要

本ドキュメントは、RenderDemoアプリケーションにおけるSkCanvas（SkiaCanvas描画）ページの画面設計を定義するものです。このページは、SkiaSharpライブラリを使用したカスタム描画機能を視覚的にデモンストレーションします。Avaloniaの標準描画APIを超えた高度なグラフィックス処理が可能であることを示しています。

### 本画面の処理概要

**業務上の目的・背景**：Avaloniaフレームワークは標準でクロスプラットフォームの描画APIを提供しますが、より高度なグラフィックス処理（シェーダー、フィルター、複雑なブレンド処理など）が必要な場合、SkiaSharpの低レベルAPIを直接使用することが求められます。本画面は、ICustomDrawOperationインターフェースを実装してSkiaSharpのSKCanvasに直接アクセスし、Perlinノイズ、グラデーション、ブラー効果などを組み合わせた動的なビジュアルエフェクトを開発者が学習できるようにすることを目的としています。

**画面へのアクセス方法**：RenderDemoアプリケーションを起動後、左側のHamburgerMenuから「SkCanvas」タブを選択することでアクセスできます。

**主要な操作・処理内容**：
1. 画面表示時に自動的に動的アニメーションが開始される
2. スイープグラデーション（シアン、マゼンタ、イエロー）がPerlinノイズと合成
3. ブラー効果がアニメーションで動的に変化
4. 疑似光源が円運動でコントロール全体を照らす効果
5. 画面は連続的に再描画され、60fps相当のアニメーション

**画面遷移**：
- 遷移元：RenderDemo MainWindow（HamburgerMenuより選択）
- 遷移先：なし（デモページのため画面遷移機能は持たない）

**権限による表示制御**：本画面はデモ用途のため、権限による表示制御は実装されていません。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 88 | SkiaPlatform | 主機能 | SkiaCanvas描画のデモ。SkiaSharpによる2D描画 |

## 画面種別

デモ / カスタム描画・エフェクト表示

## URL/ルーティング

本アプリケーションはデスクトップアプリケーションのため、URLルーティングは使用しません。
HamburgerMenuのタブ選択により画面切り替えが行われます。

## 入出力項目

本画面はデモ表示専用のため、ユーザー入力項目はありません。

| 項目名 | 入力/出力 | 型 | 説明 |
|--------|----------|-----|------|
| なし | - | - | 表示専用画面 |

## 表示項目

| 項目名 | 型 | 説明 |
|--------|-----|------|
| カスタム描画領域 | Control | SkiaSharpで描画されるエフェクト領域（コントロール全体） |
| フォールバックテキスト | GlyphRun | Skiaが利用不可の場合に表示されるメッセージ |

## イベント仕様

### 1-ページ読み込み時

ページがロードされると、カスタム描画が開始されます。

**処理フロー**:
1. CustomSkiaPageコントロールがインスタンス化される
2. コンストラクタでClipToBounds=trueが設定される
3. フォールバック用のGlyphRunが生成される（"Current rendering API is not Skia"）
4. Renderメソッドが呼ばれ、CustomDrawOpが実行される

### 2-フレーム描画時

各フレームでカスタム描画処理が実行されます。

**処理フロー**:
1. Render(DrawingContext)が呼ばれる
2. context.Custom(CustomDrawOp)でカスタム描画を登録
3. CustomDrawOp.Render()でSkiaSharp APIにアクセス
4. ISkiaSharpApiLeaseFeatureでSKCanvasを取得
5. シェーダー、フィルター、ペイントを設定して描画
6. Dispatcher.UIThread.InvokeAsync(InvalidateVisual)で次フレームを要求

## データベース更新仕様

本画面はデモ表示専用のため、データベース操作は行いません。

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| なし | - | - | データベース操作なし |

## メッセージ仕様

| メッセージID | 種別 | 内容 | 表示条件 |
|-------------|------|------|---------|
| M-01 | 情報 | "Current rendering API is not Skia" | レンダリングAPIがSkiaでない場合 |

## 例外処理

| 例外 | 対処 |
|------|------|
| Skia API利用不可 | フォールバックとしてGlyphRunでテキストメッセージを表示 |
| レンダリングエラー | Avaloniaフレームワークの標準エラーハンドリングに委譲 |

## 備考

- ICustomDrawOperationインターフェースにより、Avaloniaの描画パイプラインにカスタム処理を挿入
- ISkiaSharpApiLeaseFeatureでSKCanvasへのアクセスを取得
- 複数のシェーダー（SKShader.CreateSweepGradient、CreatePerlinNoiseFractalNoise）を合成
- SKImageFilter.CreateBlurでアニメーション付きブラー効果
- 疑似光源はCreateRadialGradientで実装
- Animate関数で時間ベースのパラメータ変化を実現
- Stopwatch.StartNew()で経過時間を計測

---

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

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

### 推奨読解順序

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

カスタム描画の基本構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CustomSkiaPage.cs | `samples/RenderDemo/Pages/CustomSkiaPage.cs` | クラス全体の構造を確認。ControlクラスとICustomDrawOperationの関係 |

**読解のコツ**: CustomSkiaPageはControl基底クラスを継承し、Renderメソッドをオーバーライドしています。内部クラスCustomDrawOpがICustomDrawOperationを実装してSkia APIを呼び出します。

#### Step 2: エントリーポイントを理解する

コントロールの初期化とレンダリング開始を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CustomSkiaPage.cs | `samples/RenderDemo/Pages/CustomSkiaPage.cs` | コンストラクタでGlyphRun生成、Renderでカスタム描画登録 |

**主要処理フロー**:
1. **行18-24**: コンストラクタでClipToBounds=true、フォールバックGlyphRunを生成
2. **行116-120**: Render()でCustomDrawOpを作成しcontext.Custom()に渡す
3. **行119**: InvokeAsyncでInvalidateVisualを呼び、連続再描画

#### Step 3: カスタム描画処理を理解する

SkiaSharp APIを使用した描画処理の詳細を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CustomSkiaPage.cs | `samples/RenderDemo/Pages/CustomSkiaPage.cs` | CustomDrawOp.Render()メソッドのSkia API呼び出しを確認 |

**主要処理フロー**:
- **行45-50**: ISkiaSharpApiLeaseFeatureでSKCanvasを取得（取得失敗時はフォールバック）
- **行52-79**: スイープグラデーション + Perlinノイズ + ブラーで背景描画
- **行81-95**: 疑似光源（RadialGradient）を重ねて描画
- **行99-111**: Animate関数で時間ベースの値変化を計算

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

```
MainWindow
    |
    +-- HamburgerMenu (controls:HamburgerMenu)
           |
           +-- TabItem[Header="SkCanvas"]
                  |
                  +-- CustomSkiaPage (Control)
                         |
                         +-- Render(DrawingContext)
                                |
                                +-- CustomDrawOp (ICustomDrawOperation)
                                       |
                                       +-- ISkiaSharpApiLeaseFeature.Lease()
                                              |
                                              +-- SKCanvas.DrawPaint()
                                              |      |
                                              |      +-- SKShader (Sweep + Perlin)
                                              |      +-- SKImageFilter (Blur)
                                              |
                                              +-- SKCanvas.DrawPaint()
                                                     |
                                                     +-- SKShader (RadialGradient - 疑似光源)
```

### データフロー図

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

Stopwatch           --> Animate()           --> アニメーション値
(経過時間)              (周期計算)              (ブラー量、光源位置等)

SKCanvas            --> CreateShaders       --> シェーダー合成
(ISkiaApiLease)         |
                        +-- SweepGradient (色相環)
                        +-- PerlinNoise (ノイズテクスチャ)
                        +-- RadialGradient (疑似光源)

シェーダー群         --> SKPaint            --> 画面描画
+ ImageFilter           (DrawPaint)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CustomSkiaPage.cs | `samples/RenderDemo/Pages/CustomSkiaPage.cs` | C# | カスタムSkia描画を実装したControl |
| MainWindow.xaml | `samples/RenderDemo/MainWindow.xaml` | XAML | ホスト画面（HamburgerMenuでページを管理） |
