# 帳票設計書 4-RTF形式出力（Rich Text Format）

## 概要

本ドキュメントは、Windows Terminal のテキストバッファから選択範囲のテキストをRTF（Rich Text Format）形式で生成する処理の設計を記述する。フォント・色・スタイル情報を含むRTF文書をクリップボードコピー時に出力する。

### 本帳票の処理概要

テキストバッファ上でユーザーが選択した範囲のテキストデータを、RTF 1.5/1.9.1仕様に準拠したRTF文書として生成する。フォントテーブル、カラーテーブル、および各テキストランのスタイル情報（前景色・背景色・太字・斜体・取り消し線・下線）がRTF制御ワードとして埋め込まれる。

**業務上の目的・背景**：ターミナルの出力テキストを、Microsoft Word・WordPad・リッチテキストエディタなどのRTF対応アプリケーションに貼り付ける際に、色やフォント情報を維持するための出力形式を提供する。RTFはWindows環境で広くサポートされているリッチテキスト形式である。

**帳票の利用シーン**：ユーザーがターミナル画面上でテキストを選択し、クリップボードにコピーする際に、CopyFormatting設定でRTF形式が有効になっている場合に使用される。

**主要な出力内容**：
1. RTFヘッダー（\\rtf1\\ansi\\ansicpg1252\\deff0\\nouicompat）
2. フォントテーブル（\\fonttbl - フォント名とcharset定義）
3. カラーテーブル（\\colortbl - 使用される全色のRGB値定義）
4. 段落スタイル（\\pard, \\slmult1, \\f0, \\fsN）
5. テキストラン（各属性ごとのRTFグループ：\\cf, \\chshdng, \\b, \\i, \\strike, 下線制御ワード）
6. Unicode文字のRTFエスケープ（\\uN? 形式）

**帳票の出力タイミング**：ユーザーがテキスト選択後にコピー操作を行い、CopyFormatting設定でRTFが有効な場合に出力される。

**帳票の利用者**：ターミナル出力をRTF対応アプリケーションにスタイル付きで貼り付けたいユーザー。

## 帳票種別

リッチフォーマット出力（RTFクリップボードフォーマット）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | ターミナルペイン | - | テキスト選択 + コピー操作（CopyFormatting に RTF が含まれる場合） |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | RTF（Rich Text Format 1.5/1.9.1準拠） |
| 用紙サイズ | 該当なし |
| 向き | 該当なし |
| ファイル名 | 該当なし（クリップボード経由） |
| 出力方法 | クリップボードへのコピー（CF_RTF 形式） |
| 文字コード | ANSI (codepage 1252) + Unicode エスケープ |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

RTF文書はフォントテーブル、カラーテーブル、本文の3部構成。全体が RTF グループ（波括弧）で囲まれる。

