# 帳票設計書 3-HTML形式出力（CF_HTML）

## 概要

本ドキュメントは、Windows Terminal のテキストバッファから選択範囲のテキストをCF_HTML準拠のHTML形式で生成する処理の設計を記述する。フォント・色・スタイル情報を含むHTML構造を出力し、クリップボードコピー時に使用される。

### 本帳票の処理概要

テキストバッファ上でユーザーが選択した範囲のテキストデータを、CF_HTML（Clipboard Format HTML）仕様に準拠したHTML文書として生成する。前景色・背景色・フォント・太字・斜体・下線・取り消し線・上線などのスタイル情報がCSS属性としてHTMLのSPAN要素に埋め込まれる。

**業務上の目的・背景**：ターミナルの出力テキストを、Webブラウザ・Word・メールクライアントなどのリッチテキスト対応アプリケーションに貼り付ける際に、色やフォント情報を維持するための出力形式を提供する。CF_HTMLはWindows標準のクリップボードフォーマットであり、広く対応されている。

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

**主要な出力内容**：
1. CF_HTMLヘッダー（Version:0.9、StartHTML/EndHTML/StartFragment/EndFragment/StartSelection/EndSelection のバイトオフセット）
2. HTML文書構造（DOCTYPE, HTML, HEAD, BODY タグ）
3. DIV要素（グローバルスタイル：フォントファミリ・フォントサイズ・背景色・padding）
4. SPAN要素（各属性ランごとの前景色・背景色・太字・斜体・下線・取り消し線・上線のCSS）
5. BR要素（改行）

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

**帳票の利用者**：ターミナル出力をリッチテキスト形式で他のアプリケーションに貼り付けたいユーザー。

## 帳票種別

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

## 利用画面

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

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | CF_HTML（HTML Clipboard Format 0.9） |
| 用紙サイズ | 該当なし |
| 向き | 該当なし |
| ファイル名 | 該当なし（クリップボード経由） |
| 出力方法 | クリップボードへのコピー（CF_HTML 形式） |
| 文字コード | UTF-8（std::string） |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

CF_HTMLフォーマットに準拠した構造で、クリップボードヘッダー、HTML文書、フラグメントの3層構造を持つ。

