# 02 全体アーキテクチャ ## 採用構成 Qt 6 / C++20 / Qt Quickをアプリケーション基盤とし、PDFは独立したPDFiumワーカー、HTML・EPUBはQt WebEngineで描画する。CMakeで構成し、両OSの依存バージョンを同じリリース単位で固定する。具体的なQtパッチ版・PDFiumコミットは実装開始時に選ぶ。 Qt PDFはアプリのPDF処理には使わない。PDFiumの公開APIにアクセスする窓口を一つにし、構造タグの読取りも同じワーカーに閉じ込める。Qt WebEngine内蔵のPDFビューアは無効化する。Qt WebEngine自身の内部依存に含まれるPDFiumまで配布物から除去できるとは想定しない。 ```mermaid flowchart TB UI[Qt Quick Reader Shell] --> APP[Application Services] APP --> BROKER[Main Process / File Broker] BROKER --> PDF[Sandboxed PDFWorker / PDFium] BROKER --> ARCHIVE[Sandboxed ArchiveWorker] BROKER --> WEB[Qt WebEngine / Isolated Content] APP --> STORE[Config and State Store] PDF --> UI ARCHIVE --> BROKER BROKER --> ROOT[Document Scoped Resources] ROOT --> WEB ``` 矢印は論理的な要求・応答を表す。PDFWorker・ArchiveWorkerは別OSプロセスであり、Qt WebEngineは独自のマルチプロセス構成を持つ。主プロセスから子プロセスを起動するだけではOSによるアクセス制限は成立しないため、07の隔離条件を別途満たす。 ## 責務分割 | 層・要素 | 責務 | 保有しない責務 | |---|---|---| | Reader Shell | 本文領域、目次、一覧、ステータス、コマンド欄、アクセシブル名 | 形式固有の解析、任意ファイル読取り | | Input Router | モード・フォーカス・IMEを考慮したキー解釈、コマンド生成 | PDFページ番号への直接変換 | | Document Controller | セッション、遷移、位置、戻る/進む、エラーの統括 | 描画エンジンの内部API露出 | | Navigation Service | アダプターの目次・見出し・リンクを共通モデルへ変換 | 見た目だけによる見出しの推測 | | Render Scheduler | 可視域優先、先読み、取消し、キャッシュ、世代管理 | ファイルの権限判定 | | Format Adapter | PDF/HTML/EPUB固有の能力・位置・描画の変換 | 他形式の特例をUIへ要求すること | | File Broker | 開く操作で許可されたファイル、範囲読取り、仮想資源の提供 | PDF/XML/HTML/画像の主プロセス内解析 | | PDFWorker | PDFium初期化、文書解析、ページ描画、文字・構造・リンク抽出 | 外部通信、原本文書の書込み | | ArchiveWorker | ZIP検証・展開、EPUB XML解析、文書資源索引 | 任意パスへの書込み、外部実体参照 | | Web Content Host | docスキーム、通信遮断、DOMナビゲーション、本文表示 | アプリ全体の権限や設定へのアクセス | | Settings / State Store | 検証済み設定とローカル読書状態の保存 | 文書由来スクリプトの評価 | 依存の向きはUI→アプリケーション→抽象インターフェース。形式固有コードは抽象インターフェースを実装する。PDFium、WebEngine、OS APIはそれぞれの境界内へ閉じ込める。 ## 文書を開く流れ 1. UIがOSファイル選択または明示されたローカルパスをFile Brokerへ渡す。Brokerは通常ファイル・権限・実体パス・容量を確認する。 2. 拡張子と先頭の限定的なシグネチャを照合する。ZIPとEPUBの詳細判定はArchiveWorkerで行う。HTMLは拡張子/MIMEと文字コード情報から扱い、文書本文を主プロセスで解釈しない。 3. 新しいsessionIdとgenerationを発行する。既存の文書は新文書の入口検証が済むまで保持し、失敗時に元の位置へ戻れるようにする。 4. PDFは読取り専用ハンドルまたは範囲読取りチャネルをPDFWorkerへ渡す。HTMLは選択ファイルの親ディレクトリを許可ルート候補にし、ZIP/EPUBは検証済みのセッション用資源集合を構築する。 5. 最初に必要な本文と最低限のメタデータを要求する。全ページのサムネイル、全文字抽出、全ファイルのハッシュ計算が終わるまで本文表示を待たせない。 6. 初期本文が表示できた時点でReadyへ移行し、目次・見出し・先読みを低優先で進める。準備途中の目次は「読込中」とし、「目次なし」と区別する。 7. 新文書のコミット後に旧セッションを破棄し、旧要求・共有メモリ・一時資源を解放する。旧generationの応答は採用しない。 複数文書を常駐させない。切替中の旧文書保持は一時的な例外とし、メモリ圧迫時は最後の表示画像と復帰位置だけを保つ。 ## 描画・スケジューリング PDFiumのAPI呼出しはワーカー内で直列化する。複数スレッドから無保護で呼び出さない。最初はアクティブ文書につきPDFWorker一つとし、追加並列化は性能実測後の変更とする。PDFiumのスレッド条件は[公開API](https://pdfium.googlesource.com/pdfium/+/refs/heads/main/public/fpdfview.h)を参照する。 優先度は「新しい可視ページ→可視ページの高解像度化→移動方向の隣接ページ→逆方向→サムネイル→検索索引/構造抽出」。先読みはまず前後1ページまでとし、キャッシュ余裕とキー操作から調整する。解析中にUIスレッドを同期的に待たせない。 拡大したページは512×512デバイスピクセルのタイルを基本とし、外周に2ピクセルの描画余白を持たせて表示時に切り落とす。CropBox、回転、倍率、DPRを含む変換行列をタイルとリンク・文字の当たり判定で共有する。タイルの継ぎ目・端の欠落は08の必須試験で確認する。 倍率変更中は既存画像を暫定拡大し、新しい倍率で再描画する。旧倍率の応答が新しい画面を上書きしないようgenerationとrenderRevisionを検証する。リサイズだけでは全文書を再解析しない。 PDFの段階描画を利用できる処理は短い区間で取消しを確認する。中断不能なデコードや解析はワーカー監視の期限で扱い、UI側の取消し完了とワーカーの実処理終了を同一視しない。 ## キャッシュと資源管理 | 資源 | 方針 | 初期提案 | |---|---|---| | PDF画像タイル | バイト数基準LRU、可視タイル優先 | 256 MiB、設定可能 | | PDFページオブジェクト | 現在・前後を保持し不要分を閉じる | 前後1ページ | | サムネイル | パネル表示時に可視行から作る | 64 MiB以内で画像予算と調整 | | WebEngine | 文書セッション用off-the-record profile | 永続Cookie・遠隔cacheなし | | ZIP展開 | 安全検証済み専用ディレクトリ、一時資源 | 上限は03・07 | | 読書状態 | 小さなJSON、画像や本文は保存しない | 06を参照 | PDFの画像キャッシュ予算はアプリ全体のRSS上限を意味しない。WebEngine、GPU、パーサー、一時バッファは別に消費するため、08で子プロセス込みの総使用量を測る。メモリ圧迫時は先読み停止→不可視キャッシュ解放→解像度抑制の通知→文書処理停止の順で対応する。 ## 拡張の契約 新形式の追加はFormatAdapterの実装、型判定の登録、能力情報、位置型の追加、共通適合試験への登録で行う。UIは能力情報を見てページ一覧・見出し・検索の可否を決める。画面内へ形式名による条件分岐を散在させない。 キーはCommand Registry内の安定したcommandIdに対応する。新しい操作は同じ入口へ登録し、既定キーがない操作もコマンド欄から実行できる。設定ファイルはスキーマに定義された値だけを受け付ける。 初期版の拡張は配布元がビルド時に組み込むモジュールに限る。第三者の任意コードを読み込むプラグイン機構は将来設計とする。将来導入する場合も、文書がプラグインや設定を自動的に選択・実行することは許可しない。 ## 主な依存とビルド境界 | 部分 | 採用案 | 管理単位 | |---|---|---| | UI・共通基盤 | Qt Core / Gui / Quick / Qml / Quick Controls、C++20 | 同一Qtリリース | | HTML・EPUB本文 | Qt WebEngine / WebEngineQuick | Qtと整合したChromium依存 | | PDF | PDFium公開C API、V8/XFA無効ビルドを基本 | 固定コミット・ビルドオプション | | ZIP・XML | 維持管理されているライブラリをArchiveWorkerへ組込み | G0でZIP64・文字コード・制限設定を確認し固定 | | 設定 | TOML 1.0互換パーサー、独自スキーマ検証 | parser版とschema_versionを別管理 | | IPC | 長さ付きCBORメッセージと制御された共有バッファ | protocolVersion | ZIP・TOML等のライブラリ名は、制限付き処理・ライセンス・更新頻度を確認してG0で固定する。ライブラリ選定未了でも、受け入れるデータと制限は03・05・06・07で固定する。