```
┌─────────────────────────────────────┐
│ {\rtf1\ansi...                      │
│   {\fonttbl{\f0\fmodern... フォント名}} │
│   {\colortbl ;\red...\green...\blue...} │
│   \viewkind4\uc1                    │
│   \pard\slmult1\f0\fsN             │
│   \chshdng0\chcbpatN (背景色)       │
│   {\cfN\chshdng0\chcbpatN テキスト} │
│   \line (改行)                      │
│   ...                               │
│ }                                   │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | RTFバージョン | RTF 1.x ANSI文書宣言 | 固定値 | \\rtf1\\ansi\\ansicpg1252\\deff0\\nouicompat |
| 2 | フォントテーブル | 使用フォントの定義 | fontFaceName | {\\fonttbl{\\f0\\fmodern\\fcharset0 フォント名;}} |
| 3 | カラーテーブル | 使用色のRGB定義一覧 | GetAttributeColors + backgroundColor | {\\colortbl ;\\redR\\greenG\\blueB;...} |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|------|
| 1 | 前景色 | テキストの前景色 | getColorTableIndex(fg) | \\cfN | 可変 |
| 2 | 背景色 | テキストの背景色 | getColorTableIndex(bg) | \\chshdng0\\chcbpatN | 可変 |
| 3 | 太字 | 太字スタイル | attr.IsBold(isIntenseBold) | \\b | 可変 |
| 4 | 斜体 | 斜体スタイル | attr.IsItalic() | \\i | 可変 |
| 5 | 取り消し線 | 取り消し線スタイル | attr.IsCrossedOut() | \\strike | 可変 |
| 6 | 下線 | 下線スタイル（複数種類） | attr.GetUnderlineStyle() | \\ul/\\uldb/\\ulwave/\\uld/\\uldash + \\ulcN | 可変 |
| 7 | テキスト | RTFエスケープ済みテキスト | row.GetText(x, nextX) | ASCII直接 or \\uN? 形式 | 可変 |
| 8 | 改行 | 行間区切り | 固定値 | \\line | 可変 |

### フッター部

該当なし（RTFグループの閉じ括弧で終了）

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 選択開始位置（beg） | テキスト選択の開始座標 | Yes |
| 選択終了位置（end） | テキスト選択の終了座標 | Yes |
| CopyFormat::RTF | RTFフォーマットの有効フラグ | Yes（true） |
| fontHeightPoints | フォントサイズ（ポイント） | Yes |
| fontFaceName | フォント名 | Yes |
| backgroundColor | デフォルト背景色（COLORREF） | Yes |
| isIntenseBold | Intense属性をBoldとして扱うか | Yes |
| GetAttributeColors | 属性から色を取得するコールバック関数 | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | 行番号（y座標） | 昇順 |
| 2 | 属性ラン順序 | 昇順（左から右） |

### 改ページ条件

該当なし

## データベース参照仕様

### 参照テーブル一覧

該当なし（メモリ上の TextBuffer から直接データを取得する）

### テーブル別参照項目詳細

#### TextBuffer（メモリ上バッファ）

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| ROW::Attributes().slice().runs() | 属性ラン一覧 | rowBeg ~ rowEnd | 各ランの属性とテキスト |
| GetAttributeColors(attr) | 前景色・背景色・下線色 | 各ラン | COLORREF タプル |
| attr.IsBold(isIntenseBold) | 太字判定 | 各ラン | |
| attr.IsItalic() | 斜体判定 | 各ラン | |
| attr.IsCrossedOut() | 取り消し線判定 | 各ラン | |
| attr.GetUnderlineStyle() | 下線スタイル | 各ラン | 6種類 |
| ROW::GetText(x, nextX) | テキスト | 各ラン | RTFエスケープが必要 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| フォントサイズ（半ポイント） | fontHeightPoints * 2 | 該当なし | RTFではフォントサイズを半ポイント単位で指定（\\fsN） |
| カラーテーブルインデックス | colorMap.size() + 1（新色追加時） | 該当なし | 0はデフォルト色用に予約、1から開始 |
| Unicode RTFエスケープ | \\u{int16_t(codeUnit)}? | 該当なし | wchar_t をsigned int16_tにbit_cast |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[コピー操作要求 CopyFormat::RTF=true] --> B[CopySelectionToClipboard]
    B --> C[RetrieveSelectedTextFromBuffer]
    C --> D[TextBuffer::GenRTF 呼び出し]
    D --> E{beg > end?}
    E -->|Yes| F[空文字列を返却]
    E -->|No| G[RTFヘッダー生成]
    G --> H[フォントテーブル生成]
    H --> I[カラーテーブル構築開始]
    I --> J[段落スタイル設定]
    J --> K[行ループ開始]
    K --> L[属性ラン走査]
    L --> M[RTFグループ開始 - 色・スタイル設定]
    M --> N[テキスト出力 - RTFエスケープ]
    N --> O[RTFグループ閉じ]
    O --> P{改行?}
    P -->|Yes| Q[\\line 追加]
    P -->|No| R[次のラン/行へ]
    Q --> R
    R --> S{最終行?}
    S -->|No| K
    S -->|Yes| T[カラーテーブルをRTFに挿入]
    T --> U[コンテンツをRTFに追加]
    U --> V[完成したRTF文字列を返却]
    V --> W[終了]
    F --> W
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 無効な範囲 | beg > end | なし | 空文字列を返却 |
| 例外発生 | RTF生成中の任意の例外 | なし | LOG_HR でログ記録し空文字列を返却 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 最大9001行 |
| 目標出力時間 | 即座（同期処理） |
| 同時出力数上限 | 1（ターミナルロック取得による排他制御） |

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

- RTFの特殊文字（\\, {, }）はバックスラッシュでエスケープされる
- 非ASCII文字は \\uN? 形式でUnicodeエスケープされる
- テキストバッファへのアクセスはロックで排他制御される

## 備考

- RTFのフォントサイズは半ポイント単位（\\fs20 = 10pt）で指定する
- カラーテーブルはオンデマンドで構築される。テキスト走査中に新しい色が見つかると追加される
- 背景色の適用には \\chshdng0\\chcbpatN を使用する（標準の \\cbN はMS Wordでサポートされないため）
- \\nouicompat により、Word 97-2003互換モードを無効化し、新しいRTF機能を利用可能にする
- 下線スタイルは5種類をサポート: \\ul（単線）, \\uldb（二重線）, \\ulwave（波線）, \\uld（点線）, \\uldash（破線）
- _AppendRTFText で ASCII文字は直接出力、127より大きいコードポイントは \\uN? 形式でエスケープされる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | textBuffer.hpp | `src/buffer/out/textBuffer.hpp` | GenRTF のシグネチャ（284-289行目）。GenHTMLと同一のパラメータ構成 |

**読解のコツ**: GenRTF も noexcept 指定されており、内部で try-catch して例外をログに記録する。GenHTML と同じパターン。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | TerminalSelection.cpp | `src/cascadia/TerminalCore/TerminalSelection.cpp` | RetrieveSelectedTextFromBuffer（1000-1003行目）。rtf=true 時に GenRTF を呼び出す分岐 |

**主要処理フロー**:
1. **1000行目**: rtf が true かチェック
2. **1002行目**: textBuffer.GenRTF() を呼び出し

#### Step 3: GenRTF の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | textBuffer.cpp | `src/buffer/out/textBuffer.cpp` | GenRTF メソッド（2422-2603行目）。RTFヘッダー、フォントテーブル、カラーテーブル、本文の構築 |
| 3-2 | textBuffer.cpp | `src/buffer/out/textBuffer.cpp` | _AppendRTFText メソッド（2605-2629行目）。RTFテキストエスケープ処理 |

**主要処理フロー**:
- **2439行目**: RTF文書開始（波括弧）
- **2455行目**: RTFヘッダー（\\rtf1\\ansi\\ansicpg1252\\deff0\\nouicompat）
- **2459行目**: フォントテーブル生成
- **2464-2482行目**: カラーテーブル構築用のgetColorTableIndexラムダ関数
- **2489行目**: \\viewkind4\\uc1（Normal viewモード、Unicode fallback 1文字）
- **2495行目**: 段落スタイル（\\pard\\slmult1\\f0）
- **2499行目**: フォントサイズ（\\fsN、半ポイント単位）
- **2505行目**: ページ背景色（\\chshdng0\\chcbpatN）
- **2507行目**: 行ループ開始
- **2527行目**: RTFグループ開始（波括弧）
- **2529-2567行目**: 色・スタイルの制御ワード設定
- **2575行目**: _AppendRTFText でテキスト出力
- **2577行目**: RTFグループ閉じ
- **2586行目**: \\line で改行
- **2591-2594行目**: カラーテーブルとコンテンツの結合

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

```
ControlCore::CopySelectionToClipboard (ControlCore.cpp:1343)
    |
    +-- Terminal::RetrieveSelectedTextFromBuffer (TerminalSelection.cpp:962)
    |       |
    |       +-- TextBuffer::GenRTF(req, ...) (textBuffer.cpp:2422)
    |               |
    |               +-- TextBuffer::_RowCopyHelper (textBuffer.cpp:2088)
    |               +-- getColorTableIndex (ラムダ関数、2470行目)
    |               +-- ROW::Attributes().slice().runs()
    |               +-- ROW::GetText(x, nextX)
    |               +-- TextBuffer::_AppendRTFText (textBuffer.cpp:2605)
    |
    +-- WriteToClipboard.raise (ControlCore.cpp:1365)