```
┌─────────────────────────────────────┐
│ CF_HTMLヘッダー (157バイト)           │
│  Version:0.9                        │
│  StartHTML / EndHTML                 │
│  StartFragment / EndFragment        │
│  StartSelection / EndSelection      │
├─────────────────────────────────────┤
│ HTML文書                            │
│  <!DOCTYPE><HTML><HEAD></HEAD><BODY>│
│  <!--StartFragment -->              │
│  <DIV STYLE="グローバルスタイル">     │
│    <SPAN STYLE="色・装飾">テキスト   │
│    </SPAN>                          │
│    <BR> (改行)                      │
│  </DIV>                            │
│  <!--EndFragment -->                │
│  </BODY></HTML>                     │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Version | CF_HTMLバージョン | 固定値 | "Version:0.9" |
| 2 | StartHTML | HTML開始位置（バイトオフセット） | 計算値（157） | "StartHTML:0000000157" |
| 3 | EndHTML | HTML終了位置 | 計算値 | "EndHTML:NNNNNNNNNN" |
| 4 | StartFragment | フラグメント開始位置 | 計算値 | "StartFragment:NNNNNNNNNN" |
| 5 | EndFragment | フラグメント終了位置 | 計算値 | "EndFragment:NNNNNNNNNN" |
| 6 | StartSelection | 選択開始位置 | StartFragmentと同値 | "StartSelection:NNNNNNNNNN" |
| 7 | EndSelection | 選択終了位置 | EndFragmentと同値 | "EndSelection:NNNNNNNNNN" |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|------|
| 1 | グローバルスタイル | DIV要素のスタイル | フォント・背景色設定 | CSS属性 | 可変 |
| 2 | 前景色 | テキストの前景色 | GetAttributeColors(attr).fg | color:#{hex} | 可変 |
| 3 | 背景色 | テキストの背景色 | GetAttributeColors(attr).bg | background-color:#{hex} | 可変 |
| 4 | 太字 | 太字スタイル | attr.IsBold(isIntenseBold) | font-weight:bold | 可変 |
| 5 | 斜体 | 斜体スタイル | attr.IsItalic() | font-style:italic | 可変 |
| 6 | 取り消し線 | 取り消し線スタイル | attr.IsCrossedOut() | text-decoration:line-through | 可変 |
| 7 | 上線 | 上線スタイル | attr.IsOverlined() | text-decoration:overline | 可変 |
| 8 | 下線 | 下線スタイル（複数種類） | attr.GetUnderlineStyle() | text-decoration:underline [style] | 可変 |
| 9 | テキスト | HTMLエスケープ済みテキスト | row.GetText(x, nextX) | HTMLエンティティ変換済み | 可変 |
| 10 | 改行 | 行間区切り | 固定値 | \<BR\> | 可変 |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | DIV閉じタグ | | 固定値 | \</DIV\> |
| 2 | EndFragment コメント | | 固定値 | \<!--EndFragment --\> |
| 3 | HTML閉じタグ | | 固定値 | \</BODY\>\</HTML\> |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 選択開始位置（beg） | テキスト選択の開始座標 | Yes |
| 選択終了位置（end） | テキスト選択の終了座標 | Yes |
| CopyFormat::HTML | HTMLフォーマットの有効フラグ | 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, COLORREF, COLORREF) のタプル |
| attr.IsBold(isIntenseBold) | 太字判定 | 各ラン | isIntenseBold設定に依存 |
| attr.IsItalic() | 斜体判定 | 各ラン | |
| attr.IsCrossedOut() | 取り消し線判定 | 各ラン | |
| attr.IsOverlined() | 上線判定 | 各ラン | |
| attr.GetUnderlineStyle() | 下線スタイル | 各ラン | 6種類のスタイル |
| ROW::GetText(x, nextX) | テキスト | 各ラン | HTMLエスケープが必要 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ClipboardHeaderSize | 157（固定値） | 該当なし | CF_HTMLヘッダーのバイト数 |
| htmlStartPos | ClipboardHeaderSize | 該当なし | HTML文書の開始オフセット |
| htmlEndPos | ClipboardHeaderSize + htmlBuilder.length() | 該当なし | HTML文書の終了オフセット |
| fragStartPos | ClipboardHeaderSize + htmlHeader.length() | 該当なし | フラグメント開始オフセット |
| fragEndPos | htmlEndPos - HtmlFooter.length() | 該当なし | フラグメント終了オフセット |
| 色16進数 | Utils::ColorToHexString(COLORREF) | 該当なし | #RRGGBB形式 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[コピー操作要求 CopyFormat::HTML=true] --> B[CopySelectionToClipboard]
    B --> C[RetrieveSelectedTextFromBuffer]
    C --> D[TextBuffer::GenHTML 呼び出し]
    D --> E{beg > end?}
    E -->|Yes| F[空文字列を返却]
    E -->|No| G[HTMLヘッダー生成]
    G --> H[StartFragment コメント追加]
    H --> I[DIV要素 グローバルスタイル設定]
    I --> J[行ループ開始]
    J --> K[_RowCopyHelper で行範囲計算]
    K --> L[属性ラン走査]
    L --> M[SPAN要素生成 - 色・スタイルCSS]
    M --> N{下線あり?}
    N -->|Yes| O[ネストSPAN生成 - 下線スタイル]
    N -->|No| P[テキスト出力 HTMLエスケープ]
    O --> P
    P --> Q{改行?}
    Q -->|Yes| R[BR要素追加]
    Q -->|No| S[次のラン/行へ]
    R --> S
    S --> T{最終行?}
    T -->|No| J
    T -->|Yes| U[DIV閉じ + EndFragment]
    U --> V[HTMLフッター追加]
    V --> W[CF_HTMLヘッダー生成 - オフセット計算]
    W --> X[ヘッダー + HTML本体を結合して返却]
    X --> Y[終了]
    F --> Y
```

## エラー処理

### エラーケース一覧

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

## パフォーマンス要件

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

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