```

### データフロー図

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

TextBuffer (メモリ)        ---> GenRTF()                 ---> std::string (RTF文書)
  |                                |                             |
  +-- ROW[]                      +-- _RowCopyHelper()          +-- RTFヘッダー
  +-- TextAttribute[]            +-- フォントテーブル生成          +-- フォントテーブル
  +-- 選択範囲(beg,end)          +-- カラーテーブル構築           +-- カラーテーブル
                                 +-- 属性ラン走査                +-- 本文
フォント情報                     +-- RTF制御ワード生成               +-- 制御ワード + テキスト
  +-- fontHeightPoints           +-- _AppendRTFText()
  +-- fontFaceName
背景色(backgroundColor)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| textBuffer.hpp | `src/buffer/out/textBuffer.hpp` | ヘッダー | GenRTF シグネチャ定義 |
| textBuffer.cpp | `src/buffer/out/textBuffer.cpp` | ソース | GenRTF、_AppendRTFText の実装 |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | CopySelectionToClipboard |
| TerminalSelection.cpp | `src/cascadia/TerminalCore/TerminalSelection.cpp` | ソース | RetrieveSelectedTextFromBuffer |
| Terminal.hpp | `src/cascadia/TerminalCore/Terminal.hpp` | ヘッダー | TextCopyData 構造体（rtf フィールド） |
| TextAttribute.hpp | `src/buffer/out/TextAttribute.hpp` | ヘッダー | 属性情報の定義 |