- HTMLエスケープ処理（`<` -> `&lt;`、`>` -> `&gt;`、`&` -> `&amp;`）により、テキスト内のHTML特殊文字がエスケープされる
- テキストバッファへのアクセスはロックで排他制御される
- GH#5347: HTMLタイトルは意図的に省略されている（Webアプリがタイトルを先に貼り付ける問題を回避）

## 備考

- 下線スタイルは6種類をサポート: NoUnderline, SinglyUnderlined, DoublyUnderlined, CurlyUnderlined, DottedUnderlined, DashedUnderlined
- 下線は取り消し線・上線と同じCSS text-decoration プロパティを使用するため、ネストした SPAN 要素で分離して異なる色を適用する
- MS Wordではpaddingがサポートされないことがコメントに記載されている
- 関数は noexcept 指定されており、例外はcatchされてログに記録される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | textBuffer.hpp | `src/buffer/out/textBuffer.hpp` | GenHTML のシグネチャ（277-282行目）。引数として CopyRequest, fontHeightPoints, fontFaceName, backgroundColor, isIntenseBold, GetAttributeColors コールバックを受け取る |
| 1-2 | textBuffer.hpp | `src/buffer/out/textBuffer.hpp` | CopyRequest 構造体（204-271行目） |

**読解のコツ**: GenHTML は std::string を返す（UTF-8）。他のテキスト系関数が std::wstring（UTF-16）を返すのと異なる点に注意。

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

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

**主要処理フロー**:
1. **991行目**: bgColor をデフォルト背景色から取得
2. **992行目**: isIntenseBold をレンダー設定から取得
3. **993行目**: fontSizePt をフォント情報から取得
4. **998行目**: textBuffer.GenHTML() を呼び出し

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | textBuffer.cpp | `src/buffer/out/textBuffer.cpp` | GenHTML メソッド（2211-2407行目）。HTML文書構築、属性ラン走査、CSS生成、HTMLエスケープ、CF_HTMLヘッダー生成 |

**主要処理フロー**:
- **2233行目**: HTMLヘッダー文字列定義
- **2236行目**: StartFragment コメント
- **2240-2254行目**: DIV要素のグローバルスタイル（display, white-space, background-color, font-family, font-size, padding）
- **2257行目**: 行ループ開始
- **2266行目**: 属性ランのループ
- **2278-2332行目**: SPAN要素のCSS生成（色・太字・斜体・取り消し線・上線・下線）
- **2336-2353行目**: テキストのHTMLエスケープ（<, >, &）
- **2355-2359行目**: 下線用ネストSPANの閉じタグ
- **2382-2398行目**: CF_HTMLヘッダーの生成（バイトオフセット計算）
- **2400行目**: ヘッダーとHTML本体の結合

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

```
ControlCore::CopySelectionToClipboard (ControlCore.cpp:1343)
    |
    +-- Terminal::RetrieveSelectedTextFromBuffer (TerminalSelection.cpp:962)
    |       |
    |       +-- TextBuffer::GenHTML(req, ...) (textBuffer.cpp:2211)
    |               |
    |               +-- TextBuffer::_RowCopyHelper (textBuffer.cpp:2088)
    |               +-- Utils::ColorToHexString (色変換)
    |               +-- til::u16u8 (UTF-16 -> UTF-8変換)
    |               +-- ROW::Attributes().slice().runs()
    |               +-- ROW::GetText(x, nextX)
    |
    +-- WriteToClipboard.raise (ControlCore.cpp:1365)
```

### データフロー図

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

TextBuffer (メモリ)        ---> GenHTML()                 ---> std::string (CF_HTML)
  |                                |                             |
  +-- ROW[]                      +-- _RowCopyHelper()          +-- CF_HTMLヘッダー
  +-- TextAttribute[]            +-- HTMLヘッダー生成              (Version:0.9, オフセット)
  +-- 選択範囲(beg,end)          +-- DIVグローバルスタイル       +-- HTML文書
                                 +-- 属性ラン走査                  +-- SPAN要素(CSS)
フォント情報                     +-- CSS生成                      +-- テキスト(エスケープ済)
  +-- fontHeightPoints           +-- HTMLエスケープ               +-- BR改行
  +-- fontFaceName               +-- CF_HTMLヘッダー計算
背景色(backgroundColor)
```

### 関連ファイル一覧

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