initial commit
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# 原設計との受入照合
|
||||
|
||||
2026-09-20。基準は変更していない [設計書11件](design/00-guide.md)。個別試験の成功と製品全体の完成を区別する。実行結果とビルドの対応は [検証記録](VALIDATION.md) に置く。
|
||||
|
||||
## 要件の追跡
|
||||
|
||||
2026-09-20追記:[第2PDFium候補](../tests/results/pdfium-intent-context/README.md)を専用ビルドとUbuntu validation4へ統合した。旧試験の `shading-pattern-inherit` 8点の期待値は誤りだったため、旧648点の成功をその規則の根拠にしない。訂正版600点・元48点・追加324点はArch・Ubuntuで成功し、新ビルド各24群、上流1,979試験も成功した。SoftMask/tiling専用試験、Ubuntu配布境界13試験、2回のdeb生成一致、SDKなし既存VMの12条件起動・削除、PDF性能4条件と約1GBの負荷試験まで実施済み。以下の第1候補・元依存版の未完了記述は当時の履歴である。T01/G-RENDER全体の承認と対象実機・Windows・公開配布の最終受入は未完了のまま。
|
||||
|
||||
2026-09-20追記:[ICC変換指定の修正候補](../tests/results/pdfium-intent-build/README.md)では、固定ソースへのパッチを再適用確認し、隔離ビルドの648点・上流1,976試験・DocView全22群が成功した。製品依存とUbuntuパッケージは未変更で、T01/G-RENDERの完成判定は進めない。比較先のshading pattern RI指定の差、候補のUbuntu・配布統合、SoftMask/tiling専用の画素試験、人による承認は残る。
|
||||
|
||||
2026-09-20追記:[ICC CMYK追加比較](../tests/results/cmyk-lut/README.md)で、文書の相対的測色指定に対して固定PDFiumが知覚的変換を使う差を確認した。Arch・Ubuntu各48点中30点が許容差を超えた。原因は照合済みだが、T01/G-RENDERのこの色一致条件は未達である。変換指定への対応または明示的な互換性判断、検出可能な制約の通知を未完了事項に追加する。
|
||||
|
||||
2026-09-20追記:[Qt告知補足版](../tests/results/qt-notice-supplement/README.md)はWebM/WebPのPatent本文を固定ソースと照合してUbuntu debへ追加した。梱包8試験×2環境、deb再現性と全2,016ファイル検証、SDKなしVMでの起動12条件・install/remove/purgeが成功。本体と同梱ランタイムは同一である。全Chromium告知・対応ソースの完成、Windows/物理環境/人による描画承認の受入を済ませたとはしない。
|
||||
|
||||
2026-09-20追記:[実ファイル選択の追加試験](../tests/results/portal/README.md)で特殊なファイル名のHTMLが読込中になる問題を発見・修正した。新しい本体ではArch・Ubuntuの全22群が成功。以下の過去の性能・GPU・IME等の証拠は固定した旧版の範囲に限り、現行本体への再実行は別に扱う。
|
||||
|
||||
修正後の[性能10条件と追加負荷](../tests/results/portal/performance-suite/README.md)も再実行した。新規プロセス300回・同一プロセス内300回・移動2,500操作、約1GB/5,000ページPDFが成功し、測定した参考予算の超過は0だった。基準機・対象OS・実フレーム提示の受入条件は変更しない。
|
||||
|
||||
| 原要件 | 現在の証拠 | 最終判定に残るもの |
|
||||
|---|---|---|
|
||||
| R01 PDF描画、R14 原本を編集しない | 本番の隔離PDFWorker、独立レンダラー比較、原本ハッシュ、注釈・フォーム・日本語・幾何試験 | G-RENDERの承認画像、対象OS、代表制作ソフトの互換性判断 |
|
||||
| R02 HTML、R03 HTML ZIP、R04 EPUB | 本番WebEngine/ArchiveWorker、相対資源・spine・RTL・縦書き・固定見開き・入口選択試験 | 両OSのG-WEB・実ディスプレイ。遅延レイアウトと実読取量の回帰はLinuxで確認 |
|
||||
| R05 キー操作、R08 最小UI、R15 GUIのTUI風操作 | InputRouter、設定、QMLの実キーイベント試験、パネル表示/フォーカス試験 | X11 US/JP XKBとX11/Wayland IBus/Mozcは追加検証済み。物理入力・Windows IME・対象ディスプレイ |
|
||||
| R06 見出し、R07 目次 | PDF構造/内部宛先outline代替・Form所有元、DOM/ARIA、EPUB nav/NCX、抽出とGUI移動、索引loadingの待機表示・失敗した見出し章境界の破棄 | 特殊構造の既知制約、対象OSのG-HEADINGS |
|
||||
| R09 拡張性 | [接続契約の採用記録](adapter-contract.md)、能力スキーマ、操作と解析プロセスの分離 | 形式追加の実装時は同契約と取消・位置のレビューを適用 |
|
||||
| R10 ファイル設定 | TOMLの有限スキーマ、一括適用、未知キー/型/衝突/不正時の保持、再読込試験、日本語の行・原因案内 | 対象OSの実入力系 |
|
||||
| R11 書籍の応答性 | 冷起動/再open各30回・各125操作、500ページ/章、約1GB/5,000ページ、cache上限・旧応答破棄・メモリ圧迫対処 | 基準機・GPU/60Hzと長時間負荷 |
|
||||
| R12 Linux/Windows、R13 OS配置 | ArchとUbuntu 24.04専用VMのX11/Wayland、ArchのAMD OpenGL、XDG・専用保存先、Windows Known Folders/LPAC/pipe等の実装 | Windows nativeビルドと試験、対象OSのGPU/IME、製品配布の実機検証 |
|
||||
|
||||
補助機能T-P01〜04、安全試験T-S01〜05、通常受入T01〜21の個別範囲は [検証記録の対応表](VALIDATION.md#受入idとの対応) を参照する。外部から追加環境は提供されていないが、このPC内にUbuntu 24.04専用KVM環境を作り、全22群・Wayland GUI・配置後起動を[検証した](../tests/results/ui-final/ubuntu/README.md)。生成文書を使うことは利用者が指定済みであり、実書籍がないことを理由にローカル試験を止めない。
|
||||
|
||||
## 今回の照合で見つけたローカル項目
|
||||
|
||||
| 項目 | 原文 | 対応・必要な証拠 |
|
||||
|---|---|---|
|
||||
| 現在位置と目次選択を別表示 | [04 §2.2](design/04-ui-navigation.md#22-閲覧画面) | 現在節の記号と選択枠を分け、選択のみで本文が動かないGUI試験。折りたたみ・文書切替・古い応答も確認する |
|
||||
| 現在PDFページとズーム中心 | [04 §5.1](design/04-ui-navigation.md#51-pdf) | 中央線のページ/余白の距離/同距離の前ページと、保存用先頭位置を分離。ズーム中心のPDF座標保持を検証する |
|
||||
| ページ精度・回転見出しの反復移動 | [04 §5.4](design/04-ui-navigation.md#54-見出し移動の共通定義) | `navigationY`で表示上の前後を判定。ページ先頭を前操作で再選択しないこと、回転時の実GUI移動を試験 |
|
||||
| ICC入力 | [G-RENDER](design/09-decisions-roadmap.md#4-実装前の技術ゲート) | 自作RGB ICCの54点と独立比較。元依存版のCMYK CLUTで48点中30点の差を再現し、第2候補で48点・訂正済み状態600点・SoftMask/tiling等324点が各OSで成功。校正済み印刷色や人による描画承認は未完了 |
|
||||
| Web rendererの応答監視 | [07 §3.2](design/07-security-errors.md#32-上限の初期提案) | RSSだけでなく有限deadlineの応答監視、実renderer停止、取消/世代/対象identity/2viewを検証する |
|
||||
| メモリ圧迫の段階的縮退 | [02 資源管理](design/02-architecture.md#キャッシュと資源管理)、[06 設定](design/06-config-storage.md#設定項目) | OSの空き監視、先読み停止→不可視cache回収→解像度抑制通知→処理停止と回復。[契約](memory-pressure.md)と注入試験 |
|
||||
| 依存告知・配布アーカイブ | [09 配布](design/09-decisions-roadmap.md) | 同梱とシステム依存、実版・由来・license・対応sourceを区別したmanifest。再現可能な開発版パッケージ・サイズ・解凍起動の証跡 |
|
||||
| XHTMLの章内見出しと目次 | [03 EPUB](design/03-formats.md)、[04 見出し移動](design/04-ui-navigation.md#54-見出し移動の共通定義) | 実XHTMLでnative見出しの小文字タグ名と名前空間付きepub:typeを扱う。著者目次と章内見出しを区別し、測定時も実索引の種類・件数を記録する |
|
||||
| 原本の識別と位置保存 | [06 読書状態と履歴](design/06-config-storage.md#読書状態と履歴) | 全形式のopen時identityを保存時に照合し、閲覧中に置換された新原本へ旧位置を転用しない。通常openでの復元不能通知も実ファイルで検査 |
|
||||
| 目次の準備中表示 | [02 開く処理](design/02-architecture.md) | DOM索引が空でも能力loadingなら要求を保持し、読み込み中のパネルを表示。索引確定後の表示までGUIで検査 |
|
||||
| PDF見出し代替の内部宛先 | [04 §5.1](design/04-ui-navigation.md#51-pdf) | 外部・禁止アクションを代替見出し候補から除外。外部だけの場合の能力と、混在時の次/前移動をGUIで検査 |
|
||||
| Webリンクと章境界の取消 | [04 入力・見出し移動](design/04-ui-navigation.md) | EscでDOMリンク選択とfocusを解除。成立した章移動にだけ最初/最後の見出し指示を付け、失敗後の通常章移動へ残さない |
|
||||
| PDF情報の省略通知 | [03 PDF](design/03-formats.md)、[07 エラー](design/07-security-errors.md) | 注釈本文長・ページ内件数・CBOR情報予算超過を通知し、取得済みprefixを保持。本文省略でも注釈を一覧から消さない |
|
||||
| 一時入力とダイアログの焦点復帰 | [04 入力状態](design/04-ui-navigation.md) | 目次・ページ一覧からのコマンド取消、help/file dialog終了後は有効な元領域へ戻す。明示的な本文移動と非表示領域へのfallbackを検査 |
|
||||
| Web倍率の表示と位置保存 | [04 ステータス](design/04-ui-navigation.md)、[06 状態](design/06-config-storage.md) | HTML/ZIP/EPUBの倍率を表示・保存・再復元。fixedはfitの基準と論理倍率を分け、25〜500%の境界を検査 |
|
||||
| 開く操作の失敗案内 | [04 失敗表示](design/04-ui-navigation.md) | 失敗した対象名・有限の分類・対処を表示し、表示中の旧文書と区別して文書情報へ試行内容を保持する |
|
||||
| 日本語初期表示と翻訳資源 | [01 対象環境](design/01-requirements.md) | tr/qsTrのTS抽出・QM埋込・QTranslatorとQt標準部品の日本語資源を接続。英語localeの実Qt Quick Dialogを検査。OSネイティブdialogはOS言語に従う |
|
||||
|
||||
この表のうちXHTML修正までの履歴はLinux統合19試験群(2026-09-19、162.00秒)と、その時点のPDFWorkerに対応する6組の比較で確認した。後から加えた原本同一性・目次待機・PDF候補・Web取消等は[追加回帰](../tests/results/completion-regressions/controller-state.md)で確認した。翻訳試験を含む[前回20試験群](../tests/results/completion-final/ctest/tests.xml)はすべて成功した(165.61秒)。[描画6系列・実時間watchdog・再現可能な開発パッケージと6条件起動](../tests/results/completion-final/README.md)も再検証した。T20の[10条件と負荷の再測定](../tests/results/completion-final/performance-summary.md)も完了し、[検証記録](VALIDATION.md)の現行版と履歴の区別に従う。旧結果を現行バイナリーへ読み替えない。
|
||||
|
||||
今回のUI追加修正は[最新の22群のX11統合](../tests/results/ui-final/README.md)で検証した。Waylandの6条件起動と全GUIも成功した。見開きresizeの初回2失敗は試験側の確定待ちを修正し、製品の描画処理は変更していない。修正前の本体の[性能10条件と操作負荷](../tests/results/ui-final/performance-summary.md)、[約1GB・5,000ページ](../tests/results/ui-final/stress/README.md)も成功した。以下の20群・従来性能測定は修正前に固定したビルドの結果であり、最新本体へ読み替えない。
|
||||
|
||||
## 追加測定と個別の検証結果
|
||||
|
||||
1. **T20の測定範囲** — [08 §3.3](design/08-performance-tests.md#33-再現可能な測定手順) は開始時・最大・文書close後の本体/プロセス群RSS、同一文書10開閉、見出し/章の固定100操作、連続scrollフレーム間隔、描画待ち数を要求する。測定経路を拡充し、アプリキャッシュなし30回、同一プロセス30回、29同条件開閉と最後のclose、各125操作系列、240scroll、描画待ち/旧要求破棄を記録する。別の固定操作列で長押し・遠距離ジャンプ・resize・異文書切替・取消を確認する。実scanoutとの結合と基準機判定は未実施。
|
||||
2. **遅延フォント・画像による再配置** — [03 EPUB](design/03-formats.md) の「レイアウト確定後に同じ論理位置へ再配置」について、load成功時/設定時/resizeの一度の復元後にフォントが届く場合を実DOMで再現し、位置保持と取消を確認する。遅延資源の実読込み、横/縦の文字位置保持、新しい移動を優先する回帰を実装した。連続scroll、native anchoring、poll先行、クリック後の画像到着も追加し、Web全34ケースが成功した。
|
||||
3. **圧縮率の実入力量** — [07 §3.2](design/07-security-errors.md#32-上限の初期提案) の200倍判定は入力消費量/出力量を指定している。ZIP索引のcompressed sizeだけの判定を補い、source callbackの実read量を各展開に計数する修正を実装した。5圧縮方式のpadding資料、正規6方式、本番sandbox workerを含むArchive全76ケースが成功した。実出力256MiB/文書2GiBの別上限があることを、この比率の検証の代用にしない。
|
||||
|
||||
4. **メモリ圧迫** — 検出/遷移27ケース、Canvas21ケースとDPR2、GUIでの段階縮退・停止・回復・原本保持を検証。実RAMを枯渇させず、同じ本番経路へ有限sampleを注入した。
|
||||
5. **初期画面サイズ** — 配置後の実測で200%時の画面超過を検出し、利用可能な画面へ収める修正を実施。配置後/別展開先の6条件で寸法と表示を確認した。
|
||||
6. **XHTMLの見出し** — 小型EPUBの性能試験を契機に、HTMLとXHTMLのタグ名表現の違いでnative見出しが欠落する問題を実DOMで再現した。見出しと目次を修正し、計測側の著者目次による代用も除いた。[修正前の失敗記録](../tests/results/performance-before-xhtml-fix/README.md)は保持し、旧EPUBの見出し系列は最終版の証拠に使わない。
|
||||
7. **章末の重複移動先** — 章末で同じスクロール位置へ収まる2見出しを交互に再選択する問題を横書き・縦書きで再現した。実移動がない候補をまとめ、EPUBの次章境界へ進めるよう修正した。元の500章資料を保持して章を跨ぐ往復を検証し、性能用には全13見出しの移動先が異なる別版を生成した。[回帰記録](../tests/results/xhtml-headings/README.md)
|
||||
8. **PDFiumの追加告知** — 固定providerの収集処理と実libraryを調べ、libc++/libc++abiの2告知が従来の15件に含まれないことを確認した。固定ソースの全文と出典をinstallへ追加し、版・library・本文の不一致を拒否する。[新パッケージ](../tests/results/linux-development-package/README.md)は553ファイルを照合し、独立生成2回のbyte一致・6条件の別展開先起動を確認。packaging 12件とprovenance 23件の限定試験も成功した。この告知追加時点では全3実行ファイルとPDFiumのバイト列は従来版と同一だった。後続の製品修正後のバイナリー一致を示す記録ではない。[現行パッケージ](../tests/results/completion-final/linux-development-package/README.md)は別のhashで2回生成一致・6条件の起動を再確認し、[由来台帳](../tests/results/completion-final/dependency-provenance/README.md)も更新した。
|
||||
|
||||
9. **高解像度画像・高密度ベクターの取消** — [追加GUI試験](../tests/results/heavy-pdf/README.md)では600dpi相当のRGB画像と60,000個の半透明パスを生成し、独立復号と実ウィンドウ画素を照合した。実open/render RPCが未完の状態で取消・文書切替を行い、原本不変、旧session回収、通常解像度とGUI応答の維持をArch/Ubuntuで確認した。単一生成資料での機能検証であり、長時間・基準機の性能受入ではない。
|
||||
|
||||
10. **実IMEと日英配列** — [Ubuntu X11のIBus/Mozc試験](../tests/results/ime/README.md)で、検索・コマンド入力の変換確定、変換候補/未確定入力のEsc取消、j/k・数字の入力保護、通常操作への復帰を検証した。US pc105/JP jp106のXKBとXTestキー番号で記号操作を確認。[WaylandのQt+IBus D-Bus経路](../tests/results/ime/WAYLAND.md)も実変換と入力保護が成功。物理キーボード・Windowsは未実施。
|
||||
|
||||
11. **固定PDFiumのソースと配布ヘッダー** — [Git snapshot収集](../tests/results/source-archives/PDFIUM.md)で、本体と27依存・追加gitlinkの計29件を保管。Git objectと全アーカイブ内容を検査し、先行原文31件・公開ヘッダー24件・告知15件が一致した。Linux3件/Windows4件のproviderパッチは専用コピーに適用成功。ビルドの再現、Windows実行、全ビルド入力の回収とは区別する。
|
||||
|
||||
12. **Ubuntu SDK内のChromium告知** — [SBOM本文抽出](../tests/results/source-archives/QT-SDK-NOTICES.md)で、129entry・105本文をQt source原文と照合した。元SDK archiveのファイルhashをSBOM67件・Ubuntu実行時83件と一致確認。元SBOMの参照ID不整合1件と本文なし2部品を記録し、生成器のskipも保持した。SDKの全告知やArchの実GN構成の完全性を示すものではない。
|
||||
|
||||
13. **Ubuntu用debの配置と回収** — [ローカル検証パッケージ](../tests/results/ubuntu-package/README.md)は2回生成でbyte一致し、全2,009ファイルを照合した。元SDK・build/installを隠した通常ユーザーでX11/Waylandの12条件がReadyとなり、install/reinstall/remove/purge、AppArmorの登録・解除、設定と文書の保持probeが成功した。さらに[新しいUbuntu OS](../tests/results/ubuntu-package/clean-vm/README.md)でも宣言依存の解決、12条件起動、remove/purgeが成功した。公開配布条件と実機desktopの受入は残る。
|
||||
|
||||
## 外部条件を要する受入
|
||||
|
||||
UbuntuのOSファイル選択は、[実XDG/GTK portal](../tests/results/portal/README.md)のX11/Wayland計10ケースで追加検証した。生成資料の日本語・空白・予約文字を含む名前を用い、取消・4形式の選択・焦点復帰を確認。仮想入力とheadless描画の証拠であり、以下の物理環境の項目は残る。
|
||||
|
||||
- Windows 11 native、物理入力・Windows IME・対象OSのGPU・物理表示、公開配布条件と実機desktopの検証。Ubuntu 24.04は専用VMのXvfb/Swayで全22群、100%・200%を含む起動、配置後起動を確認済み。Archでは[AMD OpenGLのGUIと6条件起動](../tests/results/ui-final/wayland/GPU-VALIDATION.md)も成功したが、対象OSのGPU・物理表示の受入とは区別する。
|
||||
- 本番期限の[現行実時間watchdog](../tests/results/completion-final/worker-deadlines/README.md)は成功しているが、基準機の性能・メモリ・実フレーム提示は未判定。仮想X11の開発機数値は参考値に限定する。
|
||||
- 実際の配布範囲に対する対応source・告知・ライセンス条件の最終照合。[台帳](DEPENDENCY-PROVENANCE.md)と[ソース対応記録](../tests/results/source-correspondence/README.md)で、告知追加版の553ファイル、PDFiumの15+2告知、toml++組込コード、Qtの動的リンク、146件の同版キャッシュmetadata、主要4 recipeと1,632実ファイルを照合した。[現行アーカイブの由来台帳](../tests/results/completion-final/dependency-provenance/README.md)も別に生成し、2回一致を確認した。[Qt一式とtoml++のsource取得・照合](../tests/results/source-archives/README.md)は後続で完了した。独立PDFium等を含む完全な対応source・全linked入力・全Chromium告知は未完了。収集状況と実際の配布条件から生じる必要性の判断を区別する。DocView自身の公開ライセンスは未選定であり、ローカルアーカイブ生成は公開配布を意味しない。
|
||||
- G-RENDERで指定された正解画像の人による承認。[現行21組の比較画面](../tests/results/completion-final/render-review/index.html)に確認項目・既知の差分・原本/画像ハッシュをまとめた。独立Popplerとの19組と同一PDFiumのTTC/TTF比較2組を区別する。生成時の期待値やエージェントの画像確認だけで承認済みとは記録しない。
|
||||
|
||||
保存外観のない非Text注釈のNoZoomとannotation所有OBJR/StmOwnは検出時に制約を示す。PDFの情報上限による省略も黙って欠如として扱わず通知する。原設計は検証済み互換範囲と明示制約の管理を許すため、これらを任意PDFへの無制限な対応義務とは読み替えない。一方、対象OSや承認ゲートの不足を「既知制約」で合格に変更しない。
|
||||
@@ -0,0 +1,86 @@
|
||||
# Arch recipe とローカル依存版の対応
|
||||
|
||||
最終開発版の[依存由来台帳](DEPENDENCY-PROVENANCE.md)に記録した 4 件について、
|
||||
キャッシュ `.BUILDINFO` の `pkgbuild_sha256sum` と**完全一致する**公式 Arch packaging
|
||||
Git の固定 commit を確認した。latest recipe で代用していない。
|
||||
全 SHA-256、URL、Git blob ID、取得ファイル一覧は
|
||||
[correspondence.json](../tests/results/source-correspondence/arch/correspondence.json)に保存した。
|
||||
|
||||
| パッケージ版 | 一致した公式 Arch commit | recipe SHA-256 の先頭 |
|
||||
|---|---|---|
|
||||
| qt6-base 6.11.2-3 | [dc5728701868](https://gitlab.archlinux.org/archlinux/packaging/packages/qt6-base/-/commit/dc5728701868792b88f1a3e7f9b56aa3362c5474) | `217bd5ea50a3c721` |
|
||||
| qt6-declarative 6.11.2-2 | [9eac2c716283](https://gitlab.archlinux.org/archlinux/packaging/packages/qt6-declarative/-/commit/9eac2c716283905721fdcbc5bb18494f0a486325) | `f955fe1f3f93ca32` |
|
||||
| qt6-webengine 6.11.2-1 | [f701f0aa989dc](https://gitlab.archlinux.org/archlinux/packaging/packages/qt6-webengine/-/commit/f701f0aa989dcbc653805d696118f48d6a70dd0d) | `e4395367f03fd6ca` |
|
||||
| tomlplusplus 3.4.0-2 | [69b0e478ef49](https://gitlab.archlinux.org/archlinux/packaging/packages/tomlplusplus/-/commit/69b0e478ef49b2a5636346d8c9b64c1effc39cfa) | `08383384ca64c9cd` |
|
||||
|
||||
同 commit の packaging ファイル 30 件、25,299 bytes を取得した。PKGBUILD、展開済み
|
||||
参照一覧 `.SRCINFO`、local patch、packaging 自体の LICENSE/REUSE 等を含む。
|
||||
全件の SHA-256 と Git blob ID を照合した。recipe のコードは実行していない。
|
||||
元の本体・ワーカー・PDFium lock・最終 tar は変更していない。
|
||||
|
||||
## 元ソースと適用差分
|
||||
|
||||
- **Qt base**: `qtbase` の `v6.11.2` を参照。Qt 公式 tag の現在の解決先は
|
||||
`ef55f427f2c8b410d34f8a7681020a3000cf6866`。Arch の
|
||||
`qt6-base-cflags.patch` と `qt6-base-nostrip.patch` は取得し、recipe 内 SHA-256 と一致。
|
||||
さらに upstream commit `e80e3f0cebae9c3a45a1b7ce81d6454c699d89c6` を
|
||||
`cherry-pick -n` する。対応する公式 patch 本文も取得した。
|
||||
- **Qt declarative**: `qtdeclarative` の `v6.11.2` を参照し、現在の解決先は
|
||||
`4e3399c26ec57246c08de019cfcbda8d23604cfa`。
|
||||
`2efb7c60ef45952cc8e04b9c9a07965d14c30446` の cherry-pick patch 本文を取得した。
|
||||
- **Qt WebEngine**: `qtwebengine` の `v6.11.2` と別取得する `qtwebengine-chromium` を参照。
|
||||
Qt tag の現在の解決先は `a33fa2a897e5ee58e385b3f88dc247d99fca56db`、その
|
||||
`src/3rdparty` gitlink は `5170777d28bee1ce92cc693a0dbf2ad01492e5cf`。
|
||||
この exact recipe の `_chromium` は空なので、prepare は `git submodule update` の
|
||||
gitlink を使い、別 commit の checkout は行わない。packaging にある
|
||||
`bump-chromium-commit` は保守用 helper で、この recipe からは実行されない。
|
||||
Chromium source 行の checksum は `SKIP`。これを検証済み source hash と扱っていない。
|
||||
- **toml++**: GitHub の公式 `v3.4.0.tar.gz` を `tomlplusplus-3.4.0.tar.gz` として参照。
|
||||
recipe の SHA-512 / BLAKE2b を記録した。当時は元 archive 未取得だった。後続の[取得・検査](../tests/results/source-archives/README.md)で両checksumと現在の51ヘッダー・LICENSEの一致を確認した。tag の Git commit 解決はこの追加作業には含まない。
|
||||
|
||||
上の Qt tag 解決は今回の公式 metadata の観測であり、当時の builder が受け取った
|
||||
source bytes を再現した証明とは異なる。Git source に宣言された SHA-256 も台帳へ保持したが、
|
||||
全 checkout を取得してその checksum を計算したとは扱わない。
|
||||
|
||||
## Chromium の版表記
|
||||
|
||||
固定 gitlink の `chromium/chrome/VERSION` は `140.0.7339.225`。
|
||||
Qt の `src/core/configure/BUILD.root.gn.in` は `build/util/version.py` へ
|
||||
`//chrome/VERSION` を渡し、その結果を `CHROMIUM_VERSION` macro にする。
|
||||
`QtGnGen.cmake` が指定する GN root は submodule の `chromium` ディレクトリーである。
|
||||
`web_engine_context.cpp` の `qWebEngineChromiumVersion()` はこの macro を文字列化する。
|
||||
したがって、この source から得られる版は[実ライブラリで別途観測した
|
||||
`140.0.7339.225`](../tests/results/source-correspondence/qt-credits/resource-extraction.json) と整合する。
|
||||
[取得した固定 source とハッシュ](../tests/results/source-correspondence/arch/upstream-metadata/version-sources.json)
|
||||
|
||||
一方、Qt repository 上位の説明ファイル `CHROMIUM_VERSION` は
|
||||
base `140.0.7339.264` / security patches `151.0.7922.71` を記載する。
|
||||
この説明ファイルは上記 API の生成元ではない。
|
||||
`qWebEngineChromiumSecurityPatchVersion()` の source は `151.0.7922.71` の固定文字列を返す。
|
||||
base API、security patch API、説明 metadata の値を混ぜて単一の runtime 版としない。
|
||||
個々の security patch の完全性を、この版表記だけから保証するものでもない。
|
||||
|
||||
## 再検証と未完了範囲
|
||||
|
||||
[collect.py](../tests/results/source-correspondence/arch/collect.py) は既定で保存済み証拠を
|
||||
オフライン検証する。`--fetch --output NEW_DIRECTORY` は固定 commit の小ファイルと metadata
|
||||
だけを再取得する。1 ファイル 512 KiB、保存対象合計 4 MiB、packaging 64 ファイルを上限とし、
|
||||
対象は公式 Arch/Qt の HTTPS に限定する。source archive、clone、build は実施しない。
|
||||
HTML metadata には生成時刻が入り得るため、再取得時は semantic commit を照合し、
|
||||
recipe・patch・固定 source 本文は byte hash を照合する。
|
||||
|
||||
```sh
|
||||
python3 tests/results/source-correspondence/arch/collect.py
|
||||
python3 tests/results/source-correspondence/arch/test_collect.py
|
||||
python3 tests/results/source-correspondence/arch/collect.py --fetch \
|
||||
--output tests/results/source-correspondence/arch/new-fetch
|
||||
```
|
||||
|
||||
正式な G-DISTRIBUTION は引き続き未達。この作業で、4 recipe の版・commit・付属 patch・source
|
||||
参照の対応は進んだが、全対応ソース、build toolchain、生成物の再ビルド再現、署名の真正性、
|
||||
全第三者告知や適用条件の判定、対象 OS のクリーン配布検証まで完了したものではない。
|
||||
DocView の公開ライセンスや製品版の同梱方針も選択していない。
|
||||
|
||||
## 公式リリースソース取得の追加結果
|
||||
|
||||
[Qt 6.11.2一式の公式archive](../tests/results/source-archives/README.md)を公開SHA-256と照合し、全390,976通常ファイルを検査した。上記WebEngineの固定source 8件が一致し、base/declarativeの4差分は専用コピーへ適用できた。CFLAGS patchは元recipeのGNU patch既定許容範囲でfuzz 1を必要とし、upstream 2差分はfuzz 0で確認した。適用後のmkspec 2件は現在のArchファイルと一致した。実ビルド、全コンパイル入力・全告知の照合、G-DISTRIBUTIONの完了は示さない。
|
||||
@@ -0,0 +1,35 @@
|
||||
# 依存関係とビルド記録
|
||||
|
||||
2026-09-19のLinux検証で使用した構成。依存ライブラリは動的リンク、DocView内部のライブラリは静的リンクで本体・ワーカーに組み込む。
|
||||
|
||||
| 要素 | 検証版 | 固定・取得方法 |
|
||||
|---|---|---|
|
||||
| Qt Base | 6.11.2-3(Arch) | CMakeで6.11.2 EXACT |
|
||||
| Qt Declarative | 6.11.2-2(Arch) | 同上 |
|
||||
| Qt WebEngine | 6.11.2-1(Arch) | 同上。文書JavaScript・通信をアプリ側で制限 |
|
||||
| PDFium | 155.0.8057.0 / chromium/8057 | [lock](../cmake/pdfium.lock.json)の取得URL・SHA-256を照合 |
|
||||
| libzip | 1.11.4-1 | システムライブラリ、CMake下限1.11 |
|
||||
| toml++ | 3.4.0-2 | システムライブラリ、CMake下限3.4 |
|
||||
| libseccomp | 2.6.0-1 | Linuxのみ、CMake下限2.5 |
|
||||
| Fontconfig | 2.18.3 | LinuxのMain側FontBrokerのみ、CMake下限2.13。OS font索引・選択に利用 |
|
||||
| GCC | 16.2.1+r23+gd564253eb6c8-1 | C++20、Releaseビルド |
|
||||
| CMake / Ninja | 4.4.3 / 1.13.2 | ビルド・CTest |
|
||||
| Poppler | 26.08.0-1 | 試験のみ。PDFiumと独立した比較器 |
|
||||
| libqpdf / qpdf | 12.4.1-1 | CMakeで12.4.1 EXACT。PDFWorker内でリンク注釈辞書・構造見出しの共有メタデータ読取り。CLIは試験資料の暗号化生成にも利用 |
|
||||
| Xvfb | 21.1.24-1 | GUI自動試験の仮想X11画面 |
|
||||
|
||||
PDFiumの上流コミットは`a5a7089234f121990b336b3841008009dca143bf`。配布元はbblanchon/pdfium-binariesのLinux x64成果物で、V8・XFAは無効。アーカイブSHA-256は`7788fa57a2996ebd21afc4090eb0a42b9f95ef3a72e7ef4c0756f1ea703c0415`。公開APIだけを利用するが、構造タグのAPIと`FPDF_SYSFONTINFO` version 2にはExperimental指定があるため、更新時にタグ・MCID・座標に加え、TTCのface選択とshort-buffer callbackの回帰試験を行う。
|
||||
|
||||
FontBrokerはPDFiumをMainにリンクせず、LinuxではFontconfig、WindowsではOSのGDI(`gdi32`)を専用threadで利用する。選択済みfontは上限付きのバイト列としてPDFWorkerへ転送し、Workerにはfontディレクトリーの読取り権限を与えない。static TTF/OpenType/collectionを初期対象とし、候補順と実際の選択情報を[font broker契約](font-broker-contract.md)に記録する。WindowsのGDI実装はソースと補助コンパイルまでで、native実行は未検証である。
|
||||
|
||||
Linuxの実行にはシステムのQt WebEngineプロセス、資源、ロケール、Qtプラグインも必要。Linuxでの`cmake --install`はPDFium本体とLICENSE/licensesを同梱し、Qtその他はシステムから利用する開発用配置である。クリーンOS向けの自己完結した配布物ではない。
|
||||
|
||||
libqpdfはPDFWorkerにだけリンクし、MainにはPDFパーサーを追加しない。同じ継承済みの読み取り専用ファイルから、PDFium公開APIでは取得できないリンク枠のdash配列・Border Style辞書を読む。ファイル名による再openや書込みは行わない。CMakeパッケージとtargetは[公式のライブラリー利用方法](https://qpdf.readthedocs.io/en/stable/library.html)に従う。使用したLinuxパッケージのApache-2.0ライセンス本文を[resources/licenses/qpdf](../resources/licenses/qpdf/README.txt)に複写し、installへ含める。各配布物の推移依存と告知の最終確認は残る。
|
||||
|
||||
Windows x64の同一版PDFiumアーカイブも取得し、SHA-256 `e307d519e42f2e69b1b531f0c2a32dffcdf3891ec0eba60328ba51a57cec01ed`、非V8・非XFAのビルド引数、DLLとimport library、Linux版と公開ヘッダー22件の一致を確認した。Windows上でのロード・実行は未検証。WindowsではCMakeパッケージのlibzip/toml++とqpdf 12.4.1 EXACT、libqpdfの推移依存DLL、MSVC x64、対応する公式Visual C++ Redistributableを必要とし、Qt資源は`windeployqt`を呼ぶ配置コードを用意した。[Windowsの準備手順](WINDOWS-BUILD.md)
|
||||
|
||||
PDFiumのBSD系ライセンスと同梱第三者ライセンス、Qtの利用するモジュールごとのライセンス、libzip、toml++、libseccomp、Fontconfigのライセンスを配布方式に応じて収集・表示する工程が残る。DocView自身の公開ライセンスはこの作業では指定していない。
|
||||
|
||||
試験文書の本文・図形は本リポジトリーの生成スクリプトで作成した。追加日本語PDFはBIZ UDPGothic Regularをsubset埋込し、[OFL本文](../tests/fixtures/pdf/extended/FONT-OFL.txt)と元フォントSHA-256を[manifest](../tests/fixtures/pdf/extended/manifest.json)に保存している。フォント自体をアプリのランタイム依存として追加してはいない。
|
||||
|
||||
セキュリティ修正版の導入時は、Qt、PDFium、libqpdf、libzipを独立に更新せず、版・ハッシュを更新して全CTest、PDF独立比較、WebEngine隔離試験を再実施する。記載版の将来のサポート継続や無脆弱性を保証するものではない。
|
||||
@@ -0,0 +1,119 @@
|
||||
# 開発版パッケージの依存由来台帳
|
||||
|
||||
URL比較修正前のArch開発版について、[ui-final台帳](../tests/results/ui-final/dependency-provenance/README.md)は、焦点・Web倍率・失敗案内の修正後のArch開発版を対象にする。561ファイル、圧縮6,378,914 bytes、展開内容17,504,986 bytes。tarは2回生成してSHA-256 `83e69c6c6354f99a8666c94cbdd669a7d4e1a86ee87d956f566132a0ea6f1153`が一致し、台帳も2回生成して`be6ed689820ce414ff23831fee2266e08bbdb3e2bf617b2324c4a924b21cad35`が一致した。
|
||||
|
||||
146件の同版cache metadata、system告知530件、PDFium告知17件を照合した。追加したQtの7本文は13資源・2 DataPack・固定版/hash/元全文との対応を検証した部分集合であり、`completeChromiumNotices=false`、runtimeはsystem依存である。この保存台帳のsource欄は当時の未収集状態を保持する。後続の[ソース取得](../tests/results/source-archives/README.md)ではQt 6.11.2一式とtoml++を収集・検査し、現在の収集状況は部分完了となった。[抽出の証拠](../tests/results/source-correspondence/qt-embedded-notices/README.md)と[境界試験](../tests/results/ui-final/dependency-provenance/tests.log)を保存した。Qt資源調査の旧「credits文字列の検索結果」と、後から抽出した完全な告知コメント7件は区別する。
|
||||
|
||||
[告知補足版](../tests/results/qt-notice-supplement/README.md)では、固定ソースのWebM/WebPメタデータが指定するPatentファイル2件をUbuntu用debへ追加した。本文は同一だが元の2パスを保持する。IDのみのmini_chromium/libdrmは、上流メタデータが非同梱と記すことを保存し、実SDKのリンク構成未確認という制約を分けて記録した。全告知の完全性判定は引き続き未完了。
|
||||
|
||||
## Ubuntu専用環境の配置確認
|
||||
|
||||
[Ubuntuの別台帳](../tests/results/ui-final/ubuntu/installed-runtime-final/runtime.json)は公式Qt SDK 6.11.2、専用prefixのqpdf/libzip、Ubuntu 24.04の85 packageを対象にし、1,740ファイルの依存解決を確認した。告知104件、SDK SBOM43件、PDFium出典metadata1件を保存した。Qtの選択位置の告知本文とqpdf/libzipのinstall先告知directoryの欠落3件を明示し、後者2件は選択sourceから各告知を別途採取した。完全なChromium告知・対応sourceとはしない。Archの固定告知pinは流用していない。この台帳の採取後に、[Ubuntu用deb](UBUNTU-PACKAGE.md)を生成して配置・起動・削除を検証した。[範囲と実起動の記録](../tests/results/ui-final/ubuntu/README.md)を併読する。
|
||||
|
||||
後続の[SDK告知抽出](../tests/results/source-archives/QT-SDK-NOTICES.md)で、保存済みSBOMに含まれていたChromium告知129entry・105本文を採取し、Qt source原文・元SDK archive・Ubuntu実行時inventoryと照合した。元SBOMの外部package参照不整合1件と本文のない2部品、生成器の除外を明示しており、完全性は未判定。旧台帳の採取時点の本文件数は変更していない。
|
||||
|
||||
## 日本語UI修正時の前回台帳
|
||||
|
||||
Arch Linux 開発版 tar に何が含まれ、どの資料まで照合できたかを記録する。
|
||||
前回の[台帳](../tests/results/completion-final/dependency-provenance/first/provenance.json)は、
|
||||
日本語UI・Web操作等の修正後に生成した `completion-final` パッケージを対象にする。
|
||||
前回tarのSHA-256は`e384c8c21da11343f845a5ca7310ee6ca944e51c9585de4b2b5c7c73ca352e0e`。
|
||||
553ファイル、圧縮後6,367,967 bytes、展開内容17,460,237 bytesを全照合した。
|
||||
2回の台帳生成はbyte一致し、台帳SHA-256は
|
||||
`9d43b6ae79bb8e7d4ced790ef25f399b4c616ad0d02cf286f59ae93d29d3220b`。
|
||||
146件のcache metadata、PDFium告知17件とsystem告知523件を照合し、限定23試験が成功した。
|
||||
Qtの日本語QMはsystem依存の `qt6-translations 6.11.2-1` に対応する。
|
||||
DocView自身の日本語catalogは本体に含むが、QtのQMをtarへコピーしたとは扱わない。
|
||||
限定試験・再生成の結果は[前回結果 README](../tests/results/completion-final/dependency-provenance/README.md)、
|
||||
従来版は[履歴 README](../tests/results/dependency-provenance/README.md)、
|
||||
固定recipe・告知原文と実ファイルの照合は[別の記録](../tests/results/source-correspondence/README.md)にある。
|
||||
|
||||
## 追加告知を収録した従来版
|
||||
|
||||
[従来の台帳](../tests/results/dependency-provenance/notices-final/provenance.json)は、
|
||||
固定ソースとの照合で見つかったPDFiumの2告知を補った時点のパッケージを対象とする。
|
||||
そのtarのSHA-256は`df9c0cc5396d7d952804a4611c85e5e2130fad821311e76f880a17e78be49c06`。
|
||||
553ファイル、圧縮後6,342,588 bytes、展開内容17,418,141 bytesを照合した。
|
||||
追加はlibc++/libc++abi告知と出典metadataの3ファイル。変更は説明文・告知一覧・manifestの5ファイルで、
|
||||
当時の本体・2ワーカー・PDFiumの全バイナリーは、下記550ファイル版と同一だった。
|
||||
今回の現行バイナリーとの同一性を主張する記録ではない。
|
||||
追加告知はソースrevision・版・実ライブラリー・本文hashを結び付けて検証する。
|
||||
2回の独立パッケージ生成はbyte一致し、別展開先から6条件のGUI起動が成功した。
|
||||
|
||||
## 元のローカル採取で確認した範囲
|
||||
|
||||
対象は `docview-0.1.0-arch-x86_64-development.tar.gz`、SHA-256 は
|
||||
`fe1cbeb7af6bf53c82dbee3a571b369454115b5c0f1561674cdb09e26c089c4d`。
|
||||
圧縮後 6,338,459 bytes、展開ファイル合計 17,369,299 bytes、550 ファイルを
|
||||
tar 内の payload manifest と照合した。manifest 自身は自己ハッシュから除外されるが、
|
||||
そのハッシュも台帳へ保存する。元の dependency manifest のハッシュも記録する。
|
||||
|
||||
| 対象 | 実際の含有・参照 | 追加で採取した証拠 |
|
||||
|---|---|---|
|
||||
| DocView と 2 ワーカー | tar 内の実行ファイル 3 本 | 全ファイル SHA-256 と `readelf` の直接 `DT_NEEDED` |
|
||||
| 独立 PDFium 155.0.8057.0 | `lib/libpdfium.so` を同梱 | ローカルのライブラリ・15 告知文が tar と一致。`VERSION`、全 10 項目の `args.gn`、固定 lock のハッシュと値を照合 |
|
||||
| Qt 6.11.2 | Qt/WebEngine の runtime 本体はシステムから動的に参照 | tar 内の 3 実行ファイルから Qt の直接リンクを確認。元の依存 inventory の Qt 共有ライブラリ 42 行を保持 |
|
||||
| toml++ 3.4.0-2 | 共有ライブラリはシステム側。ヘッダー由来コードは DocView 本体に含む | 本体に定義された `toml::` シンボル 27 件、`toml++/toml.h` の include、同梱 MIT 告知文のハッシュ |
|
||||
| システム依存候補 146 パッケージ | 元 inventory が記録した共有ライブラリ・Qt 資源など。runtime 本体をこの tar へコピーしていない | 全 146 件で同版・同 architecture・同 package base の cache `.PKGINFO` / `.BUILDINFO` を照合。各 raw metadata と `PKGBUILD` の SHA-256 |
|
||||
|
||||
システム共有ライブラリの非同梱は、ヘッダー・テンプレート由来コードが実行ファイルに
|
||||
含まれないという意味ではない。toml++ は両方を実物で確認した。Qt を含むその他全依存の
|
||||
ヘッダー由来コードの列挙までは実施していない。また、146 件の一覧は元 inventory の
|
||||
依存候補集合であり、各資料を開くたびに全件を実際にロードしたとの主張ではない。
|
||||
|
||||
PDFium の先頭 `LICENSE` は binary provider の MIT 文である。
|
||||
PDFium upstream の BSD 条件は `licenses/pdfium.txt` にあり、残りのライセンス文も別々に
|
||||
対応させた。上位の `LICENSE` だけを PDFium 全体の条件として扱っていない。
|
||||
lock 記載の provider archive SHA-256 は既存の固定値として記録し、今回その取得 archive を
|
||||
再ダウンロード・再検証したとは扱わない。
|
||||
|
||||
## キャッシュ証拠の意味
|
||||
|
||||
Qt base/declarative/webengine と toml++ の 4 archive は全体の SHA-256 も記録した。
|
||||
他の 142 archive は展開を進めず、最大 8 MiB の先頭領域にある metadata のみ採取する。
|
||||
raw metadata はハッシュだけを保存し、本文からは package 名・版・architecture・license label・
|
||||
build date・build tool・`PKGBUILD` hash を選択する。氏名、メール、build directory、
|
||||
builder の全 installed-package 一覧は保存しない。利用者のホーム内データも探索しない。
|
||||
|
||||
このcollector単独では、recipe本文やcacheのruntime payloadを検査しない。
|
||||
後続の[照合](../tests/results/source-correspondence/README.md)では主要4パッケージの
|
||||
実行時ファイル1,581件と現在のtoml++ヘッダー51件をcache payloadと照合し、全て一致した。
|
||||
4つの`PKGBUILD`本文もBUILDINFOのhashに一致する公式commitへ対応させ、patchを取得した。
|
||||
残り142パッケージのpayload比較、cacheの署名認証、過去のコンパイル時点のヘッダー証明、
|
||||
システム全体のソース回収を行ったという意味ではない。
|
||||
|
||||
## 再実行
|
||||
|
||||
Python 3.14 以上の zstd 対応 `tarfile`、GNU `nm` / `readelf`、既存の最終 tar、
|
||||
`.deps/pdfium`、ローカル Arch package cache を使う。既存結果は上書きしないため、
|
||||
`--output` は新しいディレクトリーにする。
|
||||
|
||||
```sh
|
||||
python3 tools/record_dependency_provenance.py \
|
||||
--archive tests/results/ui-final/linux-development-package/package/docview-0.1.0-arch-x86_64-development.tar.gz \
|
||||
--output tests/results/ui-final/dependency-provenance/new-run
|
||||
python3 tests/test_dependency_provenance_qt.py -v
|
||||
```
|
||||
|
||||
別配置の入力は `--archive`、`--pdfium-root`、`--package-cache` で指定できる。
|
||||
同じ tar・ローカル PDFium・cache metadata・調査ツール・source include から同じ JSON を生成する。
|
||||
時刻や作業ディレクトリーを出力に含めない。cache がない項目は明示的に未採取と記録し、
|
||||
版不一致や壊れた metadata は成功へ変換しない。本体やワーカー、`ldd` は実行しない。
|
||||
|
||||
## 原設計に対して残る作業
|
||||
|
||||
[設計 09 §4 G-DISTRIBUTION と §5](design/09-decisions-roadmap.md) は、
|
||||
実配布物と対応ソース・告知・依存一覧の対応、および対象 OS での配布確認を求める。
|
||||
この台帳だけで合格とはしない。`sourceCollectionStatus: not-collected` は資料収集状況であり、
|
||||
全 146 システム依存のソースを一律に再配布する法的義務が確定したという判定でもない。
|
||||
|
||||
1. **対応ソースと告知の整理**: 主要4つのArch recipe/patch、PDFium providerの固定recipe・
|
||||
依存pin・既存15告知の原文対応は確認した。見つかったlibc++/libc++abiの告知不足は現行tarへ
|
||||
反映した。Qt一式とtoml++のsource取得・固定hash照合、Archの4差分の適用確認は[追加記録](../tests/results/source-archives/README.md)で完了した。[PDFiumのGitソース収集](../tests/results/source-archives/PDFIUM.md)では本体と27依存・追加gitlinkを保管し、公開ヘッダー24件と告知15件の一致、Linux/Windows用パッチの適用を確認した。全linked component・compiler runtime/sysroot・完全な対応ソース、
|
||||
Qt WebEngineの実GN構成に対応する全Chromium告知は未完了。
|
||||
[追加の資源調査](../tests/results/source-correspondence/qt-embedded-notices/README.md)で7件の完全な告知本文を収集したが、全Chromium告知は取得できておらず、
|
||||
当該buildの生成物または同じ構成による生成が必要になる。これらを対象OS試験の不在だけで説明しない。
|
||||
2. **公開方針の決定を伴う整理**: DocView 自身の公開ライセンス、採用する Qt の条件、
|
||||
製品で実際に同梱する範囲・形式を決め、その具体的な配布に適用する告知・ソース提供等を
|
||||
確認する。この台帳は条件の選択や法的適合の断定を行わない。
|
||||
3. **追加環境が必要な確認**: Windows 11 x64 の署名済み配布・削除、対象OSの物理GPU・表示・入力の受入は残る。Ubuntu 24.04については[新しいOSから作成した専用VM](../tests/results/ubuntu-package/clean-vm/README.md)で依存解決・sandbox・X11/Waylandの起動・削除を検証し、[URL修正版](../tests/results/portal/README.md)では更新と実ファイル選択も確認した。これらをWindowsや物理環境の代わりとはしない。
|
||||
@@ -0,0 +1,32 @@
|
||||
# 実装時の判断記録
|
||||
|
||||
設計書は[docs/design](design/00-guide.md)へそのまま複写し、[SHA-256](design/sha256.json)を保存した。本書は実装時の追加判断であり、原設計の受入条件を書き換えない。
|
||||
|
||||
| 判断 | 実装と理由 | 検証・影響 |
|
||||
|---|---|---|
|
||||
| フォントを選択したバイト列だけで供給 | MainのFontconfig/GDIでOS索引から選択し、64 KiBずつ既存IPCでWorkerへ渡す。SFNT/TTC解析とPDFiumはWorker内 | Linuxのフォントディレクトリー許可を撤去。日本語CID横/縦と転送・取消・上限を試験。Windows実行は未確認。[契約](font-broker-contract.md) |
|
||||
| Linuxから実装 | Arch Linux x64に加え、専用KVMのUbuntu 24.04でもQt 6.11.2と固定PDFiumをビルド・検証 | UbuntuはXvfb/Swayのsoftware描画、ArchはAMD OpenGLも確認。Windows native、対象OSの物理表示・IME、製品配布の受入は未完了 |
|
||||
| PDFタイルのオフスクリーン余白16px | 設計案の2pxでは、タイル境界を横切る文字のアンチエイリアスに差が出た。16px描画して要求矩形だけを返す | タイルと全ページの切り出しが試験資料でbyte一致。転送タイルは最大514px、通常512pxのまま |
|
||||
| アーカイブワーカーを読み取り専用にする | ZIP解析・CRC確認・フォント難読化解除はワーカー、最大64KiBずつの展開結果の保存はメイン側 | パーサー侵害で一時領域を無制限に書き込む経路を除去。メイン側で資源256MiB・文書2GiBを確認し、完了後だけ公開 |
|
||||
| 索引を分割する | PDF目次最大20,000件、初回64件/128KiB、継続最大256件/512KiB。ページ情報は最大256件/256KiB。アーカイブ目次等も件数と実バイト数で分割 | IPC制御フレーム1MiBを保ち、大きなラベルで一括応答が溢れる問題を防止。メイン側でも累積32MiBの索引上限 |
|
||||
| 先読みの予算と優先度 | 可視タイルと通常操作が完了した後、設定された隣接ページの可視域相当の帯を1件ずつ読む。前ページは末尾、後ページは先頭を対象にする | 0〜3ページ、隣接1ページ最大8タイル。余白がなければ先読みせず、先読みで既存キャッシュを追い出さない |
|
||||
| メモリ圧迫の段階的対応 | OSの利用可能物理メモリを1秒ごとに読み、先読み停止→不可視タイル回収→描画解像度抑制と通知→文書処理停止の順で進む。LinuxはMemAvailable、WindowsはGlobalMemoryStatusEx | 閾値・ヒステリシス・位置保持・回復と停止後の再openは [契約](memory-pressure.md)。設定のキャッシュ上限・隔離の資源上限は維持する。Windows側の実行は未確認 |
|
||||
| 実際に提示した位置を保存 | PDFは可視タイル完成後のframeSwapped、Webは提示時の論理位置を状態へ渡す | 未表示のジャンプ先を終了時に保存しない。2秒debounce/10秒最大間隔はStateStoreへ集約 |
|
||||
| 保存先の原本をセッション開始時と照合 | 全形式のopen時に取得した正規パス・サイズ・更新時刻・物理ファイルIDを保存時にも照合する | 閲覧中の変更・置換で古い位置を新原本へ転用しない。通常openでも履歴との同一性不一致を通知。[実ファイル置換の回帰](../tests/results/completion-regressions/controller-state.md) |
|
||||
| 目次の準備中を欠如と区別 | 能力がloadingの間は空の索引でも表示要求を保持し、パネルに読み込み中と示す | 本文のReadyを待たせず、DOM索引到着後に同じパネルへ項目を表示する |
|
||||
| 見出しの代替と章境界を限定 | PDFのoutline代替は内部宛先だけを採用。EPUBの最初/最後の見出しへの指示は成立した章移動にだけ結び付ける | 外部だけの目次を見出しありと判定しない。失敗した章境界操作の指示が後の通常移動へ残らない |
|
||||
| 日本語を初期表示し翻訳資源を分離 | tr/qsTr/固定contextからTSを生成し、QMを本体へ埋め込む。Qt標準部品の日本語資源も読み込む | 英語localeでの設定・コマンドの案内とQt Quick Dialogを検査。OSネイティブdialogはOS言語に従う。[更新・配置条件](TRANSLATIONS.md) |
|
||||
| Webの内部URLを履歴から除外 | Mainで位置の型・上限・originを検証し、resourcePath/CFI/進捗とEPUB package/spineで復元する。旧state/backupのlocation.urlも書込み可能時に除去 | 旧href形式の復元を維持。読み取り専用・forceReadOnlyではファイルを変えず、本文引用中のURLは削除しない |
|
||||
| ZIP入口は読書位置と別に保存 | 選んだ相対HTMLを同じ原本identityと現在の候補で再確認し、表示成功後だけ記憶する | recent-only/position-only、別GUIプロセス再起動、取消・消去・原本置換を試験。[記録](../tests/results/zip-entry-choice/README.md) |
|
||||
| 固定EPUBの見開きは最大2ビュー | 同じ文書profileのprimary/companionへ左右を配置し、author viewportと共通倍率を維持。renderer監視は2枠に限定 | LTR/RTL、両向き、単独中央、混在、取消を確認。章loadの同期通知は現在章のみ更新し、読書位置保存は提示後のまま |
|
||||
| 資源拒否を分類・件数だけ集約 | broker、interceptor、ブラウザーCSPの検出を文書内でまとめ、`:info`へ表示する | URL・本文を記録しない。合成イベント・古いセッションを拒否。[契約](resource-warning-contract.md) |
|
||||
| PDFリンク枠の辞書をWorker内で補完 | PDFium公開APIで不足するBorder/BSをlibqpdfで読み、保存外観がないリンクにだけ数値から一時外観を生成する | 原本は書かず、既存外観を維持。通常枠の欠落を解消。NoZoom/NoRotateは描画中だけRect/回転を補正し、原本座標と保存APを保持する。[比較](../tests/results/link-borders/README.md) |
|
||||
| PDF注釈へキーボードで到達 | 既存のリンク順の後に本文付き注釈を加え、Tab/Shift+Tabで選びEnterで読み取り専用の本文を表示する | CropBox外の注釈も選択可能。通常モードのEscで選択解除し、Web文書へ切り替えた後はPDFの選択と画像を回収する |
|
||||
| 生成資料を使用 | 利用者から既存コーパスなしとの回答。本文・図形・座標・色の期待値を持つ資料を生成 | PDFiumとは独立したPopplerで比較。実書籍全般・全描画機能の互換性を保証する試験には置き換えない |
|
||||
| OSの保護が利用できないときは停止 | LinuxはLandlock ABI3以上・seccomp・資源上限。WindowsはLPAC・Job・明示ハンドル継承・子側の実token検証を本番経路へ接続 | Windows固有部分は未ビルド・未実行。保護なしで起動するフォールバックを設けない |
|
||||
| Windowsワーカーの依存物を個別コピー | ビルド時に有限のDLL一覧とハッシュを生成し、起動時に検証して専用領域へコピーする | インストール先や原本のACLを変更しない。実機でのPE解析・初期表示速度・配布確認は残る |
|
||||
| Windowsのprofileを読み取り専用にする | AppContainer作成時にできる固有filesystem/registryの書込権限も制限し、子側で検証する | 任意Tempと自身のprofileへの書込拒否を試すnative試験を追加。Windowsでの保護成立は未確認 |
|
||||
|
||||
PDF見出しはWorker内の共有qpdf contextでページ/Formの所有元、ParentTree、RoleMapと構造順を読み、文字・座標は公開PDFium APIから取得する。FormだけのStructParentsにも対応し、入れ子Form・名前付きproperty・複数ページの子要素順を試験した。複数呼出や一意に対応できないFormは理由付きページ精度へ下げ、別のstreamの同じMCIDから文字や座標を借用しない。跨ページ見出しはページ別の断片として扱い、フォントサイズから見出しを推測しない。[補完アダプター](pdf-structure-adapter-plan.md)。
|
||||
|
||||
本文の検索・保存位置・最近使った文書のローカル記録を実装した。これら補助機能の合格範囲は検証記録のT-P系列で区別する。OCR、PDF入力・編集・保存、外部通信、文書スクリプト実行を追加しない。
|
||||
@@ -0,0 +1,122 @@
|
||||
# Linux開発版のローカルパッケージ
|
||||
|
||||
この手順は、現在の **Arch Linux x86_64・Qt 6.11.2** 環境向けの開発版を
|
||||
tar.gzにまとめる。公開・アップロード・署名は行わない。Ubuntu 24.04、Windows、
|
||||
任意Linuxでの互換性やクリーンインストールの合格を意味しない。
|
||||
|
||||
## 形式と対象範囲
|
||||
|
||||
| 候補 | この段階での判断 |
|
||||
|---|---|
|
||||
| tar.gz + システム依存 | ローカル開発版に採用。展開先を移して検証でき、元に戻す操作も明確。配布先のパッケージ管理やABIを変更しない |
|
||||
| Ubuntu向けdeb | 初期対象の製品版候補。Ubuntu上で依存解決・インストール/削除の検証が必要なため未採用 |
|
||||
| AppImage等のランタイム同梱方式 | Qt/WebEngine/GPU・sandbox・ライセンス集合を含む別検証が必要。今回の開発版には採用しない |
|
||||
|
||||
製品版の初期対象ごとの形式決定は未完了。Windowsの既存配置コードをこの判断で変更しない。
|
||||
|
||||
同梱するランタイムは本体、PDF/アーカイブワーカー、固定版の独立PDFium共有ライブラリ。
|
||||
Qt、WebEngine helper/資源/翻訳/QML/plugin、libqpdf、libzip、libseccomp、
|
||||
Fontconfig等はシステムから読み込む。Qt共有ライブラリとpluginの配置は別の依存条件である。
|
||||
[QtのLinux配布資料](https://doc.qt.io/qt-6/linux-deployment.html)
|
||||
|
||||
toml++はシステムパッケージのヘッダーから実行ファイルへ組み込むため、
|
||||
実行時だけのシステム依存とは区別する。MIT本文は同梱済みである。
|
||||
実際の含有範囲とローカルビルド由来は[依存物の証跡台帳](DEPENDENCY-PROVENANCE.md)を参照する。
|
||||
|
||||
`third-party/dependency-manifest.json`に実際のArchパッケージ版、共有ライブラリや
|
||||
Qt資源のハッシュ、実行ファイルが要求するGLIBC/GLIBCXX/CXXABIのsymbol versionを記録する。
|
||||
Archのrolling-release ABIに依存し、単に同じCPUやQtのmajor版であれば動くという主張はしない。
|
||||
X11/Wayland、IME、GPU driver、フォント、Landlock ABI 3以上とseccompが別途必要。
|
||||
隔離できない環境ではワーカーを起動せず、sandboxを無効にして実行しない。
|
||||
|
||||
## 生成
|
||||
|
||||
Python 3.11以上、CMake、Archのpacmanデータベース、`ldd`、`readelf`、
|
||||
`/usr/lib/qt6/bin/qtpaths`とビルド済み実行ファイルを必要とする。
|
||||
自分でビルドした信頼できる実行ファイルだけを入力にする。
|
||||
初回は[READMEのビルド手順](../README.md#ビルドと起動)に従い、依存物と固定版PDFiumを準備する。
|
||||
|
||||
```sh
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build
|
||||
python3 tools/package_linux_development.py --build-dir build --output build/package-local
|
||||
```
|
||||
|
||||
Pythonが見つかったLinuxビルドには`linux-development-package` targetも登録する。
|
||||
その既定出力先は`build/linux-development-package`で、必要ならCMakeの
|
||||
`DOCVIEW_LINUX_PACKAGE_OUTPUT`で変更する。`BUILD_TESTING`時は軽量の`linux_package`試験も登録する。
|
||||
|
||||
生成スクリプトは一時領域に`cmake --install`し、実依存を調査して告知を収集する。
|
||||
既に存在する出力アーカイブは上書きしない。別の出力ディレクトリーを指定して再生成する。
|
||||
既存の新規install treeを使う場合は`--build-dir`の代わりに`--prefix`を指定できる。
|
||||
利用者の設定・履歴・文書や、system library/fontの実体はパッケージに含めない。
|
||||
LinuxのinstallにはPDFium providerの15告知に加えて、固定ソースから補った
|
||||
libc++/libc++abiの2告知と出典metadataを含める。版・commit・ライブラリー・告知の
|
||||
ハッシュをconfigure時とpackage生成時に照合する。PDFiumを更新した場合は再調査が必要。
|
||||
追加の根拠は[PDFiumのソース対応記録](PDFIUM-SOURCE-CORRESPONDENCE.md)を参照する。
|
||||
Linux packagerはさらに、QtWebEngineの実DataPack内13資源から得た7種類の完全な告知本文と
|
||||
出典metadataを収録する。固定Qt版・Arch package版・DataPackのpath/hash・本文のsize/hashを
|
||||
現在のsystem inventoryへ照合し、不明な版・variantや欠落・改変は新たなレビューまで拒否する。
|
||||
本文とmetadataだけをコピーし、QtのruntimeとDataPackはsystem依存のままとする。
|
||||
これは全Chromium告知の完成ではない。根拠と比較範囲は
|
||||
[資源内告知の抽出記録](../tests/results/source-correspondence/qt-embedded-notices/README.md)にある。
|
||||
|
||||
- `docview-0.1.0-arch-x86_64-development.tar.gz`: ローカル開発版。
|
||||
- 同名`.json`: アーカイブSHA-256、圧縮後サイズ、展開後ファイルサイズ合計、
|
||||
ファイル数、本体/workerハッシュ、含めていないsystem runtime候補の合計サイズ。
|
||||
- アーカイブ内`share/doc/docview/package-manifest.json`: 全payloadの相対パス・mode・
|
||||
サイズ・SHA-256。自己ハッシュは含めない。
|
||||
- 同`third-party/`: 依存版/出典/対応ソースの収集状況・NOTICE・収集したlicense本文。
|
||||
|
||||
順序、uid/gid、所有者名、mode、mtimeとgzip headerを固定する。
|
||||
`SOURCE_DATE_EPOCH`は未指定時0。必要なら`--epoch`で指定できる。
|
||||
同じinstall内容・ホスト依存/告知・スクリプト・Python/zlib・epochから同じバイト列を得る。
|
||||
コンパイラーや実行ファイル自体の再現可能ビルドを証明する手順ではない。
|
||||
生成時に展開して全hashを確認し、その展開物から再圧縮したhashが一致することも要求する。
|
||||
|
||||
## 展開、起動、削除
|
||||
|
||||
```sh
|
||||
mkdir -p /tmp/docview-local-check
|
||||
tar -xzf build/package-local/docview-0.1.0-arch-x86_64-development.tar.gz -C /tmp/docview-local-check
|
||||
/tmp/docview-local-check/docview-0.1.0-arch-x86_64-development/bin/docview /absolute/path/to/book.pdf
|
||||
```
|
||||
|
||||
PDFiumの検索先はworkerからの相対RPATHを使う。`LD_LIBRARY_PATH`の追加は不要。
|
||||
実行すると通常は利用者のXDG設定・履歴を使う。試験は次の専用スクリプトで行い、
|
||||
一時XDG領域へ隔離する。
|
||||
試験結果を区別するため、`--output`には毎回新しいディレクトリーを指定する。
|
||||
|
||||
```sh
|
||||
python3 tests/test_linux_package.py -v
|
||||
xvfb-run -a -s '-screen 0 1100x760x24' \
|
||||
env QT_QPA_PLATFORM=xcb QT_QUICK_BACKEND=software QTWEBENGINE_CHROMIUM_FLAGS=--disable-gpu \
|
||||
python3 tests/smoke_linux_package.py \
|
||||
--archive build/package-local/docview-0.1.0-arch-x86_64-development.tar.gz \
|
||||
--output tests/results/linux-development-package/new-run
|
||||
```
|
||||
|
||||
後者は全payloadを検証して空の一時ディレクトリーへ展開し、6条件の本番GUI smokeを実行する。
|
||||
元のinstall pathと異なる位置からPDF/HTML/ZIP/EPUBを開く。Chromiumとworkerのsandboxは有効。
|
||||
成功時も失敗時も一時展開先を回収する。同一開発機での検証なのでclean-OS試験ではない。
|
||||
同じ出力先を再利用した場合も、開始時に前回の`results.json`と`package-smoke.json`を除去する。
|
||||
途中失敗では成功集計を残さず、古い画像だけでは当該実行の成功を示さない。
|
||||
|
||||
この配置はpackage managerやsystem directoryに登録しない。不要になった展開ディレクトリーを
|
||||
削除すれば実行ファイルの配置を取り除ける。通常起動で保存した設定・履歴は別に残る。
|
||||
原本文書を削除対象に含めない。
|
||||
|
||||
## 告知と未完了事項
|
||||
|
||||
DocView自身の公開ライセンスは未指定。第三者のlicense本文やpackage labelsを収録しても、
|
||||
DocViewのライセンスを選択したことにはならない。主要4つのArch recipeとpatch、PDFium
|
||||
providerと固定依存ソースの対応は[別の調査記録](../tests/results/source-correspondence/README.md)に
|
||||
保存した。各依存の対応ソース一式・完全なbuild materialはパッケージに含めず、Qt WebEngineの
|
||||
build固有の全Chromium告知も未取得。今回の7本文は有限の部分告知集として記録し、
|
||||
`completeChromiumNotices = false`を維持する。manifestの`source.status = not-collected`は
|
||||
パッケージ側の完全なソース収集が未完了であることを表す。ソースURLだけを履行済みの証拠にしない。
|
||||
|
||||
今回計測する圧縮サイズはWebEngine込みの自己完結した配布サイズではない。
|
||||
system runtime候補の合計は必要ディスク量の参考であり、共有・既存install・任意追加providerを
|
||||
含むため、追加インストール容量や製品配布サイズと同一視しない。
|
||||
G-DISTRIBUTION/T-S05の正式合格には、対象OSの実配布・依存/告知/対応ソース整理が引き続き必要。
|
||||
@@ -0,0 +1,54 @@
|
||||
# 修正版PDFiumの配置とビルド
|
||||
|
||||
現在の候補は `v2` です。ICC変換指定、パターンの初期状態、未着色タイルの線色を修正しています。[検証記録](../tests/results/pdfium-intent-context/README.md)に、元ソース・パッチ・バイナリーと試験結果の対応を保存しています。
|
||||
|
||||
## この作業環境での起動
|
||||
|
||||
配置済みの `.deps/pdfium-context` を選択した `build-context` を使用します。
|
||||
|
||||
```sh
|
||||
./build-context/docview "/path/to/book.pdf"
|
||||
```
|
||||
|
||||
新しいprefixを作る場合は、まだ存在しないパスを指定します。既存prefixを上書きすることはできません。
|
||||
|
||||
```sh
|
||||
python3 tools/stage_pdfium_candidate.py --candidate v2 --verify-only
|
||||
python3 tools/stage_pdfium_candidate.py --candidate v2 --output "$PWD/pdfium-context-prefix"
|
||||
cmake -S . -B build-context-new -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
-DDOCVIEW_PDFIUM_ROOT="$PWD/pdfium-context-prefix"
|
||||
cmake --build build-context-new -j 6
|
||||
```
|
||||
|
||||
この配置ツールは、検証済みソース・ツール・結果が保存された本作業環境を入力にします。ネットワーク取得やPDFiumの再ビルドは行いません。CMakeには新しいビルドディレクトリーを使い、別版のライブラリーが残るキャッシュを避けます。
|
||||
|
||||
## 固定値と照合
|
||||
|
||||
| 項目 | 値 |
|
||||
|---|---|
|
||||
| upstream revision | `a5a7089234f121990b336b3841008009dca143bf` |
|
||||
| 候補library SHA-256 | `cb049fe434f4c911b5eb047c0aca572d4dd9f5e405dde329b76c05a6aa771403` |
|
||||
| 固定ビルド記録 | `tests/results/pdfium-intent-context/record.json` |
|
||||
| 記録SHA-256 | `80af72b06d5c9a6a3ab8b9311373e6a23e8df28668ce575e1124350e69aa160b` |
|
||||
| 配置検証の固定値 | `cmake/pdfium-candidate-v2.lock.json` |
|
||||
|
||||
配置時は固定記録、パッチ、変更ソース60件、ツールアーカイブ、実際のGN引数、公開ヘッダー24件、告知17件を照合します。ヘッダーはproviderパッチを逆適用して元Git inventoryとの一致も確認します。告知は元ソースとの対応記録に結び付けます。
|
||||
|
||||
`include/`、`lib/`、告知、`VERSION`、`args.gn`、`provenance/`、`BUILDINFO.json`を配置します。入力のリンクや特殊ファイルを拒否し、検証したバイト列から一時prefixを作成して、既存出力を置換しないrenameで公開します。
|
||||
|
||||
CMakeは候補libraryとヘッダーの選択先を確認し、BUILDINFO・原記録・パッチ・告知を固定lockに照合します。配置先へコピーする前に再検証します。配置後とUbuntu deb検証でも同じ対応を確認します。配置済みの告知・由来記録は `share/doc/docview/pdfium/` に含まれます。
|
||||
|
||||
## 回帰試験
|
||||
|
||||
LinuxのCTestには配置ツールと配布対応の試験を含めています。個別にも実行できます。
|
||||
|
||||
```sh
|
||||
python3 -m unittest discover -s tests -p test_stage_pdfium_candidate.py -v
|
||||
python3 -m unittest discover -s tests -p test_pdfium_candidate_integration.py -v
|
||||
```
|
||||
|
||||
合成入力の改変、ヘッダーと原本の同時改変、既存出力・リンク・特殊ファイル、書込み途中の失敗、公開時の競合、配置前の改変、自己整合だけを装ったdebを検査します。実debの境界試験には `dpkg-deb` が必要です。
|
||||
|
||||
第1候補は `--candidate v1` で履歴再現用に保持しています。パターン状態の問題があり、現在のCMake配置先としては受理しません。CLIの既定値は以前の再現手順を保つv1なので、現在の候補には `--candidate v2` を指定してください。
|
||||
|
||||
この成果物はLinux x64の検証用です。Windows、物理表示・基準機、人による正解画像承認、公開配布の最終判断は別の未完了条件です。
|
||||
@@ -0,0 +1,119 @@
|
||||
# PDFium配布物と固定ソースの対応
|
||||
|
||||
2026-09-19、DocViewが固定するPDFium **155.0.8057.0**について、配布元・ビルド手順・依存pin・同梱告知の対応を調査した。これは技術的な出所確認であり、法的適合性の認定、全対応ソースの収集完了、再現ビルドの成功を意味しない。製品ソース、PDFium lock、配布アーカイブは変更していない。
|
||||
|
||||
**後続の収集状況:** [固定Gitソースの追加記録](../tests/results/source-archives/PDFIUM.md)で、本体と27依存、FreeType内の追加参照dlgを取得した。Git objectとアーカイブ全payloadを検査し、先行取得原文31件、パッチ後の全公開ヘッダー24件、同梱告知15件の一致を確認した。Linux3件・Windows4件のパッチを専用コピーへ適用済み。以下の「未取得・未適用」は先行調査時点の範囲を記録したもので、現在の取得状況は追加記録を参照する。コンパイラー/sysroot等の全入力と再現ビルドは引き続き未完了。
|
||||
|
||||
機械可読の結果は[report.json](../tests/results/source-correspondence/pdfium/report.json)、取得URL・時刻・元応答と保存内容のSHA-256は各`*.retrieval.json`、全保存物の一覧は[manifest.json](../tests/results/source-correspondence/pdfium/manifest.json)にある。保存物は小規模なメタデータ・レシピ・patch・告知原文であり、巨大ソースarchive、依存checkout、ビルドは取得・実行していない。
|
||||
|
||||
## 配布物からレシピへの対応
|
||||
|
||||
| 対象 | 確認した固定値 |
|
||||
|---|---|
|
||||
| PDFium upstream commit | `a5a7089234f121990b336b3841008009dca143bf` |
|
||||
| provider tag | `bblanchon/pdfium-binaries`の`chromium/8057` |
|
||||
| provider recipe commit | `f2e9a1c45bb17b85b540abf1af30146ef65416ac` |
|
||||
| GitHub release ID | `388577209`、公開APIの`immutable=true` |
|
||||
| build workflow run | `34853011437`、attempt 1、`workflow_dispatch`、`success` |
|
||||
| Linux x64 archive SHA-256 | `7788fa57a2996ebd21afc4090eb0a42b9f95ef3a72e7ef4c0756f1ea703c0415` |
|
||||
| Windows x64 archive SHA-256 | `e307d519e42f2e69b1b531f0c2a32dffcdf3891ec0eba60328ba51a57cec01ed` |
|
||||
|
||||
上のarchive digestは、既存[lock](../cmake/pdfium.lock.json)、[GitHub release API](https://api.github.com/repos/bblanchon/pdfium-binaries/releases/tags/chromium/8057)、releaseに同梱されたattestationのsubjectで一致した。今回archive本体は再取得していない。
|
||||
|
||||
[タグAPI](https://api.github.com/repos/bblanchon/pdfium-binaries/git/ref/tags/chromium/8057)、releaseの`target_commitish`、[workflow run](https://github.com/bblanchon/pdfium-binaries/actions/runs/34853011437)、attestation payloadの`resolvedDependencies`は、同じprovider commitを示す。Linux x64 / Build(job `104005424482`)とWindows x64 / Build(job `104005424089`)の成功も公開job metadataで確認した。
|
||||
|
||||
[attestation原文](../tests/results/source-correspondence/pdfium/provider/attestation.json)のSHA-256は`3928dc9e52ebda1b200d9cb2dcbd971aee57b08190a49ea3e6cd7c31ee445719`で、release assetのdigestと一致する。DSSE payloadは[読取り用JSON](../tests/results/source-correspondence/pdfium/provider/attestation-payload.json)へbase64展開した。**Sigstore署名・証明書・透明性ログの信頼検証は未実施**であり、payloadを読めたことを署名検証済みとは扱わない。payloadが固定するソースはprovider repositoryであり、PDFium本体のcheckout SHAや全依存は列挙していない。
|
||||
|
||||
PDFiumの[固定commit](https://pdfium.googlesource.com/pdfium/+/a5a7089234f121990b336b3841008009dca143bf)と調査時点の`refs/heads/chromium/8057`は一致した。ただしproviderは`gclient sync -r origin/chromium/8057`で取得するため、現在のbranch参照とversionだけで当時の全checkout状態を暗号学的に証明したことにはならない。
|
||||
|
||||
## レシピと適用patch
|
||||
|
||||
固定commitの[レシピ一式](https://github.com/bblanchon/pdfium-binaries/tree/f2e9a1c45bb17b85b540abf1af30146ef65416ac)から、6 workflow、`build.sh`、11段階の`steps`、全`patches`、README、LICENSEの計44ファイルを保存した。全ファイルのGit blob SHA-1を固定commitのtreeと照合し、個別SHA-256も記録している。別OS用・static版用を含むpatch集合全体を保持し、対象に適用する集合とは区別した。
|
||||
|
||||
| 対象 | `steps/03-patch.sh`の分岐が選ぶpatch |
|
||||
|---|---|
|
||||
| Linux x64、shared、V8無効 | `shared_library.patch`、`public_headers.patch`、`clang_rt.patch` |
|
||||
| Windows x64、shared、V8無効 | 上記3件+`win/build.patch`。別途`win/resources.rc`をversion/yearで展開 |
|
||||
|
||||
`shared_library.patch`はPDFium targetを共有library化し、Windows resourcesを追加する。`public_headers.patch`はexport条件と公開C++ headerの相対includeを調整する。`clang_rt.patch`はChromium build側の未対応platform分岐を調整し、`win/build.patch`はresource compilerの呼出しを変更する。これらは公開元のpatchをそのまま保存したもので、今回新規に適用してビルドしたものではない。
|
||||
|
||||
[checkout手順](../tests/results/source-correspondence/pdfium/provider/recipe/steps/02-checkout.sh)はV8無効時に`checkout_configuration=minimal`を使う。[configure手順](../tests/results/source-correspondence/pdfium/provider/recipe/steps/05-configure.sh)と既存Linux配布物の[args.gn](../tests/results/source-correspondence/pdfium/packaged/args.gn)は、Release、standalone、shared、x64、V8/XFA/partition allocator無効と整合する。配布物の`args.gn`には指定した値のみがあり、全GN既定値の展開結果ではない。
|
||||
|
||||
## 依存ソースのpin
|
||||
|
||||
[固定PDFium DEPS](https://pdfium.googlesource.com/pdfium/+/a5a7089234f121990b336b3841008009dca143bf/DEPS)はSHA-256 `55e7f4ecba645a748d99b91df6ff8ed9133faa08a07d39a6c0324a717926b44e`。Pythonとして実行せず、定数・文字列連結・`Var`参照だけを読取り、56依存のURL/revision、条件、CIPD version、GCS object hash/generationを[dependency-pins.json](../tests/results/source-correspondence/pdfium/dependency-pins.json)へ保存した。
|
||||
|
||||
明示された`recursedeps`は3件で、いずれもその固定revisionのDEPSを取得した。そこからさらに`recursedeps`は宣言されていない。
|
||||
|
||||
| recursive dependency | 固定revision | 宣言された追加依存 |
|
||||
|---|---|---:|
|
||||
| Chromium build | `2cd94c0abeada712aeea6906d99021913c9fc28d` | 9 sysroot |
|
||||
| Chromium buildtools | `6f6a5dbf04b734214f3b1f386567d101ec9d607e` | 4 formatter package |
|
||||
| instrumented_libraries | `d15c278eed5d38d9acf2d8054cf37baba93cef8e` | 1条件付きbinary集合 |
|
||||
|
||||
これはgclientが宣言する取得グラフであり、全てが今回のlibraryへリンクされるという意味ではない。条件は評価せず原文を保持する。固定`build_overrides/pdfium.gni`ではBrotli、Skia、Fontations、Rust BMP/JPEG/PNGが無効。V8無効のminimal checkout、partition allocator無効というrecipeの設定も別に記録した。CIPDのversion文字列からinstance IDへの解決、toolchain/sysroot archiveの取得、実際の最終`build.ninja`との照合は未実施。
|
||||
|
||||
## 同梱15告知とソース原文
|
||||
|
||||
対象は既存Linux配布物のトップレベル`LICENSE`と`licenses/`の14ファイル。providerの[収集手順](../tests/results/source-correspondence/pdfium/provider/recipe/steps/08-licenses.sh)とstage手順の指定を、データ変換として再現した。**15件全てが同梱ファイルとbyte単位で一致**した。各原文URL・固定revision・原文hash・変換後hash・同梱hashは[license-correspondence.json](../tests/results/source-correspondence/pdfium/license-correspondence.json)にある。
|
||||
|
||||
| 同梱ファイル | ソース所在/固定revision | 対応方法 |
|
||||
|---|---|---|
|
||||
| `LICENSE` | provider `f2e9a1c45bb17b85b540abf1af30146ef65416ac` | LICENSEへ第三者告知の案内を追記 |
|
||||
| `pdfium.txt` | PDFium `a5a7089234f121990b336b3841008009dca143bf` | LICENSEの先頭`//`を除去 |
|
||||
| `agg23.txt` | 同PDFium内`third_party/agg23` | `agg_array.h`冒頭の告知を抽出 |
|
||||
| `lcms.txt` | 同PDFium内`third_party/lcms` | `include/lcms2.h`冒頭の告知を抽出 |
|
||||
| `libopenjpeg.txt` | 同PDFium内`third_party/libopenjpeg` | `openjpeg.c`冒頭の告知を抽出 |
|
||||
| `freetype.txt` | PDFium内FTL.TXT。実ソースpin `4800589f76dc62fbe523a74a59e0d4850a5dd7df` | 原文と一致 |
|
||||
| `abseil.txt` | `435e7d977fb36fb47854a4c552c0706dad0bd7cf` | LICENSEと一致 |
|
||||
| `fast_float.txt` | `34164f547b7df3f5d794ff67e9f885c36819ebfc` | LICENSE-MITと一致 |
|
||||
| `icu.txt` | `8cc91d9b6ab9991802fd208ee03a69714fd0251c` | LICENSEと一致 |
|
||||
| `libjpeg_turbo.md` | `640f254ad0fa03f6b1f29f89b7dd9366f2f6e533` | LICENSE.mdと一致 |
|
||||
| `libjpeg_turbo.ijg` | 同libjpeg-turbo revision | README.ijgと一致 |
|
||||
| `libpng.txt` | `6d5341764ef4e38cbc07d35514a8aa73de50de8a` | LICENSEと一致 |
|
||||
| `llvm-libc.txt` | `320824188c37e5c28738b9652a0ca8087c934bc9` | LICENSE.TXTと一致 |
|
||||
| `simdutf.txt` | `f7356eed293f8208c40b3c1b344a50bd70971983` | LICENSEと一致 |
|
||||
| `zlib.txt` | `285e94b8fa95ad3b7d16b80798ec8dce6febb8c8` | zlib.h冒頭の告知を抽出 |
|
||||
|
||||
AGG、Little CMS、OpenJPEGはPDFium内へ取り込まれた変更済みソースである。保存したREADMEにはAGG 2.3 hard fork、Little CMS 2.19の原revision `b76633e60c8387a77268fb3359277ca25b5fd75c`、OpenJPEG 2.5.4の原revision `6c4a29b00211eb0430fa0e5e890f1ce5c80f409f`とローカル変更が記載される。対応ソースとしては元のreleaseだけでなく、上表の固定PDFium treeが必要になる。
|
||||
|
||||
fast_floatのREADMEはversion 7.0.0/`cb1d42aaa1e14b09e1452cfdef373d051b8c02a4`を記載する一方、DEPSのcheckout pinは`34164f5…`である。この差を推測で統一せず、checkoutの特定にはDEPSの完全なrevisionを採用した。
|
||||
|
||||
## 追加告知の技術的根拠
|
||||
|
||||
15件の一致は告知一式の網羅性を証明しない。providerの収集処理は`build.ninja`の`third_party`名を英小文字・数字・`_`・`-`の範囲で抽出するため、`libc++`と`libc++abi`は`libc`へ切り詰められ、そのcaseは収集対象から除かれる。
|
||||
|
||||
固定Chromiumの`config/c++/c++.gni`は`use_custom_libcxx=true`を既定にし、配布Linux `args.gn`にはその無効化がない。加えて、実`libpdfium.so`(SHA-256 `08f6ea53a64f6fbb9f5ba8d9c02e0051987c6a9175f3fb5ba25f219174731aaa`)から次の小規模な証拠を保存した。
|
||||
|
||||
- [DT_NEEDED](../tests/results/source-correspondence/pdfium/local-readelf-dynamic.txt)は`libpthread`、`libm`、`libgcc_s`、`libc`、dynamic loaderで、外部`libstdc++`/`libc++`依存はない。この観測だけで標準libraryの実装までは決定しない。
|
||||
- [公開symbol](../tests/results/source-correspondence/pdfium/local-readelf-cxx-symbols.txt)には、定義済みの`std::__Cr::__libcpp_verbose_abort`がある。
|
||||
- [読取り文字列](../tests/results/source-correspondence/pdfium/local-cxx-string-indicators.txt)には`third_party/libc++abi/src/src/private_typeinfo.cpp`、`fallback_malloc.cpp`と`libc++abi:`がある。
|
||||
|
||||
これらを合わせると、libc++/libc++abiの告知を追加する技術的根拠がある。取得済みの固定原文は次の通り。`llvm-libc`とは別のcomponentである。
|
||||
|
||||
| 追加候補 | DEPS固定revision | 原文SHA-256 |
|
||||
|---|---|---|
|
||||
| [libc++ LICENSE.TXT](../tests/results/source-correspondence/pdfium/dependencies/third_party/libc++/src/LICENSE.TXT) | `97b436da4c33663581d394f4ee0a5977fc38c2f4` | `539dd7aed86e8a4f12cbdd0e6c50c189c7d74847e4fecc64ce2c6ee3a01da38b` |
|
||||
| [libc++abi LICENSE.TXT](../tests/results/source-correspondence/pdfium/dependencies/third_party/libc++abi/src/LICENSE.TXT) | `fc1897a2c12aa27e703c3ed48b62eba8abf4ce19` | `e2b35be49f7284a45b7baca8fc7b3ab7440e7902392b2528a457816b5bb2a15c` |
|
||||
|
||||
調査後、固定原文を`resources/licenses/pdfium-supplemental/`へ追加し、Linuxのinstallと
|
||||
開発パッケージへ反映した。[配布検証記録](../tests/results/linux-development-package/source-notices-record.json)は
|
||||
2件の告知・出典metadataの追加、全553ファイルの整合、従来版とのバイナリー一致を記録する。
|
||||
configureとpackagerはPDFium版・commit・library hash・告知hashを照合する。
|
||||
新しい[provenance](../tests/results/dependency-provenance/notices-final/provenance.json)は、
|
||||
repository原本・package内metadata・実告知の対応も検査する。
|
||||
|
||||
## 未証明の範囲と再確認
|
||||
|
||||
現段階で得たのは固定レシピ、patch集合、宣言された依存pin、既存15告知の原文対応である。全ソースの保管、全linked componentの一覧、compiler runtimeとsysrootを含む対応ソース、再現ビルド、Windows archiveの告知照合は未完了。providerの初期`depot_tools`取得は無指定のcloneであり、GitHub Actionsも`@v6`等の可変tagを使う。root DEPS内の`depot_tools_revision`を、その前に使用したbootstrap cloneのrevisionと同一視しない。
|
||||
|
||||
レシピの解釈と公開API metadataだけから、全入力のbit単位再現性や配布条件の充足を宣言しない。G-DISTRIBUTIONの完了判定には、これらの不足を対象に追加確認が必要である。
|
||||
|
||||
オフラインで再確認する場合はrepository rootから以下を実行できる。取得済みmetadataだけを読み、元PDFiumのビルドスクリプトは実行しない。
|
||||
|
||||
```sh
|
||||
python3 tests/results/source-correspondence/pdfium/check_correspondence.py
|
||||
python3 tests/results/source-correspondence/pdfium/summarize.py
|
||||
```
|
||||
|
||||
再取得URLは`provider-plan.json`、`upstream-plan.json`、`supplement-plan.json`と各retrieval sidecarに保持する。1件の`README.pdfium` HTTP 404は[失敗記録](../tests/results/source-correspondence/pdfium/retrieval-failures.json)に残し、固定treeで確認した`README.md`を取得した。全source cloneや巨大archive取得へ置き換えていない。
|
||||
@@ -0,0 +1,44 @@
|
||||
# 日本語表示と翻訳用資源
|
||||
|
||||
設計01の初期UI言語は日本語。文書の言語やOSの数値・日付localeを変更せず、
|
||||
本体の翻訳カタログとQt標準部品の日本語カタログを起動時に読み込む。
|
||||
言語切替UIや外部から任意の翻訳ファイルを読み込む機能は提供しない。
|
||||
|
||||
本体・ワーカーの利用者向け文字列は`tr`、`qsTr`、または固定contextを持つ
|
||||
`QCoreApplication::translate`で抽出する。コマンドID、設定キー、IPCキー、
|
||||
エラーコード、文書の本文・見出し・パスは翻訳しない。
|
||||
構文解析器が返す英語の詳細は、日本語の原因・行番号案内と区別して表示する。
|
||||
|
||||
## 更新とビルド
|
||||
|
||||
Qt 6.11.2のLinguistToolsを必要とする。
|
||||
|
||||
```sh
|
||||
cmake --build build --target docview_lupdate
|
||||
# resources/i18n/docview_ja.ts の新規・変更文言と訳文を確認する
|
||||
cmake --build build --target docview_lrelease
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
`docview_lupdate`は本番C++ targetとQMLから文言・相対ソース位置を収集する。
|
||||
日本語の原文に同じ日本語の訳文を登録したTSを基準にし、追加時も訳文を確認する。
|
||||
生成QMは本体へ埋め込み、通常ビルドではTSを書き換えない。新しい言語への翻訳には
|
||||
TSを別言語として作成し、読み込む言語を選ぶ設計とワーカーの運用を別途追加する。
|
||||
現状の多言語動作を保証するものではない。
|
||||
|
||||
Qt標準部品には、Qtの`TranslationsPath`にある`qtbase_ja.qm`と
|
||||
`qtdeclarative_ja.qm`を使用する。配置時に統合される`qt_ja.qm`も読込み対象にする。
|
||||
Linuxではシステム依存として明示し、開発版packagerが
|
||||
存在とhashを検査する。Windowsの配置コードは`windeployqt`のtranslations出力を使う。
|
||||
資源が欠けても文書処理を終了させず、Qtの原文へ戻るが、その配置を日本語表示の
|
||||
合格とはしない。OS自身が提供するネイティブダイアログはOS側の言語設定に従う。
|
||||
|
||||
`translations`試験は英語localeのプロセスで、埋込QM、設定の行・原因、コマンド入力エラー、
|
||||
実Qt Quick Dialogの「開く」「キャンセル」を検査する。統合実行の4ケースは成功し、最新の533件のTS文言を完了状態で収録した。
|
||||
|
||||
[CTestログ](../tests/results/ui-final/ctest-font-final/LastTest.log)と
|
||||
[対象ビルドのhash](../tests/results/ui-final/build-record.json)に記録した。
|
||||
|
||||
実装はQt公式の[翻訳ビルド手順](https://doc.qt.io/qt-6/qtlinguist-cmake-qt-add-translations.html)と
|
||||
[QTranslator](https://doc.qt.io/qt-6/qtranslator.html)の公開APIに基づく。
|
||||
配置時の統合カタログは[Qtの翻訳配置資料](https://doc.qt.io/qt-6/qt-deploy-translations.html)を参照する。
|
||||
@@ -0,0 +1,87 @@
|
||||
# Ubuntu 24.04用ローカル検証パッケージ
|
||||
|
||||
Ubuntu 24.04 amd64向けのDebianパッケージを作成した。Qt SDK、PDFium、qpdf、libzipを`/opt/docview`へ配置し、`/usr/bin/docview`が必要な実行時パスを設定する。呼び出す側で環境変数を設定する必要はない。現在の検証版は、修正版PDFiumを含む[validation4](../tests/results/pdfium-intent-context/ubuntu-package/README.md)。一般公開用のリリースではない。
|
||||
|
||||
[debファイル](../tests/results/pdfium-intent-context/ubuntu-package/guest/package/package/docview_0.1.0~validation4_amd64.deb)は123,417,928バイト、SHA-256は `bd4f00912078d406cb466cd6910ed01c0c9fdd32b76cb2f47b74cfb9719f1bd9`。
|
||||
|
||||
## インストールと起動
|
||||
|
||||
Ubuntu 24.04 amd64のデスクトップ環境で実行する。
|
||||
|
||||
```sh
|
||||
sudo apt install ./docview_0.1.0~validation4_amd64.deb
|
||||
docview
|
||||
docview '/path/to/日本語の文書.pdf'
|
||||
```
|
||||
|
||||
PDF、HTML、HTML ZIP、EPUBを開ける。アプリケーションメニューにはDocViewを登録する。基本操作と設定は[README](../README.md)を参照する。
|
||||
|
||||
共有システムライブラリーはDebian依存情報に記載した版以上を要求する。日本語代替フォントとして`fonts-noto-cjk`、ラテン文字用に`fonts-dejavu-core`を要求する。同梱ライブラリーだけでOSの依存をすべて代替する構成ではない。
|
||||
|
||||
`/etc/apparmor.d/docview`は同梱`QtWebEngineProcess`の正確な実行パスに対するプロファイルで、Ubuntuのuser namespace制限下でChromiumの隔離を起動するために使う。インストール時に読み込み、削除時に解除する。カーネルのuser namespace制限を無効にせず、アプリのsandbox無効化オプションも設定しない。
|
||||
|
||||
## 削除
|
||||
|
||||
```sh
|
||||
sudo apt remove docview
|
||||
sudo apt purge docview
|
||||
```
|
||||
|
||||
`remove`は実行ファイル・同梱ランタイム・メニュー登録を削除し、システム設定ファイルを保持する。`purge`は保持されたAppArmor設定も削除する。どちらも利用者の文書・設定・読書履歴を削除しない。
|
||||
|
||||
## 生成と照合
|
||||
|
||||
収集器と梱包処理の限定試験は次のコマンドで実行できる。通常の本体CTestとは別の結果として保存する。
|
||||
|
||||
```sh
|
||||
python3 tests/test_ubuntu_validation_runtime.py -v
|
||||
python3 tests/test_ubuntu_package.py -v
|
||||
```
|
||||
|
||||
生成はUbuntu 24.04 amd64で行う。ビルドとSDKの準備は[専用VM手順](../tests/ubuntu_vm/README.md)、候補prefixの選択は[修正版PDFiumの手順](PDFIUM-CANDIDATE.md)を参照する。以下は候補を選択して配置した `$HOME/docview-context-install` を入力にする。入力するSDK告知とQt LICENSESは、[元SDK・ソースとの照合済み資料](../tests/results/source-archives/QT-SDK-NOTICES.md)を使う。
|
||||
|
||||
```sh
|
||||
python3 tools/package_ubuntu.py \
|
||||
--prefix "$HOME/docview-context-install" \
|
||||
--version '0.1.0~validation4' \
|
||||
--qtpaths /opt/docview-qt/6.11.2/gcc_64/bin/qtpaths \
|
||||
--dependency-prefix /opt/docview-deps \
|
||||
--source-root "$HOME/dependency-sources/qpdf-12.4.1" \
|
||||
--source-root "$HOME/dependency-sources/libzip-1.11.4" \
|
||||
--input-manifest "$HOME/incoming/sdk-downloads.json" \
|
||||
--sdk-notices tests/results/source-archives/qt-sdk-notices-final \
|
||||
--sdk-supplement tests/results/qt-notice-supplement/collection \
|
||||
--qt-licenses tests/results/ubuntu-package/inputs/qt-licenses \
|
||||
--output "$HOME/validation/new-ubuntu-package"
|
||||
python3 tools/verify_ubuntu_package.py \
|
||||
--archive "$HOME/validation/new-ubuntu-package/docview_0.1.0~validation4_amd64.deb" \
|
||||
--output "$HOME/validation/new-ubuntu-package/verification.json"
|
||||
```
|
||||
|
||||
生成先は毎回新しいディレクトリーを指定する。生成器は固定入力のハッシュを確認し、ランタイムの通常ファイルだけをコピーする。シンボリックリンクは参照先のバイト列を所定のロード名へ配置する。全ファイルのサイズ・モード・SHA-256をmanifestへ記録し、独立した検証器が`.deb`のdata/controlアーカイブを読み戻す。`SOURCE_DATE_EPOCH=0`と所有者・権限を固定し、同じ入力から2回生成した結果が一致した。
|
||||
|
||||
Qt SDKの抽出告知129entry、対応する105本文、QtのLICENSES 64ファイルと実行時依存の部分台帳を含む。validation3はさらに、生成器が除外していたWebM/WebPのPatentファイル2件(同一本文)と出典メタデータ4件を補う。補足台帳・元台帳・実行時ファイル・全補足原文のハッシュを確認し、一致しない入力では生成を拒否する。元SBOMの不整合や除外範囲、全対応ソースと公開ライセンスの未確定事項は解消済みとはしない。告知文書内のArch用開発パッケージ説明は従来の別方式を説明するものであり、このUbuntuパッケージの起動手順は本書に従う。
|
||||
|
||||
## validation4の検証
|
||||
|
||||
候補を明示的にリンクしたUbuntu新ビルドは全24試験群、実debを含む候補境界13試験、色probe972点が成功した。生成2回のdebが一致し、archive内の2,100ファイルを検証した。候補library、ヘッダー、BUILDINFO、固定ビルド記録、パッチ、補足告知の対応も検証する。参照CMMは色probe専用で、配布物には追加していない。
|
||||
|
||||
ビルド環境ではSDK・依存・旧新のbuild/install/prefixを隠し、配置後2,095ファイルと131 ELFを確認した。X11・Wayland各6条件の起動とinstall/remove/purgeが成功した。[SDKのない既存試験VM](../tests/results/pdfium-intent-context/ubuntu-package/clean-vm/README.md)でも同じ12条件、配置の照合、remove/purgeと4つの利用者データprobe保持が成功した。このVMには過去の試験ツールが残っており、新規OSでの試験とは扱わない。2台とも試験後に正常終了した。
|
||||
|
||||
## validation3の検証履歴
|
||||
|
||||
validation3は補足告知を追加した版で、本体・両ワーカー・同梱ランタイムはvalidation2と同じバイト列である。[今回の記録](../tests/results/qt-notice-supplement/README.md)で、Arch/Ubuntu各8試験、独立したdeb生成2回の一致、全2,016ファイルのarchive検証を確認した。
|
||||
|
||||
SDKのない既存試験VMでも、インストール後2,011ファイルと131 ELFの依存、X11/Waylandの起動12条件、remove/purge・ユーザーデータ保持が成功した。このVMには前回の試験ツールが残っている。新しいOSでの検証と、validation2で行った実portal試験の範囲は以下の履歴に分ける。
|
||||
|
||||
## validation2の検証履歴
|
||||
|
||||
validation2は日本語・空白等を含むHTML名のURL比較を修正した版である。[修正後の全22群と実portal](../tests/results/portal/README.md)はArch・UbuntuおよびUbuntu X11/Waylandで確認した。debは約123 MB、2回生成が同一で、SDKのない試験VMの旧版からの更新・配置ファイル/依存の照合も成功した。
|
||||
|
||||
X11/Waylandで通常起動12条件、実OSファイル選択の取消と4形式の表示10ケース、remove/purgeと4つのユーザーデータprobe保持を確認した。全Chromium告知・対応ソース・公開ライセンス、Windowsと物理環境の受入は未完了である。
|
||||
|
||||
## 旧版validation1での配置検証
|
||||
|
||||
専用Ubuntu VMでインストール・再インストール・削除・完全削除を確認した。元のQt SDK、依存ライブラリー、build/install先を私有マウント名前空間内で隠し、通常ユーザーの空の実行時環境からX11とWaylandの各6条件を起動した。131個のELFの依存解決、配置された2,004ファイルの所有者・権限・バイト列も確認した。
|
||||
|
||||
さらに、元のUbuntu cloud imageから作った[新しいVM](../tests/results/ubuntu-package/clean-vm/README.md)でも、SDKやコンパイラーを別途導入せずにインストール・依存解決・同じ12条件の起動・remove/purgeが成功した。共有ライブラリーの解決はGUI試験ツール追加前に確認した。この節の結果は旧版validation1の記録であり、修正版の実OSファイル選択は別記録で検査する。実GPU・物理表示、Windows、署名・公開配布条件の受入は残る。パッケージの再現性は梱包工程の一致であり、依存ライブラリーのソースからの再現ビルドを意味しない。
|
||||
@@ -0,0 +1,297 @@
|
||||
# 実装・検証記録
|
||||
|
||||
2026-09-20追加:[PDFium第2候補の統合検証](../tests/results/pdfium-intent-context/README.md)。ICC変換指定・パターン状態継承・タイル線色を修正し、Arch・Ubuntu各972描画点、新ビルド各24試験群、上流1,979試験が成功した。旧パターン期待値の誤りと比較先の差は別に記録する。
|
||||
|
||||
対象日: 2026-09-20。対象はこのリポジトリーのLinux開発版であり、設計書一式の完成版受入は未完了である。Windows向けワーカー保護・通信・資源アクセス・フォント供給・renderer監視・配布コードはソース上で統合したが、Windows版は未ビルド・未実行。Windows 11での実行、製品としての配布、基準機の性能判定が残っている。外部の追加試験環境は提供されていないため、このPC内にUbuntu 24.04の専用KVM環境を作成し、X11・Waylandで追加検証した。
|
||||
|
||||
## 現在の修正版と検証範囲
|
||||
|
||||
起動先は `build-context/docview`。専用prefix `.deps/pdfium-context` を明示的に選択し、元の依存版・旧ビルド・旧パッケージは保持した。候補の由来、ライブラリ、ヘッダー、告知の固定値をCMake・配置・deb検証で照合する。配置の再検査は実行物のコピー前に行い、不正入力で既存配置が変わらない回帰を含む。[ビルド手順](PDFIUM-CANDIDATE.md)
|
||||
|
||||
[Ubuntu validation4](../tests/results/pdfium-intent-context/ubuntu-package/README.md)は全24群と配布境界13試験が成功し、2回生成した123,417,928バイトのdebが完全一致した。ビルド環境のSDK等を隠した試験と、SDKのない既存VMで、それぞれX11・Wayland各6条件の起動、install/remove/purge、利用者データ保持が成功した。後者は過去の試験ツールが残る再利用環境である。参考色の計算用CMMは配布物に追加していない。
|
||||
|
||||
[PDF性能4条件](../tests/results/pdfium-intent-context/performance/README.md)は、新規プロセス120回・同一プロセス内120回・750操作・960スクロール入力が成功した。約1GB・5,000ページPDFの3回open・100操作・末尾確認も成功した。測定した暫定予算の超過は0。Xvfb・software描画の参考値で、物理表示や基準機の受入ではない。今回の変更はPDFiumと配布対応であり、HTML・EPUBの性能を今回再測定したとはしない。
|
||||
|
||||
[21組の比較画面](../tests/results/pdfium-intent-context/render-review/index.html)を新ワーカーで再生成した。83枚の復号RGBAは前回と完全一致し、既知の比較差を保持している。人によるG-RENDER承認は未実施。[現在の統合JSON](validation-record.json)は固定ビルドアンカーと最終成果物・結果を結び付け、以下の旧結果を履歴として参照する。
|
||||
|
||||
残る最終受入はWindows 11でのビルド・実行・配布、対象OSの物理GPU・表示・入力と基準機・長時間負荷、人による描画承認、公開配布に必要な対応ソース・告知・ライセンスの最終確認である。
|
||||
|
||||
## 第1候補の履歴:2026-09-20のPDFium色変換修正
|
||||
|
||||
[固定ソースへの修正候補](../tests/results/pdfium-intent-build/README.md)を隔離先でビルドし、元のCMYK試験48点と4種類のintent・継承・画像キャッシュ・Type3等の600点が一致した。許容差4を維持し、最大差はそれぞれ0と2。上流の単体1,104件・結合872件、既存DocViewの全22試験群も候補を使って成功した。パッチを元ソースへfuzzなしで再適用し、変更後の全51ファイルが一致することを確認した。
|
||||
|
||||
比較先Popplerにはshading patternのRI指定で18点の不一致が残るため、比較全体の受入は未合格のまま保存した。候補は既存依存ライブラリ・Ubuntu validation3パッケージへ未導入で、以下の製品の失敗記録を上書きしない。Ubuntuでの候補試験・梱包、SoftMask/tiling専用の画素試験、Windows、人による描画受入は残る。[統合JSON](validation-record.json)は製品と候補の識別・結果を分けて保持する。
|
||||
|
||||
## 元の依存版の履歴:2026-09-20のICC CMYK追加比較
|
||||
|
||||
[4次元ICC CLUTの比較](../tests/results/cmyk-lut/README.md)で、文書の相対的測色指定に対してPDFiumが知覚的変換を使う差を確認した。Arch・Ubuntu各48測定点のうち30点が許容差を超え、最大channel差は74。独立Popplerは全点が数式の期待値に一致し、PDFiumの画素は固定ソースの知覚的変換と照合できた。原因が分かったことを描画受入の合格とはしない。
|
||||
|
||||
資料の構造・プロファイル16頂点・埋込バイト列・原本不変・3倍率の寸法を検証し、[追加比較画面](../tests/results/cmyk-lut/index.html)を用意した。製品ソースとバイナリーは不変で、全22群や配布試験の以前の結果と、今回の色一致の失敗は別の範囲である。ICCの変換指定への対応または明示的な互換性判断と、検出可能な制約の通知は未完了。[現在の統合JSON](validation-record.json)にも失敗を記録した。
|
||||
|
||||
## 2026-09-20のQt告知補足
|
||||
|
||||
[Ubuntu validation3](../tests/results/qt-notice-supplement/README.md)に、SDKのSBOM生成器が省いたWebM/WebPのPatentファイル2件(同一本文)と元メタデータを追加した。Arch/Ubuntu各8件の梱包試験、2回のdeb生成一致、全2,016ファイルのarchive検証、SDKのない既存VMでのinstall・起動12条件・remove/purgeとデータ保持が成功した。元SBOMの不整合・全告知と対応ソースの未確定範囲は残る。
|
||||
|
||||
本体・ワーカー・同梱ランタイムと全コンパイル対象ソースはvalidation2から不変である。以下の全22群・性能・実portalは元の実行結果を保持し、今回の再実行とは数えない。[告知補足時点の統合JSON](../tests/results/qt-notice-supplement/record.json)と[その直前のJSON](../tests/results/qt-notice-supplement/prior-validation-record.json)も変更せず保存する。
|
||||
|
||||
## 2026-09-20のURL比較修正
|
||||
|
||||
実OSファイル選択の追加試験から、日本語・空白・予約文字を含むHTMLの読込みが停止する不具合を発見し、URLの表現をそろえて比較するよう修正した。[追加記録](../tests/results/portal/README.md)に再現・変更・新しいビルドとの対応を保存する。修正後の全22試験群はArchで171.56秒、Ubuntuで184.71秒、いずれも失敗0だった。
|
||||
|
||||
この変更で本体バイナリーは変わった。以下の`ui-final`等による性能・GPU・IME・重負荷・旧パッケージの記録は、各記録で固定した修正前の版の履歴である。「現行」と記した従来節の語も当時の版を指す。新しい本体へ実行結果を読み替えない。旧統合JSONも[履歴として保存](../tests/results/portal/prior-validation-record.json)した。
|
||||
|
||||
新しい本体の[性能10条件](../tests/results/portal/performance-suite/README.md)を再測定し、新規プロセス300回・同一プロセス内300回・移動2,500操作、操作負荷と約1GB/5,000ページPDFが成功した。open p95は条件間最大266.85ms、応答p95は最大23.74ms、群RSS最大830.83MiBで、測定した暫定予算の超過は0。開発機の仮想表示・software描画の値である。Ubuntu修正版debは、実portal選択10ケース、通常起動12条件、旧版からの更新・remove/purgeも成功した。[現在の統合JSON](validation-record.json)と[履歴・制約](../tests/results/portal/README.md)を併記する。
|
||||
|
||||
## URL比較修正前のUI実装と検証
|
||||
|
||||
焦点復帰、Web倍率の表示・保存、開く操作の失敗対象と対処案内を修正した。詳細は[最新の統合記録](../tests/results/ui-final/README.md)と[変更前後の回帰](../tests/results/final-ui-regressions/README.md)へ保存する。ArchのX11全22試験群が166.00秒で成功し、WaylandではApp110・Web36と6条件起動が成功した。同行した旧Canvas21件は内部でoffscreenを強制していたため、Wayland描画の証拠から除外する。初回の見開き2件の失敗は、非同期resizeの確定前に次の要求を送った試験側の問題と診断し、サーバーとQt双方の確定寸法を待つ手順へ修正した。製品の描画処理は同一である。
|
||||
|
||||
[AMD GPUのOpenGL経路](../tests/results/ui-final/wayland/GPU-VALIDATION.md)でもApp110・Web36・Canvas22と本体6条件起動が成功した。Canvasは実platformの検査とQQuickWindowの取得画素によるページ表示・切替・画像消去の試験を追加し、Wayland/softwareとoffscreen/200%でも成功した。追加試験後も製品バイナリーは同一で、既存の全22群と後続の限定試験を別記録にしている。実モニターのscanout・物理入力・基準機の性能受入は未実施である。実IMEの追加範囲は以下に分けて記録する。
|
||||
|
||||
以下の`completion-final`の20試験群・性能10条件・大容量PDFは、今回のUI修正前に固定した前回の結果である。PDF/Archive worker、core試験、実時間watchdogとcommon libraryの5バイナリーは今回も同一であり、[変更されていない部品の対応記録](../tests/results/ui-final/unchanged-component-evidence.json)に既存比較との一致を残した。全アプリ測定を新本体へ読み替えない。新しい561ファイルの開発パッケージは[2回生成一致・6条件起動](../tests/results/ui-final/linux-development-package/README.md)、部分告知台帳は[2回一致](../tests/results/ui-final/dependency-provenance/README.md)を確認した。
|
||||
|
||||
[URL比較修正前の性能10条件](../tests/results/ui-final/performance-summary.md)は、新規プロセス300回・同一プロセス300回、対応する移動系列の計2500操作を完了した。Xvfb 1100×760・100%・software描画で、起動p95は最大271.03ms、初期応答p95は最大23.82ms、群RSS最大831.23MiBとなり、測定した暫定予算の超過はなかった。[別の操作負荷](../tests/results/ui-final/performance-interaction/record.json)と[約1GB・5,000ページの追加負荷](../tests/results/ui-final/stress/README.md)も同じ修正前の本体で成功した。後者の3回open p95は92.31ms、独立標本の群RSS最大は721.07MiBだった。実GPU・基準機の判定ではない。初回にホストの画面設定を引き継いだ[条件不一致の失敗](../tests/results/ui-final/performance-display-mismatch/README.md)は別保存し、採用していない。
|
||||
|
||||
[600dpi相当画像と60,000個の半透明ベクター](../tests/results/heavy-pdf/README.md)もArchとUbuntuで表示でき、実open処理中のEsc取消と実render処理中の文書切替が成功した。画像の独立復号hashと取得画素を検査し、原本不変、旧session回収、メモリ圧迫なしを確認した。既存の本番GUI部品・ライブラリ・ワーカーを使う独立試験で、通常の22群や本体の性能10条件とは別に記録する。単一試験のheartbeat最大間隔31/38msは視覚応答p95の代用ではない。
|
||||
|
||||
[実IBus/MozcとUS pc105・JP jp106配列の追加試験](../tests/results/ime/README.md)もUbuntuのX11で成功した。検索・コマンド欄の日本語変換、Enter/Escの保護、物理キー番号からの記号操作、入力後のj/k復帰を確認し、原本と本体は不変だった。2ケース・setup/cleanupを含む4件が12.329秒で成功。合成IMEイベントの既存試験とは別であり、後続の[Wayland試験](../tests/results/ime/WAYLAND.md)でもQt Wayland+IBusのD-Bus経路が1ケース・setup/cleanup込み3件、7.474秒で成功した。同一補助バイナリーのX11 US/JP回帰は4件・12.438秒で成功。物理入力・Windowsは未検証で、Waylandのkeysym入力を日英物理配列の証拠へ読み替えない。
|
||||
|
||||
## Ubuntu 24.04の追加検証
|
||||
|
||||
[専用KVM環境の記録](../tests/results/ui-final/ubuntu/README.md)で、X11全22試験群が177.63秒で成功した。WaylandでもApp110・Web36、6条件の本体起動が成功し、配置済み本体は別install prefixからX11の6条件でReadyとなった。Landlock ABI 4、seccomp、Chromium sandboxとUbuntuのuserns制限を維持した。公式Qt SDK 6.11.2とGCC 13.3.0によるUbuntu用ビルドであり、Archの実行ファイルを流用していない。
|
||||
|
||||
Canvas試験のplatform強制を除いた後、[通常/200%の2群](../tests/results/ui-final/ubuntu/canvas-ctest/tests.xml)と[実Waylandの22件](../tests/results/ui-final/ubuntu/canvas-wayland/report.json)も成功した。追加の実ウィンドウ画素検査を含み、本体・ワーカーのhashは全22群の実行時から同一である。
|
||||
|
||||
CMake 3.28の配置一時名の残留とPython 3.12のzstd非対応に対応した。provenanceの5件はUbuntuだけ明示skipし、30件が成功している。非埋込日本語PDFの試験は、RPCを待つ実イベントループへ変更した後、単独3回と全体実行で成功した。製品コードと15秒の期限は同じである。Archでも修正後の全22群が成功した。
|
||||
|
||||
配置の依存検査は1,740ファイル・85システムpackageで解決し、追加したSDK metadata上限の20試験も成功した。告知104件とmetadata44件は部分収集であり、Qt/Chromiumの告知と対応source全体は未完了。公式SDKを別配置した専用環境での検査であり、自己完結したUbuntu配布物や実GPU/IMEの受入を意味しない。
|
||||
|
||||
## Ubuntuパッケージの追加検証
|
||||
|
||||
[Ubuntu 24.04用deb](../tests/results/ubuntu-package/README.md)を約123 MBで作成し、2回生成のbyte一致、全2,009ファイルのarchive検証、配置後2,004ファイルと131 ELFの依存を確認した。元のSDK・依存・build/install先を私有マウント名前空間で隠し、呼出側のQt/LD環境変数なしでX11/Wayland各6条件がReadyとなった。install/reinstall/remove/purge、AppArmorの登録・解除、ユーザーデータ保持probeも成功した。本体・workerは既存のUbuntu配置済みバイナリーと一致し、全22群を今回再実行したものではない。さらに[新しいUbuntu OS](../tests/results/ubuntu-package/clean-vm/README.md)でも、SDKなしで宣言依存を導入し、131 ELF解決・12条件起動・remove/purgeが成功した。実GPU・native portalと公開配布条件は別の受入とする。[使用手順](UBUNTU-PACKAGE.md)
|
||||
|
||||
## 対応ソース収集の追加
|
||||
|
||||
[Qt 6.11.2一式とtoml++ 3.4.0](../tests/results/source-archives/README.md)を固定した公開hashと照合して取得した。Qtの390,976通常ファイル・約4.74GBを検査し、告知等3,309件の所在を記録。固定WebEngine source 8件、現在のtoml++ヘッダー51件、Arch差分4件の適用とmkspec 2件の一致を確認した。本体・ワーカーは変更していない。実GN構成に対する全Chromium告知、独立PDFium等を含む全対応ソース、実配布条件の最終確認は残る。
|
||||
|
||||
[独立PDFiumの固定Gitソース](../tests/results/source-archives/PDFIUM.md)では、本体と27依存、追加gitlink 1件を保管し、通常46,430ファイル・リンク4件を検査した。先行Gitiles原文31件、パッチ後の公開ヘッダー24件、同梱告知15件が一致し、Linux3件/Windows4件のパッチ適用を確認した。検査の再実行結果もbyte一致した。Windowsのコンパイル・実行、compiler/sysroot等の全入力、再現ビルドはこの結果に含まない。
|
||||
|
||||
[Ubuntu用Qt SDKのChromium告知](../tests/results/source-archives/QT-SDK-NOTICES.md)は、実ビルドのSBOMから129entry・105本文を取り出し、Qt sourceの原文と全件一致した。SBOM記載67ファイルとUbuntu実行時83ファイルが元SDK archiveと一致。外部package参照IDの不整合1件、本文を持たない2部品と生成器の除外処理を記録し、全告知の網羅性とは区別する。
|
||||
|
||||
## 環境と資料
|
||||
|
||||
Arch Linux x64、Linux 7.2.2-zen1-1-zen、AMD Ryzen 9 9955HX(16コア/32スレッド)、約62 GiB RAM。Qt 6.11.2、GCC 16.2.1、Fontconfig 2.18.3、固定PDFium 155.0.8057.0をReleaseビルドした。全体CTestと性能測定はXvfb上のX11、Qt Quick software backend、WebEngine GPU無効で実行し、Chromium・Linuxワーカーの隔離は有効のままとした。Waylandは専用Sway headless/pixmanとAMD OpenGLの2経路を別々に記録する。実ディスプレイの60 Hzと実IMEの試験は含めない。
|
||||
|
||||
文書は生成した。PDFの本文、MCID、注釈、リンク、回転、切り抜き座標を生成元で指定し、追加日本語PDFはOFLフォントをsubset埋込した。さらにフォント非埋込のUniJIS-UCS2-H/V資料と、変換Form・回転・跨ページ構造を持つtagged PDF資料を生成した。HTML/ZIP/EPUBはローカルCSS・SVG・見出し・spineを持つ資料、破損資料、隔離攻撃用資料を生成した。
|
||||
|
||||
- [基本PDFの期待値と比較](../tests/PDF-VALIDATION.md)
|
||||
- [21組のPDF比較レビュー画面](../tests/results/completion-final/render-review/index.html)・[資料と確認方法](../tests/results/completion-final/render-review/README.md)(人による承認は未実施)
|
||||
- [追加PDFの原版・制約・ハッシュ](../tests/fixtures/pdf/extended/manifest.json)
|
||||
- [非埋込日本語CID横/縦の前回比較](../tests/results/completion-final/pdf-fonts/comparison.json)・[手順と旧結果](../tests/results/pdf-fonts/README.md)・[フォント供給契約](font-broker-contract.md)
|
||||
- [実TTCのface選択とTTF比較](../tests/results/completion-final/font-collection/comparison.json)・[手順と旧結果](../tests/results/font-collection/README.md)
|
||||
- [保存外観のないPDFリンク枠の前回比較](../tests/results/completion-final/link-borders/comparison.json)・[補完の制約と旧結果](../tests/results/link-borders/README.md)
|
||||
- [EPUB見開き](../tests/results/epub-spreads/README.md)・[ZIP入口の再利用](../tests/results/zip-entry-choice/README.md)・[資源警告](../tests/results/resource-warnings/README.md)
|
||||
- [タグ付きPDFの境界資料](../tests/fixtures/pdf/headings/README.md)・[構造解析の検証](../tests/results/pdf-structure/README.md)
|
||||
- [注釈の倍率・回転・DPI](../tests/results/pdf-annotation-flags/README.md)・[コメントのキー操作](../tests/results/pdf-comments/README.md)
|
||||
- [資源エラーの詳細分類](../tests/results/resource-classification/README.md)
|
||||
- [ICCプロファイルの3倍率・54点比較](../tests/results/completion-final/pdf-icc/comparison.json)・[手順と旧結果](../tests/results/pdf-icc/README.md)
|
||||
- [ナビゲーションと遅延レイアウト](../tests/results/navigation-reflow/README.md)
|
||||
- [Web応答監視](../tests/results/renderer-response/README.md)・[アーカイブ実読取量](../tests/results/archive-ratio/README.md)
|
||||
- [メモリ圧迫への段階的対応](memory-pressure.md)
|
||||
- [XHTML見出し・目次と章末の重複移動先](../tests/results/xhtml-headings/README.md)
|
||||
- [前回Linux開発パッケージの証跡](../tests/results/completion-final/linux-development-package/README.md)・[作成手順](LINUX-DEVELOPMENT-PACKAGE.md)
|
||||
- [同梱コード・システム依存・ローカルビルド由来の台帳](DEPENDENCY-PROVENANCE.md)
|
||||
- [固定recipe・ソース参照・実行時ファイルの照合](../tests/results/source-correspondence/README.md)
|
||||
- [原設計との受入照合](ACCEPTANCE-AUDIT.md)
|
||||
- [原本同一性・目次待機・見出しとリンク取消の追加回帰](../tests/results/completion-regressions/controller-state.md)
|
||||
- [日本語の初期表示・翻訳資源](TRANSLATIONS.md)
|
||||
- [追加PDFの前回独立比較](../tests/results/completion-final/pdf-extended/comparison.json)・[手順と旧結果](../tests/results/pdf-extended/README.md)
|
||||
- [HTML/EPUB資料のハッシュ](../tests/fixtures/web/manifest.json)
|
||||
- [性能資料のハッシュ](../tests/fixtures/performance/manifest.json)
|
||||
- [約1GB・5,000ページの画像PDF負荷試験](../tests/STRESS-PDF-VALIDATION.md)
|
||||
- [ビルド依存](DEPENDENCIES.md)・[実装判断](IMPLEMENTATION-DECISIONS.md)
|
||||
|
||||
前回ビルドの[6系列の比較](../tests/results/completion-final/comparison-run.json)はすべて完了し、原本とバイナリーは前後で不変だった。TTCの初回は選択したPythonにfontToolsがなく失敗し、失敗ログを残してsystem Pythonで再実行した。旧比較の対応83画像とは[RGBA画素が一致](../tests/results/completion-final/comparison-pixel-regression.json)した。これは人による正解画像の承認ではない。
|
||||
|
||||
追加PDFは5文書・9ページ。独立したsystem Poppler 26.08.0とproduction PDFiumを144 DPIで比較し、全9ページの寸法、CropBox/Rotateの16色位置、透明合成3点を確認した。日本語の抽出・検索も成功し、全ページの比較画像を確認した。RGB平均絶対差は0.5207〜2.5135/255だが、校正済みの互換性合格閾値には使わない。基本PDFの保存外観のない標準リンク枠は補完し、比較領域8,448画素がPopplerと一致した。コメントアイコンと文字のアンチエイリアスには比較器間の差が残る。
|
||||
|
||||
フォント選択はMainの専用処理で行い、選択済みバイト列だけを既存IPCでPDFWorkerへ渡す。SFNT/TTC解析はWorker内に残し、Linuxのfontディレクトリー許可を撤去した。非埋込日本語資料ではIPAexMincho/BIZ UDPGothicを選択し、横/縦2ページと検索を確認した。Popplerとは代替書体が異なり、その差を記録した。任意フォント名・範囲・応答・時間・キャッシュ上限も試験した。実際の2書体TTCでも通常/太字のface 0/1を選択し、個別TTF条件と2資料・892,800画素が一致した。試験用フォントは保存・配布せず回収した。
|
||||
|
||||
## 自動試験の範囲
|
||||
|
||||
今回の追加修正より前の統合結果は **19試験群すべて成功(失敗0、未実行0)**、所要162.00秒。記録は[旧CTest JUnit](../tests/results/completion-regressions/prior-19-tests.xml)、[旧CTestログ](../tests/results/completion-regressions/prior-19-LastTest.log)、[旧集計とバイナリーハッシュ](../tests/results/completion-regressions/prior-validation-record.json)へ保存した。通常CTestのapp群で計測専用slotを1件意図的にskipし、別runnerで実行する運用は継続する。Windows固有試験はLinuxの成功件数に含めない。
|
||||
|
||||
その後、原本の同一性・目次待機・PDF見出し候補・Web操作取消・PDF情報省略通知・翻訳資源を修正した。独立した`build-worker`では[追加回帰と全GUI](../tests/results/completion-regressions/controller-state.md)を実行し、core 111成功、GUI 96成功・0失敗・計測専用1skipを確認した。[Web全36ケース](../tests/results/completion-regressions/docview-web-navigation-regression.txt)も成功した。これらは最終の統合実行とは区別する。
|
||||
|
||||
前回ソースの統合実行は、`translations`を加えた **20試験群すべて成功(失敗0、未実行0)**、165.61秒。[前回CTest JUnit](../tests/results/completion-final/ctest/tests.xml)、[前回CTestログ](../tests/results/completion-final/ctest/LastTest.log)、[対象ビルドのhash](../tests/results/completion-final/build-record.json)を保存した。内訳はcore 111、PDF 75、Web 36、translations 4、app 96成功・計測専用1skipを含む。後から追加したpackaging境界2件は[限定14件の再実行](../tests/results/completion-final/ctest/linux-package-focused.txt)で成功し、全体CTest内の12件とは区別する。試験中も本番と同じLandlock・seccompの保護を使用した。
|
||||
|
||||
PDFiumのlibc++/libc++abi告知を追加した時点のpackaging 12件・provenance 23件と、[553ファイルの整合・生成一致・6条件起動](../tests/results/linux-development-package/README.md)は修正前バイナリーの配布履歴である。告知追加時には主3実行ファイルのhashが不変だったが、今回の製品変更後まで同一と主張しない。前回版は[553ファイルのアーカイブを独立に2回生成](../tests/results/completion-final/linux-development-package/README.md)し、hash一致と別展開先6条件のReadyを確認した。配布物・6系列の描画比較・実時間watchdogは[前回記録](../tests/results/completion-final/README.md)へ保存済みで、同じビルドの性能再測定も完了した。
|
||||
|
||||
| 試験群 | 主な確認 |
|
||||
|---|---|
|
||||
| core | 開いた原本identityと保存時の再照合、変更と履歴なしの区別、能力スキーマ、TOMLの一括適用、型・未知キー・衝突、論理キー正規化、数値G、期限・長押し・入力状態、XDG、位置・privacy・ロック・バックアップ |
|
||||
| archive | ZIP名・型・重複・展開上限・CRC、source実read量による膨張率制限、5codecのpadding攻撃と正規6方式、XML制限、入口選択、EPUB 2/3・NCX/nav/spine・nonlinear・固定レイアウト・RTL・難読化フォント |
|
||||
| pdf | コメント本文・ページ内件数・CBOR応答予算の省略通知とprefix保持、PDFium metadata・ラベル・タグ/RoleMap/MCID・リンク・注釈・フォーム外観・パスワード・検索・座標・タイル一致・破損・目次/ページ分割 |
|
||||
| security | 資源の不在・安全拒否・権限・サイズ・読取/保存I/Oの分類、パス・シンボリックリンク・IPCフレーム・索引総量、展開途中の非公開、原本保護、一時領域回収、OSの読取/書込/通信/子プロセス/シグナル拒否、font grantなしで実fontファイル読取拒否 |
|
||||
| instance | 同一ユーザーの二重起動、ロック、引渡し、ACK、異常要求、ソケット所有・リンク、読み取り専用時の回復 |
|
||||
| memory_pressure | OSサンプルの有限解析、段階順序、閾値境界、回復ヒステリシス、無効値保持、1秒timerと注入 |
|
||||
| renderer_watchdog | Chromium rendererの識別、親子関係とPID再利用防止、RSS上限、30秒の応答期限、保持pidfd/handleによる対象終了、取消・旧probe失効 |
|
||||
| worker_process | 実IPCで成功・エラー、要求ID/世代/操作不一致、過大応答、異常終了、一度だけの失敗通知、キュー取消、展開ストリームの順序、font逆RPCの親・副ID・範囲・遅い応答・取消 |
|
||||
| benchmark_runner | 起動失敗・timeoutで古い成功証跡を破棄、冷起動失敗と測定検査失敗を最終successへ反映 |
|
||||
| linux_package | 相対パス・リンク・型・重複・未登録ファイル・サイズ/hashの境界、告知補完の版/hash、固定epochのtar/gzip再現性、失敗時の旧成功記録除去、Qt日本語資源の存在・hash検査(統合12件、追加後の限定実行14件) |
|
||||
| runtime_manifest | 合成MZファイルによる有限の依存一覧、名前・型・件数・サイズ、SHA-256、衝突拒否、コピー・配置後の改変検知。native PE解析の証拠ではない |
|
||||
| runtime_staging | 一覧の厳密なスキーマ、hash/size検証、未登録ファイルの除外、リンク拒否、原本不変、一時コピーの回収 |
|
||||
| font_contract | font逆RPCの厳密な型・ID・上限、切断時の即時終了 |
|
||||
| font_broker | OS索引の限定選択、16参照・256選択・512MiB累積転送、revoke、2thread上限、GUIで待たない破棄、文書間LRU回収と使用中参照保護 |
|
||||
| system_font_adapter | SFNT/TTCの表・face境界、短いbuffer、hash、再利用、128MiB上限と使用中cacheの保持、エラー時の代替成功抑止 |
|
||||
| pdf_canvas | 中央ページと保存用先頭位置の分離・余白同距離・ズーム中心保持、CropBox/回転の双方向変換、PDF座標の復元、古い移動の取消、先読みの優先度・件数・上限、メモリ圧迫での先読み停止・不可視cache回収・解像度抑制・回復、旧応答破棄、キャッシュ予算、先読み/旧倍率のfont致命エラー・旧文書応答の破棄 |
|
||||
| pdf_canvas_hidpi | DPR 2で192条件の通常/抑制解像度の注釈の実描画画素とクリック・選択領域を照合 |
|
||||
| translations | 英語localeで埋込QM・設定/コマンドの日本語案内・実Qt Quick Dialogの「開く」「キャンセル」。OSネイティブdialogの言語は対象外 |
|
||||
| app | 全4形式の閲覧中原本置換と復元不能通知、DOM目次loadingパネル、内部宛先だけのPDF見出し代替、失敗したEPUB境界指示の破棄、WebリンクのEsc取消、本番QML/Controller、コメントのTab/Enter・CropBox外・極小ページ・解除・文書切替、検索完了/取消時の能力状態、実展開worker終了時の資源分類、初期パネル表示/480・1100px幅/表示切替、現在節と選択の分離・折りたたみ・IDなし見出しの履歴復元、PDFラベル/実ページ、明示closeと旧応答破棄、メモリ圧迫での処理停止・新open拒否・回復後の明示再open、能力境界、5,000ページの遠距離移動と取消、特殊キー、IMEイベント、パネル、全形式の文書切替、元資料ハッシュ、履歴消去・未提示位置、font失敗後の表示維持・新workerでの再open・警告の保存、文書切替の失敗/取消とRecoveringの整合 |
|
||||
| web | リンク選択解除と作者outline復元、同一資源の見出し境界・新navigationによる旧指示失効、本番WebEngine、HTML/XHTMLのnative/ARIA見出し・名前空間付き目次・入れ子階層、章末重複移動先・内部scroll、MainWorldとApplicationWorldの分離、実通信拒否、meta refresh/フォーム拒否、CSS/SVG、縦書き/RTL、CFI・リフロー復元、遅延image/fontの横/縦・連続scroll・native anchoring・poll先行、生成見出しのbase解決、固定viewport、検索、実renderer SIGSTOPと取消・再open |
|
||||
|
||||
5,000ページGUI試験は全ページ描画を待たず末尾へ移動し、異なる描画世代を連続要求して最後の緑色ページの画素を確認する。元の青いページの混入、置換後の旧画像、staging文書の取消、10ms周期のUI heartbeatも確認する。この試験の最大停止1.5秒という閾値は回帰検出用であり、T20のp95予算を緩和するものではない。
|
||||
|
||||
追加のGUI回帰では、[最近使った文書の初期画面](../tests/results/recent-documents/README.md)と[EPUBの文書端移動・Web検索取消](../tests/results/web-epub-boundaries/README.md)を確認した。Web位置はMainで型・上限・originを確認して論理位置だけを採用し、EPUBのpackage/spineを照合して復元する。履歴とバックアップに残る旧`location.url`は、書込み可能な状態だけで原子的に除去する。CFI・進捗・本文引用を保持し、lock取得失敗や`forceReadOnly()`ではファイルを変更しない。
|
||||
|
||||
## 受入IDとの対応
|
||||
|
||||
「Linux限定」は記載した生成資料・開発環境の個別試験が成功した範囲を指す。対象OS全体の最終合格を意味しない。「一部」は記載以外の確認が残る。
|
||||
|
||||
| ID | 判定範囲 | 実結果・残る確認 |
|
||||
|---|---|---|
|
||||
| T01 | 一部 | 文字・画像・ベクター・透明・回転・CropBox、埋込日本語を比較。非埋込UniJIS-UCS2-H/Vの横組・縦組も描画/検索/目視確認。保存appearanceなしの通常リンク枠を補完し、NoZoom/NoRotateは生成リンク枠・保存リンク/コメント外観・Textアイコンで検証。任意CID/CMap、校正済みICC/CMYK、特殊合成、両OS・全倍率の広いコーパスは未実施 |
|
||||
| T02 | Linux限定 | ページ移動・倍率・回転・保存座標・旧tile破棄を自動確認 |
|
||||
| T03 | Linux限定 | 5,000ページの直接末尾移動・応答性・取消・文書置換をGUI確認。約1GB(0.940 GiB)の実画像ストリームを持つ5,000ページ資料でも100操作と末尾移動を確認 |
|
||||
| T04 | Linux限定 | ローカルHTMLのCSS/SVG/別HTML/アンカーを本番WebEngineで確認 |
|
||||
| T05 | Linux限定 | ZIP相対資源・別HTML・入口不在/複数、ストリーム展開を確認。手動入口を原本identityへ結び付け、別GUIプロセスで再利用。変更・消去・取消・privacyを検証 |
|
||||
| T06 | 一部 | EPUB 2/3・spine/目次順相違・nonlinear・RTL・固定viewportを確認。gg/Gの通常読書対象の先頭/末尾と章内端を横書きLTR/RTL・縦書きで確認。見開き・package/item上書き・左右/RTL・中央単独・混在・resize・zoom・取消を生成資料で確認。実XHTMLの章内見出し、章末の重複移動先と次章/前章への往復、失敗した境界移動が後の通常章移動へ残らないことも検証。両OSは未判定 |
|
||||
| T07 | Linux限定 | 開く・読む・数値ページ・目次・パネル・文書置換のキーイベント試験 |
|
||||
| T08 | Linux限定 | 内容・パネル・入力欄の分岐、文字入力中の閲覧停止 |
|
||||
| T09 | 一部 | IME preedit/commitイベントと論理キーは確認。Ubuntu X11では実IBus/Mozc・US/JP XKBの変換と取消も成功。Waylandも実Qt+IBus/MozcのD-Bus経路が成功。物理入力・Windowsは未実施 |
|
||||
| T10 | Linux限定 | 期限・Esc・操作先変更・長押し・数値列・設定再読込時の取消 |
|
||||
| T11 | 一部 | 構造タグ/アウトライン、RoleMap、複数MCID、同一ページの異なる見出し、推測しないfallbackを確認。外部/禁止アクションのみと内部宛先混在の目次で能力・移動を検証。変換Form、回転CropBox、直接/子MCRの跨ページ順、vector衝突のfallbackを追加。FormだけのStructParentsは共有qpdfアダプターで取得し、実位置への移動もGUIで確認。annotation所有構造は明示的制約 |
|
||||
| T12 | Linux限定 | 階層・現在位置印/選択の分離・折りたたみ・確定・不正宛先、更新後の選択保持、IDなし見出しの履歴と同HTML内復元、20,000件上限と分割目次、DOM索引のloadingと欠如の区別・表示要求の保持を確認 |
|
||||
| T13 | Linux限定 | 3パネルの独立切替・隠した操作領域から本文への復帰 |
|
||||
| T14 | 一部 | 暗/明テーマとPDF原色保持をGUI確認。表示スケールの証跡は下記。両OSは未実施 |
|
||||
| T15 | Linux限定 | 有効設定を一括適用、キー一覧更新、文字設定変更と論理位置維持 |
|
||||
| T16 | Linux限定 | 型・範囲・未知キー・重複・接頭辞衝突・別表記衝突を拒否して前設定を保持 |
|
||||
| T17 | 一部 | XDG・非ASCII/空白パス・状態書込ロック・設定失敗を確認。Windows Known Folders実行・対象OS初回起動は未実施 |
|
||||
| T18 | 一部 | 静的注釈・コメント・widget保存外観、欠損外観の通知、通常リンク枠の表示補完、入力不能・原本ハッシュ不変。NoZoom/NoRotateは生成リンク・保存AP・Textアイコンで確認。DPI、実画素とhit領域、Tab/Enterでのコメント閲覧を確認。APなしの他形式注釈はNoZoomの制約を通知。本文長・1,000件・512KiB情報予算での省略を明示し、取得済みprefixと注釈の存在を保持 |
|
||||
| T19 | レビュー採用 | [接続契約のレビュー](adapter-contract.md)。解析をUIから分離し、能力・位置・ナビゲーション・取消しの既存経路と追加手順を追跡。全8能力・4状態・未対応理由を共通境界で検証。同名の抽象基底や動的登録は論理契約の必須条件としない |
|
||||
| T20 | 一部 | 生成資料の新プロセス冷起動30回と同一プロセスopen30回、各系列125操作、29同条件開閉、連続scroll・操作集中時の開発機測定を実施。約1GB画像PDFでも3回open・100操作を追加。対象OS・基準機・GPU/60 Hzの受入は未実施 |
|
||||
| T21 | Linux限定 | 破損・欠損資源・パスワード誤り・失敗時の旧文書維持・Esc・旧世代破棄。broker/interceptor/CSPの検出をURLなしで集計し、文書情報に分類と件数を保持。broker側も不在・安全拒否・アクセス拒否・CRC・上限・保存/読取失敗を有限分類で区別する |
|
||||
| T-P01 | Linux限定 | PDF/HTMLの日本語/英語検索・n/N・文字情報なしを確認。04 §7の表示テキスト検索としてWebは現在の章/HTMLを対象にする。全spine一括検索は提供せず、入力欄とREADMEに範囲を表示 |
|
||||
| T-P02 | Linux限定 | 入力モードの隔離、PDF/Webの検索revision取消、同文書内取消と文書切替後の旧callback破棄 |
|
||||
| T-P03 | Linux限定 | PDF表示済み座標、Web CFI/DOM位置、package/spine解決、受信位置の型・範囲・origin検証、font/幅変更と遅延image/fontの横/縦同一文字維持、連続scroll・native anchoring・poll先行、全形式のopen時identityを保存時にも照合し閲覧中の置換先へ旧位置を転用しない。通常openの同一性不一致も通知。近似復元通知。内部URLを新規保存せず、旧履歴/backupも移行 |
|
||||
| T-P04 | Linux限定 | 初期画面の一覧・キーで再表示・保存上限・無効化・履歴消去・終了時に消去位置が復活しないことを確認。削除・変更・置換された原本は以前の項目から開かず、明示的な再選択を案内 |
|
||||
| T-S01 | Linux限定 | 絶対/親/リンク/重複名・実展開量・CRC・一時ファイル公開の境界を確認。実readを各streamで計数し、paddingされた5圧縮方式を途中で停止(codec内部の先読み量を含む) |
|
||||
| T-S02 | Linux限定 | 実WebEngineで文書JS・外部通信・フォーム・meta/任意遷移・外部ファイル・ダウンロードを制限 |
|
||||
| T-S03 | 一部 | OS隔離、資源上限、異常終了・不正返信・取消を確認。実時間でPDFの30秒通知/120秒停止、展開の10秒通知/30秒停止、途中応答で期限が延長されないことと取消を追加確認。Web rendererの実停止・応答期限・再open・取消も確認。Windows native攻撃試験は未実施 |
|
||||
| T-S04 | Linux限定 | 現在/backup状態消去、原本不変、自分の未使用一時領域だけ回収 |
|
||||
| T-S05 | 未完了 | Arch開発版tar.gzの依存/告知manifest、再現可能な生成、移動先からの6条件起動を確認。Ubuntu用debは同梱SDKで12条件起動・install/remove/purgeを確認。新しいUbuntu OSでも同じ12条件とremove/purgeが成功。Windows配布、対応sourceと全Chromium告知を含む公開パッケージは未完了 |
|
||||
|
||||
## 性能・表示・配置の証跡
|
||||
|
||||
前回ビルドでは [10条件の再測定](../tests/results/completion-final/performance-summary.md)が完了した。新プロセスopen計300回、同一プロセスopen計300回、各適用系列125操作、各240scroll入力で測定検査は成功し、10条件の暫定予算の参考超過はなかった。原本・バイナリーのhashも照合した。500章EPUBを含む群RSS最大は830.75 MiB。OSファイルキャッシュは保持した。
|
||||
|
||||
[操作集中時の再測定](../tests/results/completion-final/performance-interaction/README.md)は3成功、長押し120入力・24ジャンプ・10resize・4切替を確認した。最大heartbeat超過145.82 msは独立して報告し、各入力の視覚応答や物理scanoutと同一視しない。[大容量PDF](../tests/results/completion-final/stress/README.md)も3回open・100操作・5,000ページ目を確認した。原本不変・一時資料回収済みで、最終品質p95は24.40 ms、独立監視の群RSS最大は720.46 MiBだった。これらは対象OS・基準機の受入を代替しない。
|
||||
|
||||
[前回の実時間watchdog試験](../tests/results/completion-final/worker-deadlines/README.md)では本番の待機時間を変更せず、隔離済みの試験用IPC peerが応答しない場合の停止を確認する。Mainのイベントループと別要求の取消も確認し、結果は通常CTestとは分けて記録する。PDFium/libzip自体を停止させた試験や、GUIフレーム性能の測定としては扱わない。前回実行は3成功・120.172秒、PDF通知/停止30,007/120,006ms、archive通知/停止10,008/30,008ms。実行ファイルとcommon libraryは統合ビルドのhashに一致する。[旧結果と再現手順](../tests/results/worker-deadlines/README.md)も保持する。
|
||||
|
||||
以下の数値とJSONは今回の原本同一性・翻訳等の修正前のビルドによる履歴である。前回版の再計測結果は[別の集計](../tests/results/completion-final/performance-summary.md)へ記録しており、履歴値を前回版の測定と扱わない。履歴の性能JSONは[小型資料](../tests/results/performance/)、[500ページ/500章資料](../tests/results/performance-standard/)、[非埋込日本語PDF](../tests/results/performance-fonts/)に保存する。記録したビルドの各条件を、新プロセス・空のXDG設定/状態/キャッシュで30回開く。OSファイルキャッシュとシステムフォントは保持するため、完全コールドとは呼ばない。計測の起点はアプリ起動後のファイルopenであり、プロセス起動時間は含めない。同一プロセスの計30回は、初回1回と明示的な再open29回に分けて集計する。
|
||||
|
||||
各資料で同条件のopen→最初の表示→closeを29回、close後1秒待ちで観測する。その後のナビゲーション/scrollを含む最後のcloseは別に記録する。対応するページ・見出し・章の系列は各125操作。PDFのページ系列は実ページ移動101回と倍率変更24回で、同じ位置へのno-opをcache hitへ算入しない。見出しがない原500ページPDFは対象不足を明示し、500件の著者outlineを持つ別資料で見出し系列を確認する。
|
||||
|
||||
Webの見出し系列は実DOMの`html-heading`索引だけを使い、EPUBの著者目次では代用しない。各系列には対象数・対象の種類・往復範囲を記録する。XHTMLのnative見出しが欠落していた修正前の測定は[別記録](../tests/results/performance-before-xhtml-fix/README.md)へ保存し、最終版の見出し性能の証拠から除外した。
|
||||
|
||||
500章EPUBの測定資料は、章末の複数見出しが同じスクロール位置に収まらないよう最後の節に1画面分の最小高さを指定し、13見出しに異なる到達点を持たせた。元資料は`standard-500-clamped.epub`として同じバイト列で保持する。元資料で見つかった同位置の見出しを交互に再選択する不具合は製品側で修正し、横書き・縦書きの実DOMとEPUB章境界の回帰試験を追加した。[資料の版と目的](../tests/fixtures/performance/README.md)を区別する。
|
||||
|
||||
入力はフォーカス中の本番ウィンドウへの合成QKeyEvent。`firstResponseFrameMs`は操作成立後の最初のQtフレーム通知までの時間で、PDFでは可視tileの完成前にも記録する。Webのスクロールは操作ID付きACK、見出しはACKと論理位置変化、章移動は検証済み`resourcePath`の変化を成立条件とする。`finalQualityFrameMs`は2回以上の通知を待ち、PDFでは対象の可視tileがそろった後の通知に限定する。以前のフレームの遅延callbackは除外する。
|
||||
|
||||
QtのframeSwappedは提示キューの通知であり、物理的なscanoutの時刻ではない。WebはChromium compositorのframe IDと結合していないため、両値とも対象画素の提示時刻を直接検証した値ではない。`success`は要求回数・移動・close・原本不変等の計測検査の成功であり、暫定性能予算の合格ではない。50 msとの参考比較は全操作系列をまとめた`firstResponseFrameMs`のp95を使い、原設計の視覚応答を直接測定した値とは区別する。
|
||||
|
||||
本体RSS、および本体+全子孫のRSS合計を100msごとに採取し、開始・最大・close後・反復差分を分ける。表の群ピークと1 GiBの参考比較は同一プロセスの開閉・操作系列を対象とし、新プロセス起動30回のRSSは各生JSONへ別に記録する。close後は1秒待ってEmptyと描画cacheゼロを確認するが、全補助プロセスの消滅を条件にはしない。RSS合計は共有ページの重複を含み、採取の間に生じたピークは捕捉できない。保持RSSが直ちに戻らないことだけでリークと断定しない。実QWindow/QScreenの寸法・DPR・報告refresh、pressure段階も保存し、メモリ圧迫中の測定を通常品質の成功値へ混ぜない。描画cacheの課金量はRSSとは別指標とする。
|
||||
|
||||
| 資料 | 形式 | 空のアプリcacheからopen p95 (ms) | 入力→初回Qt通知 p95 (ms) | 最終品質指標 p95 (ms) | 連続scrollフレーム p95 (ms) | 群ピーク RSS (MiB) |
|
||||
|---|---|---:|---:|---:|---:|---:|
|
||||
| 小型 | pdf | 63.34 | 7.95 | 13.12 | 19.14 | 174.45 |
|
||||
| 小型 | html | 211.38 | 11.37 | 17.01 | 19.25 | 635.30 |
|
||||
| 小型 | zip | 216.61 | 6.68 | 17.07 | 18.19 | 645.33 |
|
||||
| 小型 | epub | 213.54 | 13.00 | 21.20 | 18.19 | 712.08 |
|
||||
| 500ページ/章等 | pdf | 63.75 | 7.93 | 15.84 | 18.25 | 433.72 |
|
||||
| 500ページ/章等 | pdf-headings | 66.44 | 8.04 | 16.67 | 20.33 | 451.60 |
|
||||
| 500ページ/章等 | html | 259.46 | 6.50 | 12.82 | 17.06 | 701.00 |
|
||||
| 500ページ/章等 | zip | 267.92 | 10.84 | 17.07 | 17.50 | 703.34 |
|
||||
| 500ページ/章等 | epub | 270.86 | 22.75 | 31.07 | 19.91 | 826.52 |
|
||||
| 非埋込日本語 | pdf | 87.28 | 7.80 | 12.93 | 18.56 | 211.64 |
|
||||
|
||||
10条件すべて冷起動30回・原本不変・測定条件検査が成功した。OSファイルキャッシュは保持する。上記は開発機上のQt通知時刻による参考値であり、両OS・基準機の性能合格ではない。
|
||||
|
||||
| 資料 | PDF | cache hit 件数 / p95 (ms) | miss 件数 / p95 (ms) | 同位置移動の除外件数 |
|
||||
|---|---|---:|---:|---:|
|
||||
| 小型 | pdf | 101 / 13.02 | 0 / — | 0 |
|
||||
| 500ページ/章等 | pdf | 81 / 12.14 | 20 / 13.26 | 0 |
|
||||
| 500ページ/章等 | pdf-headings | 81 / 15.87 | 20 / 28.13 | 0 |
|
||||
| 非埋込日本語 | pdf | 101 / 12.93 | 0 / — | 0 |
|
||||
|
||||
メモリは本体RSSと、本体+全子孫の群RSSを分けて記録する。以下の3値は開始 / 最大 / 最終close後(MiB)。反復差分は、同条件29開閉の最初と最後のclose後の差(MiB)である。
|
||||
|
||||
| 資料 | 形式 | 本体 開始 / 最大 / close後 | 群 開始 / 最大 / close後 | 29開閉の群差分 |
|
||||
|---|---|---:|---:|---:|
|
||||
| 小型 | pdf | 103.38 / 141.95 / 125.04 | 103.38 / 174.45 / 125.04 | +7.75 |
|
||||
| 小型 | html | 101.76 / 352.82 / 349.98 | 101.76 / 635.30 / 501.49 | +9.09 |
|
||||
| 小型 | zip | 100.92 / 339.68 / 336.52 | 100.92 / 645.33 / 490.67 | +9.69 |
|
||||
| 小型 | epub | 101.75 / 342.21 / 339.50 | 101.75 / 712.08 / 491.68 | +9.71 |
|
||||
| 500ページ/章等 | pdf | 103.19 / 393.89 / 387.09 | 103.19 / 433.72 / 387.09 | +5.79 |
|
||||
| 500ページ/章等 | pdf-headings | 101.93 / 409.69 / 346.12 | 101.93 / 451.60 / 346.12 | +2.02 |
|
||||
| 500ページ/章等 | html | 102.21 / 373.73 / 353.61 | 102.21 / 701.00 / 513.59 | +8.68 |
|
||||
| 500ページ/章等 | zip | 101.51 / 363.29 / 343.16 | 101.51 / 703.34 / 493.57 | +12.73 |
|
||||
| 500ページ/章等 | epub | 101.55 / 359.94 / 343.18 | 101.55 / 826.52 / 504.09 | +11.85 |
|
||||
| 非埋込日本語 | pdf | 103.57 / 154.39 / 154.39 | 103.57 / 211.64 / 154.39 | +18.98 |
|
||||
|
||||
暫定予算から外れた参考値: なし。予算値は変更していない。継続scrollの物理60 Hz判定、完全OS-cold、長期リーク判定はこの計測では行わない。
|
||||
|
||||
|
||||
[操作集中時の専用測定](../tests/results/performance-interaction/README.md)は長押し120入力、遠距離ジャンプ24回、resize10回、staging取消、異なる文書への4切替を含む。QtTestの本番Controller/QML/workerを使い、最後の5,000ページ目は緑色の実画素も検査する。各入力の移動有無、描画待ち/実破棄数、10ms heartbeatを記録する。通常CTestの計測専用slotのskipは、この独立実行結果と分けて報告する。
|
||||
|
||||
大容量PDFは5,000ページ・1,009,828,104 bytes(0.940 GiB)。1,280個の異なる画像を全て実際に使い、ページ間で再利用する。修正前の記録では3回openのp95は97.70 ms、100操作の最終品質p95は24.12 ms、50 ms間隔の独立監視によるプロセス群ピークRSSは約720 MiBだった。30回openの受入を置き換える値ではない。原本ハッシュ不変と5,000ページ目の画面を確認し、大容量一時資料は回収した。[詳細と再現手順](../tests/STRESS-PDF-VALIDATION.md)
|
||||
|
||||
## 前回の配置と記録の対応
|
||||
|
||||
前回の`cmake --install`と開発版tar.gzの別展開先で本体・ワーカー・PDFiumとライセンスを配置した。同じ開発機のシステムQtを使用し、クリーンOSへの独立配布の合格ではない。[前回配布記録](../tests/results/completion-final/linux-development-package/README.md)では2回のアーカイブ生成がbyte一致し、圧縮後6,367,967 bytes、553ファイル、SHA-256は`e384c8c21da11343f845a5ca7310ee6ca944e51c9585de4b2b5c7c73ca352e0e`。原本と別の一時展開先から、PDF・非埋込日本語PDF・HTML・ZIP・EPUB、100%/200%を含む[6条件すべてReady](../tests/results/completion-final/linux-development-package/smoke/package-smoke.json)を確認して一時展開先を回収した。100%は1100×760、200%は550×380論理pxの仮想画面内に収まり、worker/Chromiumのsandboxは有効だった。配置後PDFWorkerはRPATH変更でbuild直後とhashが異なるため、それぞれを記録する。[従来の配置結果](../tests/results/smoke/results.json)と[旧配布記録](../tests/results/linux-development-package/README.md)は履歴として保持する。
|
||||
|
||||
ソース、実行ファイル、試験、証跡のSHA-256と集計は[validation-record.json](validation-record.json)に記録する。今回の追加修正前の集計は[prior-validation-record.json](../tests/results/completion-regressions/prior-validation-record.json)に保存した。前回版の全試験・比較・配置・性能の結果は[completion-final](../tests/results/completion-final/README.md)にそろえ、旧結果を新しいバイナリーへ読み替えない。最終性能は10条件、PDF比較は6組を記録し、それぞれ対象バイナリーを照合する。前回の実時間watchdogは再実行済みで、専用試験実行ファイルとcommon libraryのhashを個別reportとbuild-recordで確認できる。最終集計の`workerDeadlinesBuildMatches`へも反映する。旧結果は従来の各フォルダーと旧集計へ保持する。記録の`matchesRecordedBuild`と`pdfComparisonBuildMatches`で対象を区別する。約1GBの負荷試験も最終ビルドで再実行し、主3実行ファイルの一致を`stressPdfBuildMatches`に記録する。旧ビルドの測定は`stressPdfPrior`として保持する。
|
||||
|
||||
## Windows向けに追加したコード
|
||||
|
||||
LPAC・Job・明示したハンドルだけの継承、子側での実token検証、元文書のread-onlyハンドル入力、非同期pipe通信を本番ワーカー経路へ接続した。個別runtimeの一覧・ハッシュ照合、profileのfilesystem/registry書込拒否、handle相対の資源アクセス、rendererのプロセス識別・監視、volume+128bit file IDによる保存位置の照合を追加した。Windows PDFiumの固定アーカイブと公開ヘッダーも確認した。
|
||||
|
||||
Windows限定の`windows_pipe`、`windows_resources`、`windows_worker`試験をCMakeへ登録した。これらは未実行であり、Linuxでの合成MZ試験やWineヘッダーによる構文確認では代用しない。Windows GUI試験は一時保存先を明示し、実利用の履歴を消去しない構成とした。[準備手順](WINDOWS-BUILD.md)・[隔離の詳細とフォント代替の未確認点](windows-sandbox-port.md)
|
||||
|
||||
|
||||
## リリースの残作業
|
||||
|
||||
### 追加で解消した実装上の不足
|
||||
|
||||
- 全形式でopen時の原本identityを保存時に照合し、閲覧中の変更・置換へ旧位置を転用しない。復元不能と履歴なしを区別して案内する。DOM目次のloadingは欠如と区別し、表示要求を保持する。[修正前6失敗と修正後のGUI/core](../tests/results/completion-regressions/controller-state.md)。
|
||||
- PDFの構造見出しがない場合の代替候補は内部宛先だけを採用する。EPUBの見出し章境界は成立したnavigationへ結び付け、失敗した操作の指示を次の章移動へ残さない。WebリンクのEsc取消はDOMのフォーカスと選択表示も解除する。
|
||||
- PDFのコメント本文長・ページ内1,000件・512KiB情報応答予算の省略を明示し、取得できたprefixを保持する。本文が長すぎる注釈は固定代替文で存在を示す。安全上限を緩めず、原本も変更しない。
|
||||
- 日本語sourceをQtの翻訳contextで抽出し、TS/QMと起動時のQTranslatorを接続した。英語localeでの日本語案内とQt Quick標準ボタンの4ケースを確認した。Qtの日本語資源の配置は必要条件であり、OSネイティブdialogや多言語切替の完成は主張しない。[翻訳・配置手順](TRANSLATIONS.md)。
|
||||
|
||||
- PDFのNoZoom/NoRotateは、保存APのバイト列を変更せず、描画中だけ矩形・回転を補正する。DPRを描画要求とキャッシュ識別へ渡し、Mainの選択枠・マウス判定も同じ表示座標へ合わせる。生成リンク枠、保存リンク/コメント外観、ネイティブTextアイコン、非表示指定、重なり、CropBox境界を生成資料で検証した。APなしの非Text注釈のNoZoomは制約を通知し、不正確なクリック補正を行わない。
|
||||
- 資源提供側の詳細原因を表示集計まで渡す。実在しない資源、安全検査拒否、権限、MIME、上限、CRC、容量不足、保存/読取I/O、Worker異常を区別し、取消は通知しない。[追加契約](resource-warning-contract.md)。
|
||||
- FormだけにStructParentsを持つ構造見出しは、[共有qpdfアダプター](pdf-structure-adapter-plan.md)で取得する。所有元と呼出を検証できる文字だけをexactにし、複数呼出・曖昧な対応は理由付きpage precisionへ下げる。循環・破損・quota超過は制約を返す。
|
||||
- PDF検索の能力は、走査完了の実結果でsupported/unavailableへ更新する。取消・失敗・旧応答では未確認状態を保持する。
|
||||
- PDFのコメント本文はTab/Shift+Tab、Enterで開ける。CropBox外の注釈も対象とし、通常モードのEscで選択を解除する。Web文書への切替後はPDFの選択・画像を回収する。
|
||||
|
||||
これらの資料に対する成功を、任意のPDF・全OSの互換性合格としては扱わない。
|
||||
|
||||
### 対象環境・配布・性能の残作業
|
||||
|
||||
1. 統合済みWindowsコードをMSVC・Windows Qtでビルドし、本番LPAC下のPDF/ZIP/EPUB、pipe・resource・worker試験を実行する。日本語を含む非埋込フォントの代替、profile回収、renderer監視、PE依存解析と配置を検証する。現状は利用可能と確認できたWindows版ではない。[詳細](windows-sandbox-port.md)
|
||||
2. Ubuntu 24.04ではXvfb/Sway・software描画の22試験群、100%/200%を含む起動と配置済みアプリを確認済み。X11の実IBus/Mozc・US/JP XKBは補助試験で確認済み。WaylandのQt+IBus D-Bus経路も確認済み。ローカルdebのinstall/remove/purgeは既存VMと新しいUbuntu OSで確認済み。物理入力、GPU、native desktop portalと公開配布条件を確認する。Windows 11ではnativeビルドとこれら一式が未検証。
|
||||
3. 基準機と拡張コーパスでT20のp95、継続scrollのフレーム間隔、長時間稼働、様々なスキャン文書の取消と上限を測定する。600dpi相当画像と高密度ベクターの単一生成資料はArch/Ubuntuで検証済みだが、長い実スキャン群を網羅していない。
|
||||
4. PDF互換性の未検証項目と既知の外観差を評価し、依存ライセンス・告知・配布方式を確定する。
|
||||
|
||||
以上が残るため、G-RENDER/G-HEADINGS/G-SANDBOX/G-WEBは確認済みの範囲だけを記録し、G-DISTRIBUTIONと全要件の完成判定を合格にしない。
|
||||
@@ -0,0 +1,45 @@
|
||||
# Windowsビルドと未検証項目
|
||||
|
||||
Windows向けコードと試験を用意したが、Windows SDK・MSVC・Windows版Qtを利用できる環境は今回提供されていない。以下は実装したビルド経路であり、実行済みの手順や動作保証ではない。Windows 11でのコンパイル、実行、隔離攻撃試験、クリーン環境への配置が必要である。
|
||||
|
||||
環境を新規作成する場合、[MicrosoftのWindows 11 Enterprise評価版](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-11-enterprise)は利用登録後の90日評価を案内している(2026-09-19確認)。利用可能なISO・利用条件・必要なアカウントを確認してから専用VMへ導入する。旧Developer VMの英語URLは確認時点で[開発環境案内](https://learn.microsoft.com/en-us/windows/dev-environment/)へ転送され、既成VMの現行配布元としては確認できなかった。Windows VMはまだ作成していない。
|
||||
|
||||
## 必要なもの
|
||||
|
||||
- Windows 11 x64、対応するMSVC x64コンパイラとWindows SDK。`dumpbin`を実行できるDeveloper PowerShellを使用する。
|
||||
- 同じツールチェーン向けのQt 6.11.2。Core、Gui、Network、Qml、Quick、QuickControls2、WebEngineQuick、Xml、LinguistTools、Test、QuickTestと`windeployqt`が必要。Qtの日本語翻訳資源(qtbase_ja.qm、qtdeclarative_ja.qm、または配置ツールが統合したqt_ja.qm)も配置する。
|
||||
- libzip 1.11以上、toml++ 3.4以上、qpdf 12.4.1のCMakeパッケージ。libzip/libqpdfとその依存DLLは同じアーキテクチャ・ランタイムで用意する。
|
||||
- CMake 3.24以上、Ninja、Python 3.12以上。
|
||||
- ビルドしたアプリに対応する公式Microsoft Visual C++ Redistributable。開発機のCRT DLLを自動で収集・再配布する構成にはしていない。
|
||||
|
||||
PDFiumはLinux版と同じ固定コミットのWindows x64成果物を取得する。V8とXFAは無効で、`bin/pdfium.dll`と`lib/pdfium.dll.lib`を使う。取得元とハッシュは [lock](../cmake/pdfium.lock.json) に固定した。
|
||||
|
||||
このWindows providerには、Linuxで検証した[第2候補の描画修正](PDFIUM-CANDIDATE.md)をまだ組み込んでいない。以下は元のproviderでビルド経路を確認する手順であり、修正版の完成手順ではない。Windows用PDFiumへの同修正の適用・ビルド・色とパターンの回帰試験も残っている。Linux用の共有ライブラリーと固定lockをWindowsへ流用しない。
|
||||
|
||||
## 構成・試験・配置
|
||||
|
||||
以下のQtと依存ライブラリの場所を実際の配置先へ置き換える。
|
||||
|
||||
```powershell
|
||||
$env:CMAKE_PREFIX_PATH = "C:/Qt/6.11.2/msvc2022_64;C:/docview-dependencies"
|
||||
python cmake/fetch_pdfium.py --platform windows-x64 --destination .deps/pdfium-windows
|
||||
cmake -S . -B build-win -G Ninja -DCMAKE_BUILD_TYPE=Release -DDOCVIEW_PDFIUM_ROOT="$PWD/.deps/pdfium-windows"
|
||||
cmake --build build-win --parallel 6
|
||||
ctest --test-dir build-win --output-on-failure --output-junit tests.xml
|
||||
cmake --install build-win --prefix "$PWD/build-win/install"
|
||||
& ./build-win/install/bin/docview.exe ./tests/fixtures/pdf/navigation.pdf
|
||||
```
|
||||
|
||||
実機ではQtが使用するGPU・表示環境とChromium sandboxを有効にする。保護を無効にする引数や環境変数で試験を通さない。基礎試験資料は同梱し、追加生成手順は [README](../README.md) に記載した。
|
||||
|
||||
ワーカーのリンク後、`dumpbin`とCMakeのPE依存解析を使い、必要なDLLを実行ファイルの隣へ収集する。未解決依存、異なる内容の同名DLL、大小文字だけが異なる名前はビルド失敗とする。Windows API-setとOSのDLLは収集対象から除外する。特殊な再配布DLLを追加する場合のみ、`DOCVIEW_EXTRA_WORKER_RUNTIME_DLLS`に再配布可否を確認した絶対パスを指定する。
|
||||
|
||||
各`*.exe.runtime.json`は、ワーカー本体と有限個のDLLの名前・サイズ・SHA-256を記録する。起動時には全て照合して個別の一時領域へコピーし、そのコピーにだけAppContainerアクセス権を設定する。DLL更新時に古いDLLとの衝突が出る場合は、依存構成を確認して新しいビルドディレクトリーを用意する。既存の異なるDLLを無条件に上書きしない。
|
||||
|
||||
`cmake --install`はワーカーの一覧とハッシュを再検証し、GUI用Qtプラグイン・QML・WebEngine資源を`windeployqt`で配置する。`--nopatchqt`でQt DLLの変更を止め、明示した`qt.conf`で配置先を指定する。配置後もワーカー依存のハッシュを検証する。これはインストーラー作成、署名、アンインストール、ライセンス告知を完了する処理ではない。[QtのWindows配布手順](https://doc.qt.io/qt-6/windows-deployment.html)
|
||||
|
||||
## Windows固有の試験
|
||||
|
||||
`windows_pipe`は非同期通信、上限、切断と取消、`windows_resources`はhardlink/reparse・名前変更・原子的公開、`windows_worker`は本番LPAC内の要求順序、不正応答、異常終了、原本・兄弟ファイル・設定・通信・子プロセス・余分な継承ハンドル・自身のprofile書込拒否を試す。追加試験用ワーカーは製品installの対象に含めない。GUI試験の履歴と資源は明示した一時保存先を使用する。
|
||||
|
||||
これらはWindowsではまだ実行していない。Linuxでのmanifest生成・コピー試験は合成MZファイルを使うため、PE依存解析やLPACの成立を証明しない。Windowsのフォント代替、profile回収、WebEngine renderer監視、Known Folders、IME、表示倍率、配布については [隔離の実装と残作業](windows-sandbox-port.md) と [受入対応表](VALIDATION.md) を参照する。
|
||||
@@ -0,0 +1,106 @@
|
||||
# 文書アダプターの実装契約と拡張手順
|
||||
|
||||
対象は現在の C++20 / Qt 6 実装である。設計書 01 の R09、02 の処理境界、05 の論理契約との対応を記録する。設計書にある `FormatAdapter` は操作の意図を定義したもので、現在のコードに同名の基底クラスや動的プラグイン機構はない。
|
||||
|
||||
## 現在の境界
|
||||
|
||||
| 責務 | 実装 | 境界で受け渡すもの |
|
||||
|---|---|---|
|
||||
| 開く、取消し、文書切替、履歴、操作の振分け | `src/app/controller.*` | セッショントークン、generation、検証済みの QVariant データ |
|
||||
| キー・入力欄から有限コマンドへの変換 | `src/core/input.*` | command ID、引数。シェル展開は行わない |
|
||||
| PDF 解析・描画・構造情報 | `src/pdf/pdf_document.*`、`src/pdf/main.cpp` | CBOR。PDFium ハンドルはワーカーの外へ渡さない |
|
||||
| PDF 表示・位置解決・タイルキャッシュ | `src/app/pdf_canvas.*` | PDF ポイント座標、画像タイル、renderRevision |
|
||||
| ZIP/EPUB 解析 | `src/archive/archive.*`、`src/archive/main.cpp` | メタデータ、資源一覧、上限付きの展開ストリーム |
|
||||
| HTML/EPUB 表示と資源提供 | `src/web/*`、`qml/WebPane.qml`、`resources/reader.js` | 文書別 `doc://` origin、アプリ所有の isolated-world コマンド |
|
||||
| ワーカー輸送と応答検証 | `src/common/worker_process.*`、`ipc.*`、`contracts.*` | 有限 CBOR、要求 ID、世代、用途別の受信検証 |
|
||||
| ローカル保存 | `src/core/state.*`、`config.*` | 検証した JSON 状態と TOML 設定 |
|
||||
|
||||
PDFium と libzip は GUI 実行ファイルにリンクしない。PDF タイルと WebEngine の DOM を共通画像へ変換する層もない。共有するのは文書操作の意味、位置・世代・能力の扱いである。
|
||||
|
||||
## 論理操作と実際の呼出し
|
||||
|
||||
| 設計書 05 の操作 | 現在の入口 | 結果・制約 |
|
||||
|---|---|---|
|
||||
| probe | Controller の先頭バイト判定、ArchiveReader の内部判定 | 複雑な ZIP/XML の解析はワーカー側。独立した FormatAdapter::probe はない |
|
||||
| open | WorkerProcess `open`、ローカル HTML の profile 作成 | PDF は初期 metadata と初回描画の成功を確認して切替。HTML は staging view の load 成功を確認 |
|
||||
| getOutline | PDF `outline(cursor,limit)`、archive `metadata`、Web `index` | PDF は安定 ID と parentId/depth、nextOutlineCursor。Web は読み込んだ資源の索引 |
|
||||
| getHeadings | PDF `headings(page)`、Web `index` | PDF はページごとに抽出し、exact/page と source を保持。独立した節一覧の cursor はない |
|
||||
| resolveLocation / navigate | PdfCanvas::goToLocation、Web `location.restore` / `navigate` | PDF のページ情報待ちを含む。後続の明示移動・倍率変更・取消しは未完了の復元を失効させる |
|
||||
| renderPdfTiles | PDF `render` → PdfCanvas | page、物理scale、devicePixelRatio、rotation、clip、renderRevision。返却は BGRA8888 |
|
||||
| setViewport | Canvas の geometry/DPR/fit 計算、WebPane の layout | PDF の描画 revision と Web view の documentSerial は別管理 |
|
||||
| findText | PDF `search`、WebEngineView::findText | PDF は query/page/start/limit、矩形と nextCursor。OCR はない |
|
||||
| close | WorkerProcess::stop、profile revoke、view dispose | GUI は終了期限を伴うプロセス終了を使う。PDF の close RPC は handle 解放後ワーカーを終了する |
|
||||
|
||||
PDF の `pages` は outline を再送しない。初期応答に全ページ・全目次を入れず、ページは最大 256 件かつ 256 KiB、目次は最大 256 件かつ 512 KiB 以下に分割する。目次全体の走査上限は 20,000 件・深さ 64 で、省略を warning と truncated で通知する。GUI はページ範囲・連続性を再検証し、索引は許可したフィールドだけを残してセッション合計 32 MiB に制限する。
|
||||
|
||||
## 能力情報
|
||||
|
||||
`src/core/types.h` の `DocumentCapabilities` は Qt 非依存で、次の 8 個の `Capability` を持つ。PDF の metadata 生成はこの表現を実際に使用する。通信上の既存表現は `capabilities: {name: state}`、理由コードは `capabilityReasons: {name: reasonCode}` である。
|
||||
|
||||
| 項目 | PDF open 成功時 |
|
||||
|---|---|
|
||||
| pageNavigation | supported |
|
||||
| chapterNavigation | unsupported / E_CHAPTER_NAVIGATION_UNSUPPORTED |
|
||||
| outline | supported または unavailable |
|
||||
| headings | loading。解析結果と文書内宛先を持つ outline fallback の確定は Controller の責務。外部・禁止アクションだけの目次を supported の根拠にしない |
|
||||
| textSearch | loading。現在の検索応答で文字を確認した時点で supported、全ページの探索が完了しても文字がなければ unavailable。取消し・旧セッション/旧検索の応答・エラーでは未確定の能力を確定しない |
|
||||
| textSelection | unsupported / E_TEXT_SELECTION_UNSUPPORTED |
|
||||
| reflow | unsupported / E_REFLOW_UNSUPPORTED |
|
||||
| password | unavailable。要求中は open の E_PASSWORD_REQUIRED / E_PASSWORD_INVALID とセッション状態で通知 |
|
||||
|
||||
`supported` はアダプターが機能を提供できること、`unavailable` はその文書で対象がないこと、`loading` は未確定、`unsupported` は実装範囲外を表す。未知の能力名・状態を成功扱いしてはいけない。`CommandRegistry::requiredCapability()` がコマンドと能力の対応を返す。
|
||||
|
||||
`contracts.cpp::validateCapabilities()` は 8 項目が全て存在すること、状態が上記 4 種の文字列であること、`unsupported` に理由があることを検証する。理由は既知の能力に対応する 128 文字以下の `E_` で始まる英大文字・数字・アンダースコアのコードに限る。PDF の open 応答受信時と全形式の commit 前に検証し、不正な新文書では切替を中止して以前の文書を保持する。Web の能力と理由は Controller が既定の描画ポートから構築する。能力を必要とするコマンドは、検索入力・目次表示を含めて同じ検証と可否判定を通り、未知・欠落を実行許可に変換しない。`loading` は非同期探索を開始できる状態として扱い、`unsupported` の理由は一時通知に表示する。
|
||||
|
||||
HTMLのDOM索引がまだ届いていない場合、空の配列と`outline=loading`を目次の欠如へ変換しない。利用者の表示要求を保持し、読み込み中のパネルから確定した索引へ移行する。
|
||||
|
||||
PDF metadata の `isTagged` は公開 `FPDFCatalog_IsTagged` の結果であり、タグ付き文書の宣言を示す。構造木の完全性や見出しの存在を保証する値ではない。タグ宣言がある場合でも、個々の構造と位置は `headings` の結果で判定する。参考: [PDFium の catalog API 実装](https://pdfium.googlesource.com/pdfium/%2B/e8b8183f4d7a410b42bc4af6c31dcacb3b365685/fpdfsdk/fpdf_catalog.cpp)。
|
||||
|
||||
## 位置・応答の規約
|
||||
|
||||
- 内部ページ番号は 0 始まり。画面の物理番号は 1 始まり。ページラベルは文字列として保持し、数値計算に使わない。
|
||||
- PDF の保存位置は `kind=pdf`、pageIndex、pageLabel、xPt/yPt、viewRotation、fitMode、zoom。xPt/yPt は元 PDF 空間であり、Canvas が CropBox・元回転・利用者回転・DPR を適用する。読書位置は表示上端を基準にする。
|
||||
- Web の保存位置には token を含む URL を残さず、検証済みの資源相対パス、CFI/fragment、progression等を保存する。EPUBではpackagePath/spineIdrefも照合する。`zoom`は有限数の25–500で、HTML/HTML ZIP/流込EPUBではWebEngineのzoomFactor×100、固定EPUBではページ/幅合わせを基準にするspreadZoom×100を表す。固定EPUBの`fitWidth`はbool(falseはページ合わせ)、`panX`/`panY`は表示可能なパン範囲に対する有限数の0–1。画面サイズから計算する固定ページの最終ピクセル係数やDPRをこの倍率へ混ぜない。
|
||||
- WebPaneはアプリ側の表示倍率と合わせ方を`location`の結果に加える。Controllerの`logicalWebLocation()`が表示通知・保存位置の復元の両方で型と範囲を検証し、表示済み位置の`zoom`をStateStoreの位置と倍率へ保存する。復元ではレイアウトを確定して表示倍率を適用してからDOM位置を解決する。旧位置に`zoom`がなく別保存の倍率がある場合はそれを同じ境界で検証する。両方になければ既定表示を維持する。後続コマンドは未完了のWeb位置復元を取り消す。
|
||||
- PDF outline/link の wire target は平坦な page/x/y、HTML/EPUB は href 等を持つ。設計書の再帰的 TocNode と DocumentLocation variant に全面変換する実装ではない。
|
||||
- 各 IPC メッセージは protocolVersion=1、requestId、sessionId、generation、operation と、payload または result/error のどちらかを持つ。送信元の stdout を命令として扱わない。
|
||||
- 制御は 1 MiB、画像データは 8 MiB 以下。Linuxはローカルソケット、Windowsは継承した双方向pipeを使う。どちらも同じIpcChannelのバイトストリーム内で、長さヘッダーの上位 bit により画像と制御のフレームを識別する。
|
||||
- GUI は画像の幅・高さ・stride・形式・バイト数・ページ・clip・renderRevision を再検証する。Canvas の文書番号と revision も照合して、古い画像を採用しない。
|
||||
- `discardQueued(operation)` は未送信要求だけを除去する。実行中の PDFium 呼出しは中断されず、応答破棄またはワーカー終了で取消しを成立させる。
|
||||
- `frameReady` は画像の受信であり、画面提示完了ではない。保存・性能測定で表示済み位置が必要な場合は、window の frameSwapped と viewportReady を併用する。
|
||||
- 保存する位置は全形式でopen時の原本識別情報と結び付ける。保存時にパスを再照合して変更・置換があれば拒否し、復元時は保存済み位置なしと同一性不一致を区別して通知する。完全な内容ハッシュの常時計算は行わない。
|
||||
|
||||
## フォーカスと開く失敗の受渡し
|
||||
|
||||
一時的な入力欄・操作一覧・ダイアログを開くときは、Main.qmlが元の操作領域を保持する。閉じるときは有効な目次/ページ一覧へ戻し、非表示・空になった領域は本文へ戻す。正常に完了したコマンドが`focus.content`等でフォーカスを指定した場合は、保留していた復帰先を破棄する。形式のcommitや新たなUI操作を追加するときも、後から閉じる入力欄でその指定を上書きしない。
|
||||
|
||||
`Controller::openPath()`の直接失敗とstagingセッションの失敗は、`recordOpenFailure()`がbasename・有限の原因分類・利用者対処へ変換する。認識しないコードは一般のopen失敗として扱い、任意のworkerエラー本文・内部例外を利用者説明へ流用しない。新しい失敗コードを追加する場合はこの対応も追加する。既存文書の描画やwarningsは維持し、最後の失敗はController内の`lastOpenFailure_`にだけ保持する。`:info`の別項目で表示し、次のopenPath試行で消去する。StateStoreや表示中セッションのmetadataへ保存しない。最近使った文書の欠落・置換検査など、openPath到達前の拒否は各入口の通知で扱う。
|
||||
|
||||
## 形式を追加する手順
|
||||
|
||||
1. 新形式の source、位置、能力、必要な読み取り権限、上限を定義する。既存の PDF・Web の描画ポートで扱えるかを判断する。
|
||||
2. パーサーと依存ライブラリを専用ターゲットに分離し、未信頼解析はワーカーに置く。ワーカーは許可された入力を開き、OS sandbox の成立後に解析する。保護失敗時の通常権限への再試行を作らない。
|
||||
3. IPC 操作を追加する場合は `ipc.cpp` の whitelist、ワーカーの入力スキーマ、GUI の結果スキーマを同時に更新する。ページング、総量、文字列長、数値範囲、取消し時の破棄条件を決める。
|
||||
4. Controller の型判定、staging/commit、機能振分け、位置保存を接続する。現在は中央の format 分岐の変更が必要であり、アダプター登録だけでは追加できない。
|
||||
5. 新コマンドが必要なら CommandRegistry の ID・引数・能力対応、InputRouter の既定割当、設定例、UI ハンドラーを追加する。解析済み文書からコマンド名や実行コードを注入しない。
|
||||
6. Web 資源を使う形式は文書別 origin と ResourceHandler を利用し、外部通信・文書スクリプト・ダウンロードの既定を維持する。展開先は broker 側の ResourceWriter が所有する。
|
||||
7. 形式単体、実ワーカー IPC、破損/巨大入力、取消し・文書切替、位置復元、実表示の回帰試験を追加する。依存の固定版と配布告知も更新する。
|
||||
|
||||
## R09 / 設計書 05 の評価
|
||||
|
||||
R09 の分離基盤は、ワーカー単位の解析、有限コマンド、能力表現、専用描画ポートとして成立している。一方で、形式追加の登録機構、Qt 非依存モデルを端から端まで通す adapter interface、全操作の統一取消しトークンは未実装である。`DocumentIdentity`、`DocumentLocation`、`ResponseStamp` 等は補助モデルと単体試験にとどまり、runtime の保存・通信は QVariant/QCbor と個別検証を使う。`DocumentCapabilities` の採用だけでこの差分を解消したとは扱わない。
|
||||
|
||||
UI のモデルは一部が format 分岐に依存する。利用者向け説明はQtの翻訳contextと日本語sourceへ分離したが、IPCは翻訳キーだけを送る統一エラー型ではなく、固定コードと説明文を使用する。Web の再配置には view ごとの serial と JavaScript callback の生存確認があり、設計書の単一 `layoutRevision` モデルとは異なる。これらを拡張時の変更点として扱う。不要な抽象基底を追加して runtime と別の契約を増やすより、次形式の追加時に既存 2 経路をその契約へ移すのが検証可能な手順となる。
|
||||
|
||||
証跡は `tests/test_pdf.cpp`、`test_pdf_canvas.cpp`、`test_core.cpp`、`test_archive.cpp`、`test_security.cpp`、`test_app.cpp`、`test_web_qml.cpp` と `tests/PDF-VALIDATION.md` にある。合格した個別試験と設計全体の受入完了は区別する。
|
||||
|
||||
## T19 設計レビュー記録(2026-09-19)
|
||||
|
||||
**判定: 現在の静的組込み方式による接続手順を採用する。** T19 の受入条件である「UI 固有処理にパーサーを埋め込まず、能力・位置・ナビゲーション契約で接続できる」ことは、上記の責務表・操作表・追加手順から追跡できる。第五の形式の実装や、特定の名前を持つ C++ 抽象基底の存在を合否条件にはしない。
|
||||
|
||||
- 設計書 05 は `FormatAdapter` を言語非依存の論理契約と定義し、PDF タイルと Web 可視域には別の描画ポートを認めている。IPC、専用 Canvas、Web コマンドの組合せでこの操作境界を実現することは実装上の選択である。設計書 02 の初期拡張方式も配布元が組み込むモジュールに限定しているため、動的プラグイン機構は必須ではない。
|
||||
- PDFium と libzip は各ワーカー専用ターゲットへ分離され、QML へ形式パーサーを追加する必要はない。新形式は既存の二つの描画ポートを選ぶか、別の専用ポートを定義し、Controller で正規化済みメタデータ、位置復元、ナビゲーションを接続する。
|
||||
- 能力は厳密な境界検証と有限コマンドに接続する。位置は PDF 座標または Web の資源・CFI・fragment・progression、ナビゲーションは上限付き索引、非同期応答は要求 ID とセッション世代で区別する。これらの更新が形式追加時の必須作業である。`test_core` の能力スキーマ試験と `test_app` の不正能力での操作拒否試験が、未知の能力を許可扱いしないことを検証する。
|
||||
- 設計書 02 が目指す「登録だけで追加する」依存方向には差分が残る。現在は Controller の中央分岐と一部 UI モデルを変更する必要があり、Qt 非依存の位置型を実行時全経路で利用しているわけではない。この差分は拡張時の変更箇所として明示する。T19 の接続可能性の採用を、R09 配下の全ての理想的な構造が実装済みという意味にはしない。
|
||||
|
||||
以上から、同名基底の不在は単独の未合格理由としない。必須なのは既存文書の挙動、隔離、能力・位置・ナビゲーションの検証を保つ接続経路であり、形式追加時には上記 7 手順と同等の適合試験で再評価する。
|
||||
@@ -0,0 +1,52 @@
|
||||
# DocView アプリケーション設計書
|
||||
|
||||
設計基準版 1.0 / 2026年9月19日
|
||||
|
||||
## 目的と設計の要点
|
||||
|
||||
DocView(仮称)は、PDFを中心にHTML・HTML ZIP・EPUBを読むための、Vim風操作を備えたデスクトップ文書リーダーである。本文を主役にした静かな画面と、キーボードだけで完結する移動を提供する。
|
||||
|
||||
表示基盤にはQt Quick、PDF描画には独立プロセス内のPDFium、HTML・EPUB表示にはQt WebEngineを採用する設計とする。PDFは紙面を保持し、HTML・EPUBはそれぞれの構造を使って移動する。表示形式の違いを無理に「ページ番号」だけへ統一しない。
|
||||
|
||||
本版は実装の入力となる設計基準である。動作・性能・互換性の実測結果は含まない。性能数値は受入目標、技術選定は検証ゲート付きの設計判断として示す。プログラム、ビルド環境、試作品は成果物に含まれない。
|
||||
|
||||
## 文書構成
|
||||
|
||||
| 文書 | 主な内容 | 主な読者 |
|
||||
|---|---|---|
|
||||
| [01 要件・スコープ](01-requirements.md) | 要件ID、優先順位、対応範囲、受入追跡 | 企画・開発・QA |
|
||||
| [02 全体アーキテクチャ](02-architecture.md) | 構成、責務、処理フロー、拡張点 | 開発 |
|
||||
| [03 形式別設計](03-formats.md) | PDF、HTML、ZIP、EPUBの取込みと表示 | 開発・QA |
|
||||
| [04 画面・操作設計](04-ui-navigation.md) | 画面、モード、キー、フォーカス、見出し | 企画・開発・QA |
|
||||
| [05 データ・インターフェース設計](05-data-contracts.md) | モデル、位置表現、コマンド、IPC、状態遷移 | 開発 |
|
||||
| [06 設定・保存設計](06-config-storage.md) | TOML、キーバインド、OS別配置、永続化 | 開発・運用 |
|
||||
| [07 セキュリティ・障害設計](07-security-errors.md) | 信頼境界、入力制限、障害復旧 | 開発・QA |
|
||||
| [08 性能・試験設計](08-performance-tests.md) | 目標、測定条件、互換性、受入ケース | 開発・QA |
|
||||
| [09 技術判断・開発計画](09-decisions-roadmap.md) | 選定理由、代替案、検証ゲート、残課題 | 技術責任者 |
|
||||
| [10 参考資料](10-references.md) | 公式仕様・API・配布資料 | 開発 |
|
||||
|
||||
初読は01→02→04→09の順、実装着手時は03・05・06・07・08を併読する。
|
||||
|
||||
## 設計の確度
|
||||
|
||||
| 区分 | 意味 |
|
||||
|---|---|
|
||||
| 確定要件 | 原要件、またはデスクトップGUIであるという補足合意 |
|
||||
| 設計判断 | この版で採用する構成・振る舞い。変更は関連文書と試験を同時に更新する |
|
||||
| 提案値 | 原要件に数値指定がないため設定した測定可能な初期値 |
|
||||
| 検証ゲート | 実装開始後に実機・代表文書で確認し、未達なら選定を見直す条件 |
|
||||
|
||||
PDFの再現性、構造タグからの見出し移動、隔離環境の動作、縦書きEPUB、Qt依存物を含めた配布を最初に検証する。これらが未確認の段階で、全PDFへの完全互換や全Linux環境への対応を宣言しない。
|
||||
|
||||
## 用語
|
||||
|
||||
- 文書: 開いたPDF、単独HTML、HTML ZIP、またはEPUB。HTMLの内部リンク先も同じ許可ルート内なら同一文書セッションに属する。
|
||||
- 目次: PDFアウトライン、EPUB nav/NCX、HTML見出しから構成したナビゲーションツリー。
|
||||
- 見出し: 文書構造に記録された節の起点。PDFアウトラインとPDF構造タグは出典を区別する。
|
||||
- ページ一覧: PDFの物理ページ、固定レイアウトEPUBのspine項目。流し込み文書では代わりに章一覧を使う。
|
||||
- 論理位置: 再描画やウィンドウサイズ変更後も可能な限り再発見できる読書位置。
|
||||
- 許可ルート: 文書セッションが参照できるファイル集合の境界。端末全体のファイル権限とは異なる。
|
||||
|
||||
## 文書管理
|
||||
|
||||
要件をR01〜R15、設計判断をADR、受入ケースをT、技術検証をGで識別する。要求の変更時は01の対応表から影響をたどる。補助的な機能は原要件と区別し、リリース範囲に入れる判断を記録する。外部資料は確認時点の情報であり、採用時にバージョンとライセンスを固定する。
|
||||
@@ -0,0 +1,77 @@
|
||||
# 01 要件・スコープ
|
||||
|
||||
## 製品の目的
|
||||
|
||||
PDFの紙面を正確に表示し、HTML・HTML ZIP・EPUBも同じ操作体系で読み進められる、Linux・Windows向けデスクトップGUIを提供する。TUI風とは、本文中心の簡潔な画面、必要時だけ現れる補助表示、Vim風のキー操作を指す。端末エミュレーター内での表示は対象としない。
|
||||
|
||||
## 要件一覧と設計への対応
|
||||
|
||||
「必須」は完成版の受入条件であり、段階的な開発順とは区別する。PDF表示を最初に成立させる。
|
||||
|
||||
| ID | 要件 | 優先度 | 主な設計文書 | 主な受入観点 |
|
||||
|---|---|---|---|---|
|
||||
| R01 | PDFを正確にレンダリングする | 最優先・必須 | 02・03・08 | 文字・画像・配置・透明・回転・注釈外観の再現 |
|
||||
| R02 | ローカルHTMLを表示する | 必須 | 03・07 | HTML・CSS・画像・フォントの参照とリンク移動 |
|
||||
| R03 | ZIP化HTMLを内部展開しindex.htmlと依存要素を読む | 必須 | 03・07 | 入口解決、安全な展開、相対パス・リンク |
|
||||
| R04 | EPUBを表示する | 必須 | 03・08 | package/spine/nav、縦書き・RTL・固定レイアウト |
|
||||
| R05 | キーボード主体・Vim風に操作する | 必須 | 04・05・06 | 開く・読む・移動・設定再読込・終了をキーで完結 |
|
||||
| R06 | 見出し情報があれば見出しへジャンプする | 必須 | 03・04・05 | 元形式の構造情報から移動、情報の有無を正しく表示 |
|
||||
| R07 | 目次があれば表示し、項目へジャンプする | 必須 | 03・04 | 階層・現在位置・移動先の整合 |
|
||||
| R08 | 目次・ページ一覧等を選択表示し、余分なボタンやラベルを置かない | 必須 | 04・06 | 初期の最小表示、表示切替、フォーカス復帰 |
|
||||
| R09 | 将来の拡張を容易にする | 必須 | 02・05・09 | 形式アダプター・コマンド・能力情報による分離 |
|
||||
| R10 | キーバインドや表示設定をファイルで変更する | 必須 | 06 | スキーマ、上書き、再読込、エラー時の回復 |
|
||||
| R11 | 書籍を読み込み滑らかに操作できる | 必須 | 02・08 | 初期表示、キー応答、ページ遷移、メモリの測定 |
|
||||
| R12 | 少なくともLinux・Windowsで利用する | 必須 | 06・08・09 | 両OS実機で表示・入力・配布を検証 |
|
||||
| R13 | 設定等をOSごとの慣習に沿って配置する | 必須 | 06 | XDG、Windows Known Folders、非ASCIIパス |
|
||||
| R14 | PDFの編集・マークアップ・フォーム記入を含めない | 除外 | 03・04・07 | 保存操作やフォーム入力で原本を変更しない |
|
||||
| R15 | デスクトップGUIで見た目とキー操作をTUI風にする | 確定補足 | 02・04 | GUIで正確な紙面と簡潔な操作画面を両立 |
|
||||
|
||||
R01〜R14の根拠は提供要件「Vim/TUI風文書リーダー」(docview.md)、R15は製品形態の補足合意である。試験ケースへの詳細対応は08に置く。
|
||||
|
||||
## 初期版の範囲
|
||||
|
||||
| 項目 | 設計範囲 |
|
||||
|---|---|
|
||||
| 実行環境 | Windows 11 x64、Ubuntu 24.04 LTS x64を初期の試験対象とする提案。LinuxのX11・Wayland双方で確認 |
|
||||
| 文書の開き方 | OSファイル選択、コマンドラインのローカルパス、ドラッグ&ドロップ。1ウィンドウ・1アクティブ文書 |
|
||||
| PDF | 静的ページ、内部・外部リンク、アウトライン、構造見出し、ページラベル、拡大縮小、回転、暗号化文書のパスワード入力 |
|
||||
| HTML | ローカル静的HTMLと、同じ許可ルート内の関連HTML・CSS・画像・フォント |
|
||||
| HTML ZIP | 検証済み一時領域への内部展開、index.html選択、関連資源・複数ページ |
|
||||
| EPUB | DRMなしのEPUB 2/3。流し込み、固定レイアウト、日本語縦書き、RTL。詳細は03 |
|
||||
| ナビゲーション | スクロール、ページ/章移動、見出し、目次、リンク、戻る/進む |
|
||||
| 設定 | TOMLによるキー・配色・補助パネル・文字サイズ・性能上限 |
|
||||
|
||||
## 原要件を補完する設計提案
|
||||
|
||||
本文検索、読書位置の再開、少数の最近使った文書、エラー詳細表示、簡易ヘルプを提案する。長い書籍をキーボードで読むための補助手段として初期設計に含めるが、R01〜R15を満たすうえで独立した追加要件であり、開発計画上は削減可能である。本文検索は既存の文字情報だけを対象とし、OCRを暗黙に追加しない。
|
||||
|
||||
アプリの日本語UIを初期値とし、文字列を翻訳可能な資源へ分離する。読書状態・履歴はローカルに保存する。ネットワークアカウントやサーバーは必要としない。
|
||||
|
||||
## 表示互換性の境界
|
||||
|
||||
「PDFを正確に表示する」は、対応対象の文書について文字、画像、図形、クリッピング、透明度、ページ寸法・向きが読書に影響する欠落なく再現されることを意味する。代表コーパスと目視による判定を行う。異なる表示器間のアンチエイリアス差をそのまま欠陥と判定しない。
|
||||
|
||||
電子署名の検証、添付ファイルの実行、動画・3D・JavaScript、動的XFA、DRM解除、印刷色校正、OCRは追加機能として扱い、初期版に含めない。既存の注釈・フォームの静的外観は読書内容なので描画対象とする。検出した未対応機能や読込失敗には警告または開けない理由を示す。検出可能なXFA等は事前分類する。一方、描画APIだけですべての視覚的欠落を実行時検出できるとは想定せず、検出不能な差は代表文書の比較試験と既知制約で管理する。
|
||||
|
||||
HTML・EPUBの文書スクリプトと外部通信は初期版では無効とする。ローカルにそろった静的コンテンツを対応の中心とし、スクリプトや遠隔資源が必須の資料は互換性制限を表示する。EPUB規格のすべての機能への適合を宣言する設計ではない。
|
||||
|
||||
## 主要ユースケース
|
||||
|
||||
1. 文書を開く。型と権限を確認し、処理中も画面操作と取消しを受け付け、最初の本文を表示する。
|
||||
2. j/k、ページ移動、倍率変更で読む。描画中のページは場所と進捗を示し、操作受付を止めない。
|
||||
3. 目次を出し、階層をたどって項目に移動し、本文へフォーカスを戻す。
|
||||
4. 見出し単位で進む。目次と本文見出しの出典を区別し、情報がない場合は短く通知する。
|
||||
5. 設定ファイルを編集して再読込する。不正なら現在の有効設定を維持し、行・項目・理由を表示する。
|
||||
6. 終了して同じ文書を再度開く。提案機能の位置復元が有効なら最後の位置へ戻る。
|
||||
|
||||
## 設計上の未確定事項
|
||||
|
||||
| 論点 | 本版の既定案 | 確定時点 |
|
||||
|---|---|---|
|
||||
| 配布形態・ライセンス | オープンソース依存の条件を満たす動的リンク配布を候補とする | G0・配布方式決定時 |
|
||||
| 実際の書籍の種類・最大容量 | 08の代表・負荷コーパスで開始 | G0で実利用文書を追加 |
|
||||
| PDF構造タグの位置精度 | 公開PDFium APIで見出し→ページ・矩形を抽出 | G0で採否判断 |
|
||||
| Linuxの配布先拡大・ARM64 | 初期のx64対象とは別の検証枠 | 初期版の品質成立後 |
|
||||
| 初期画面の配色 | 暗色UI・PDF原色の既定、設定で変更 | 操作レビュー時 |
|
||||
|
||||
これらは設計書作成を妨げる未回答事項ではない。実装時の判断を再現できるよう、既定案・判断時点・影響を記録する。
|
||||
@@ -0,0 +1,99 @@
|
||||
# 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で固定する。
|
||||
@@ -0,0 +1,159 @@
|
||||
# 03 フォーマット・取込み設計
|
||||
|
||||
DocView アプリケーション設計書 | 版 1.0 | 2026-09-19
|
||||
|
||||
対象要件: R01-R04、R06、R07、R09、R11、R14。
|
||||
|
||||
## 1. 対応方針
|
||||
|
||||
PDFを最優先とし、PDFiumを呼ぶ専用PDFWorkerで描画する。HTMLとEPUBの本文はQt WebEngineで描画する。TUI風の配色・枠線・文字中心の操作UIはアプリの領域に適用し、PDFや著者指定の本文レイアウトを変更しない。
|
||||
|
||||
| 形式 | 初期リリースの対応範囲 | 制約の伝え方 |
|
||||
|---|---|---|
|
||||
| PDF | 読取り専用表示、拡大縮小、回転、ページ一覧、outline、リンク | 対応限界・破損を文書情報とエラーで明示 |
|
||||
| 単独HTML | ローカルHTMLと許可された文書フォルダー内のCSS・画像・font・リンク | 外部依存資源とスクリプト依存部分は表示できない旨を通知 |
|
||||
| ZIP化HTML | `index.html` と相対参照資源を内部展開して表示 | 入口不明時は候補選択。危険なアーカイブは取込み中止 |
|
||||
| EPUB 2 / 3 | DRMのない静的本文、NCX/nav、spine、縦書き、RTL、リフロー、固定レイアウト | 音声・動画・media overlays・動的対話は初期版対象外 |
|
||||
|
||||
静的閲覧、DRM非対応、音声・動画非対応は設計上の初期範囲であり、原要件から直接指定された制限ではない。EPUBの全機能適合を宣言するものではない。PDFの編集、注釈追加、フォーム入力、保存による文書変更は行わない。既存の可視要素の表示は、編集機能とは分けて扱う。
|
||||
|
||||
## 2. 共通の取込み手順
|
||||
|
||||
1. MainのFileBrokerが利用者の選んだファイルを読取り専用で開く。拡張子と固定長のシグネチャを候補判定に利用するが、複雑な内容解析は行わない。
|
||||
2. PDFはPDFWorker、ZIP/EPUBはArchiveWorkerへ読取り専用handleを渡す。単独HTMLは許可rootと資源IDを登録する。形式の確定は担当の解析器で行う。
|
||||
3. Workerが返すメタデータは、Mainでも型・長さ・件数・参照IDを検証する。Workerは信頼境界の内側ではない。
|
||||
4. 新しい文書セッションに世代番号と推測困難なtokenを割り当てる。1ウィンドウのアクティブ文書は1つとする。切替候補の入口検証中は旧文書を維持し、新文書のコミット時に旧tokenと旧要求を失効させる。
|
||||
5. 最初の表示位置に必要な情報・資源を優先して読み込む。目次とページ一覧は段階的に更新する。取込み・描画は取消可能とする。
|
||||
6. 正常終了、文書切替、取消、失敗のすべてでhandle、共有画像、仮想URL、展開資源を解放する。画面に残っている旧文書の結果を新文書へ混ぜない。
|
||||
|
||||
位置とナビゲーションの形式非依存モデルは [データ・内部契約設計](05-data-contracts.md)、隔離と入力制限は [セキュリティ・異常系設計](07-security-errors.md) に定義する。
|
||||
|
||||
## 3. PDFの表示契約
|
||||
|
||||
### 3.1 正確性
|
||||
|
||||
PDFのページ寸法、CropBox/MediaBox、ページ回転、font、文字配置、画像、透明度、クリッピング、注釈外観を尊重する。座標はPDF文書座標を基準に保持し、device pixel ratio、ズーム、表示回転を一つの変換で適用する。CropBox左下が原点でないページ、文書のRotateと利用者の回転が重なるページも同じ変換行列で扱う。リンク矩形と文字選択の当たり判定はその逆行列を利用する。ページ本文をHTMLへ変換して表示しない。
|
||||
|
||||
画面は必要解像度のページ/タイル画像を使用する。倍率は論理画面上で計算し、DPRを一度だけ掛けて描画バッファ寸法を得る。低解像度の暫定画像を拡大表示している間は置換用の再描画を要求する。文字・図形の欠落、既存注釈の欠落、透明度の破綻は「表示できた」と判定しない。注釈の静的外観とフォームwidget外観は必要な描画経路を分けて確認し、編集を無効にしただけで外観も消える状態を避ける。具体的な評価方法は試験設計とPDF技術判断に従う。
|
||||
|
||||
未埋込みfontにはOS差が残り得る。代替fontの集合と探索順を管理し、両OSの比較対象に含める。任意PDFに対する完全一致を保証せず、検証済みの互換性範囲をリリースごとに記録する。
|
||||
|
||||
### 3.2 注釈・フォーム外観・フォント
|
||||
|
||||
通常のページ描画へFPDF_ANNOTを付けるだけではwidgetとpopupは描画されない。保存済みフォーム外観は、PDFiumのform environmentを用いるFPDF_FFLDraw系の描画経路を別途用意し、ページ本文と同じ回転・縮尺・タイル原点へ合わせて合成する。form environmentの初期化、ページ読込/破棄通知、終了処理はワーカー内で管理する。フォーム入力、action実行、JavaScript、保存APIは公開しない。タイル描画とフォーム描画の座標が一致しない場合は、可視領域単位の合成方式へ修正する。[PDFium描画API](https://pdfium.googlesource.com/pdfium/+/main/public/fpdfview.h)、[フォーム描画API](https://pdfium.googlesource.com/pdfium/+/main/public/fpdf_formfill.h)
|
||||
|
||||
既存外観が欠落したフォームは、暗黙にユーザー入力や文書保存で補修せず、表示できない可能性を通知する。popup内の注釈本文は選択時の読取り専用補助表示として扱い、紙面外に隠れたコメントの存在を見落とさない。静的注釈、widget、popup、appearance欠落をT18とG-RENDERで個別確認する。
|
||||
|
||||
埋込fontを優先し、未埋込みfontは許諾を確認した同梱候補と明示的なOS font索引を用いる。OS font索引はBrokerが管理し、PDFWorkerへは選択済みfontの読取り専用handleまたはバイト列だけを渡す。font探索目的でWorkerの任意パスアクセスを許可しない。共通font集合を固定しても、元fontが欠けた文書の完全一致を保証するものではない。
|
||||
|
||||
### 3.3 ナビゲーション
|
||||
|
||||
- PDF outlineは目次として保持し、明示destinationsとnamed destinationsをページ位置へ解決する。
|
||||
- タグ構造に有効なH/H1-H6があれば見出しジャンプを提供する。矩形まで解決できれば見出し位置、ページだけ解決できる場合はページ先頭へ移動し精度を表示する。見出しからページへの対応も解決不能なら該当項目に理由を付け、全体を「見出しなし」としない。座標が得られずページだけ分かる場合はprecision=pageで移動する。有効な構造見出しがない場合は文書内宛先を持つoutlineを代用し、「目次項目移動」と表示する。目次そのものはoutlineを使用する。文字サイズだけから推測した見出しは初期版で生成しない。
|
||||
- ページ番号は内部の0始まりindexと画面の1始まり表示を分ける。文書のPageLabelsがあれば併記し、`iv` や `1` と物理ページ番号を混同しない。
|
||||
- ページ内リンクは現在の文書へ移動する。外部HTTP(S)リンクは宛先を提示し、利用者の明示操作で既定ブラウザーへ渡す。Launch action、JavaScript action、自動外部起動は実行しない。
|
||||
- パスワードが必要な文書は専用入力を求め、値はメモリーだけに保持する。DRM等の未対応保護や未対応機能は理由を返す。
|
||||
|
||||
## 4. 単独HTMLとZIP化HTML
|
||||
|
||||
### 4.1 入口の選択
|
||||
|
||||
単独HTMLは選んだファイルを入口、その親ディレクトリーを初期rootとする。`../assets` 等でroot外の資源が必要な場合、許可範囲を自動拡大しない。「文書フォルダーを指定」で利用者が共通親を指定した場合だけrootを変更する。ブラウザーには絶対ローカルパスを渡さない。
|
||||
|
||||
ZIPの入口は次の順序で決める。
|
||||
|
||||
| 条件 | 動作 |
|
||||
|---|---|
|
||||
| root直下に完全一致の `index.html` がある | 採用 |
|
||||
| rootにはなく、共通トップディレクトリー直下に `index.html` が一つある | 採用 |
|
||||
| 上記以外でHTML候補がある | 相対パス一覧からキーボードで選択 |
|
||||
| HTML候補がない | `E_HTML_ENTRY_MISSING` |
|
||||
|
||||
`index.htm`、大小文字違いの名称、複数の深いディレクトリー内のindexは候補一覧で扱い、勝手に最初の候補へ決めない。選択結果は文書fingerprintと関連付ける。ZIPでは入口が深い場所にあってもZIP全体をrootとし、正当な相対参照を維持する。
|
||||
|
||||
### 4.2 内部展開
|
||||
|
||||
ArchiveWorkerがZIP索引を解析し、安全検査後に必要資源をストリーム展開する。Mainはエントリー記述を再検証し、専用領域へのhandle単位の書込みと実バイト数の上限監視だけを担当する。ZIP/XMLパーサーをMainへ持ち込まない。
|
||||
|
||||
最初に入口HTMLを、その後はWebEngineから要求されたCSS、画像、font等を展開する。CRCと上限の検査を終えた資源だけを確定して公開する。展開中の不完全ファイルを描画エンジンへ渡さない。全アーカイブを一括でメモリーへ展開せず、内側のZIPも自動展開しない。
|
||||
|
||||
### 4.3 URLと依存資源
|
||||
|
||||
資源URLは `doc://<session-token>/<relative-path>` とする。`QWebEngineUrlScheme::Syntax::Host` を使い、文書ごとのhostをoriginとする。URLは当該文書のResourceBrokerだけが解決できる。
|
||||
|
||||
| 入力 | 解決規則 |
|
||||
|---|---|
|
||||
| HTMLのsrc/href/srcset | 当該HTMLのURLを基準 |
|
||||
| CSSの `url()` / `@import` | 当該CSSのURLを基準 |
|
||||
| font-face、SVG資源 | 対応する資源の基準URLと同じ規則 |
|
||||
| `#fragment` | 現在の資源内の移動先 |
|
||||
| 相対URLの `..` | URL解決後にroot内なら許可 |
|
||||
| query | URL情報として保持し、OSファイル名へ直接連結しない |
|
||||
| 別origin、file URL、UNC、未知のスキーム | 読込みを拒否 |
|
||||
|
||||
percent-encodingは一箇所で一度だけ復号する。符号化された区切り・NUL・二重復号に依存するパスを拒否し、ZIPエントリー名の `%` を索引作成時にURL復号しない。HTMLの `base` は同一文書root内に解決できるものだけ許可する。外部baseはCSPと資源gateで拒否し、影響する依存資源の欠落を通知する。黙って別の場所へ読み替えない。
|
||||
|
||||
HTML、CSS、SVGの解析はQt WebEngineの描画側で行う。Mainの資源ハンドラーは内容を書き換えるためのHTML/CSSパーサーを持たない。文書タイトルや目次ラベルをアプリUIへ渡す際は文字列として表示し、HTMLとして再解釈しない。
|
||||
|
||||
### 4.4 本文の静的閲覧
|
||||
|
||||
文書JavaScript、form送信、meta refreshによる自動移動、外部iframe、外部画像・CSS・fontを無効にする。ローカルの許可資源は表示する。欠落画像・fontは代替表示、CSS欠落は本文を維持した警告とする。制限の詳細は文書情報から確認できる。
|
||||
|
||||
一般のHTMLメニューバーを自動で目次と決め付けない。`role=doc-toc` 等の意味が明確なnavを目次として読み、それ以外はh1-h6と有効なARIA見出しから「見出し一覧」を作る。見出しがないときは情報なしを示す。文書にIDを恒久追加せず、索引側に一時識別子を持つ。
|
||||
|
||||
## 5. EPUB
|
||||
|
||||
### 5.1 packageと読書順
|
||||
|
||||
ZIPの安全検査後、ArchiveWorkerが `mimetype`、`META-INF/container.xml`、OPF、manifest、spineを解析する。XMLは非検証パーサーとし、外部DTD・外部実体・実体の膨張を禁止する。先頭rootfileを既定packageとし、他のrenditionの存在もメタデータに記録する。
|
||||
|
||||
通常の次/前移動は `linear != no` のspine順で行う。`linear=no` は本文リンクや目次から到達でき、ジャンプ履歴で元へ戻れる。manifestの未知媒体には定義済みfallbackを辿り、循環参照と深さを制限する。利用可能なfallbackがなければ該当章をエラーにし、他の章へ移動可能にする。
|
||||
|
||||
### 5.2 目次・章・ページの区別
|
||||
|
||||
| 優先順/情報 | 使用方法 |
|
||||
|---|---|
|
||||
| EPUB 3 navのtoc | 著者の目次として使用 |
|
||||
| EPUB 2 NCX、またはEPUB 3 nav破損時のNCX | 目次として使用。破損fallback時は通知 |
|
||||
| spineから生成する章一覧 | 目次がない場合の補助。「章一覧」と明示 |
|
||||
| XHTMLの見出し | 見出しジャンプ用。章を開く際に段階的索引化 |
|
||||
| navのpage-list | 出版物のページラベルとして保持 |
|
||||
| landmarks | 補助ナビゲーションとして保持 |
|
||||
|
||||
著者のページラベル、固定レイアウトのページ、リフロー後の画面単位は異なる。リフロー表示では章内進捗を標準とし、画面番号を本の確定ページ番号として保存しない。navとspineの順序が違っても書き換えず、目次操作はnav、通常読書はspineに従う。
|
||||
|
||||
### 5.3 縦書き・RTL・固定レイアウト
|
||||
|
||||
CSSの `writing-mode`、`text-orientation`、`dir`、rubyを尊重する。`page-progression-direction` はページの進行方向であり、本文の文字方向と別に扱う。「次の読書位置」は論理方向で進め、h/j/k/lによる物理スクロールと分ける。
|
||||
|
||||
リフロー型は表示幅・文字サイズ変更後に再レイアウトし、保存した論理位置へ戻す。固定レイアウト型はXHTML viewportまたはSVG viewBoxを基準に拡縮し、本文fontサイズや行幅を強制しない。spine一項目を一ページとして扱い、見開き・RTL・項目ごとのrendition上書きを反映する。混在書籍は章の切替時に表示方式も切り替える。
|
||||
|
||||
### 5.4 位置の復元
|
||||
|
||||
保存情報はDocumentIdentityの内容識別情報と `packagePath / spineIdref / href / fragment / cfi / progression / textQuote` を基礎とする。対象packageとspineを確定した後の復元順はCFI、ID/fragment、textQuote、章内progression。CFIが壊れていても他の情報から近似復元し、近似であることを通知する。文書fingerprintが変わった場合は一致を確認してから古い位置を使う。
|
||||
|
||||
CFI解決と見出し抽出は、原文のDOM構造を基準にする。読書補助の要素を本文DOMへ挿入してCFIの番地を変えない。アプリが管理するUIはQt Quick側へ置く。fontや画像の読込みで位置が動く場合は、レイアウト確定後に同じ論理位置へ再配置する。縦書き・RTLのprogressionは論理読書方向へ正規化する。
|
||||
|
||||
### 5.5 保護と破損
|
||||
|
||||
`encryption.xml` があるだけでDRMと断定しない。IDPFの標準font難読化を認識して描画用に復元する。それ以外の暗号化方式、保護された本文、パスワード付きZIPは初期版非対応とし、`E_DRM_UNSUPPORTED` または `E_ARCHIVE_ENCRYPTED` を返す。
|
||||
|
||||
container/OPFが読めず読書順を確定できないときは開かない。nav破損はNCX・章一覧へfallbackする。spineの一部欠落は欠落章を明示して他の章を読めるようにする。正式な解析に成功していないEPUBを、ZIP内の最初のHTMLを開くだけで成功扱いにしない。
|
||||
|
||||
## 6. Qt WebEngineによる制御
|
||||
|
||||
`JavascriptEnabled=false` でMainWorldの文書スクリプトを停止する。アプリ所有の固定コードは `ApplicationWorld` に置き、DOMの見出し取得、CFI解決、表示位置測定、スクロールを行う。Qtのworld分離ではDOMへアクセスできる一方、JavaScript変数はworld間で共有されない。[QWebEngineSettings](https://doc.qt.io/qt-6/qwebenginesettings.html)、[QWebEngineScript](https://doc.qt.io/qt-6/qwebenginescript.html)
|
||||
|
||||
Qt Quickの `WebEngineView.runJavaScript(script, worldId, callback)` でworldを必ず指定する。文書文字列をコードへ連結せず、検証済みの型付きデータとして渡す。非同期callbackには要求ID・文書世代番号を関連付け、古い結果を捨てる。MainWorld無効化とApplicationWorld実行の組合せは、採用するQt版のG0検証で確認する。[WebEngineView](https://doc.qt.io/qt-6/qml-qtwebengine-webengineview.html)
|
||||
|
||||
本文WebEngineViewには汎用QWebChannelやOS APIを公開しない。設定ファイルから任意JavaScriptを実行する機能も初期版には設けない。位置・見出しの測定結果も未信頼データとしてMainで検査する。
|
||||
|
||||
## 7. 参照資料
|
||||
|
||||
確認日: 2026-09-19。規格の要点を基に、DocView独自の静的閲覧プロファイル・制限・回復動作を設計した。
|
||||
|
||||
- [EPUB 3.3](https://www.w3.org/TR/epub-33/) - package、spine、nav、rendition、font難読化。
|
||||
- [EPUB Reading Systems 3.3](https://www.w3.org/TR/epub-rs-33/) - rootfile選択、file URL、XML処理、script fallback。
|
||||
- [EPUB CFI 1.1](https://idpf.org/epub/linking/cfi/epub-cfi.html) - EPUB内の論理位置の表現。
|
||||
- [QWebEngineUrlScheme](https://doc.qt.io/qt-6/qwebengineurlscheme.html) - Host構文とorigin。
|
||||
- [QWebEngineUrlSchemeHandler](https://doc.qt.io/qt-6/qwebengineurlschemehandler.html) - 独自スキームの資源応答。
|
||||
@@ -0,0 +1,232 @@
|
||||
# 04 画面・操作設計
|
||||
|
||||
## 1. 設計方針
|
||||
|
||||
本文を中心にしたデスクトップGUIとし、アプリの周辺表示に等幅文字・細い区切り線・キーボード中心の操作を使う。PDFの紙面は文字端末に置き換えず、原文の色・文字・図形を保持して描画する。
|
||||
|
||||
R01〜R14は提供要件、R15は「デスクトップGUIで、見た目とキーボード操作をTUI風にする」という確定補足に対応する。本書の具体的なキー割当、初期レイアウト、タイムアウトは設計提案であり、利用者から指定された固定値ではない。要件一覧は01、位置・能力・コマンドのデータ契約は05、設定スキーマは06に置く。
|
||||
|
||||
初期版は1ウィンドウ・1アクティブ文書とする。ファイルはOSの選択画面、起動引数のローカルパス、ドラッグ&ドロップから開ける。Qt Quick側がUIとキーモードを管理し、PDFiumの表示結果とQt WebEngineの文書内容へ操作を振り分ける。文書内スクリプトにアプリのキー操作を管理させない。
|
||||
|
||||
## 2. 画面構成
|
||||
|
||||
### 2.1 初期画面
|
||||
|
||||
文書未選択時は、中央に「Ctrl+O: 文書を開く」「?: 操作一覧」の2項目を表示する。メニューバー、ツールバー、常時表示の装飾ボタンは置かない。OSのウィンドウ枠は通常どおり使用する。画面の余白、文字、区切り線は設定テーマの色を使う。
|
||||
|
||||
### 2.2 閲覧画面
|
||||
|
||||
```text
|
||||
┌─ 目次 ─────────┬──────────────────────────────────────┐
|
||||
│ 第1章 │ │
|
||||
│ > 第2章 │ 原文どおりの文書描画領域 │
|
||||
│ 2.1 │ │
|
||||
│ 2.2 │ │
|
||||
├─ ページ一覧 ────┤ │
|
||||
│ 12 │ │
|
||||
│ >13 │ │
|
||||
│ 14 │ │
|
||||
├────────────────┴──────────────────────────────────────┤
|
||||
│ book.pdf 13 / 248 125% 内容 │
|
||||
└───────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
図はすべての領域を表示した例。初期値では**文書領域と1行のステータス行だけ**を表示し、目次とページ一覧は隠す。目次とページ一覧は独立に表示・非表示を切り替えられる。両方を表示した場合は左側の上下に配置し、片方だけなら左側の高さ全体を使う。各幅・高さの下限を確保し、小さいウィンドウではパネルを自動的に増やさない。
|
||||
|
||||
- **文書領域**: PDFのページは連続縦スクロールを初期値とする。ページの背景色や埋込フォントは文書どおりに描く。アプリのテーマを変更しても文書の色を勝手に反転しない。
|
||||
- **目次パネル**: 項目を階層表示する。現在位置を含む最も近い項目を示す「現在位置」と、キーボードで選択中の行を示す「選択位置」を区別する。選択を動かすだけで本文を移動させない。
|
||||
- **ページ一覧パネル**: PDFは実ページ番号の一覧を基本とする。ページラベルがある場合は「付録-3(実ページ 213)」のように表示できる。サムネイルは必須にせず、将来追加候補とする。HTMLには表示しない。固定レイアウトEPUBではspine項目のページ一覧、リフローEPUBではpage-listがあれば出版物由来のページ参照、なければspine由来の章一覧を表示する。見出しは「ページ一覧」「出版物のページ」「章一覧」と内容に合わせる。
|
||||
- **ステータス行**: ファイル名、位置、ズーム倍率、フォーカス領域を簡潔に表示する。PDFは実ページ番号/総ページ数、HTMLは見出し名または「文書」、EPUBは章位置を表示する。HTMLやリフローEPUBに固定総ページ数を捏造しない。非表示にできる。
|
||||
- **通知**: 文書読込中・エラー・利用できない操作は短い通知として表示する。通常の閲覧時に通知領域の高さを占有しない。自動消去される通知と、明示的な対処を要するエラーを区別する。
|
||||
|
||||
ページ一覧・目次が提供されない文書で対応キーを押した場合は「この文書にはページ一覧がありません」等を表示する。空のパネルを常設しない。マウスによるスクロール、リンク選択、パネル操作も可能とするが、主要操作はすべてキーボードで到達できる。
|
||||
|
||||
### 2.3 読込と異常時
|
||||
|
||||
1. 文書を開く操作から、OS標準のファイル選択を表示する。
|
||||
2. ファイル確定後、読込状態を即座に表示する。目次や総ページ数の確定を待ってから初めて画面を更新する実装にしない。
|
||||
3. 最初に必要なページ・章を表示し、他ページや目次は準備できた時点で反映する。
|
||||
4. 読込が失敗した場合は、対象名、原因の分類、利用者が可能な対処を示す。内部例外・スタックトレースは画面に出さない。
|
||||
5. 既存文書から別文書への切替では、新文書の最低限の表示準備が完了するまで旧文書を保持する。失敗時は旧文書へ戻る。
|
||||
|
||||
PDFパスワード入力等の文字入力が必要な画面は、閲覧キーを奪わない専用ダイアログにする。対応暗号方式・パスワード保持方針は03・07に従う。
|
||||
|
||||
## 3. 操作状態とフォーカス
|
||||
|
||||
Vimの通常モードに相当する閲覧操作を採用するが、文書編集用の挿入モード・ビジュアルモードは作らない。
|
||||
|
||||
| 状態 | 入力の扱い | 遷移・終了 |
|
||||
|---|---|---|
|
||||
| 内容閲覧 | 文書用キー、リンクのTab移動、マウススクロール | パネルへフォーカス移動、ファイル選択等 |
|
||||
| 目次フォーカス | 行移動・階層開閉・選択確定 | Enterで本文へ移動して内容に戻る、Escで内容へ戻る |
|
||||
| ページ一覧フォーカス | 行移動・選択確定 | Enterで対象へ移動して内容に戻る、Escで内容へ戻る |
|
||||
| キー列待機 | `g`、`z`、`[`、`]`、`Ctrl+W`、数値カウントの後続を待つ | 完成で実行、Escで破棄、期限切れで破棄 |
|
||||
| 操作一覧表示 | スクロール・閉じる操作のみ | Escまたは?で閉じて元のフォーカスへ戻る |
|
||||
| コマンド入力 | `:`から入力欄を表示し、文字入力・IME・左右移動・削除を優先 | Enterで検証して実行、Escで取消して元のフォーカスへ戻る |
|
||||
| ダイアログ/文字入力 | OS標準の編集操作とIMEを優先 | 確定・取消で元のフォーカスへ戻る |
|
||||
| 読込中 | UIは応答し、不要になった読込の取消または別文書選択を可能にする | 成功、失敗、取消 |
|
||||
|
||||
### 3.1 キー処理の優先順位
|
||||
|
||||
1. OSまたはネイティブダイアログが占有する操作。
|
||||
2. IMEの変換・確定、ダイアログ内の文字入力と標準編集操作。
|
||||
3. 最前面にある操作一覧等の一時表示。
|
||||
4. 現在のフォーカス領域に限定された割当。
|
||||
5. アプリ共通割当。
|
||||
|
||||
`Ctrl+O`等の共通操作も、文字入力中・IME変換中に無条件で横取りしない。少なくとも `isComposing` 相当の状態にあるキーイベントは閲覧コマンドへ配送しない。コマンド入力、ファイル選択、パスワード入力、OSの標準ダイアログでは、`j`、`k`、数字、`?`等を通常の文字として入力できる。
|
||||
|
||||
### 3.2 フォーカス規則
|
||||
|
||||
- 文書を開き終えたときは内容にフォーカスする。
|
||||
- パネルを表示しても直ちに本文位置やフォーカスを変更しない。
|
||||
- フォーカス中のパネルを隠した場合は内容に戻す。
|
||||
- `Ctrl+W`の後に`w`を押すと「内容→目次→ページ一覧→内容」の順に循環する。非表示領域は飛ばす。
|
||||
- リンクの `Tab` / `Shift+Tab` は内容領域内のリンクを順に選択する。リンクがない場合は本文位置を変えず、内容にフォーカスを残す。パネル間の移動は専用キーで行う。
|
||||
- PDF内・HTML内・EPUB内の読取専用文書要素は、アプリの通常操作モードを勝手に切り替えない。フォーム記入や文書内スクリプトによるキーフックは設けない。
|
||||
- フォーカス枠、選択行、現在位置は色だけに依存せず、線・記号・濃淡で区別する。
|
||||
|
||||
## 4. 既定キーバインド案
|
||||
|
||||
キー表記は論理キー名を使う。Shiftを要する大文字は別のキーとして扱い、日本語配列/英語配列で文字を入力する物理キーが異なっても、設定上は `?`、`+` 等の文字で識別する。OSが予約するキーは上書きできない場合があるため、設定チェックと操作一覧で知らせる。
|
||||
|
||||
### 4.1 内容領域
|
||||
|
||||
| キー | 動作 | 境界・備考 |
|
||||
|---|---|---|
|
||||
| `j` / `k` | 小さく下/上へスクロール | 設定可能な移動量。キーリピートに対応 |
|
||||
| `h` / `l` | 横方向にスクロール | 横の余りがない場合は何もしない |
|
||||
| `Ctrl+D` / `Ctrl+U` | 表示領域の半分だけ進む/戻る | PDFは下/上。HTML/EPUBは書字方向に沿った読書軸を使う |
|
||||
| `Ctrl+F` / `Ctrl+B` | 表示領域のほぼ1画面分進む/戻る | 読書軸に沿って移動し、少量の重なりを残す |
|
||||
| `gg` / `G` | 文書の先頭/末尾へ | EPUBは読書順序の先頭/末尾。パネルでは先頭/末行 |
|
||||
| `数字G` | PDFの指定実ページへ | 例: `42G`。HTML/EPUBでは利用不可と通知 |
|
||||
| `J` / `K` | 次/前のPDF実ページへ | PDFのみ。移動先ページの先頭へ |
|
||||
| `]]` / `[[` | 次/前の見出しへ | 見出し情報がある場合のみ |
|
||||
| `]c` / `[c` | 次/前のEPUB章へ | EPUBのspine順に移動。非linear項目は通常順送りから除外 |
|
||||
| `+` / `-` | 拡大/縮小 | PDFは表示倍率、HTML/リフローEPUBはズーム。原文は変更しない |
|
||||
| `=` | 幅に合わせる | PDFまたは固定レイアウトに適用。リフロー形式では標準倍率へ戻す |
|
||||
| `Tab` / `Shift+Tab` | 次/前のリンクを選ぶ | リンク数が多い場合もスクロール位置を選択先へ追従 |
|
||||
| `Enter` | 選択リンクを実行 | 文書内移動・別文書/外部リンクの扱いは基盤仕様に従う |
|
||||
| `Esc` | 未完成のキー列またはリンク選択を解除。読込・索引待機中は要求を取り消す | 文字入力/IMEの取消を優先し、文書自体は閉じない |
|
||||
|
||||
このキー案では `Ctrl+F` をVim流の画面送りに使う。追加提案である本文検索は `/` で開始する。原要件を満たす基本操作と、検索・位置復元等の補助機能を区別する。
|
||||
|
||||
### 4.2 目次・ページ一覧
|
||||
|
||||
| キー | 目次 | ページ一覧 |
|
||||
|---|---|---|
|
||||
| `j` / `k` | 次/前の可視行 | 次/前の行 |
|
||||
| `h` | 展開中なら折りたたみ、そうでなければ親へ | 何もしない |
|
||||
| `l` | 子があれば展開、展開済みなら最初の子へ | 何もしない |
|
||||
| `gg` / `G` | 先頭/末尾の可視行 | 先頭/末尾の行 |
|
||||
| `Ctrl+D` / `Ctrl+U` | 半画面分の行を移動 | 同左 |
|
||||
| `Enter` | 選択項目へ移動 | 選択ページへ移動 |
|
||||
| `Esc` | 内容へフォーカスを戻す | 同左 |
|
||||
|
||||
### 4.3 共通操作
|
||||
|
||||
| キー | 動作 |
|
||||
|---|---|
|
||||
| `Ctrl+O` | 文書を開く |
|
||||
| `t` | 目次の表示/非表示を切り替える |
|
||||
| `p` | ページ一覧の表示/非表示を切り替える |
|
||||
| `zs` | ステータス行の表示/非表示を切り替える |
|
||||
| `Ctrl+W` `w` | 表示中の領域間でフォーカスを移す |
|
||||
| `:` | コマンド入力欄を表示する |
|
||||
| `?` | 現在の設定を反映した操作一覧を表示する |
|
||||
|
||||
`t`、`p`、`J`、`K`には文書リーダー独自の役割を割り当てる。Vimの完全互換ではないことを操作一覧で示す。`q`単押しで終了する操作は誤操作を避けて既定に含めず、OS標準のウィンドウ終了を使う。
|
||||
|
||||
### 4.4 キー列と設定検証
|
||||
|
||||
- 接頭辞待機の既定値は800 msとする設計提案。06に従い200〜3,000 msへ変更でき、0は無期限待機とする。
|
||||
- 単一キーと、そのキーを接頭辞とする長いキー列を同じ有効コンテキストへ割り当てた場合はエラーにする。例: `g` と `gg` の併存は不可。
|
||||
- 同じ有効コンテキストで同じキーを複数動作へ割り当てる設定は拒否する。共通割当と領域別割当で同じキー列がある場合は領域別を優先する。利用者設定は(mode, context, keys)が一致する既定定義を置換する。異なる長さの接頭辞衝突は、同時に有効なcontext間でも拒否する。
|
||||
- 設定変更はファイル全体の構文・値・キー衝突検証が成功した後、一括で適用する。失敗時は最後に有効だった設定を維持し、行番号と修正可能な理由を表示する。
|
||||
- 数字は内容領域のPDFページ指定にのみ使い、先行ゼロを除き1以上の整数に制限する。入力中の数字は必要時だけ通知する。末尾が `G` 以外または期限切れなら入力列を破棄して、直前キーを別のコマンドとして勝手に実行しない。
|
||||
- フォーカス変更、文書切替、ダイアログ表示時は未完成キー列を破棄する。
|
||||
- リピートイベントで接頭辞待機を何重にも作らない。`j`等の連続スクロールはリピートを受け付けるが、パネル表示切替は長押しで点滅しない。
|
||||
|
||||
## 5. 形式別の位置と移動
|
||||
|
||||
### 5.1 PDF
|
||||
|
||||
- 内部のページ番号は0始まり、利用者向けの実ページ番号は1始まりとし、変換箇所を位置型の境界へ限定する。
|
||||
- `42G` はラベル「42」ではなく42枚目を開く。ページラベルと実ページが異なる場合は、ステータスと一覧に両方を表示する。
|
||||
- 現在ページは、文書表示領域の中央線に交わるページを基本とする。中央線がページ間の余白にある場合は近いページ、同距離なら前のページとする。これにより、ページ端で次/前操作が不安定になることを避ける。
|
||||
- 次/前ページは現在ページ番号に±1を適用し、移動先ページの上端へ移動する。末尾・先頭ではその位置にとどまり、短く境界を通知する。
|
||||
- PDFの目次は文書内のアウトライン情報を利用する。構造タグのH/H1〜H6から有効なページ位置を取得できる場合は、これを見出しジャンプへ用いる。構造タグの有効な見出しがない場合は、文書内宛先を持つアウトラインを代わりに用い、表示名を「目次項目移動」とする。構造タグ由来の見出しとアウトライン由来の項目は共通位置型へ変換しても、情報源の種別を保存する。両方を単純に併合して同一の項目へ二度移動させない。文字サイズ推定・OCRによる見出し生成は行わない。
|
||||
- ズーム変更時は、表示領域の中心にある文書上の点をできる限り保持する。異なる大きさや回転を持つページへ移動しても、そのページ固有の幾何情報を尊重する。
|
||||
|
||||
### 5.2 HTMLとZIP HTML
|
||||
|
||||
- 通常HTMLはそのファイルを入口とする。ZIP HTMLは現在表示するHTMLを基準に相対URLを解決する。CSS内の参照はそのCSS自身の場所を基準とする。入口が複数ある場合・存在しない場合の選択規則は基盤仕様に従う。
|
||||
- `h1`〜`h6` と有効なARIA見出しをDOM順で収集して見出し移動を提供する。`display:none`等で表示されない要素は対象外とする。見出し文言が空の場合は「見出し(レベルN)」と表示する。
|
||||
- HTMLの目次は、明示的な文書内目次のリンク構造が認識可能な場合にそれを採用する。認識不能でも見出しから作成した**見出し一覧**を利用できる。この一覧を著者作成の目次と混同しないようにラベルを区別する。
|
||||
- ZIP内の別HTMLへのリンクは同じ出版物コンテキストで開く。ページ一覧をファイル一覧として流用しない。HTMLを開いた順を「章順」として推定しない。
|
||||
- `gg` / `G` は現在のHTMLリソースの先頭/末尾である。ZIP全体の先頭/末尾とは解釈しない。
|
||||
- リフロー・ズーム変更後は、先頭可視要素とその要素内の相対位置を基準に位置を回復する。DOMに安定した位置がない場合はスクロール比率へフォールバックする。
|
||||
|
||||
### 5.3 EPUB
|
||||
|
||||
- 章の通常移動はパッケージのspine順に従う。目次の表示順から章の読書順を推定しない。
|
||||
- リフロー形式は表示領域と作者の書字方向に従って組版する。横書きの通常文書は縦スクロール、日本語縦書き等はwriting-modeとdirectionに合った読書軸を使う。`j`/`k`と`h`/`l`は物理方向、半画面/1画面移動は読書方向に対応する。次/前章は次/前の通常読書対象spine項目の先頭へ移動する。
|
||||
- 目次はEPUB 3のnavigation document、EPUB 2はNCXを利用する。両方ある場合の優先順位はEPUB基盤仕様で固定する。
|
||||
- EPUB内の `h1`〜`h6` と有効なARIA見出しを見出しジャンプの対象とする。章境界を越える見出し移動は、次/前の通常読書対象spine項目の最初/最後の有効見出しへ移る。先読みは必要最小限とし、全章を描画してから読書開始する構成にしない。
|
||||
- 章単位の位置と章内アンカーを持ち、画面幅の変更でページ数が変わっても同じ箇所に留まる。EPUB page-listのページ番号は書籍が提供した参照であり、現在の画面分割数ではない。
|
||||
- 固定レイアウトはそのviewportと読み方向を尊重する。日本語縦書き・RTLを含め、作者のCSSと出版物の方向情報を使う。固定レイアウトとリフロー文書では倍率・幅合わせの意味を分ける。
|
||||
|
||||
### 5.4 見出し移動の共通定義
|
||||
|
||||
「次の見出し」は現在の読書位置より後ろにある最初の有効な見出し、「前の見出し」は現在の読書位置より前にある最後の有効な見出しとする。同一の目的地へ重複する見出しは一度にまとめる。見出しの先頭ぴったりにいる場合、その見出しを再選択しない。PDFで見出しのページだけが確定し座標が確定しない場合は、`precision=page`としてページ先頭へ移動し、その精度を表示する。確定していない位置を正確な見出し位置と扱わない。目的地が不正な目次項目は選択時に理由を示し、他の目次項目まで使えなくしない。
|
||||
|
||||
## 6. コマンド契約と文字入力
|
||||
|
||||
設定ファイル、キー入力、コマンド入力は同じコマンドIDへ解決する。コマンド入力欄は必要時だけ最下部に現れ、ステータス行が非表示でも利用できる。入力中は等幅文字で `:` と文字列、エラーがあればその理由を示す。
|
||||
|
||||
| ID | 既定キー/文字列 | 引数・適用対象 |
|
||||
|---|---|---|
|
||||
| `file.open` | `Ctrl+O`、`:open` | 引数なしはファイル選択。`:open "path"` は指定ローカルパスを開く |
|
||||
| `app.quit` | `:q` | 終了。OS標準の終了操作も使用可 |
|
||||
| `operation.cancel` | 読込/索引待機中の`Esc`、`:cancel` | 現在の待機要求を取り消す。新文書のコミット前なら旧文書へ戻る。文字入力/IMEの取消が優先 |
|
||||
| `document.root.choose` | `:root` | 単独HTMLの許可フォルダーをOSの選択画面で指定。新root内へ資源を再解決 |
|
||||
| `document.info` | `:info` | 形式、検出した制限、欠落資源、エラー詳細を表示 |
|
||||
| `history.clear` | `:history clear` | 保存した履歴・位置を件数確認後に消去。補助機能 |
|
||||
| `scroll.down` / `scroll.up` | `j` / `k` | 内容領域の縦スクロール |
|
||||
| `scroll.left` / `scroll.right` | `h` / `l` | 内容領域の横スクロール |
|
||||
| `scroll.half_down` / `scroll.half_up` | `Ctrl+D` / `Ctrl+U` | 表示領域の半分 |
|
||||
| `scroll.page_down` / `scroll.page_up` | `Ctrl+F` / `Ctrl+B` | 表示領域のほぼ全体 |
|
||||
| `nav.document_start` / `nav.document_end` | `gg` / `G` | 形式別に定める文書範囲 |
|
||||
| `nav.page` | `数字G`、`:page N` | 1始まりのPDF実ページ番号。範囲外はエラー、暗黙に末尾へ丸めない |
|
||||
| `nav.page_next` / `nav.page_previous` | `J` / `K` | PDFのみ |
|
||||
| `nav.heading_next` / `nav.heading_previous` | `]]` / `[[` | 有効な見出しまたは代替目次項目がある文書 |
|
||||
| `nav.chapter_next` / `nav.chapter_previous` | `]c` / `[c` | EPUBのみ |
|
||||
| `panel.toc.toggle` | `t`、`:toctoggle` | 目次または見出し一覧の表示を切り替える |
|
||||
| `panel.pages.toggle` | `p`、`:pagestoggle` | 利用可能なページ/章一覧の表示を切り替える |
|
||||
| `panel.status.toggle` | `zs`、`:statusbar` | ステータス行の表示を切り替える |
|
||||
| `focus.next` | `Ctrl+W` `w` | 表示中の領域を循環 |
|
||||
| `zoom.in` / `zoom.out` | `+` / `-` | 現在位置を保持して拡大/縮小 |
|
||||
| `zoom.fit_width` | `=` | 固定ページでは幅合わせ、リフローでは標準倍率 |
|
||||
| `view.rotate` | `:rotate 90`、`:rotate -90` | PDFの表示回転のみ。原本へ保存しない |
|
||||
| `command.open` | `:` | コマンド入力状態へ移行 |
|
||||
| `config.reload` | `:reload` | 06で定義する検証と一括再読込 |
|
||||
| `help.toggle` | `?`、`:help` | 現在のキー設定に対応する操作一覧 |
|
||||
| `nav.back` / `nav.forward` | `Alt+Left` / `Alt+Right` | 同一文書コンテキスト内の明示的なジャンプ履歴 |
|
||||
| `search.open` | `/` | 本文検索の入力欄。補助機能の提案 |
|
||||
| `search.next` / `search.previous` | `n` / `N` | 検索結果。補助機能の提案 |
|
||||
|
||||
`nav.back` / `nav.forward` は目次・リンク・指定ページ等のジャンプを戻す。小さなスクロールのすべてを履歴へ積まない。新しい文書を開くことと、同じZIP内HTMLへの移動は、文書コンテキストの境界によって区別する。
|
||||
|
||||
コマンドの引数はアプリ内パーサーで処理し、シェルへ渡さない。パスは空白を含む場合に二重引用符で囲み、Windowsのバックスラッシュは文字どおり扱う。シェル変数、ワイルドカード、`!`による外部コマンド実行は展開しない。未知のコマンド、引数不足、余分な引数は入力欄に理由を表示し、文書状態を変更しない。IME確定のEnterはコマンド実行と兼用せず、変換確定後のEnterで実行する。
|
||||
|
||||
## 7. 補助機能の提案
|
||||
|
||||
本文検索、読書位置の再開、最近使った文書は原要件の独立した追加提案である。実装順の判断により削減できる。これらを省略してもR01〜R15の試験を省略しない。
|
||||
|
||||
- **本文検索**: `/`で検索欄を開く。入力中はIMEと文字編集を優先する。Enterで検索し、`n`/`N`で結果を移動する。PDFの既存テキストとHTML/EPUBの表示テキストを対象とし、画像へOCRを適用しない。検索処理は取消可能にし、結果なしと文字情報なしを区別する。
|
||||
- **読書位置の再開**: 文書を閉じる前の論理位置・倍率をローカル保存し、同じ文書を開いたときに回復する。原文の変更やウィンドウ幅の違いによる復元精度の低下を考慮し、保存先と識別方式は05・06に従う。HTML/リフローEPUBの画面上のページ数を永続キーにしない。
|
||||
- **最近使った文書**: 初期画面の追加表示として設定で有効化できる。初期画面を履歴の大量表示で埋めない。消去機能と保存上限を持ち、原本を変更しない。
|
||||
|
||||
## 8. UI実装前の確認項目
|
||||
|
||||
Qt QuickとQt WebEngineの間のフォーカス、IMEのcompositionイベント、日本語/英語キーボード配列、Wayland/X11、Windowsの表示スケール差を実機で確認する。PDFのアウトラインと構造タグ由来の見出し位置は出典を区別して保持する。これらは実装開始時の技術検証対象とする。
|
||||
@@ -0,0 +1,128 @@
|
||||
# 05 データ・インターフェース設計
|
||||
|
||||
## 設計原則
|
||||
|
||||
文書の位置は形式ごとの意味を保持した直和型で表現する。内部のページ番号は0始まり、画面の物理ページ番号は1始まりとする。ページラベルは文字列であり数値として計算しない。ドメインモデルはQtやPDFiumのオブジェクトを直接含めず、非同期操作の全応答に文書の世代を付ける。
|
||||
|
||||
## 主要モデル
|
||||
|
||||
| モデル | 主なフィールド | 制約・意味 |
|
||||
|---|---|---|
|
||||
| DocumentIdentity | documentId、canonicalPath、fileIdentity、size、mtime、contentHash? | documentIdは端末内UUID。物理ファイルIDは利用可能時のみ。ハッシュ未計算を許容 |
|
||||
| DocumentSession | sessionId、generation、format、state、capabilities | sessionIdは起動ごとの予測困難な識別子。保存IDとは別 |
|
||||
| DocumentMetadata | title、author?、language?、pageCount?、spineCount? | 未判明と0を区別。文字列長を制限しUIへプレーンテキスト表示 |
|
||||
| PageInfo | pageIndex、label?、widthPt、heightPt、cropBox、rotation | PDFの元座標と表示変換を保持 |
|
||||
| TocNode | id、parentId?、title、target?、source、children | sourceはpdf-outline / epub-nav / epub-ncx / html-toc / html-heading / spine |
|
||||
| Heading | id、level?、title、target、source、precision | level不明可。precisionはexact / page / approximate |
|
||||
| Link | region?、target、label?、kind | kindはinternal / external / blocked。文字列をコマンドとして実行しない |
|
||||
| ViewState | location、zoomMode、zoomValue、rotation、panels、focus | ズームはpercent / fit-width / fit-page。本文フォントサイズとは別 |
|
||||
| ReaderState | documentId、savedLocation、updatedAt、formatVersion | 文書が変わった場合は位置の再解決が必要 |
|
||||
|
||||
配列は必要に応じページングして応答する。巨大な目次や数万項目を一度にUIへ投入しない。titleの空白・制御文字を整理する際も原本は変更しない。
|
||||
|
||||
## 位置の表現
|
||||
|
||||
| 型 | 保存する値 | 再解決 |
|
||||
|---|---|---|
|
||||
| PdfLocation | pageIndex、pageLabel?、xPt、yPt、viewRotation、fitMode | PDFユーザー空間の位置をCropBox・回転・DPRで画面へ変換。変更文書ではページ範囲を検証 |
|
||||
| HtmlLocation | resourcePath、fragment?、domPath?、textQuote?、progression | fragment→DOMと文字列照合→資源内進捗の順。progressionは0〜1 |
|
||||
| EpubLocation | packagePath、spineIdref、href、cfi?、fragment?、textQuote?、progression | パッケージ内のspine→CFI→fragment→文字列→進捗の順で解決 |
|
||||
|
||||
PDFのxPt/yPtは元PDF座標系を明示して保存し、画面左上基準のCSS座標とは混ぜない。常に変換行列と逆行列を使う。CropBox外の指定は最寄りの可視領域へ調整し、精度をpageまたはapproximateとして通知する。
|
||||
|
||||
HTML/EPUBのスクロール軸はwriting-modeとdirectionから決める。progressionは読み進めた割合であり、scrollTop/scrollHeightだけでは定義しない。書体や幅が変わっても文字列アンカーを先に試す。レイアウト完了前の仮サイズから復元位置を確定しない。
|
||||
|
||||
textQuoteは短い前後文脈を持つが保存を無効化できる。ローカル状態には文書パスと短い本文断片が含まれ得るため、06の履歴消去対象に含める。スクリプト、DOMオブジェクト、任意XPath評価式は保存しない。
|
||||
|
||||
## 能力情報
|
||||
|
||||
能力はsupported / unavailable / loading / unsupportedの4状態を基本とし、単純な真偽値で「未取得」と「存在しない」を同一視しない。
|
||||
|
||||
| 能力 | 意味 |
|
||||
|---|---|
|
||||
| pageNavigation | 安定した物理ページに移動できる |
|
||||
| chapterNavigation | spineや複数HTML資源に沿った移動がある |
|
||||
| outline | 文書に目次として使える構造がある |
|
||||
| headings | 本文または構造情報から節の起点を得られる |
|
||||
| textSearch | 既存文字情報を検索できる。画像PDFではunavailableになる場合がある |
|
||||
| textSelection | 内容が文字選択を許容し、テキストを取得できる |
|
||||
| reflow | 本文の文字サイズ・行幅変更を反映できる |
|
||||
| password | 現在パスワードを要求している |
|
||||
|
||||
unsupportedには理由コードを付ける。UIは理由をヘルプ/一時通知に出し、無効ボタンを常時並べない。
|
||||
|
||||
## FormatAdapterの論理契約
|
||||
|
||||
以下は実装言語に依存しないインターフェース定義であり、アプリケーションコードではない。操作は非同期、sessionIdと取消しトークンを受け取る。
|
||||
|
||||
| 操作 | 入力 | 結果 | 特記事項 |
|
||||
|---|---|---|---|
|
||||
| probe | 制限付きファイル情報・先頭バイト | format、confidence、理由 | ZIP内部の詳しい判定は隔離側 |
|
||||
| open | DocumentSource、policy、password? | session、metadata、capabilities | パスワード再入力と破損を区別 |
|
||||
| getOutline | cursor、limit | TocNodeの部分集合、nextCursor | 同一文書で安定したID |
|
||||
| getHeadings | resource/page範囲、cursor | Headingの部分集合、完了状態 | 抽出途中のジャンプ要求は待機/取消し可能 |
|
||||
| resolveLocation | 保存位置、復元方針 | 解決済み位置、precision | 失敗時は先頭へ黙って移さず通知 |
|
||||
| navigate | target、alignment | 到達位置、renderRevision | jump履歴への記録はControllerが担当 |
|
||||
| renderPdfTiles | page、matrix、clip、revision | TileBatch | PDF専用描画ポート。WebEngineは可視域通知ポートを使う |
|
||||
| setViewport | size、DPR、readingStyle | layoutRevision | reflow後に位置再解決 |
|
||||
| findText | query、direction、cursor、limit | match位置、nextCursor | 提案機能。平文検索が既定 |
|
||||
| close | sessionId | released | 繰返し呼出しは無害 |
|
||||
|
||||
共通契約は操作の意図をそろえるためのもので、PDFの画像タイルとHTMLのDOMを同一の描画データへ変換しない。
|
||||
|
||||
## コマンドと入力の境界
|
||||
|
||||
Command RegistryはcommandId、引数スキーマ、実行可能モード、必要な能力、取消し可否を持つ。Input Routerからはキー名そのものではなく検証済みCommandを受け取る。マウス操作も同じCommandを経由する。
|
||||
|
||||
コマンド入力欄は定義済み文法だけを解釈する。シェル、外部コマンド、JavaScriptの実行機能は持たない。パスの引用符は構文として扱うが、変数展開・コマンド置換・グロブ実行はしない。`:open`のパスは明示操作による新しい許可対象としてBrokerで検証する。
|
||||
|
||||
## プロセス間メッセージ
|
||||
|
||||
IPCは長さ付きCBORフレームをローカル専用チャネルで送る。外部待受ポートを開かない。子プロセスの標準出力を信頼済みのコマンドストリームとして解釈しない。実装時にパイプ/ローカルソケットを選び、OSごとのアクセス制御を適用する。
|
||||
|
||||
| フィールド | 内容 |
|
||||
|---|---|
|
||||
| protocolVersion | 整数。未知版は接続を拒否し依存不整合を報告 |
|
||||
| requestId | セッション内一意、応答・取消しの対応づけ |
|
||||
| sessionId / generation | 文書と世代。旧文書の応答を破棄 |
|
||||
| operation | ホワイトリスト列挙。任意メソッド名を実行しない |
|
||||
| payload | 操作別の有限スキーマ。整数範囲・文字列長・配列数を検証 |
|
||||
| result / error | どちらか一方。errorはコード、再試行可否、利用者向け説明キー |
|
||||
|
||||
制御フレームの上限は1 MiB、PDFタイル/資源データは別の分割チャネルで1片8 MiB以下を提案する。1タイルの最大寸法・stride・ピクセル形式・バッファ長を受信側で再検証し、乗算の桁あふれを拒否する。数値は08で測定し、07の入力制限と合わせて変更する。
|
||||
|
||||
共有メモリを使う場合はBrokerが割り当てた短命のバッファIDだけをワーカーへ渡し、サイズ上限・所有セッション・読書き方向を管理する。ワーカーが示す任意パスやハンドル値を主プロセスの権限で開かない。close/取消し/クラッシュ時に参照数を解放し、解放済み応答を表示しない。
|
||||
|
||||
## 状態と遷移
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Empty
|
||||
Empty --> Opening: open
|
||||
Ready --> Opening: open another
|
||||
Opening --> PasswordRequired: encrypted
|
||||
PasswordRequired --> Opening: submit
|
||||
Opening --> Ready: initial content
|
||||
Opening --> Failed: invalid or unsupported
|
||||
Ready --> Recovering: worker crash
|
||||
Recovering --> Ready: explicit retry
|
||||
Recovering --> Failed: retry fails
|
||||
Ready --> Closing: close
|
||||
Closing --> Empty: resources released
|
||||
```
|
||||
|
||||
OpeningとPasswordRequiredの取消しは、旧文書があればReadyへ戻し、なければEmptyへ戻す。図のFailedはエラー状態を表し、元文書を保持している場合はエラー表示後に旧Readyへ復帰できる。終了要求はどの状態からでも受け付ける。
|
||||
|
||||
ReadyにはnavigationIndex=loadingという独立した副状態を持てる。スクロール・ズームのたびにOpeningへ戻さない。パネル表示は文書状態と独立し、読み込み途中に目次を開いても競合しない。
|
||||
|
||||
## 整合性と取消し
|
||||
|
||||
- 文書切替でgeneration、倍率や向きの変更でrenderRevision、HTML/EPUBの再配置でlayoutRevisionを進める。
|
||||
- PDFium処理は直列キューとし、取消し要求は予約済み処理を除去する。実行中の処理は安全な区切りで止める。
|
||||
- closeは読取チャネルの失効→新規要求停止→実行処理取消し→ワーカー終了→一時資源回収の順。停止不能時は期限付きで強制終了する。
|
||||
- 読書位置の保存は最後に画面へ反映された位置だけを対象とする。未到達のジャンプ要求で保存位置を更新しない。
|
||||
- 戻る/進む履歴は明示ジャンプとリンク移動を単位に記録する。連続スクロールの全フレームは記録しない。
|
||||
|
||||
## エラーの責務
|
||||
|
||||
ワーカーは技術的な原因と位置を返し、Controllerは回復操作へ翻訳する。UIへOSの例外やスタックトレースをそのまま表示しない。利用者が必要とするファイル名・ページ・理由は表示し、ログ側ではパスや本文を原則省く。コード体系と回復策は07を正とする。
|
||||
@@ -0,0 +1,150 @@
|
||||
# 06 設定・保存設計
|
||||
|
||||
## 設定方式
|
||||
|
||||
利用者が編集する設定はUTF-8のTOMLとし、`config.toml`一つを入口にする。初期設定の全項目を記載しなくても、差分だけで上書きできる。`schema_version = 1`で構造の版を識別する。設定から任意のコードやシェルを実行しない。
|
||||
|
||||
優先順位は「組込み既定値 < 利用者設定 < 起動引数で明示した一時上書き」。`--config PATH`は読む利用者設定ファイルを置き換え、二つの利用者設定を暗黙に合成しない。起動引数はファイルパス、設定パス、初期ページ等の限定された項目だけを許可する。読書状態は表示位置の復元にのみ使い、キーや配色の設定より優先させない。
|
||||
|
||||
文書と同じディレクトリにある設定やZIP内部の設定は自動読込みしない。ファイルを開くだけでキーや許可範囲が変更されることを防ぐ。
|
||||
|
||||
## OSごとの配置
|
||||
|
||||
| 種類 | Linux | Windows |
|
||||
|---|---|---|
|
||||
| 設定 | `$XDG_CONFIG_HOME/docview/config.toml` | `%APPDATA%\DocView\config.toml` |
|
||||
| 読書状態・履歴 | `$XDG_STATE_HOME/docview/state.json` | `%LOCALAPPDATA%\DocView\state\state.json` |
|
||||
| キャッシュ | `$XDG_CACHE_HOME/docview/` | `%LOCALAPPDATA%\DocView\cache\` |
|
||||
| ログ | `$XDG_STATE_HOME/docview/logs/` | `%LOCALAPPDATA%\DocView\logs\` |
|
||||
| ZIP等の作業領域 | cache配下の`sessions/<sessionId>/` | cache配下の`sessions\<sessionId>\` |
|
||||
|
||||
Linuxの未設定/空のXDG変数は順に`~/.config`、`~/.local/state`、`~/.cache`へフォールバックする。相対パスのXDG値は仕様に従い無効とする。Windowsは文字列置換した環境変数だけに頼らず、Known Folders APIでRoamingAppDataとLocalAppDataを解決する。QtのQStandardPathsは共通の経路解決を補助するが、AppConfigLocationのWindows既定はLocal側であるため、上記Roaming側設定と混同しない。[XDG仕様](https://specifications.freedesktop.org/basedir/latest/)、[QStandardPaths](https://doc.qt.io/qt-6/qstandardpaths.html)、[Windows Known Folders](https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid)を参照。
|
||||
|
||||
すべてユーザー専用領域とし、Linuxではディレクトリ0700・状態ファイル0600相当、Windowsでは現在ユーザー中心のACLを継承・確認する。インストール先、実行ファイル隣、現在ディレクトリへ暗黙に設定を書かない。
|
||||
|
||||
## 設定項目
|
||||
|
||||
数値は初期提案であり、08の性能測定に合わせて調整する。セキュリティの絶対上限・隔離の有効化は利用者設定で解除できない。
|
||||
|
||||
| キー | 型・既定値 | 範囲/効果 |
|
||||
|---|---|---|
|
||||
| schema_version | integer = 1 | 未知の将来版は適用しない |
|
||||
| ui.theme | string = "dark" | dark / light / system |
|
||||
| ui.status_bar | boolean = true | 状態1行を表示。zsで一時切替 |
|
||||
| ui.toc_visible | boolean = false | 初期の目次表示 |
|
||||
| ui.pages_visible | boolean = false | 初期のページ/章一覧表示 |
|
||||
| ui.font_size | number = 14 | 10〜28論理px、補助UIの文字サイズ |
|
||||
| ui.panel_width | integer = 280 | 160〜600論理px、画面幅でも上限を制約 |
|
||||
| pdf.zoom_mode | string = "fit-width" | fit-width / fit-page / percent |
|
||||
| pdf.zoom_percent | integer = 100 | 25〜800、percent時のみ使用 |
|
||||
| pdf.preserve_colors | boolean = true | 本文の原色を維持。falseは表示フィルターを使う追加提案 |
|
||||
| reading.font_size | number = 18 | 12〜40論理px、流し込みHTML/EPUBの利用者表示設定 |
|
||||
| reading.line_height | number = 1.6 | 1.0〜2.5。著者指定維持との切替を持つ |
|
||||
| reading.use_publisher_style | boolean = true | 既定は著者スタイル。利用者上書き時もwriting-mode等を保持 |
|
||||
| keys.sequence_timeout_ms | integer = 800 | 0(無期限)または200〜3000、複数打鍵の待機。IME合成中は解釈しない |
|
||||
| performance.tile_cache_mib | integer = 256 | 64〜512、PDFタイル予算。総RSS制限ではない |
|
||||
| performance.prefetch_pages | integer = 1 | 0〜3、前後ページ。メモリ圧迫時は自動抑制 |
|
||||
| privacy.remember_position | boolean = true | 読書位置を保存する提案機能 |
|
||||
| privacy.recent_documents | integer = 20 | 0〜100、0で最近使った一覧を無効化 |
|
||||
| privacy.store_text_anchor | boolean = false | 本文断片の永続保存。無効でもCFI/fragment等で復元可能 |
|
||||
|
||||
`pdf.preserve_colors=false`の表示フィルターは原色を変えるため、正確な再現性の受入はtrueで行う。初期実装でフィルターを採用しない場合、falseを未対応として検証エラーにし、黙って受け付けない。
|
||||
|
||||
## 設定例
|
||||
|
||||
以下は設計上の設定例であり、アプリケーションのプログラムではない。通常は変更した項目だけを記述する。
|
||||
|
||||
```toml
|
||||
schema_version = 1
|
||||
|
||||
[ui]
|
||||
theme = "dark"
|
||||
status_bar = true
|
||||
toc_visible = false
|
||||
pages_visible = false
|
||||
font_size = 14
|
||||
panel_width = 280
|
||||
|
||||
[pdf]
|
||||
zoom_mode = "fit-width"
|
||||
zoom_percent = 100
|
||||
preserve_colors = true
|
||||
|
||||
[reading]
|
||||
use_publisher_style = true
|
||||
font_size = 18
|
||||
line_height = 1.6
|
||||
|
||||
[keys]
|
||||
sequence_timeout_ms = 800
|
||||
|
||||
[performance]
|
||||
tile_cache_mib = 256
|
||||
prefetch_pages = 1
|
||||
|
||||
[privacy]
|
||||
remember_position = true
|
||||
recent_documents = 20
|
||||
store_text_anchor = false
|
||||
|
||||
[[keybindings]]
|
||||
mode = "normal"
|
||||
context = "content"
|
||||
keys = ["j"]
|
||||
command = "scroll.down"
|
||||
|
||||
[[keybindings]]
|
||||
mode = "normal"
|
||||
context = "global"
|
||||
keys = ["t"]
|
||||
command = "panel.toc.toggle"
|
||||
|
||||
[[keybindings]]
|
||||
mode = "normal"
|
||||
context = "content"
|
||||
keys = ["]", "]"]
|
||||
command = "nav.heading_next"
|
||||
```
|
||||
|
||||
## キー設定の仕様
|
||||
|
||||
1. 一つのキーは`j`、`J`、`Ctrl+D`、`Alt+Left`、`Esc`のような標準表記とする。大文字と小文字を区別し、印字キーはキーボード配列上の文字として解釈する。物理スキャンコードへの依存は初期版で導入しない。
|
||||
2. `keys`配列は順番に押すキーを表す。`["g", "g"]`、`["Ctrl+W", "w"]`のように記述する。修飾キーの同時押しは一要素に含める。
|
||||
3. `mode`はnormal / command / search / dialogとし、入力欄で合成中のIMEイベントは対応付けより優先する。`context`はglobal / content / toc / pagesとする。commandとsearchの文字入力はユーザーキー設定で奪わない。
|
||||
4. 適用キーは(mode, context, keys)で同定する。利用者設定の同じ組は既定定義を一つ置換する。既定を無効化する場合は`command = "unbound"`とする。同じファイルに同じ組が二つあれば検証エラーとする。
|
||||
5. 現在のパネルcontextを先に、globalを次に評価する。通常モードのtはどのパネルからも目次を切り替えるが、文字入力中のtは入力文字になる。
|
||||
6. `g`と`gg`のように実行コマンドが互いに前方一致する定義は、同時に有効になるcontext間も含めて拒否する。既定のgは未実行の接頭辞なのでggと共存できる。部分列の待機中に不一致のキーが来たら接頭辞を破棄し、新しいキーを一度だけ再評価する。ただし数字Gの入力中は不一致キーも消費し、意図しない操作を起こさない。
|
||||
7. Escは複数打鍵・検索・コマンド・一時モードを抜ける回復手段として予約し、再割当て不可とする。OSが予約するキーやファイル選択ダイアログの標準操作はアプリが横取りしない。
|
||||
8. コマンドID、引数、必要能力を検証する。存在しないIDは保存成功として扱わない。現在の文書で能力がない操作は理由を短く表示する。
|
||||
|
||||
数値付きページ移動`42G`はInput Routerの限定文法として扱い、数字全般の自由なキー再割当てとは衝突させない。詳細なキー一覧・文法・フォーカス動作は04を正とする。
|
||||
|
||||
## 再読込みとエラー
|
||||
|
||||
設定は起動時と`:reload`時に読み込む。初期版はファイル監視による自動適用を行わず、保存途中の内容による揺れを防ぐ。最大設定サイズは1 MiB、入れ子深度やキー数にも上限を設ける。
|
||||
|
||||
読込み→TOML解析→型と値域→キー衝突→コマンド能力→適用計画の順に検証する。全検証が成功した場合だけ設定スナップショットを一括交換する。失敗した場合は直前の有効設定を保持し、行番号・キー・修正理由を表示する。初回起動なら組込み既定値を使う。
|
||||
|
||||
未知のキーは綴り間違いを見逃さないためエラーとする。将来版のschema_versionは読取り専用の説明を表示し、利用者ファイルを自動で書き換えない。移行が必要な場合は変換案とバックアップを用意し、明示操作で保存する。
|
||||
|
||||
配色・パネル・キー・キャッシュ予算は即時反映し、再配置を伴う文字サイズは現在の論理位置を保持して反映する。適用中はキー列を取消し、二重実行を防ぐ。再起動が必要な項目を将来追加するときは、効果発生時点をスキーマに明示する。
|
||||
|
||||
## 読書状態と履歴
|
||||
|
||||
状態は`state.json`へ保存し、`state_version`、文書ID、ファイル識別情報、最終位置、倍率、更新時刻を持つ。アプリ設定は自動で書き換えない。パネルの一時切替はセッション内状態であり、次回起動はconfigの既定へ戻す。
|
||||
|
||||
元ファイルの完全ハッシュは初期表示を妨げない低優先処理にする。最初は正規化したパス・サイズ・更新時刻・利用可能なファイルIDで候補を探す。文書の同一性が確認できない場合は「以前の位置を復元できない」とし、似たファイルへ位置を自動転用しない。ファイルが変更された場合は保存アンカーを再検証し、曖昧なら位置選択を提示する。
|
||||
|
||||
位置は停止後2秒のdebounceと最大10秒間隔を提案し、正常終了時にも保存する。急な終了では直前10秒程度の位置更新を失う可能性がある。保存先と同じディレクトリ内の一時ファイルへ書き、flush後に原子的な置換を使う。前回正常版を1世代だけ残し、破損時はバックアップへ戻す。
|
||||
|
||||
アプリはユーザーごとに一つの状態Writerを持つ。二重起動は既存インスタンスへファイルオープン要求を送る。IPCは同じユーザーのプロセスだけに制限する。ロックが得られない場合は読書専用モードで起動し、設定・状態を競合上書きしない。
|
||||
|
||||
`:history clear`は最近使った一覧、保存位置、textQuote、状態バックアップを消去する提案コマンドとする。実行前に対象件数を表示し、文書原本は含めない。`privacy.remember_position=false`は将来の保存を止める設定であり、既存データの消去とは分ける。
|
||||
|
||||
## 一時データとログ
|
||||
|
||||
ZIP/EPUB作業領域はsessionIdごとに分離し、正常終了で削除する。起動時は自分の未使用セッション領域だけを回収し、他インスタンスが使用中の領域を削除しない。削除対象の実体・所有者・ロックを確認し、シンボリックリンクを追跡しない。
|
||||
|
||||
ログは日時、エラーコード、形式、処理時間、匿名の要求IDを中心とし、原則として本文・パスワード・完全パスを記録しない。ローカルに5 MiB×3世代を提案する。外部送信は行わない。詳細診断を保存する機能を将来設ける場合も、利用者が内容を確認して書き出す方式とする。
|
||||
|
||||
キャッシュは削除しても原本文書と設定に影響しない。履歴や設定の破損で本文が開けなくならないよう、保存処理のエラーは表示処理から切り離す。
|
||||
@@ -0,0 +1,166 @@
|
||||
# 07 セキュリティ・異常系設計
|
||||
|
||||
DocView アプリケーション設計書 | 版 1.0 | 2026-09-19
|
||||
|
||||
対象要件: R01-R04、R09、R11、R12、R14。文書を開く操作が、原本の変更、文書外のファイル読取り、外部送信、任意プログラム実行へ広がらないようにする。
|
||||
|
||||
## 1. 信頼境界
|
||||
|
||||
ローカルにあるPDF、HTML、ZIP、EPUBも未信頼入力として扱う。文書の名前・本文・メタデータに書かれた指示をアプリの命令や設定として解釈しない。文書処理から設定ファイルを読み替えたり、拡張コードを自動ロードしたりしない。
|
||||
|
||||
| 領域 | 許可する処理 | 禁止する処理 |
|
||||
|---|---|---|
|
||||
| Main / FileBroker | UI、検証済み設定、利用者が開いたファイルのhandle管理、限定範囲のIO、IPC検証 | PDF、ZIP、EPUB XML、HTML、CSS、画像の内容解析 |
|
||||
| PDFWorker | 渡されたPDFの解析・描画、限定的なfont資源利用 | ネットワーク、任意ファイル、原本への書込み、外部起動 |
|
||||
| ArchiveWorker | 渡されたZIPの索引・展開、EPUB構造XML、font難読化の処理 | 任意パス作成、ネットワーク、XML外部実体、外部起動 |
|
||||
| WebEngine文書側 | 文書セッション内資源の表示、アプリ管理のDOM位置操作 | 設定・履歴・任意OS API、別文書、遠隔通信、文書JavaScript |
|
||||
|
||||
MainがWorkerから受けた索引・ラベル・URL・画像を無条件に信用すると境界が失われる。型、長さ、整数範囲、参照先、文書世代番号を検査し、描画画像についてもstride、幅、高さ、共有バッファ長を照合する。制御IPCの上限は1 MiB、データチャネルは1チャンク8 MiBを初期値とし、詳細は [データ・内部契約設計](05-data-contracts.md) に従う。
|
||||
|
||||
## 2. OSによる隔離と配布条件
|
||||
|
||||
別プロセスに分けただけではファイルやネットワークへのアクセスを防げない。PDFWorkerとArchiveWorkerにはOSによる制限を設定する。実装前のG0では起動可能性だけでなく、境界の外にある試験ファイルへのアクセス拒否、通信拒否、子プロセス起動拒否、資源上限超過時の停止を実証する。未達の対象OS版は配布しない。
|
||||
|
||||
| OS/実行系 | 採用方針 | G0で確かめること |
|
||||
|---|---|---|
|
||||
| Linux Worker | seccompとLandlockを組み合わせる。要件を満たせない環境は同等の隔離launcherを利用 | 必要ABI・syscall、font読込み、handle受渡し、全threadへの制限、socket・process作成・root外IOの拒否 |
|
||||
| Windows Worker | AppContainerを権限境界とし、Job Objectで寿命・資源・子プロセスを管理 | network capabilityなし、必要handleだけの継承、font依存、DACL、停止・再起動 |
|
||||
| Qt WebEngine | Qt/Chromiumのsandboxを有効のまま利用 | 両OSの配布形態、実際のrenderer隔離、必要なLinux kernel機能、無効化フラグの検知 |
|
||||
|
||||
Landlock単独で全種類の通信制限が揃うとは想定せず、socket等の操作はseccomp側でも制限する。Job Object単独もファイル権限の代替にしない。Workerの許可資源は読取り専用文書handle、限定IPC、必要なfont/runtimeのみとし、ホーム全体や任意ディレクトリーを許可しない。[Linux Landlock](https://docs.kernel.org/userspace-api/landlock.html)、[AppContainerの起動](https://learn.microsoft.com/en-us/windows/win32/secauthz/implementing-an-appcontainer)
|
||||
|
||||
`--no-sandbox`、`QTWEBENGINE_DISABLE_SANDBOX` 等で保護を外す運用を製品の回避策にしない。sandboxが必要条件を満たさない場合は `E_SANDBOX_UNAVAILABLE` を表示し、該当形式を開かない。Qt WebEngineはrendererのsandboxを提供するが、独立したPDFWorkerやArchiveWorkerの隔離までは提供しない。[Qt WebEngine Platform Notes](https://doc.qt.io/qt-6/qtwebengine-platform-notes.html)
|
||||
|
||||
## 3. ZIP・一時資源
|
||||
|
||||
### 3.1 検証と書込み
|
||||
|
||||
ArchiveWorkerは展開前に索引を検査し、Mainも公開対象entryを再検証する。Mainは検証済みの相対名を文書rootのdirectory handleに結び付け、OSのNOFOLLOW相当の手段でファイルを開く。文字列の前方一致だけでroot内と判定しない。Workerはディスク上の任意展開先を指定できない。
|
||||
|
||||
- 絶対パス、ドライブ名、UNC、NUL、`..` セグメント、バックスラッシュ、ADSを作るコロン、Windowsデバイス名を拒否する。
|
||||
- symlink、hardlink、junction/reparse point、device、FIFOを拒否する。通常ファイルとディレクトリーだけを受け入れる。
|
||||
- 正規化後の重複、大小文字・Unicode正規化による衝突、ファイルとディレクトリーの衝突、末尾のドット/空白で曖昧になる名前を拒否する。
|
||||
- アーカイブの所有権、実行権限、ACLを再現しない。ユーザー専用の新しい一時ディレクトリーを作り、他セッションの内容を混ぜない。
|
||||
- 申告サイズだけでなく、Mainへ届いた実展開バイト数を計測する。各entryのCRC・長さ・完了状態が正常になるまで仮想URLから公開しない。
|
||||
- 内側のZIPは再帰展開しない。エラー時に展開途中ファイルを残して再利用しない。
|
||||
|
||||
これらはZIP Slip、リンクを使う脱出、解凍による資源枯渇を別々に防ぐための方針である。[OWASPアーカイブ試験](https://wstg.owasp.org/latest/4-Web_Application_Security_Testing/10-Business_Logic/09-Upload_of_Malicious_Files/)
|
||||
|
||||
### 3.2 上限の初期提案
|
||||
|
||||
数値は原要件にはなく、代表書籍と負荷試験で妥当性を確認する設計値である。初期版では06の利用者設定による緩和を提供せず、ビルド時の有限上限とする。値の変更時は安全試験を再実施し、パス・リンクの検査そのものは無効化できない。
|
||||
|
||||
| 上限対象 | 初期値 | 判定する場所 |
|
||||
|---|---:|---|
|
||||
| ZIP entry数 | 20,000 | Worker索引、Main索引受信 |
|
||||
| 1資源の実展開量 | 256 MiB | WorkerとMainストリーム受信 |
|
||||
| 1文書の実展開量 | 2 GiB | WorkerとMainセッション合計 |
|
||||
| path階層 | 64 | WorkerとMain |
|
||||
| pathのUTF-8長 | 1,024 bytes | WorkerとMain |
|
||||
| 膨張率 | 200倍。実展開量32 MiB超のentryに適用 | Workerの入力消費量/出力量 |
|
||||
| EPUB構造XML 1資源 | 16 MiB | Worker |
|
||||
| XML深さ/要素数 | 128/200,000 | Worker |
|
||||
| 同時資源展開 | 2 | スケジューラー |
|
||||
| 1資源の展開時間 | 10秒で継続表示、30秒で取消 | Main watchdog |
|
||||
| PDFの1要求 | 30秒で長時間処理を通知、120秒でワーカー停止 | Main watchdog。操作取消は待たずに受理 |
|
||||
| PDF/Archiveワーカーのメモリー | 1プロセスあたり1.5 GiBを初期の停止上限とする | OS制限とMain監視。通常時の全体1 GiB目標とは別 |
|
||||
|
||||
絶対サイズを主要防御とし、圧縮率だけで判定しない。CPU・メモリーはWorkerおよびWebEngineの資源監視でも制限する。WebEngineでの画像デコード前に全ピクセル数を安全に判定できるとは想定せず、rendererの応答監視とメモリー超過時の停止を併用する。WebEngineの停止閾値は初期1.5 GiB/rendererを提案し、監視間隔による瞬間的な超過はあり得る。展開先の空き容量不足は上限超過と別のエラーにする。上限を変更した版での再試行時も入口から同じ検査を行う。
|
||||
|
||||
終了時はそのセッションの管理領域だけを削除する。次回起動時の残骸清掃は、所有マーカーと管理下の実体を確認して行う。文書由来のパスを再帰削除の起点にしない。
|
||||
|
||||
## 4. HTML・EPUBの隔離
|
||||
|
||||
### 4.1 独自URLと資源提供
|
||||
|
||||
`doc://<session-token>/...` を `Syntax::Host` で起動初期に登録し、QQuickWebEngineProfileへ専用scheme handlerを入れる。文書ごとのoff-the-record profileを使い、Cookie、localStorage、WebEngine履歴を文書間で継承しない。文書を閉じるとprofileとtokenを破棄する。
|
||||
|
||||
`LocalAccessAllowed`、`ContentSecurityPolicyIgnored`、`ServiceWorkersAllowed`、`CorsEnabled`、`FetchApiAllowed` は付けない。`NoAccessAllowed` によって全資源が別originになる構成も使わず、同一文書内のCSS/font等の互換性を保つ。安全なschemeフラグだけに依存せず、handlerはセッションtoken・initiator・method・相対パス・resource kindを照合する。
|
||||
|
||||
許可methodは読取要求のみ。空initiatorはアプリが発行した既知のトップレベル要求に限定して受け付ける。文書から別tokenを当てられても、tokenの一致と許可資源集合の両方で拒否する。文書URLのtokenを長期履歴やログへ残さない。
|
||||
|
||||
### 4.2 3箇所の制御
|
||||
|
||||
| 制御点 | 役割 |
|
||||
|---|---|
|
||||
| QWebEngineUrlRequestInterceptor | Chromiumのネットワーク層に届く前に、同一文書の許可資源以外を拒否 |
|
||||
| QWebEngineUrlSchemeHandler | 実体root・許可entry・MIME・サイズ・寿命を検査し、読取専用資源を応答 |
|
||||
| WebEngineView.navigationRequested / newWindowRequested | トップレベル遷移、自動遷移、外部ウィンドウ作成を制御 |
|
||||
|
||||
request interceptor内で展開完了を同期的に待たない。許可判定を短時間で終え、資源の非同期応答をhandlerへ委ねる。欠落や取消ではrequest jobを失敗として終了し、jobの破棄に合わせてQIODeviceの寿命も終える。
|
||||
|
||||
外部HTTP(S)リンクはユーザーが選択したときだけMainへ通知し、宛先を表示したうえで「外部ブラウザーで開く」操作によりOSへ渡す。WebEngine内で外部サイトへ遷移しない。未知のスキーム、OSコマンド、メール送信、file URLを一般のURLとして起動しない。
|
||||
|
||||
### 4.3 本文スクリプトとCSP
|
||||
|
||||
MainWorldのJavaScriptを無効にし、ApplicationWorldのアプリ固定コードだけで読書位置・見出しを制御する。汎用WebChannelを公開せず、結果は限定されたcallbackから返す。document内の文字列をJavaScriptソースへ埋め込む方法は使わない。
|
||||
|
||||
scheme handlerの追加応答ヘッダーでCSPを設定する。基本方針は `default-src 'none'`、`script-src 'none'`、`connect-src 'none'`、`object-src 'none'`、`frame-src 'none'`、`form-action 'none'`。画像・fontは同一文書内、CSSは同一文書内と著者のinline styleを許可する。画像のdata URLはimage用途に限定して許可し、top-level documentやSVG scriptの抜け道にしない。`base-uri 'self'` とナビゲーションgateを組み合わせる。
|
||||
|
||||
応答ヘッダーのAPIはQt 6.6以降に存在する。CSPが独自schemeとApplicationWorldで意図どおり動くことをG0で確認し、CSPを迂回するフラグを付けない。CSPを差し込むためにMainで本文HTMLを解析・改変する設計は採らない。[QWebEngineUrlRequestJob](https://doc.qt.io/qt-6/qwebengineurlrequestjob.html)
|
||||
|
||||
カメラ、マイク、位置、通知、screen capture、clipboard、file picker、download、protocol登録は文書からの要求を拒否する。DNS prefetch、link auditing、local-file access、local-to-remote access、WebGL、plugins、WebEngine内蔵PDF viewerを無効にする。WebEngineが要求する権限は既定拒否とし、document内の設定で上書きしない。
|
||||
|
||||
## 5. PDFに固有の制約
|
||||
|
||||
PDFiumはV8とXFAを無効にした構成を基本とする。JavaScript action、Launch action、添付実行、外部自動起動は提供しない。ファイルは読取り専用で開き、PDF保存APIをアプリの操作として公開しない。既存の注釈・フォーム値の静的外観は描画するが、文書へ入力しない。
|
||||
|
||||
暗号化PDFのパスワードはその場の入力だけで受け取り、設定・履歴・ログ・クラッシュ情報に残さない。明示的な再入力を許し、誤りを破損ファイルと混同しない。署名が見えるPDFでも、署名検証を実施したと表示しない。
|
||||
|
||||
ワーカーへ渡すfontは許可集合に限定する。未埋込みfontに対応するためホーム全体を読めるようにしない。悪意あるfont、巨大画像、再帰的なPDF構造もPDFWorkerの時間・メモリー制限で扱う。
|
||||
|
||||
## 6. エラーの共通モデル
|
||||
|
||||
エラーは `code / severity / operation / documentGeneration / resourceId / retryable / userMessage / diagnosticId` を持つ。本文や秘密を含む生データをmessageに連結しない。短い説明と復帰操作を主表示とし、詳細は必要時に開く。繰返し発生する欠落資源は件数をまとめ、キー操作を通知で奪わない。
|
||||
|
||||
| ID | 表示と復帰 |
|
||||
|---|---|
|
||||
| E_OPEN_FAILED | ファイルを開けない。場所・権限を確認し別ファイルを選択 |
|
||||
| E_FORMAT_UNSUPPORTED | 対応形式でない、またはシグネチャ不一致。元文書へ戻る |
|
||||
| E_PASSWORD_REQUIRED | PDFパスワードを入力。取消で元文書へ戻る |
|
||||
| E_PASSWORD_INVALID | パスワードが一致しない。再入力可能 |
|
||||
| E_PDF_CORRUPT | PDFを解析できない。元文書へ戻る |
|
||||
| E_PDF_FEATURE_UNSUPPORTED | 動的XFA等の未対応内容。静的部分が読める場合も制限を通知 |
|
||||
| E_SANDBOX_UNAVAILABLE | 安全な文書処理環境を作れない。該当形式の読込みを停止 |
|
||||
| E_ARCHIVE_UNSAFE_PATH | root外へ出るパス・リンク・衝突を検出。取込みを停止 |
|
||||
| E_ARCHIVE_LIMIT | 件数・実展開量・深さ等の上限。項目と上限を提示 |
|
||||
| E_ARCHIVE_CORRUPT | 索引・長さ・CRCが破損。取込みを停止 |
|
||||
| E_ARCHIVE_ENCRYPTED | パスワード付きZIPは非対応 |
|
||||
| E_HTML_ENTRY_MISSING | HTMLの入口がない。入口候補があれば選択 |
|
||||
| E_RESOURCE_MISSING | 一部資源がない。代替表示で読書を継続 |
|
||||
| E_RESOURCE_BLOCKED | root外・遠隔資源等を遮断。読める部分を維持 |
|
||||
| E_EPUB_PACKAGE_INVALID | package/読書順が確定できない。読込みを停止 |
|
||||
| E_EPUB_NAV_INVALID | nav破損。NCXまたは章一覧へfallback |
|
||||
| E_EPUB_SPINE_MISSING | 該当章が欠落。他の章へ移動可能 |
|
||||
| E_DRM_UNSUPPORTED | 未対応の暗号化・保護方式。解除処理は行わない |
|
||||
| E_LOCATOR_UNRESOLVED | 正確な位置に戻れない。近い位置へ戻ったことを通知 |
|
||||
| E_WORKER_TIMEOUT | 処理期限超過。取消/再読込み/別文書 |
|
||||
| E_WORKER_CRASH | Worker停止。UIを維持し、利用者の明示操作で再試行。繰返す停止ではセッションを閉じる |
|
||||
| E_STORAGE_FULL | 一時領域・状態保存先の空き不足。展開を止めて清掃 |
|
||||
| E_CONFIG_INVALID | 設定エラー。現在の有効設定を維持 |
|
||||
| E_STATE_SAVE | 読書状態を保存できない。閲覧を継続し保存失敗を通知 |
|
||||
|
||||
ファイル切替中の失敗は、コミット前なら元文書と元位置を維持する。操作取消は通常結果として扱い、エラー通知を出さない。深刻な境界違反や繰返すクラッシュでは再試行ループに入らず、その文書セッションを閉じる。
|
||||
|
||||
## 7. 診断情報・更新
|
||||
|
||||
ログは時刻、エラーID、操作、件数、処理時間、依存版を中心とする。本文、パスワード、URL token、任意のローカル絶対パスを既定ログへ記録しない。必要なファイル名も利用者の診断操作で確認できる範囲に留める。クラッシュレポートや利用統計を自動送信しない。
|
||||
|
||||
Qt、Chromium、PDFium、ZIP/XMLライブラリーの依存一覧と版をリリースごとに残す。脆弱性修正時は内容解析器を優先して更新し、PDF描画の回帰と文書隔離試験を行う。更新で無効になった保護を性能改善の名目で省略しない。
|
||||
|
||||
## 8. 必須の境界試験
|
||||
|
||||
受入試験に、path traversal、symlink、大小文字衝突、ZIP bomb、偽の申告サイズ、CRC不一致、XML実体、CSS外部import、外部font、script、iframe、form、meta refresh、file URL、別token、二重percent、Worker偽応答、サイズ不正画像を含める。
|
||||
|
||||
期待結果はUIが落ちないことに加えて、許可外ファイルの読取り・書込み・送信・プログラム起動が発生しないこと。G0では監視用ファイル・通信先を用いて観測する。通常のCSS相対参照やIDPF難読化fontも同時に試験し、防御が正当な書籍を不必要に壊さないことを確認する。
|
||||
|
||||
## 9. 参照資料
|
||||
|
||||
確認日: 2026-09-19。制限値と配布ゲートはDocView独自の設計判断である。
|
||||
|
||||
- [QWebEngineUrlRequestInterceptor](https://doc.qt.io/qt-6/qwebengineurlrequestinterceptor.html) - ネットワーク層より前の要求制御。
|
||||
- [QQuickWebEngineProfile](https://doc.qt.io/qt-6/qquickwebengineprofile.html) - 文書用profileとhandler登録。
|
||||
- [QWebEngineUrlScheme](https://doc.qt.io/qt-6/qwebengineurlscheme.html) - originと権限フラグ。
|
||||
- [QWebEngineSettings](https://doc.qt.io/qt-6/qwebenginesettings.html) - 文書スクリプト・local資源等の設定。
|
||||
- [WebEngineView](https://doc.qt.io/qt-6/qml-qtwebengine-webengineview.html) - 遷移・権限・renderer停止の通知。
|
||||
- [OWASP File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html) - 展開後サイズの制限。
|
||||
@@ -0,0 +1,128 @@
|
||||
# 08 性能・受入試験設計
|
||||
|
||||
## 1. 検証方針
|
||||
|
||||
PDFの正確な表示を最初の品質判断とし、その後にキーボード操作、HTML/ZIP/EPUB、設定、Linux/Windowsでの動作を確認する。要件IDは01に対応する。本書は試験計画であり、アプリケーションの実装、性能計測、各試験の合格を報告するものではない。
|
||||
|
||||
数値は未測定の性能予算である。最低環境、実利用文書、PDFium・Qt WebEngineの組合せを固定して測定し、目標変更が必要な場合は09の意思決定記録へ理由と影響を残す。
|
||||
|
||||
## 2. 受入試験
|
||||
|
||||
### 2.1 試験の読み方
|
||||
|
||||
以下は試験の**設計**であり、合格済みの結果ではない。PDFを優先して実装・検証するが、全要件に対応したリリースの完了判断にはHTML/ZIP/EPUBと両OSの試験が必要となる。
|
||||
|
||||
試験データは再配布権を確認し、ファイルのハッシュ、出典、フォント条件、期待されるページ数・リンク先を固定する。PDF描画の正解画像は評価対象と同じ描画エンジンから作らず、独立した既知の表示環境または原版から用意し、その作成環境を記録する。
|
||||
|
||||
### 2.2 要件対応試験表
|
||||
|
||||
| 試験ID | 要件 | 入力・操作 | 合格条件 |
|
||||
|---|---|---|---|
|
||||
| T01 | R01 | 埋込フォントあり/なし、日本語・縦書き、ベクター、透明合成、画像、各種ページ寸法、回転、CropBoxを含むPDFを開く | 期待する文字・図形・画像が欠落/置換/不正配置されず、ページ寸法・回転・可視範囲が正しい。指定倍率・両OSで確認 |
|
||||
| T02 | R01 | PDFの1ページ目、途中、最終ページへ移動し、ズームを変更する | 正しいページを描画し、古いページの描画結果が現在ページへ混入しない。位置保持規則を満たす |
|
||||
| T03 | R01, R11 | 数千ページのPDFを開いて末尾へ直接移動する | 全ページの描画を待たずに要求ページを処理する。UIが応答し、不要な要求を取り消せる |
|
||||
| T04 | R02 | 相対CSS、画像、文書内アンカー、別HTMLリンクを含むローカルHTMLを開く | 仕様で対応対象の資源を表示し、相対参照とアンカーが正しく解決される |
|
||||
| T05 | R03 | ディレクトリ構造を持つZIP内index.htmlからCSS・画像・別HTMLへ進む | アーカイブ内で参照が解決し、リンク先が正しく表示される。入口不在/複数時は定義した結果になる |
|
||||
| T06 | R04 | EPUB 2/3の目次順とspine順が異なる本、縦書き/RTL、固定レイアウトを開く | 次/前章はspine、目次は目次宛先に従う。章境界、nonlinear項目、書字方向、固定viewportが仕様どおり |
|
||||
| T07 | R05, R15 | マウスなしで開く、スクロール、指定PDFページ移動、目次選択、パネル切替、別文書を開く | すべて実施でき、入力待ちとフォーカスが分かる |
|
||||
| T08 | R05 | 同じキーを内容、目次、ページ一覧、文字入力の各状態で入力する | 状態表どおりに振り分けられ、文字入力中に閲覧位置が変わらない |
|
||||
| T09 | R05, R12 | 日本語IME変換中にj/k、数字、Enter、Escを入力し、日英配列で記号キーを操作する | IME操作が閲覧コマンドにならない。日英配列で設定された論理キーを入力できる |
|
||||
| T10 | R05, R10 | キー列の期限切れ、Esc、フォーカス変更、接頭辞の長押しを試す | 未完のキー列が残らず、予期せぬ操作・連続した表示切替が起きない |
|
||||
| T11 | R06 | PDFの構造見出しのみ/アウトラインのみ/双方あり/双方なし、HTML/EPUBの見出し、同宛先の重複見出しで次/前を操作する | 出典と位置を区別し、04の優先順位で移動する。見出しなしは明示し、推測の見出しを生成しない |
|
||||
| T12 | R07 | 多階層目次を展開/折りたたみ、項目を選択する | 選択だけでは本文を動かさず、確定時に正しい宛先へ移動する。不正な宛先でも他項目を操作できる |
|
||||
| T13 | R08 | 目次・ページ一覧・ステータスを個別に切り替える | 個別に反映し、フォーカス中のパネルを隠すと内容へ戻る。隠れた領域が空白として残らない |
|
||||
| T14 | R08, R15 | 明暗テーマ、100%/200%表示スケールでPDFを表示する | アプリ外観のみテーマが変わり、PDF原文の色を変更しない。主要操作・文字が欠けない |
|
||||
| T15 | R10 | 有効なキー設定と表示設定を書き、再読込する | 全体の検証後に一括適用し、操作一覧も新設定になる |
|
||||
| T16 | R10 | 構文誤り、型誤り、範囲外値、重複/接頭辞衝突のキー設定を読む | 行/項目と理由を知らせ、直前の有効な設定を維持する。部分適用しない |
|
||||
| T17 | R12, R13 | LinuxとWindowsの初回起動、非ASCIIユーザー名、パスに空白、読み取り専用設定ディレクトリで起動する | 各OSの配置規則を満たし、パスを破損しない。書けない場合でも利用可能な既定設定で開始し、対処可能な通知を示す |
|
||||
| T18 | R14 | 静的注釈・popup・widget・保存済みフォーム外観・外観欠落を持つPDFを表示して操作し、終了する | 文書に既にある内容は対応描画範囲に従って表示するが、編集・入力・保存を提供しない。原本ハッシュが変わらない |
|
||||
| T19 | R09 | 設計レビューで別形式アダプターの追加手順と依存関係を追跡する | UI固有処理へパーサーを埋め込まず、文書能力・位置・ナビゲーション契約で接続できる。採否は設計レビュー記録で残す |
|
||||
| T20 | R11 | 次節の代表文書と操作列を両OSで測定する | 合意された測定条件と性能予算を満たす。実測値・分位値・失敗数を記録する |
|
||||
| T21 | R01-R04, R05 | 破損、読めないファイル、必要資源欠損、読込途中でEscを押す、または別文書を開く | 明確なエラーまたは部分表示の状態を示す。クラッシュせず、旧要求の完了が新文書を上書きしない |
|
||||
|
||||
### 2.3 PDF描画の判定
|
||||
|
||||
PDFの正確性を単一の画素一致率だけで判定しない。アンチエイリアスや色管理の違いがあるため、少なくとも以下を確認する。
|
||||
|
||||
1. ページ数、ページ寸法、回転、切り抜き範囲の一致。
|
||||
2. 文字・グリフの欠落、豆腐表示、順序違い、画像欠損、合成順序違いがないこと。
|
||||
3. 正解画像との重ね合わせによる図形・文字位置と可視領域の一致。
|
||||
4. 透明・マスク・グラデーション・色空間など、PDFエンジン依存箇所の目視比較。
|
||||
5. 低倍率・標準倍率・高倍率および表示スケール差の確認。
|
||||
|
||||
差分画像は検出補助として保存し、許容できる縁の差と本文の欠落を分けて判定する。画素差の閾値は代表コーパスで校正してから確定する。現時点で「99%一致なら正確」等の数値を保証値として置かない。
|
||||
|
||||
## 3. 性能測定設計
|
||||
|
||||
### 3.1 指標と暫定目標
|
||||
|
||||
以下の数値は、実測前の**提案する性能予算**であり、現在の達成値ではない。基盤選定時の試作測定で達成可能性を確認し、製品の最低動作環境とともに確定する。
|
||||
|
||||
| 指標 | 起点と終点 | 標準コーパスでの暫定予算 |
|
||||
|---|---|---|
|
||||
| 入力への視覚応答 | キーイベント受領→移動/選択/読込中表示が画面へ提示される | p95 ≤ 50 ms |
|
||||
| 開く操作後の最初の内容表示 | ファイル選択確定→最初に読む内容を判読できるフレーム提示 | アプリキャッシュなしp95: PDF 2 s、HTML 2 s、ZIP HTML 5 s、EPUB 5 s |
|
||||
| キャッシュ済みPDFページ移動 | ページ移動キー受領→対象ページの最終品質フレーム提示 | p95 ≤ 100 ms |
|
||||
| 未キャッシュPDFページ移動 | ページ移動キー受領→対象ページの最終品質フレーム提示 | 標準コーパスp95 ≤ 500 ms |
|
||||
| 継続スクロール | 同一の操作列のフレーム間隔を取得する | 60 Hz環境でp95 ≤ 33 msを目安とする |
|
||||
| プロセス群のメモリ | アプリ・PDFワーカー・WebEngine等を含むRSS合計 | 標準コーパスの通常閲覧で1 GiB以下を目標とする。厳密なハード上限ではない |
|
||||
| キャッシュメモリ | 文書描画キャッシュの実使用量 | 設定上限を超えない。プロセス群のRSSとは別に記録 |
|
||||
|
||||
PDFを開く際に小さいプレビューだけを先に描く設計なら、「最初に判読可能な表示」と「最終品質到達」を別々に測る。HTML/EPUBでは最初の文字だけを出してスタイル適用を遅らせた状態を完了にしない。必要なCSSと表示範囲内の主要な内容が反映された時点を記録する。
|
||||
|
||||
### 3.2 コーパスの構成
|
||||
|
||||
| 区分 | 代表例 | 目的 |
|
||||
|---|---|---|
|
||||
| 標準PDF | 100 MiB以下/500ページ以下の代表群、文字中心、画像混在、埋込日本語フォント | 日常の読書操作と開く時間 |
|
||||
| 重いPDF | 1 GiB/5,000ページ規模の代表群、大きいスキャン画像、複雑な透明/ベクター | 長時間停止を防ぐ処理、キャッシュと取消 |
|
||||
| HTML | 100 MiB以内の参照資源群を持つ長い見出し構造、CSS、ローカル画像 | レイアウト変更と見出し移動 |
|
||||
| ZIP HTML | 圧縮時100 MiB以下、展開後500 MiB以下、複数階層の相対リンク、画像資源が多い書籍 | 展開・入口解決・内部リンク |
|
||||
| EPUB | 100 MiB以下/500 spine項目以下、画像混在、日本語、章数が多い例 | spine移動、章の切替、位置保持 |
|
||||
|
||||
これらのページ数や容量は試験セットの選定目安であり、それだけで入力上限を決定しない。アーカイブ展開量等の安全上限はセキュリティ仕様と整合させる。極端な文書には標準コーパスと同じ表示時間を一律に保証せず、応答・取消・資源上限の維持を優先して別枠で評価する。実際に採用した各ファイルのハッシュと特性を試験報告に固定する。
|
||||
|
||||
### 3.3 再現可能な測定手順
|
||||
|
||||
1. 暫定の基準機は物理4コア相当のCPU、メモリ8 GiB、SSD、内蔵GPU、1,920×1,080/60 Hzとする。LinuxとWindowsの対象バージョン、CPU型番、コア数、メモリ、ストレージ、GPU、ドライバー、表示解像度/倍率、リフレッシュレート、アプリと描画エンジンのバージョンを記録する。同じ構成の比較を基本にする。
|
||||
2. 冷起動はアプリのキャッシュなしで測る。OSファイルキャッシュを消していない場合は、その事実を明記して「完全コールド」と呼ばない。アプリを開き直すだけの試験と区別する。
|
||||
3. 読込試験は文書ごと30回を目安とし、p50/p95、最小/最大、失敗数を報告する。p95の安定性が不足する場合は追加測定する。
|
||||
4. 操作試験は固定したページ/見出し/章の移動列を最低100操作実施し、キャッシュヒットとミスを分離する。入力時刻と実際の画面提示時刻を計測し、要求を送っただけの時刻で完了にしない。
|
||||
5. キー長押し、遠いページへの連続ジャンプ、ウィンドウのリサイズ、別文書への切替を含め、古い仕事を破棄した回数、描画待ちの数、UI停止時間も記録する。
|
||||
6. メモリはアプリ単体と補助プロセスを含むプロセス群を分けて測る。開始時、最大、文書閉鎖後の使用量を記録し、同じ文書を10回開閉して無制限増加しないか確認する。OSのRSSが直ちに基準値へ戻らないことだけでリークと断定しない。
|
||||
7. 最低動作環境の正式決定後、その環境で受入判定する。高性能な開発機だけの達成を製品保証としない。
|
||||
|
||||
## 4. 補助機能の試験
|
||||
|
||||
以下は01・04の追加提案を採用した場合の受入条件である。必須要件の合否と区別する。
|
||||
|
||||
| 試験ID | 対象 | 合格条件 |
|
||||
|---|---|---|
|
||||
| T-P01 | 本文検索 | 日本語/英語で検索でき、`n`/`N`で正しい位置へ移動する。画像PDFは文字情報なしを示し、勝手にOCRを開始しない |
|
||||
| T-P02 | 検索中の入力 | IME変換・Enter/Escが閲覧操作にならない。検索取消後に古い結果が新しい文書へ反映されない |
|
||||
| T-P03 | 位置復元 | 同じ文書の再開位置が復元される。リフロー時は論理位置を使い、原本が変化した場合は不正な位置を適用しない |
|
||||
| T-P04 | 最近使った文書 | 保存上限・無効化・履歴消去が機能する。削除済みの原本は理由を示し、別ファイルとして誤って開かない |
|
||||
|
||||
## 5. 異常系・非機能の追加確認
|
||||
|
||||
07の安全境界の設計が実際に有効であることを、通常文書の試験とは独立して確認する。以下の拒否は仕様に基づく挙動であり、アプリケーションのクラッシュを合格としない。
|
||||
|
||||
| 試験ID | 対象 | 合格条件 |
|
||||
|---|---|---|
|
||||
| T-S01 | ZIPの絶対パス・親ディレクトリ参照・シンボリックリンク・展開量超過 | 07の規則で拒否し、許可ルート外へファイルを書かない。中断した一時領域を回収する |
|
||||
| T-S02 | HTML/EPUBの外部URL・文書スクリプト・フォーム・ローカルルート外参照 | 07の通信/参照規則を守る。文書から任意のファイルやOS機能へ到達できない |
|
||||
| T-S03 | PDFワーカーの異常終了・固まった読込・不正な応答 | UIは応答し、対象文書の失敗を示す。古いワーカー応答を新文書へ適用しない |
|
||||
| T-S04 | データ消去・一時ファイル回収 | 読書履歴等の対象を区別して消去し、原本を消さない。異常終了後の一時領域も起動時の規則で回収する |
|
||||
| T-S05 | 配布物からの初回起動 | WindowsとLinuxの対象環境で依存ライブラリ、サンドボックス、WebEngine資源、ライセンス同梱が成立する |
|
||||
|
||||
## 6. 合否の記録と完了条件
|
||||
|
||||
試験報告には、試験ID、要件ID、対象ビルド、OS/表示環境、文書ハッシュ、手順、期待結果、実結果、証拠画像または計測記録、判定、既知制限、再試験条件を記載する。未実施と失敗を区別し、将来機能の保留を必須要件の合格に置き換えない。
|
||||
|
||||
完成版の受入条件は次のとおり。
|
||||
|
||||
1. R01〜R15に対応するT01〜T21が、対象OSで合格している。PDF描画の対応範囲は03と一致し、検出可能な未対応要素を通知する。実行時に検出できない描画差はコーパスの比較試験で判定する。
|
||||
2. T-S01〜T-S05の隔離・入出力・回復・配布確認が完了している。
|
||||
3. 合意された基準機・コーパスで性能予算を達成している。未達項目があれば、制限と判断を記録して受入判断を行う。黙って目標値を実績値へ書き換えない。
|
||||
4. 補助機能を採用した場合は対応するT-P系列の試験が完了している。
|
||||
5. 残っている問題が、原文の欠落、データ破損、キー操作不能、原本書換え、UI長時間停止を引き起こさない。
|
||||
@@ -0,0 +1,95 @@
|
||||
# 09 技術選定・設計判断・実装ロードマップ
|
||||
|
||||
対象: DocView(仮称)/設計日: 2026-09-19/状態: 設計基準案
|
||||
|
||||
## 1. 採用構成
|
||||
|
||||
**Qt 6 / C++20 / Qt Quick を用いたデスクトップ GUI とし、PDF は独立プロセスの PDFium、HTML と EPUB は Qt WebEngine で表示する。** UI は TUI 風の簡潔な外観と Vim 風キーボード操作を備える。今回の成果物は設計書であり、アプリケーションの実装・試作・性能測定は含まない。
|
||||
|
||||
Qt、PDFium、WebEngine、ZIP ライブラリ、フォント、ビルドツールの具体的な版は、実装開始時にサポート状況と検証結果を確認して固定する。PDFium は公開 C API を使用し、取得元、コミット、ビルドオプション、成果物のハッシュを記録する。最新版へ無条件に追従せず、修正版の評価と回帰試験を伴って更新する。
|
||||
|
||||
## 2. 候補比較
|
||||
|
||||
下表の評価は本アプリケーションの要件に対する設計判断であり、各製品の公式な優劣評価ではない。描画精度の順位を示す比較試験は未実施である。
|
||||
|
||||
| 候補 | 適合する点 | 本件で負担となる点 | 判断 |
|
||||
|---|---|---|---|
|
||||
| Electron + PDF.js | Web 技術による UI、HTML、EPUB の統合が容易。PDF.js を個別更新できる | Electron / Chromium / Node.js / PDF.js の更新と権限境界を管理する。PDF 互換性は別途検証が必要 | 代替候補として保存 |
|
||||
| Qt Quick + Qt PDF + Qt WebEngine | Qt PDF の目次、リンク、検索、ビューア部品を利用できる | 確認した Qt PDF 公開 API に PDF 構造タグの取得 API がなく、アウトラインなしの tagged PDF の見出し対応が不足する | 不採用 |
|
||||
| Qt Quick + 直接 PDFium + Qt WebEngine | PDF 描画、構造、座標の制御を一つのアダプターに集約できる。PDF 処理の障害を GUI から分離できる | ワーカー通信、キャッシュ、表示部品、ビルドと更新管理が必要。構造関連 API の一部は Experimental | 採用設計 |
|
||||
| Qt Quick + MuPDF + Qt WebEngine | PDFium と異なる描画系として比較できる | AGPL または商用ライセンスと配布方針の整合を検討する必要がある。別途統合と検証が必要 | 採用再検討時の候補 |
|
||||
|
||||
公式の機能・ライセンス・API 根拠は [参考資料](10-references.md) の S01-S14 を参照する。PDFium が PDF.js より常に正確、または Qt を使うだけで軽量になるとは判断していない。Qt WebEngine を含めた配布サイズとメモリ量を測定対象にする。
|
||||
|
||||
## 3. 設計判断記録
|
||||
|
||||
| ID | 決定 | 根拠と結果 | 要件 |
|
||||
|---|---|---|---|
|
||||
| ADR-001 | デスクトップ GUI と TUI 風 UI を採用 | 利用者が GUI を選択済み。PDF は本来のレイアウトを保持して描画し、周囲の UI を簡素化する | R01, R05, R08, R15 |
|
||||
| ADR-002 | PDFium の公開 C API を独立ワーカーに集約 | tagged PDF の構造情報と描画を同じ PDF バックエンドで扱う。Qt PDF の private API は利用しない | R01, R06, R07, R09 |
|
||||
| ADR-003 | PDF ワーカー内の PDFium 呼び出しを直列化 | PDFium API は thread-safe ではない。UI と独立したキューで実行し、採用版で確認した中断方法とプロセス終了による回復を設計する | R11, R12 |
|
||||
| ADR-004 | HTML / EPUB に Qt WebEngine を使用 | 現代的な CSS、縦書き、フォント等をブラウザ描画系に委ねる。EPUB のコンテナー、目次、読書順序はアプリ側で扱う | R02, R03, R04, R06, R07 |
|
||||
| ADR-005 | PDF 描画ルートを一本化 | Qt WebEngine 内蔵 PDF ビューアを無効にし、PDF リンクはアプリの PDF オープン処理へ渡す。Qt PDF と直接 PDFium を併用しない | R01, R05, R09 |
|
||||
| ADR-006 | 文書内容とアプリ操作の権限を分離 | 文書を未信頼入力として扱い、文書のスクリプトや設定が任意ファイル・外部通信・OS コマンドへ到達しない境界を設ける | R02, R03, R04, R09, R10 |
|
||||
| ADR-007 | 既存の見出し情報を使う | PDF outline と構造タグ、HTML 見出し、EPUB の目次を区別する。文字サイズからの見出し推定を必須機能にしない | R06, R07 |
|
||||
| ADR-008 | PDF は閲覧専用とする | 元ファイルを書き換えない。既存の注釈や保存済みフォーム appearance の表示と、編集操作の提供を分ける | R01, R14 |
|
||||
| ADR-009 | 設定と文書アダプターを分離 | キー入力はコマンドへ変換し、フォーマット固有処理はアダプターへ委譲する。設定ファイルは OS の慣習に沿って配置する | R05, R09, R10, R13 |
|
||||
| ADR-010 | 初期サポート OS を明示する | Linux 全般という無限定な互換性保証を避け、実機検証済みの組合せをサポート表で公開する | R12 |
|
||||
|
||||
Qt WebEngine 自体にも PDFium 由来コードが含まれ得るため、ADR-005 は配布物全体から PDFium の重複がなくなることを意味しない。独自 PDF ワーカーと WebEngine は、それぞれの依存部品と更新責任を記録する。
|
||||
|
||||
## 4. 実装前の技術ゲート
|
||||
|
||||
G0は以下の技術ゲート一式を実施する段階の総称である。以下は後続実装で採用構成を確定するための条件である。本設計時点で合格を確認したものではない。画質判定と性能の定量基準は品質・試験設計に定義する。
|
||||
|
||||
| ゲート | 検証内容 | 合格条件・証跡 | 不合格時の判断 |
|
||||
|---|---|---|---|
|
||||
| G-RENDER | 代表 PDF の描画。日本語横組み・縦組み、埋込/非埋込フォント、CID/CMap、透明、クリップ、画像、回転/CropBox、ICC/CMYK、既存注釈、保存済みフォーム appearance | 人が承認した正解画像との比較と差分レビューを完了。文字・図の欠落、誤配置、読めない描画が残っていない | PDFium の設定・版を見直す。要件を満たせなければ別エンジンを比較し ADR を更新 |
|
||||
| G-HEADINGS | outline なしの H/H1..H6、RoleMap、複数 MCID、Form XObject、回転、ページにまたがる構造 | 見出し列と順序が妥当で、正しいページ・位置へ移動する。座標が得られない場合のページ単位移動を区別して報告できる | 必要な公開 API の不足を特定。黙ってタグ対応を省略せず、アダプター/エンジンの再選定へ戻る |
|
||||
| G-SANDBOX | Linux と Windows の PDF ワーカー権限制限、クラッシュ回復、IPC 境界 | 許可された入力と通信のみ成功。任意パスの読取・書込、外部通信、子プロセス生成を拒否する試験の記録。GUI が継続しワーカーを再作成できる | 配布対象ごとに制限方式を再設計。sandbox を無効化する起動オプションを通常運用の解決策にしない |
|
||||
| G-WEB | 文書別 origin、文書スクリプト抑止、アプリ所有の isolated world 操作、読み取り範囲、ページ遷移、リンク、ダウンロード、通信遮断、内蔵 PDF ビューア無効 | HTML / EPUB の表示と見出し操作が機能し、書籍からアプリ権限や許可外リソースへ到達しない。通常 HTML と ZIP / EPUB の双方で確認 | Qt WebEngine 設定・scheme handler・操作経路を修正。文書 JavaScript を広く許可して回避しない |
|
||||
| G-DISTRIBUTION | クリーン OS 環境での配布と依存・ライセンス確認 | ランタイム、プラグイン、WebEngine 補助プロセス、フォント、PDFium 等の不足なし。配布物と対応ソース・告知・依存一覧の対応が確認済み | パッケージと採用条件を見直して再試験 |
|
||||
|
||||
PDF 正解画像は一つのビューアの出力だけで無条件に決めない。仕様に基づく期待、複数の独立した描画系、元文書の作成条件、人による確認を使う。アンチエイリアスの軽微な差と内容の欠落を同じ問題として扱わない。特殊な印刷表現や壊れた文書は、対応範囲・既知制約を明記する。
|
||||
|
||||
PDFium の構造タグ API には Experimental な項目がある。必要な API の一覧、固定コミット、文字列長・寿命・エラー処理、MCID と座標の対応を検証記録に残す。見出しのラベルを得ても、正しい位置へ移動できたとは判定しない。
|
||||
|
||||
## 5. OS と配布方針
|
||||
|
||||
| 環境 | 初期方針 | 必須確認 |
|
||||
|---|---|---|
|
||||
| Windows 11 x64 | 正式サポートの提案対象 | クリーン環境、表示倍率、IME、非 ASCII パス、ワーカー権限、署名済み配布物、アンインストール |
|
||||
| Ubuntu 24.04 x64 | 正式サポートの提案対象。X11 / Wayland を個別に確認 | GPU と software rendering、フォント、IME、ファイル選択、sandbox、Qt / WebEngine の共有ライブラリ依存 |
|
||||
| Fedora x64 | 追加検証対象 | 対象版を実装時に選定。Wayland、SELinux、ライブラリ、sandbox、パッケージ形式を検証してからサポートを宣言 |
|
||||
| その他 Linux、Windows on ARM、旧 Windows、macOS | 初期の正式サポートに含めない | 要望と検証コストに基づき別途追加 |
|
||||
|
||||
Qt の一般的なサポート対象と、本アプリケーションで検証した対象は区別する。Qt WebEngine には独自のビルド制約があり、一般的な Qt 構成のすべてを利用できるわけではない。確認した資料では Windows の MinGW ビルドは Qt WebEngine に適合せず、静的ビルドも非対応である。[Qt WebEngine Platform Notes](https://doc.qt.io/qt-6/qtwebengine-platform-notes.html)
|
||||
|
||||
Windows は MSVC 系の Qt と互換性のあるツールチェーンを使い、PDFium のビルドは upstream の Clang 系要件と整合させる。Linux では対象環境に合う共有ライブラリと sandbox を梱包・依存解決する。具体的なパッケージ形式は G-DISTRIBUTION で比較し、初期対象ごとに一つを決める。単一実行ファイル化や任意 Linux での起動を前提にしない。
|
||||
|
||||
ライセンスはライブラリ名だけで結論を出さず、実際に同梱する版・モジュール・ビルド方式で確認する。Qt 商用ライセンスの採用だけで Chromium 等の第三者条件が消えるとは扱わない。MuPDF は代替評価対象にとどめ、ライセンス整理を行わず自動フォールバックとして同梱しない。
|
||||
|
||||
## 6. 後続の実装順序
|
||||
|
||||
| 段階 | 完了させるもの | 次へ進む条件 |
|
||||
|---|---|---|
|
||||
| 0. 設計基準の固定 | 対応範囲、テスト文書、参照画像、初期 OS、設定形式、依存版、ライセンス方針 | 未決事項の担当と期限が決まり、上記ゲートの評価環境が用意されている |
|
||||
| 1. PDF 基盤の検証 | 描画、構造見出し、座標、ワーカー制御、権限制限、最小配布経路 | G-RENDER / G-HEADINGS / G-SANDBOX を満たし、配布成立の見通しがある |
|
||||
| 2. PDF 閲覧機能 | 通常表示、移動、拡大縮小、目次、見出し、ページ一覧、設定、状態復元 | PDF の機能・性能・操作性の受入試験に合格 |
|
||||
| 3. HTML / ZIP HTML / EPUB | パッケージ読込、リソース解決、目次、見出し、読書順序、位置復元 | G-WEB と各形式の受入試験に合格 |
|
||||
| 4. 製品化 | OS 別配布、クリーンインストール、更新、障害回復、ヘルプ、告知文書 | 全対象 OS の回帰試験と G-DISTRIBUTION に合格 |
|
||||
|
||||
PDF 最優先は開発・検証順序を意味する。最終的な初期リリースが要件を満たすためには、HTML、ZIP HTML、EPUB を含む全必須要件を受け入れる必要がある。PDF のみの中間成果物を要件一式の完成とは扱わない。
|
||||
|
||||
## 7. 継続管理する不確実性
|
||||
|
||||
| 項目 | 設計時点の扱い | 解消時点 |
|
||||
|---|---|---|
|
||||
| 実際の書籍での PDF 描画互換性 | 代表コーパスは後続で収集・承認。完全一致は未保証 | G-RENDER |
|
||||
| tagged PDF の全構造と座標 | 公開 API による経路を採用し、特殊構造は要検証 | G-HEADINGS |
|
||||
| PDFium の固定版と更新頻度 | 実装開始時にコミットを固定し、脆弱性・互換性を継続評価 | 段階 0 以降 |
|
||||
| ワーカーの OS 別権限制限 | 別プロセス化と sandbox を別の要件として扱う | G-SANDBOX |
|
||||
| WebEngine の文書操作と無権限化の両立 | 文書の JavaScript とアプリ所有の操作を区別して検証 | G-WEB |
|
||||
| 配布ライセンスとパッケージ方式 | 実際の依存集合に基づいて固定 | G-DISTRIBUTION |
|
||||
| 性能の成立 | 品質・試験設計の測定条件と合格値を使用。未測定 | 各段階の受入試験 |
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# 10 参考資料
|
||||
|
||||
確認日: 2026-09-19
|
||||
|
||||
一次資料を用いて API、機能、ライセンス表記、サポート条件を確認した。Web 上の最新資料は変更されるため、実装開始時には採用版に対応した資料・ソースコミットも固定する。以下の資料は設計の根拠であり、本アプリケーションの描画品質、性能、ライセンス適合性を実証するものではない。
|
||||
|
||||
## 1. PDF と技術選定
|
||||
|
||||
| ID | 資料 | 本設計で確認した事項 |
|
||||
|---|---|---|
|
||||
| S01 | [PDFium README](https://pdfium.googlesource.com/pdfium/+/refs/heads/main/README.md) | Linux / Windows のビルド経路、JavaScript / XFA のビルド選択、公開 API の範囲、ピクセル試験の存在 |
|
||||
| S02 | [PDFium fpdfview.h](https://pdfium.googlesource.com/pdfium/+/main/public/fpdfview.h) | 公開 C API、読込と描画、API が thread-safe ではないこと |
|
||||
| S03 | [PDFium fpdf_structtree.h](https://pdfium.googlesource.com/pdfium/+/main/public/fpdf_structtree.h) | ページの構造ツリー、要素型、子要素、MCID の取得。一部 API が Experimental であること |
|
||||
| S04 | [PDFium fpdf_edit.h](https://pdfium.googlesource.com/pdfium/+/main/public/fpdf_edit.h) | ページオブジェクトの読取、MCID と境界情報へのアクセス。ファイル名に edit を含むが、読取 API の参照に使う |
|
||||
| S05 | [PDFium LICENSE](https://pdfium.googlesource.com/pdfium/+/refs/heads/main/LICENSE) | PDFium のライセンス本文。依存部品の条件を含めて確認する起点 |
|
||||
| S06 | [Qt PDF](https://doc.qt.io/qt-6/qtpdf-index.html) | Qt PDF の描画、ビューア、目次、リンク、検索等の機能 |
|
||||
| S07 | [QPdfDocument](https://doc.qt.io/qt-6/qpdfdocument.html) | 読込、描画、ページラベル、テキスト、エラーの公開 API。構造タグ API の有無を評価する対象 |
|
||||
| S08 | [Qt PDF Licensing](https://doc.qt.io/qt-6/qtpdf-licensing.html) | Qt PDF の商用 / LGPLv3 / GPLv2 表記と、PDFium スナップショット・第三者ライセンス |
|
||||
| S09 | [PDF.js 公式サイト](https://mozilla.github.io/pdf.js/) | PDF.js の位置づけと Apache 2.0 の表記 |
|
||||
| S10 | [PDF.js FAQ](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions) | ブラウザ環境による対応差、Worker と本体のバージョン整合、可視ページを優先するメモリ上の考え方 |
|
||||
| S11 | [Electron Security](https://www.electronjs.org/docs/latest/tutorial/security) | Node.js 能力の分離、context isolation、sandbox、IPC 検証、依存更新の必要性 |
|
||||
| S12 | [Electron Releases](https://www.electronjs.org/docs/latest/tutorial/electron-timelines) | 直近三つの stable major release というサポート方針と更新周期 |
|
||||
| S13 | [What is MuPDF?](https://mupdf.readthedocs.io/en/latest/guide/what-is-mupdf.html) | PDF 等の閲覧・変換・操作のためのライブラリとツールという位置づけ |
|
||||
| S14 | [MuPDF License](https://mupdf.readthedocs.io/en/latest/license.html) | AGPL または商用ライセンスという提供形態 |
|
||||
|
||||
## 2. Qt WebEngine と配布
|
||||
|
||||
| ID | 資料 | 本設計で確認した事項 |
|
||||
|---|---|---|
|
||||
| S15 | [QWebEngineSettings](https://doc.qt.io/qt-6/qwebenginesettings.html) | MainWorld の JavaScript、ローカルファイル/外部 URL、DNS prefetch、内蔵 PDF ビューア等の設定 |
|
||||
| S16 | [Qt WebEngine Platform Notes](https://doc.qt.io/qt-6/qtwebengine-platform-notes.html) | Chromium renderer の sandbox、Linux の実行条件、C++20、Windows ビルド制約、静的ビルド非対応 |
|
||||
| S17 | [Qt WebEngine Licensing](https://doc.qt.io/qt-6/qtwebengine-licensing.html) | Qt 部分と Chromium 側の両方の条件が関係すること、第三者ライセンスの一覧 |
|
||||
| S18 | [Deploying Qt WebEngine Applications](https://doc.qt.io/qt-6/qtwebengine-deploying.html) | 補助プロセス、リソース、翻訳等を含む配布の検討事項 |
|
||||
| S19 | [Qt Supported Platforms](https://doc.qt.io/qt-6/supported-platforms.html) | Windows 11 / Ubuntu 24.04 の掲載、版ごとのサポート条件、モジュール固有の例外 |
|
||||
|
||||
## 3. 文書形式・隔離・保存
|
||||
|
||||
| ID | 資料 | 本設計で確認した事項 |
|
||||
|---|---|---|
|
||||
| S20 | [PDFium fpdf_formfill.h](https://pdfium.googlesource.com/pdfium/+/main/public/fpdf_formfill.h) | フォーム環境とwidget描画。通常ページ描画との違い |
|
||||
| S21 | [EPUB 3.3](https://www.w3.org/TR/epub-33/) | package、spine、nav、rendition、font難読化 |
|
||||
| S22 | [EPUB Reading Systems 3.3](https://www.w3.org/TR/epub-rs-33/) | rootfile、XML処理、スクリプトfallback、ローカル参照の制約 |
|
||||
| S23 | [EPUB CFI 1.1](https://idpf.org/epub/linking/cfi/epub-cfi.html) | 文書の論理位置表現 |
|
||||
| S24 | [QWebEngineScript](https://doc.qt.io/qt-6/qwebenginescript.html) | ApplicationWorld、DOMアクセスと変数の分離 |
|
||||
| S25 | [WebEngineView](https://doc.qt.io/qt-6/qml-qtwebengine-webengineview.html) | runJavaScriptのworld、ナビゲーション・権限の通知 |
|
||||
| S26 | [QWebEngineUrlScheme](https://doc.qt.io/qt-6/qwebengineurlscheme.html) | Host構文によるoriginとscheme権限 |
|
||||
| S27 | [QWebEngineUrlSchemeHandler](https://doc.qt.io/qt-6/qwebengineurlschemehandler.html) | 文書資源の応答 |
|
||||
| S28 | [QWebEngineUrlRequestJob](https://doc.qt.io/qt-6/qwebengineurlrequestjob.html) | Qt 6.6以降の追加応答ヘッダー |
|
||||
| S29 | [QWebEngineUrlRequestInterceptor](https://doc.qt.io/qt-6/qwebengineurlrequestinterceptor.html) | 要求の事前検査 |
|
||||
| S30 | [QQuickWebEngineProfile](https://doc.qt.io/qt-6/qquickwebengineprofile.html) | 文書ごとのprofileとhandler |
|
||||
| S31 | [Linux Landlock](https://docs.kernel.org/userspace-api/landlock.html) | OSアクセス制限とABIによる機能差 |
|
||||
| S32 | [Windows AppContainer](https://learn.microsoft.com/en-us/windows/win32/secauthz/implementing-an-appcontainer) | 制限されたプロセス環境の構成 |
|
||||
| S33 | [OWASP Archive Testing](https://wstg.owasp.org/latest/4-Web_Application_Security_Testing/10-Business_Logic/09-Upload_of_Malicious_Files/) | 不正アーカイブの試験観点 |
|
||||
| S34 | [OWASP File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html) | 解凍後サイズの制限 |
|
||||
| S35 | [XDG Base Directory](https://specifications.freedesktop.org/basedir/latest/) | 設定・状態・キャッシュの配置と既定値 |
|
||||
| S36 | [QStandardPaths](https://doc.qt.io/qt-6/qstandardpaths.html) | OS別保存経路、AppConfigLocationとAppDataLocationの差 |
|
||||
| S37 | [Windows Known Folders](https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid) | RoamingAppDataとLocalAppData |
|
||||
|
||||
## 4. 参照の読み方
|
||||
|
||||
- **資料の事実:** 公開 API の存在、スレッド安全性の注意、ライセンス表記、サポート対象等。上表に対応する一次資料で確認する。
|
||||
- **設計判断:** Qt Quick と直接 PDFium の組合せ、ワーカー分離、初期 OS、PDF 描画ルートの一本化等。[技術選定・設計判断](09-decisions-roadmap.md) の ADR に記録する。
|
||||
- **未検証事項:** 対象書籍の描画互換性、特殊な構造見出しの座標、実機性能、OS 別 sandbox、最終配布物。公式資料に機能があることだけで合格とせず、受入試験で確認する。
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"00-guide.md": "179fa4a28b5ba994d3d71ffca310da78f071520f9fc8b18f529e5e5f2210ac38",
|
||||
"01-requirements.md": "ee35438cf3c749b7410db2b1e4b941dd3a5fc1e3b4bb1cd6c0e3cf6056c34961",
|
||||
"02-architecture.md": "afbc10d91dc6ddcd9727f3af1b861535c6d9e6da977ac19a9e2ad55c49bf83c3",
|
||||
"03-formats.md": "5590019c96f8935175670b9d1a4876d5f365303e63c53953de006cde105eaa53",
|
||||
"04-ui-navigation.md": "9ccb90ad0549c8a8dc41b2d883842ebcf28358796398cf62c36e218980387456",
|
||||
"05-data-contracts.md": "2b9d28523e68950b48d57db363c663416c957145ad3f4e460774ac3740287a71",
|
||||
"06-config-storage.md": "c7e00e61f686c36288a87f01dc00429a68174001984def78b75446b1e6c954ed",
|
||||
"07-security-errors.md": "855450a9791dce0e6afb9f0e18f2f5bbd7b6cecfe6cf8c5ad677ac2af5608c8a",
|
||||
"08-performance-tests.md": "eb852e6b6016e732c715ed061ea25ed1a911c092bb6de6e71aabbf4acb4f6483",
|
||||
"09-decisions-roadmap.md": "55c176637d017acc66b46ba1780100854f671442d465c329b5d258f4c8fb2ebb",
|
||||
"10-references.md": "4d0614abd7104a1e68c3b061fc797c3e1576d1127907a08c75c6e008da2ca0da"
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
# Font broker contract
|
||||
|
||||
This implementation supplements design 03 §3.2 and 05. The selected font is
|
||||
transferred as an immutable, bounded byte snapshot through the existing IPC
|
||||
connection. No filesystem path or OS font handle crosses the boundary. The
|
||||
main process selects fonts through Fontconfig on Linux and GDI on Windows;
|
||||
PDFium and SFNT/TTC table parsing remain inside the sandboxed PDF worker.
|
||||
See [the API investigation](font-broker-plan.md) for pinned upstream evidence.
|
||||
Windows implementation and native Windows execution are separate claims;
|
||||
consult [the validation record](VALIDATION.md) for actual execution coverage.
|
||||
|
||||
## Request envelope and identity
|
||||
|
||||
Only a `WorkerProcess` with an explicitly registered font handler accepts
|
||||
`font.map`, `font.read`, or `font.close` requests. Production registers the
|
||||
handler only for PDF workers. Requests use the current parent operation's
|
||||
`sessionId`, `generation`, and `requestId`. The payload contains a positive,
|
||||
monotonically increasing `fontRequestId`; the result or error repeats it.
|
||||
Only one font request may be outstanding. These are control frames, with no
|
||||
streaming `more` field and the existing 1 MiB encoded control-frame limit.
|
||||
Unknown fields, wrong types, stale identities and unissued handles are rejected.
|
||||
|
||||
The main process routes font requests before ordinary PDF responses. It never
|
||||
finishes or replaces the active PDF operation or extends its deadline as a
|
||||
side effect. The callback API removes `fontRequestId` from request/result maps;
|
||||
the transport layer owns that field. Broker completion returns either the
|
||||
inner result map or `{error: {code, message}}`. Cancellation discards pending
|
||||
completion and invalidates issued handles. A parent timeout error can end a
|
||||
pending font request without interpreting it as successful font acquisition.
|
||||
|
||||
| Operation | Additional payload fields | Additional result fields |
|
||||
| --- | --- | --- |
|
||||
| `font.map` | `faceLocal` bytes, `weight` integer, `italic` boolean, `charset` integer, `pitchFamily` integer | `found` boolean. If true: `fontId`, `actualFaceLocal`, `charset`, `size`, `sha256`, `substituted`, and exactly one of `faceIndex` / `faceOffset` |
|
||||
| `font.read` | `fontId`, `offset`, `length` | Same `fontId` / `offset`, and exactly `length` bytes in `data` |
|
||||
| `font.close` | `fontId` | `released: true` |
|
||||
|
||||
Names use the system local encoding as required by the pinned PDFium public
|
||||
API, contain no NUL, and are at most 256 bytes. Requested names may be empty;
|
||||
selected names must not be empty. Weight is 0–1000. Charset is one of
|
||||
0, 1, 2, 128, 129, 134, 136, 161, 163, 177, 178, 204, 222, 238.
|
||||
Pitch/family accepts family values 0x00–0x50 in steps of 0x10 with pitch 0–2.
|
||||
Names are typed family values, never fontconfig pattern expressions or paths.
|
||||
The font ID is 32 lowercase hexadecimal characters, scoped to one service.
|
||||
SHA-256 is 32 raw bytes. Face index is 0–65535; face offset is inside the snapshot.
|
||||
|
||||
## Limits and errors
|
||||
|
||||
| Resource | Bound |
|
||||
| --- | --- |
|
||||
| Snapshot | 64 MiB per font/collection |
|
||||
| Read | 1–65536 bytes; checked against the issued snapshot's actual size |
|
||||
| Open font handles | 16 per session |
|
||||
| Different selection requests | 256 per session, including misses |
|
||||
| Total transferred font bytes | 512 MiB per session |
|
||||
| Worker snapshot cache | 128 MiB; live callback references cannot be evicted |
|
||||
| Broker snapshots | 256 MiB across active, staging and revoked services; global LRU of unreferenced snapshots |
|
||||
| OS font threads | Two per application process; excess services fail explicitly |
|
||||
| Broker task queue | Eight entries per service (production wire permits only one pending request) |
|
||||
| One reply / complete font fetch | 5 seconds / 15 seconds, within the unchanged parent deadline |
|
||||
|
||||
`E_FONT_LIMIT` is a new registered error for these resource bounds. It is not
|
||||
reported as a missing font. `E_FONT_FAILED` is a new registered error for OS
|
||||
font acquisition, unsupported/invalid font data. A snapshot hash or wire mismatch uses the protocol-failure path.
|
||||
Existing `E_WORKER_TIMEOUT` and `E_WORKER_CRASH` represent transport/deadline
|
||||
failure. All four font error maps contain `fontRequestId`, `code`, and a
|
||||
nonempty message of at most 4096 characters. Malformed reverse RPC uses the
|
||||
existing worker protocol-failure path. A genuine absent match is the success
|
||||
result `found: false`; PDFium may use its built-in fallback and the adapter
|
||||
records a warning. A communication/resource error must fail the PDF operation.
|
||||
Fatal font errors remain sticky for the adapter lifetime, because PDFium may
|
||||
have cached an internal substitute during the failed call. Retry requires a
|
||||
new worker/document; clearing only the error would hide that failed selection.
|
||||
|
||||
## Execution and font data
|
||||
|
||||
Normal PDF operations run from a queued invocation after the transport's
|
||||
receive stack unwinds. Font responses are routed during the bounded nested
|
||||
wait without reentering PDFium or starting another PDF operation. Main-thread
|
||||
GUI processing never waits for Fontconfig/GDI. Revocation prevents new work
|
||||
and drops late callbacks, while an already running OS call retains its bounded
|
||||
thread and snapshot charges until cleanup. Snapshot eviction considers unused
|
||||
entries across services, so an old document cannot monopolize reclaimable
|
||||
cache space while a new document opens. In-process test/low-memory constructor
|
||||
arguments may lower the cache bound; they cannot raise the production cap.
|
||||
|
||||
The worker always installs `FPDF_SYSFONTINFO` version 2. A missing provider
|
||||
does not reactivate PDFium's default filesystem font mapper. The production
|
||||
Linux worker receives no font-directory grants. Downloaded chunks must match
|
||||
declared size and SHA-256 before the immutable snapshot reaches PDFium.
|
||||
|
||||
For a TTC, `ttcf` returns the complete collection and table zero returns the
|
||||
bytes from the selected face offset to the end. A normal table tag resolves
|
||||
through that face's checked directory. A short non-null caller buffer is
|
||||
zero-initialized and filled with the available prefix; the required size is
|
||||
returned. This also supports the pinned PDFium mapper's 1024-byte checksum
|
||||
read. Font parsing rejects out-of-range tables, invalid collection indices and
|
||||
duplicate table tags. Static TTF/OpenType/collections are the initial scope;
|
||||
named variable instances are not silently mapped to face zero. A collection
|
||||
may contain at most 256 faces and each face at most 4096 table entries. These
|
||||
parser bounds are separate from the wire field range for an OS face index.
|
||||
|
||||
Font substitution depends on installed candidates. Fixed aliases and family
|
||||
priorities are maintained in `src/broker/font_backend.cpp`; selected family,
|
||||
charset, face metadata and substitution status describe the actual result.
|
||||
The synthetic unembedded Japanese H/V corpus exercises native CID writing
|
||||
modes. Its independent-renderer comparison is additional evidence, not a
|
||||
human-approved golden image or a claim about every PDF CMap.
|
||||
@@ -0,0 +1,300 @@
|
||||
# PDF font broker 実装計画
|
||||
|
||||
調査日: 2026-09-19。対象: PDFium 155.0.8057.0、固定 commit
|
||||
`a5a7089234f121990b336b3841008009dca143bf`、Qt 6.11.2。
|
||||
この文書は実装前の調査・計画を保存したものである。現在の実装契約は[font-broker-contract.md](font-broker-contract.md)、実行結果は[VALIDATION.md](VALIDATION.md)を参照。以下の「現行」「未実装」は調査時点を指し、Windowsの実行確認を示すものではない。
|
||||
|
||||
## 結論
|
||||
|
||||
最小の推奨構成は、Main 側の FontBroker が OS font 索引と選択を管理し、
|
||||
PDFWorker の公開 `FPDF_SYSFONTINFO` version 2 callback から、既存 IPC を使う
|
||||
限定的な逆方向 RPC で選択済み font のバイト列を取得する方式である。
|
||||
font の表・glyph の解析は PDFWorker 内に残す。Main に PDFium をリンクしない。
|
||||
新しい socket、継承 handle、任意パス指定、font ディレクトリーの Worker 読取り権限は追加しない。
|
||||
|
||||
バイト列方式なら Linux の SCM_RIGHTS と Windows の起動後 handle 複製を別実装にせず、
|
||||
現在の socket/匿名 pipe で共通化できる。全 font の先行転送ではなく、要求された font のみを
|
||||
64 KiB ごとの明示的な read 要求で取得する。巨大な TTC の一括 IPC frame も避けられる。
|
||||
|
||||
現行 `src/pdf/main.cpp:16` は `/usr/share/fonts`、`/usr/local/share/fonts`、
|
||||
`/etc/fonts`、`/var/cache/fontconfig` を Worker に許可している。これは削除対象である。
|
||||
固定版 Linux PDFium の既定実装は fontconfig ではなく、フォルダー列挙と独自の
|
||||
CJK 代替候補を使う。したがって Broker を fontconfig に替えるだけで、同一 Linux 上でも
|
||||
未埋込み font の選択が変化し得る。
|
||||
[固定版 Linux 実装](https://pdfium.googlesource.com/pdfium/+/a5a7089234f121990b336b3841008009dca143bf/core/fxge/linux/fx_linux_impl.cpp)
|
||||
|
||||
## PDFium 公開 API の適用
|
||||
|
||||
ローカル `.deps/pdfium/include/fpdf_sysfontinfo.h` の 49–52 行に version 2 の
|
||||
per-request matching があり、86–87 行では EnumFonts を呼ばないことが明記されている。
|
||||
version 2 は experimental のため、この固定版への依存と更新時の回帰試験を明記する。
|
||||
private header の include や private symbol の利用は不要である。
|
||||
|
||||
| Callback/公開関数 | 推奨実装 |
|
||||
| --- | --- |
|
||||
| `FPDF_SetSystemFontInfo` | `FPDF_InitLibraryWithConfig` 後、文書読込み前に Worker 専用 adapter を登録 |
|
||||
| `MapFont` | weight/italic/charset/pitch-family/face を Broker へ送り、選択済みバイト列を得て Worker 内 `FontBlob` を返す |
|
||||
| `GetFont` | version 2 では主経路でないが、同じ選択処理への限定 wrapper として用意 |
|
||||
| `GetFontData` | Worker の immutable blob から全体または選択 face の table を返す。パスを開かない |
|
||||
| `GetFaceName`/`GetFontCharset` | Broker の選択結果を返す。要求名を実際の選択名として偽装しない |
|
||||
| `DeleteFont` | Worker の callback handle を破棄。PDFium が保持するコピーとは寿命を分離 |
|
||||
| `Release` | `FPDF_DestroyLibrary` まで adapter 自体を生存させる。二重解放しない |
|
||||
|
||||
`MapFont` の face は公開 header 上「system local encoding」であり、無条件に UTF-8 と
|
||||
解釈しない。callback 側で最大 256 bytes まで NUL を探し、raw bytes を RPC に載せる。
|
||||
Broker が当該 OS の同一規約で解釈し、別名表に照合する。埋込み font の処理は既存 PDFium
|
||||
のまま維持する。custom adapter が欠けた状態で既定 filesystem font mapper に戻す経路は設けない。
|
||||
[公開 API と固定版 wrapper](https://pdfium.googlesource.com/pdfium/+/a5a7089234f121990b336b3841008009dca143bf/fpdfsdk/fpdf_sysfontinfo.cpp)
|
||||
|
||||
想定する内部 API は次の程度に限定する。名前は実装時に確定する。
|
||||
|
||||
```cpp
|
||||
struct FontRequest {
|
||||
QByteArray faceLocal; // <= 256 bytes, no embedded NUL
|
||||
int weight; // 0..1000
|
||||
bool italic;
|
||||
int charset; // supported FXFONT_* values
|
||||
int pitchFamily; // accepted pitch/family bits only
|
||||
};
|
||||
struct SelectedFont {
|
||||
QByteArray fontId; // opaque, scoped to this worker session/generation
|
||||
QByteArray actualFaceLocal;
|
||||
int charset;
|
||||
quint64 size;
|
||||
QByteArray sha256;
|
||||
int faceIndex; // Linux FC_INDEX for a supported static face
|
||||
quint64 faceOffset; // Windows GDI-derived TTC face offset; otherwise unset
|
||||
bool substituted;
|
||||
};
|
||||
// Broker-owned asynchronous service; no PDFium dependency.
|
||||
// select(request), read(fontId, offset, length), release(fontId), revoke(session)
|
||||
// Worker-owned synchronous callback adapter over the routed async transport.
|
||||
// fetchSelected(request) -> immutable FontBlob
|
||||
```
|
||||
|
||||
## RPC 契約
|
||||
|
||||
新 operation は `font.map`、`font.read`、`font.close` の三つとする。
|
||||
既存 envelope の `protocolVersion/sessionId/generation/requestId/operation` と
|
||||
`payload` XOR `result/error` を維持する。`requestId` は現在実行中の親 PDF 要求の ID、
|
||||
各 payload と result/error の `fontRequestId` は Worker が単調増加させる副要求 ID とする。
|
||||
同時に保留する副要求は一つだけである。
|
||||
|
||||
| Operation | Worker → Broker payload | Broker → Worker result | 主な照合 |
|
||||
| --- | --- | --- | --- |
|
||||
| `font.map` | `fontRequestId, faceLocal, weight, italic, charset, pitchFamily` | `fontRequestId, found`。found=true のとき `fontId, actualFaceLocal, charset, size, sha256, faceIndex/faceOffset, substituted` | PDFWorker にだけ有効。現在の親 requestId/session/generation 一致。文字列をパスや fontconfig pattern 構文として解釈しない |
|
||||
| `font.read` | `fontRequestId, fontId, offset, length` | `fontRequestId, fontId, offset, data` | ID は同セッションに発行済み、`1 <= length <= 65536`、加算 overflow と `offset+length <= size` を確認。返却サイズは要求どおり |
|
||||
| `font.close` | `fontRequestId, fontId` | `fontRequestId, released:true` | 発行済み ID を一度だけ解放。revoke 後の ID は無効 |
|
||||
|
||||
全応答は control frame のまま 1 MiB 以下とし、64 KiB を超える data は拒否する。
|
||||
`more` は使わず、一回の read に一回の応答を返す。最終 size と SHA-256 が一致してから
|
||||
blob を PDFium に公開する。CRC 等の font 内容検証を Main で行う意味ではなく、転送を
|
||||
途中で使わないための完整性確認である。
|
||||
|
||||
Broker の受信側は通常 PDF 応答を照合する前に、`payload` を持つ三つの font operation を
|
||||
専用分岐へ送る。通常の `active_` を完了させず、キューを進めず、親 deadline を延長しない。
|
||||
不正な role/ID/offset/連続要求は既存の protocol failure として Worker を停止する。
|
||||
ArchiveWorker と試験用一般 worker には、このサービスを明示的に登録しない。
|
||||
ファイル名や fontconfig の `FC_FILE` は応答に含めない。
|
||||
|
||||
font が存在しない場合は `found:false` として PDFium 内部代替と UI の代替警告を許す。
|
||||
通信破損、資源上限超過、timeout は font 不在と区別し、当該 PDF 操作を失敗させる。
|
||||
新規 error code を増やす場合は data contract に登録し、未定義の code を先行実装しない。
|
||||
|
||||
## 同期 callback、deadlock、取消
|
||||
|
||||
現在の `src/pdf/main.cpp` は `IpcChannel::messageReceived` の direct slot 内で PDFium
|
||||
を呼ぶ。そのまま callback 内で `QEventLoop` を回して font を待ってはいけない。
|
||||
Qt の `readyRead` は再帰的に再送されず、Windows の現 `WindowsPipeDevice::completeRead`
|
||||
も `emit readyRead()` の後に次の `beginRead()` を置いている。いずれも受信処理の
|
||||
stack を抜ける前に次の受信を待つ構成が停止の原因になる。
|
||||
[QIODevice の通知規約](https://doc.qt.io/qt-6/qiodevice.html#readyRead)
|
||||
|
||||
1. Worker の受信 slot は envelope と状態を検証する router にする。通常の PDF 要求は
|
||||
一件だけ保存し、`Qt::QueuedConnection` または queued invocation で後から実行する。
|
||||
queued 実行が始まる前から reserved 状態とし、二件目の通常要求を通さない。
|
||||
2. PDFium 処理は受信通知の stack を抜けた後、引き続き同じ Worker thread で実行する。
|
||||
PDFium の並列呼出しや新 Worker thread は導入しない。
|
||||
3. callback の同期待ちは、該当 font 応答・transport failure・副要求 deadline だけで解決する。
|
||||
router は font 応答を通常要求の handling guard より先に処理する。待機中に他の PDF
|
||||
操作を実行しない。callback から C++ exception を C ABI 越しに送出しない。
|
||||
4. Main の選択/ファイル読取りは専用 Broker thread に非同期で渡す。HDC と fontconfig
|
||||
config はその thread が所有する。Main UI thread で同期待ちをせず、font 選択処理から
|
||||
Worker の応答を待たない。送信時に Worker の生存・session・generation を再確認する。
|
||||
5. Worker 停止/新 generation/staging 取消で Broker の ID と待機処理を revoke する。
|
||||
進行中 OS API の終了を GUI が待つ必要はない。遅れて来た結果は捨てる。既存の process
|
||||
kill と親 deadline が最終的な中断手段になる。単なる検索キュー破棄では、現在の render
|
||||
に必要な font を revoke しない。
|
||||
|
||||
QueuedConnection は受信側 event loop へ制御が戻ってから slot を実行する。
|
||||
同じ thread で `BlockingQueuedConnection` を使う方式は採らない。
|
||||
[Qt connection type](https://doc.qt.io/qt-6/qt.html#ConnectionType-enum)
|
||||
|
||||
## OS ごとの Broker 選択
|
||||
|
||||
### Linux
|
||||
|
||||
Broker が `FcInitLoadConfigAndFonts`/`FcFontList` または `FcConfigGetFonts` で許可索引を作り、
|
||||
font のファミリー・style・charset coverage・`FC_FILE`・`FC_INDEX` を内部に保存する。
|
||||
Worker の値は `FcPatternAddString` 等の typed API の値として渡し、`FcNameParse` に流さない。
|
||||
固定 alias と優先順位を先に適用し、`FcConfigSubstitute`、`FcDefaultSubstitute`、
|
||||
`FcFontMatch`/必要なら限定した `FcFontSort` の順で選ぶ。OpenType weight は
|
||||
`FcWeightFromOpenType` で変換し、固定幅/serif/italic と charset に対応する言語を保持する。
|
||||
`FcFontMatch` は事前 substitution が必要であり、`FC_INDEX` はファイル内の face index である。
|
||||
[Fontconfig 一次リファレンス](https://fontconfig.pages.freedesktop.org/fontconfig/fontconfig-devel/)
|
||||
|
||||
結果は Broker が構築した索引内の候補に再照合する。Worker からファイル、ディレクトリー、
|
||||
fontconfig config、`FC_FT_FACE`、任意 pattern オブジェクトを受け取らない。選ばれた索引の
|
||||
ファイルを Broker が read-only で開き、通常ファイルとサイズを確認して bounded snapshot
|
||||
を作る。索引作成時と file identity が変わっていれば、その候補を再索引または拒否する。
|
||||
font 更新との競合でバイト列が壊れても、font 内容を解析するのは隔離 Worker である。
|
||||
索引の入力は OS/アプリの font 設定だけであり、PDF 内の添付 font を fontconfig に登録しない。
|
||||
|
||||
単に `sans:lang=ja` に委ねることは固定順序の代わりにならない。今回の環境では
|
||||
`fc-match 'sans:lang=ja'` と `serif:lang=ja` が両方 `FORM UDPGothic` を返した。
|
||||
これは環境の観測であり一般的な fontconfig の保証ではない。
|
||||
|
||||
### Windows
|
||||
|
||||
Broker が `EnumFontFamiliesExW` で名前・style・charset の索引を作る。候補を
|
||||
`LOGFONTW` と `CreateFontIndirectW` で作成し、Broker 専有 HDC へ `SelectObject` して
|
||||
`GetTextFaceW`/`GetTextMetricsW` で実際の選択を検証する。要求名がそのまま選ばれる保証は
|
||||
ないので、許可索引と alias 規則に照合する。HDC と HFONT は Broker thread だけで使い、
|
||||
元の選択 object を戻してから `DeleteObject`/`DeleteDC` する。
|
||||
[列挙](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-enumfontfamiliesexw)、
|
||||
[論理 font の選択](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createfontindirectw)、
|
||||
[LOGFONTW](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfontw)
|
||||
|
||||
`GetFontData` で選択済み font をバイト列にする。collection は GDI の `'ttcf'`
|
||||
`0x66637474` で全体を取得し、table 0 のサイズとの差から選択 face の offset を求める。
|
||||
通常の TTF/OTF は table 0。`GDI_ERROR`、0、上限超過を失敗として扱う。Worker に HFONT
|
||||
や HDC は渡さない。font ファイルパスの探索も Worker へ移さない。必要追加 library は
|
||||
Broker target の `gdi32` だけである。
|
||||
[GetFontData の全体・collection・サイズ取得](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getfontdata)
|
||||
|
||||
OS font のバイト列はプロセス内の表示用途とし、文書への再埋込みや配布用ファイル生成を
|
||||
この機能に含めない。同梱 font は別途、配布許諾・LICENSE・hash を固定する。
|
||||
|
||||
## TTC、table、short buffer の具体的な注意
|
||||
|
||||
公開 API に faceIndex を直接 PDFium へ渡す欄はない。固定版 `GetCachedTTCFace` は
|
||||
`ttc_size - data_size` を face offset とし、それを collection 内の face index に戻している。
|
||||
そのため Linux の `FC_INDEX` も Windows の選択済み HFONT も、下表の callback の振舞いへ
|
||||
変換しなければならない。全ファイルだけを table 0 として返す実装では collection の
|
||||
選択 face が失われる。
|
||||
[固定版 mapper の TTC 経路](https://pdfium.googlesource.com/pdfium/+/a5a7089234f121990b336b3841008009dca143bf/core/fxge/cfx_fontmapper.cpp#784)
|
||||
|
||||
| 入力/状況 | Worker adapter の契約 |
|
||||
| --- | --- |
|
||||
| 単独 TTF/OTF、table 0 | ファイル全体の size/bytes |
|
||||
| 単独 TTF/OTF、`0x74746366` (`ttcf`) | 0、collection ではない |
|
||||
| TTC、`ttcf` | collection 全体の size/bytes |
|
||||
| TTC、table 0 | `collectionSize - selectedFaceOffset`。必要な bytes は selectedFaceOffset から末尾まで |
|
||||
| 通常の table tag | 選択 face の directory を参照。tag は PDFium 側の big-endian 数値、offset/length は checked arithmetic で blob 内に制限 |
|
||||
| `buffer == nullptr` または size 0 | 必要サイズだけ返す |
|
||||
| buffer が足りる | 全対象 bytes をコピーし、コピーしたサイズを返す |
|
||||
| 小さい非 NULL buffer | 最大 buf_size だけ prefix を埋め、公開 header に従い必要サイズを返す。後述の固定版 1024-byte 読取りを試験する |
|
||||
|
||||
TTC header の offsets と各 SFNT table directory を Worker の bounded reader で解析する。
|
||||
offset は collection の先頭を基準とする。face count、table count、offset + length、重複 tag、
|
||||
選択 index を検証し、Main にこの font parser を置かない。
|
||||
[OpenType collection と table directory](https://learn.microsoft.com/en-us/typography/opentype/spec/otff#font-collections)
|
||||
|
||||
固定版 `GetChecksumFromTT` は 1024 bytes の buffer を渡し、返却サイズを使わず、その
|
||||
buffer から checksum を計算する。したがって「短い buffer では何も書かず必要サイズだけ
|
||||
返す」という解釈では未初期化 bytes が残る。adapter は buffer 範囲を初期化し、存在する
|
||||
prefix を必ず埋める。短い collection の場合の余りはゼロにする。この挙動は公開 API
|
||||
記述だけから推定せず、固定版実装を対象とする回帰試験にする。
|
||||
[固定版 checksum 呼出し](https://pdfium.googlesource.com/pdfium/+/a5a7089234f121990b336b3841008009dca143bf/core/fxge/cfx_fontmapper.cpp#333)
|
||||
|
||||
Windows GDI は tag の整数 byte order が異なる。PDFium の既定 Windows adapter も
|
||||
`FromBE32(table)` で変換してから GDI に渡している。Worker の SFNT reader と GDI の
|
||||
`GetFontData` を同じ tag 値で無条件に呼ばない。
|
||||
[固定版 Windows adapter](https://pdfium.googlesource.com/pdfium/+/a5a7089234f121990b336b3841008009dca143bf/core/fxge/win32/cwin32_platform.cpp#456)
|
||||
|
||||
初期対応は static TTF/OpenType/TTC/OTC とする案を推奨する。variable font の named
|
||||
instance、色付き font、Type1 の扱いを実装せずに対応済みとはしない。索引にはあっても
|
||||
未対応なら別の静的候補を選び、代替を記録する。variable instance を黙って face 0 として
|
||||
渡す方式は採らない。これらは既存 mapper に対する潜在的な互換性縮小である。
|
||||
|
||||
## 上限と lifetime の初期案
|
||||
|
||||
以下は設計書に既存の値ではなく、font broker 向けの提案値である。CJK collection の実測と
|
||||
性能試験で妥当性を確認してから contract に固定する。
|
||||
|
||||
| 対象 | 初期上限案/扱い |
|
||||
| --- | --- |
|
||||
| face 名 | raw bytes 256、embedded NUL 拒否 |
|
||||
| 1 font/collection snapshot | 64 MiB。超過時は別候補、なければ明示的制限 |
|
||||
| 1 read | 64 KiB、同時副要求 1、write queue に全体を先積みしない |
|
||||
| font 選択 handle | session 内 16、通常は map→read 全体→close で短く保持 |
|
||||
| Broker snapshot cache | 全体 256 MiB、参照中を避ける LRU。複数 session 合計で計測 |
|
||||
| Worker font blob cache | 128 MiB。callback handle が参照中の blob を捨てない |
|
||||
| session の異なる選択数/転送累計 | 256/512 MiB。repeated malicious names による無制限列挙を防ぐ |
|
||||
| RPC 待機 | 1応答 5秒、1 font 取得全体 15秒。成功 chunk ごとに全体期限を延長しない |
|
||||
| 全体の処理 | 既存親要求期限と 1.5 GiB Worker 制限を維持。font 待機もその中に含める |
|
||||
|
||||
64 MiB は未検証の大きな CJK collection を切り捨て得るため、上限到達を「font が無い」と
|
||||
黙って扱わない。PDFium 自身の font cache も bytes を複製するので、adapter cache のみを
|
||||
数えて 1.5 GiB を守れたと判断しない。Broker の snapshot と OS index は Worker から
|
||||
呼び出せる任意ファイル読み取りサービスに拡張しない。
|
||||
|
||||
## 固定 alias と回帰 corpus
|
||||
|
||||
fontconfig の全ホスト設定を置き換えるのではなく、アプリが管理する候補順を先に試す。
|
||||
例として Base14 の Courier/Helvetica/Times と各 bold/italic を個別の entry にし、
|
||||
承認した同梱書体、既知の metrically compatible OS 書体、最後に charset/family に沿う
|
||||
OS 選択という順を固定する。Symbol/ZapfDingbats は generic sans に置換せず、既存の
|
||||
PDFium 内蔵経路または専用の承認候補を維持する。
|
||||
|
||||
日本語は Gothic/Mincho、等幅/比例、weight/italic、英語名/ローカル名を分ける。
|
||||
`@` で始まる縦書き face、Shift-JIS に由来する face 名、CJK の charset を別ケースとして
|
||||
試験する。alias の具体的な font を決める前に、対象 OS に存在することと配布条件を確認する。
|
||||
試験用 BIZ UDPGothic の埋込み許諾が確認済みでも、それだけで製品の全 fallback 資産が揃った
|
||||
ことにはならない。
|
||||
|
||||
| Corpus/試験 | 固定する観測と合格条件 |
|
||||
| --- | --- |
|
||||
| 既存埋込み日本語/画像/透明合成/CropBox PDF | font broker を入れる前後で選択・glyph・配置が変わらない。埋込み font を system font に置換しない |
|
||||
| 既存 `unembedded-font.pdf` | 現在は Standard-14 の限定 corpus。選択 family/file hash/style を記録し、Poppler 対照と文字位置・幅を比較 |
|
||||
| 新規未埋込み日本語 | 正しい CID encoding を持つ horizontal/vertical の原本を生成。単に subset font stream を削除する方式は glyph ID が変わるため用いない |
|
||||
| alias/weight/italic/symbol | exact installed name、Base14 alias、不在名、日本語ローカル名、記号をそれぞれ検証。Broker が選んだ実名と hash も期待値に含める |
|
||||
| TTC の複数 face | 同一 collection の異なる faceIndex を描画し、face 0 固定にならないこと。table offset/collection read/1024-byte prefix を単体試験 |
|
||||
| malformed font bytes | truncated directory、過大 table count、範囲外 offset、加算 overflow、重複 tag、短い buffer を Worker adapter 単体で拒否 |
|
||||
| sandbox 攻撃 | font broker 正常動作中でも Worker から font directory/設定/無関係ファイルを open できない。path 風 face 値を使っても任意パスを読まない |
|
||||
| RPC/取消 | 偽 fontId、別 generation、重複応答、途中切断、読取り範囲超過、response timeout、font 取得中の close/kill、遅い応答を投入。UI が待ち合わせで停止しない |
|
||||
| lifecycle/メモリー | 一覧にない要求の連打、font 名の大量変化、TTC 再利用、長時間読書を測定。Broker と Worker 両方のメモリー、送信 queue、UI 応答を記録 |
|
||||
| 両 OS | alias policy、選択結果、PDFium adapter が同じでも OS font の bytes が違う点を記録。Windows は native 環境で実施するまで未検証 |
|
||||
|
||||
この検証は固定 corpus に対する互換性範囲を増やすもので、欠けた元 font の完全再現や
|
||||
任意 PDF の一致を保証しない。既存 Linux/Poppler 比較は embedded 日本語と Standard-14 を
|
||||
中心にしており、未埋込み日本語・TTC・variable instance の新経路の合格証拠にはならない。
|
||||
|
||||
## 必要変更箇所と実装順
|
||||
|
||||
| 場所 | 変更 |
|
||||
| --- | --- |
|
||||
| 新 `src/common/font_contract.*` | font RPC の型・値・サイズ・role・ID 検証。QtCore のみ |
|
||||
| 新 `src/broker/font_broker.*` | OS index、alias、選択、snapshot と quota。PDFium 非依存。OS backend は別ファイルに分割 |
|
||||
| 新 `src/pdf/system_font_adapter.*` | 公開 SYSFONTINFO、immutable blob、checked SFNT/TTC reader。PDFWorker/adapter test にだけリンク |
|
||||
| `src/common/ipc.*` | 三 operation の許可と envelope の限定拡張。control/data 上限は増やさない |
|
||||
| `src/common/worker_process.*` | font request の role 分岐、親 active 保持、応答送信、deadline、stop 時 revoke |
|
||||
| `src/pdf/main.cpp` | router と queued PDF 実行、font response 待機、font directory 権限の全削除 |
|
||||
| `src/pdf/pdf_document.*` | adapter を init 時登録し destroy まで保持。テストは explicit in-memory font provider を注入可能にする |
|
||||
| `src/app/controller.*` | PDF session だけに Broker を登録。代替・制限警告と寿命管理 |
|
||||
| `CMakeLists.txt` | Broker Linux backend に fontconfig、Windows backend に gdi32。Main に `docview_pdf`/PDFium を追加しない |
|
||||
| tests/fixtures/results | 契約、callback、実 IPC、sandbox denial、両 OS 描画比較を追加 |
|
||||
|
||||
実装順は、(1) memory-only callback と TTC 単体試験、(2) bounded font 契約+偽 provider で
|
||||
同一 transport の応答/取消/deadlock 試験、(3) Linux index と alias、(4) font directory
|
||||
権限を外した PDFWorker で回帰、(5) Windows GDI backend と native gate とする。
|
||||
最初の callback 実装と IPC 試験は独立して進められるが、権限削除だけを先行して
|
||||
既定 font mapper の失敗を内部 fallback で隠さない。
|
||||
|
||||
## 調査の検証範囲
|
||||
|
||||
公開 local header、固定 commit の PDFium 公式ソース、Fontconfig・Qt・Microsoft の一次資料を
|
||||
読んで確認した。Linux の fontconfig 2.18.3 と現在の `fc-match` 選択を読み取りで確認した。
|
||||
この調査では production code を変更せず、callback prototype の実行、逆方向 RPC、GDI の
|
||||
native 実行は行っていない。上限値・alias の最終集合・描画閾値は、実装と corpus 計測で
|
||||
確定する必要がある。
|
||||
@@ -0,0 +1,44 @@
|
||||
# メモリ圧迫への対応
|
||||
|
||||
原設計02「キャッシュと資源管理」と06「先読みの自動抑制」を実装する。
|
||||
描画キャッシュの設定値とは別に、OSが報告する利用可能な物理メモリを監視する。
|
||||
Linuxでは `/proc/meminfo` の `MemTotal` / `MemAvailable`、Windowsでは
|
||||
`GlobalMemoryStatusEx` の物理メモリ値を用いる。1秒間隔で読み、圧迫状態の変化を
|
||||
Controllerへ通知する。パーサーワーカーにはこの監視を追加しない。
|
||||
|
||||
## 閾値と遷移
|
||||
|
||||
閾値は実装時に決めた暫定値であり、原設計08の性能予算を変更しない。
|
||||
|
||||
- 空きが総物理メモリの10%未満、かつ1 GiB未満になったら先読みを止める。
|
||||
- 同条件が続くと、5サンプルごとに不可視キャッシュ回収、解像度抑制、文書処理停止へ進む。
|
||||
- 空きが3%未満、かつ256 MiB未満の場合は、毎サンプル1段階ずつ進む。処置の順を飛ばさない。
|
||||
- 空きが15%以上、または1.5 GiB以上の状態が5サンプル続いたら通常状態へ戻す。
|
||||
- 取得失敗、不正な数値、欠損、重複、オーバーフローは状態を維持し、連続判定をリセットする。
|
||||
不明な値を空きゼロや回復として扱わない。
|
||||
|
||||
監視はOSの物理メモリ報告に基づく。cgroup固有の割当量、GPUメモリ、仮想アドレス空間の
|
||||
残量をこのサンプルから推測しない。これらを含む全種類の割当失敗を予知する保証ではない。
|
||||
既存のworker資源上限、renderer監視、キャッシュ予算と併用する。
|
||||
|
||||
## 文書処理
|
||||
|
||||
PDFの先読み停止は設定値を書き換えず、既存の描画世代を失効させる。
|
||||
不可視キャッシュは位置が変わった後も回収し、表示中の画像を優先する。
|
||||
解像度抑制では論理倍率とページ・注釈座標を変えず、描画時の画素密度を原則半分にする。
|
||||
workerが受け付ける最小倍率・DPRを下回らないよう制限する。読書位置を維持し、通知する。
|
||||
低解像度画像が揃った後に旧画像を回収する。回復時は通常の解像度で再描画する。
|
||||
|
||||
HTML/ZIP/EPUBのWebEngine内部キャッシュや描画解像度を外部から操作したとは扱わない。
|
||||
これらは圧迫継続の通知と、最終段階での資源提供・renderer・展開処理の停止を適用する。
|
||||
最終段階では読込中の新文書を取り消し、現在の文書の処理を止め、PDF画像も回収する。
|
||||
状態は `Recovering` とし、原本へ書き込まない。圧迫中の新規openを拒否する。
|
||||
メモリが回復しても停止した文書は自動で再読込せず、利用者が明示的に開き直す。
|
||||
|
||||
## 検証方法
|
||||
|
||||
メモリを実際に枯渇させず、同じ監視・Controller・Canvas経路へ有限のサンプルを注入する。
|
||||
状態遷移、閾値境界、破損サンプル、ヒステリシス、先読み・キャッシュ・解像度・座標の保持、
|
||||
取消、原本ハッシュ、停止後の明示的再openを試験する。Linuxの実サンプル取得も別に確認する。
|
||||
この方法をOS全体のOOM耐性試験やWindows実行の証拠とはしない。結果は
|
||||
[検証記録](VALIDATION.md)へ記録する。
|
||||
@@ -0,0 +1,64 @@
|
||||
# PDF Form構造見出しアダプターの実装契約
|
||||
|
||||
状態: **実装済み、Linux回帰確認済み**(2026-09-19)。当初のForm-only構造を取得できない制約は、Worker内の共有qpdfメタデータ読取で解消した。本書は実装範囲を記録し、全OS・任意の実文書に対するG-HEADINGS合格を宣言するものではない。[試験記録](../tests/results/pdf-structure/README.md)、[合成資料の期待値](../tests/fixtures/pdf/headings/manifest.json)を参照。
|
||||
|
||||
## 構成と所有権
|
||||
|
||||
`PdfDocument`は一つの`PdfMetadataContext`を作り、`LinkBorderReader`と`StructureReader`で共有する。qpdf 12.4.1はPDFWorkerだけのprivate依存であり、MainにはPDF解析オブジェクトを渡さない。元の読み取り専用QFileとパスワードをPDFium/qpdfの双方が使用し、パスからの再openや原本への保存を行わない。qpdf入力の論理オフセットは独立し、各読取でQFileをseekする。終了時は両reader、context、PDFium document、入力の順で破棄する。
|
||||
|
||||
構造解析は`headings(page)`時だけ行う。open時に全構造・全ページを走査しない。共有contextは生のページ木を順番に検証し、読んだページ参照を保持する。探索の例外後はそのcontextのページ探索を停止し、次要求で壊れたノードを飛ばしてページ番号を詰めることを禁止する。
|
||||
|
||||
qpdf 12.4.1の`setMaxWarnings(nonzero)`には、初期parseでページ木を走査・修復する副作用があるため使用しない。公開`QPDFLogger::setWarn`の破棄Pipelineで、初期解析を含め警告32行・64KiBを制限する。sinkは警告本文を保持・出力せず、超過はstickyにして以降の入力読取でも停止する。qpdfはsinkを呼ぶ直前に警告を内部へ追加するため、境界を越えた最後の1件は内部に存在し得る。xref回復は無効である。この選択はnull Kid保持、32/33警告、初期警告bytes超過の回帰で検証した。[qpdf 12.4.1 Objects::parse](https://github.com/qpdf/qpdf/blob/v12.4.1/libqpdf/QPDF_objects.cc)、[Pages::cache](https://github.com/qpdf/qpdf/blob/v12.4.1/libqpdf/QPDF_pages.cc)
|
||||
|
||||
## 構造の所有元と順序
|
||||
|
||||
対象ページと実際に`Do`で呼ばれたFormの`StructParents`から、`ParentTree`のNums/Kidsを解決する。リソース辞書にあるだけの未使用Formは見出し候補にしない。候補の`P`をたどってH/H1–H6を得て、各祖先の順序付き`K`内の位置から表示順を決める。RoleMapは循環と深さを検証する。文字の大きさから見出しを推測しない。
|
||||
|
||||
`K`の整数MCID、MCR、配列、子StructElemを同じ順序で展開する。`Pg`は最寄りの構造祖先から継承し、局所指定を優先する。`Stm`付きMCRの所有元はそのForm object/generation、なしならページである。**MCID単独をキーにせず、所有元object/generationと組にする。** 各参照をParentTreeへ逆照合し、その所有元のMCIDが同じ見出しの祖先経路に属することを確認する。子要素のP/K不一致も拒否する。
|
||||
|
||||
跨ページのHはページ別fragmentとして返す。同一ページ内では構造オブジェクト同一性で重複を除き、同名の別見出しは統合しない。これにより、ページ、別Form、別ページに同じ数値MCIDがあっても文字や位置を借用しない。
|
||||
|
||||
## PDFiumオブジェクトとの対応
|
||||
|
||||
固定PDFium公開APIはFormの元stream object番号を返さない。このためqpdfの公開tokenizerで、ページと使用Formの`q/Q/cm/Do`、`BDC/BMC/EMC`、名前付きProperties、Form MatrixとResourcesを解析する。画像Doは構造Formに数えず、inline imageは画素を復号しない。未知演算子は対応の信頼性を下げ、壊れたgraphics stackは制約応答にする。
|
||||
|
||||
PDFium側は公開Form/PageObject APIで親子関係、局所行列、直接のMCID集合を集める。親ごとに行列とMCID集合が一意に合うFormだけを対応させ、列挙順で決めない。固定版ではFormオブジェクトのGetMatrixは呼出元CTMを示し、そのForm自身のMatrixは子オブジェクトの行列に含まれる。非identity Matrixを持つ入れ子の資料で、この扱いとページ座標を検証している。
|
||||
|
||||
`FPDFText_GetTextObject`から文字の所有Formを得て、対応済みの所有元付きMCIDへ文字とbboxを集める。`FPDFText_GetCharBox`はページuser spaceなのでForm行列を再適用しない。exactのx/y/rectは従来のPDF-point契約を保つ。位置の往復変換はCropBox、ページRotate、ユーザー回転0/90/180/270度で0.5pt以内を検証する。
|
||||
|
||||
## 応答とfallback
|
||||
|
||||
| 条件 | 応答 |
|
||||
|---|---|
|
||||
| 構造上のH、ページ、所有元、文字bboxを一意に確認 | `source=pdf-tag, precision=exact`、x/y/rect |
|
||||
| Hとページを確認したがForm対応が曖昧、同じFormを複数回呼出、文字bboxなし | `precision=page`と具体的reason。確認済みの文字、ActualText/T/Alt、名称なしの順でtitleを選ぶ。推測した座標は付けない |
|
||||
| ページ/所有元を確認できない、ParentTree不整合、P/K/RoleMap/Form循環 | 空見出しと`structureLimited=true`、固定の`unavailableReason`。未確認を正常な「見出しなし」にしない |
|
||||
| 解析quota超過 | `structureLimited=true, truncated=true, complete=false` |
|
||||
| 応答件数/CBOR bytes超過 | 検証済み先頭項目を残し、上と同じ未完了フラグ |
|
||||
| OBJRまたはannotation-owned StmOwn | 明示的制約。今回の通常Form対応に含めない |
|
||||
|
||||
同じFormの複数描画先を大きな矩形にunionしてexactとはしない。同一行列・MCID集合の別Formも列挙順で解決せずpage precisionにする。見出しの存在まで確定できない場合はpage移動先も作らない。
|
||||
|
||||
## 上限
|
||||
|
||||
| 対象 | 上限 |
|
||||
|---|---|
|
||||
| 共有qpdf入力 | 32MiB/操作、256MiB/文書、10秒/操作 |
|
||||
| 警告 | 32行かつ64KiB/文書。初期解析から適用、超過後継続不可 |
|
||||
| ページ木 | 深さ64、訪問200,000、未処理ノード100,000 |
|
||||
| 内容展開 | 16MiB/stream、32MiB/要求ページ。展開中のPipelineで停止 |
|
||||
| content token | 1,000,000/ページ、通常token64KiB、複合operand1MiB、operand256件、入れ子64 |
|
||||
| Form呼出 | 10,000/ページ、深さ64 |
|
||||
| PDFiumオブジェクト/文字 | 100,000オブジェクト、深さ64、1,000,000文字/ページ |
|
||||
| 構造探索 | 共通step10,000、ParentTree未処理ノード10,000、深さ64 |
|
||||
| 見出し応答 | 1,000項目、title4,096 UTF-16単位、CBOR512KiB(envelope余裕込み) |
|
||||
|
||||
streamの復号は公開`pipeStreamData`からbounded Pipelineへ行い、無制限のgetStreamData後検査をしない。復号済みstream・対応表・ParentTree参照のキャッシュは一要求の寿命だけで、別の文書全体構造キャッシュを設けない。OS側Workerメモリ制限、監視、取消時終了も維持する。Windowsは継承handleを包む同じQFile契約を使用するが、native実行の証拠は本記録に含まない。
|
||||
|
||||
## 検証範囲と残る制限
|
||||
|
||||
26個の構造資料で、元の6資料、Form-only、RoleMap/名前付きproperty、非identity入れ子、別Form同MCID、構造順、回転/CropBox、跨ページfragment、vector fallbackを検証した。陰性資料は循環、MCR/Pg/Stm不正、ParentTree所有矛盾、graphics stack破損、16MiB直前/超過、CBOR部分応答を含む。共有context専用資料4個と既存null Kid資料で、ページ番号保持と診断上限も確認した。
|
||||
|
||||
実Worker/FontBroker/IPCはexact、曖昧・繰返しpage fallback、quota、部分応答、取消を検証した。暗号化Formはqpdf CLIで試験時に作り、誤password拒否・正passwordの同じ借用QFileによるexact抽出・原本不変を確認した。画面上のForm-only heading移動はApp試験が別に担う。全体のrenderer比較、性能、配置、OS別受入記録は総合検証文書を参照する。
|
||||
|
||||
OBJR/StmOwnは未対応で、曖昧な描画instanceはpage fallbackに留まる。未検証の制作ソフト由来構造やnative Windowsの結果を、この合成資料の成功から推定しない。より広いexact対応には、元stream IDを公開するPDFium API等の別評価が必要である。
|
||||
@@ -0,0 +1,33 @@
|
||||
# 資源の警告集計
|
||||
|
||||
HTML・HTML ZIP・EPUBで読み込めない資源があっても、表示可能な本文を維持する。最初の検出時に一度だけ通知し、`:info`で理由別の検出件数を確認できる。件数は同じ資源の再試行も含み、固有URLの数ではない。
|
||||
|
||||
検出は三つの経路を使う。
|
||||
|
||||
- ResourceHandler: `ResourceFailure` の有限分類を使い、不在、危険な参照、OSアクセス拒否、許可外の資源形式、サイズ上限、アーカイブの展開上限・CRC/長さ破損、容量不足、保存失敗、読取I/O失敗、Worker停止・期限超過を区別する。OSやWorkerの生のmessage・パスは受け渡さない。
|
||||
- DocumentInterceptor: 通信・文書外参照の拒否。Chromiumの割込み処理では上限付きatomicカウンターだけを更新し、250msごとにMainで集約する。
|
||||
- ApplicationWorldの固定スクリプト: ブラウザー自身が発生させた`securitypolicyviolation`のうち、強制適用されたもの。画像、CSS、フォント等のdirective分類だけを取り出す。
|
||||
|
||||
集計は文書セッションのメモリー内だけに置く。URL、ファイル名、blockedURI、sourceFile、policy本文、sampleは収集しない。理由は固定24種類(broker 12、network 1、CSP 11)、各件数は999,999で飽和し、上限では「以上」と表示する。ブラウザーからの報告は固定11キー、有限の正整数、上限を全件検証してから反映する。不正な一項目があれば報告全体を捨てる。
|
||||
|
||||
| 検出 | 表示コード |
|
||||
|---|---|
|
||||
| 索引にない資源、OSが返す存在しないファイル・ディレクトリー | `E_RESOURCE_MISSING` |
|
||||
| root/型/リンク等の安全検査拒否、OSの権限・共有拒否、許可外MIME(理由は別集計) | `E_RESOURCE_BLOCKED` |
|
||||
| 1資源256 MiBまたは1書込64 KiBの上限 | `E_RESOURCE_LIMIT` |
|
||||
| アーカイブの累積・資源展開上限 | `E_ARCHIVE_LIMIT` |
|
||||
| CRC・圧縮データ・長さの不整合 | `E_ARCHIVE_CORRUPT` |
|
||||
| OSが明示するディスク容量・割当量不足 | `E_STORAGE_FULL` |
|
||||
| その他の一時資源の作成・書込・同期・確定失敗 | `E_STORAGE_FAILED` |
|
||||
| その他の資源open・read失敗 | `E_RESOURCE_IO` |
|
||||
| 不正/未知のworker失敗、期限超過 | `E_WORKER_CRASH` / `E_WORKER_TIMEOUT` |
|
||||
|
||||
`E_RESOURCE_LIMIT`、`E_STORAGE_FAILED`、`E_RESOURCE_IO` はこの追加契約のコードである。未知のOS失敗を欠落や容量不足と推測しない。WindowsではNTSTATUSをOSの変換APIで分類し、reparse/type/link/sizeは開いたhandleの情報から判定する。QFileは両OSとも所有済みfdを採用する。open後のread失敗は一度だけqueued signalでMainへ伝え、破棄・失効済みセッションには反映しない。
|
||||
|
||||
展開のcompletionは成功・取消・原因分類を保持する。WorkerProcessが実際に停止してRPC callbackを破棄した場合も、failed通知で保留中の資源jobへ停止理由を渡してからセッションを失効する。明示的な取消・文書切替の失効はCancelledのままとし、件数を追加しない。CRC・展開上限・不正worker応答では後続展開を停止し、既に表示した本文を保持する。失敗した途中ファイルは公開しない。保存容量不足とCRC不整合を同じコードへまとめない。汎用の章load失敗は`E_OPEN_FAILED`とし、資源不在と決め付けない。
|
||||
|
||||
取り消した文書、終了した文書、失効したセッションの報告は反映しない。固定EPUBの見開きでは現在表示する両ページから同じ文書へ集約する。履歴・保存位置には件数を保存しない。すべてのブラウザー内拒否が必ずCSPイベントを発生させるとは限らないため、一覧は実際に検出した事象を表す。
|
||||
|
||||
[Qtのinterceptor契約](https://doc.qt.io/qt-6/qwebengineurlrequestinterceptor.html)に従い、interceptRequest内でprofileのAPIやUIを呼ばない。[CSP仕様](https://www.w3.org/TR/CSP3/#securitypolicyviolationevent)のイベントを利用し、合成イベントは`isTrusted`で除外する。Qt 6.11.2での実際のイベント配送と通信拒否は[試験記録](../tests/results/resource-warnings/README.md)に残す。
|
||||
|
||||
分類の追加回帰は[resource-classification](../tests/results/resource-classification/README.md)に記録する。Windows nativeのアクセス拒否・容量不足・I/O配送は未検証であり、補助コンパイルはその代わりにならない。
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
||||
# Windows worker sandbox port
|
||||
|
||||
Status: the Windows broker, bounded handle transport, and PDF/archive worker bootstrap are connected in source. Native Windows execution and an MSVC/Windows Qt build have **not** been performed. Successful Linux regression tests and a compile-only check against Wine declarations are not Windows security or compatibility evidence. R12, G-SANDBOX on Windows, and distribution acceptance remain open.
|
||||
|
||||
## Launch and verification
|
||||
|
||||
`WorkerProcess` uses `WindowsRuntimeStaging`, `createWindowsPipePair`, and `launchWindowsWorker` on Windows. There is no unprotected `QProcess` fallback. The broker opens the original document with read access, checks the file type and reparse attributes, and supplies only duplicated handles to the worker. The shared installation tree and original document ACL are never changed.
|
||||
|
||||
The launcher creates a unique temporary AppContainer profile and requires the **LPAC** process attribute, zero capability SIDs, low integrity, a one-process Job, a 1.5 GiB per-process committed-memory limit, kill-on-close, no Job breakaway, and desktop/clipboard restrictions. The child-process policy attribute also blocks child creation. The process starts suspended; token identity and Job limits are checked before it resumes. Environment variables are reduced to the private runtime/System32 search path and SystemRoot. Arguments use Windows C runtime quoting without a shell.
|
||||
|
||||
Handle inheritance is limited to a read-only document handle, two directional overlapped pipes, and one inert `NUL` handle for standard streams. The child receives `--document-handle`, `--ipc-read-handle`, `--ipc-write-handle`, and `--sandbox-sid`; it rejects `--source` and `--socket` on Windows. `startWorkerRuntime` verifies the actual kernel token, LPAC state, SID, capability count, integrity level, immediate Job membership and limits, and private-profile access restrictions. A flag or SID argument alone cannot establish protection. A failed bootstrap exits with code 5 before parsing.
|
||||
|
||||
The document handle is duplicated again with only read rights and the inherited original is closed. `_open_osfhandle` transfers the restricted handle to a CRT descriptor; `QFile` owns that descriptor. PDFium's file-access callback and libzip's seekable source callback use this already-open `QFile`. They never reopen the original path. Source callbacks retain bounded index and entry checks; archive output is streamed as provisional chunks to the Main broker, which alone verifies and commits files.
|
||||
|
||||
`WindowsPipeDevice` uses overlapped I/O, `QWinEventNotifier`, a 256 KiB transport read buffer and a 16 MiB write queue. CBOR framing retains the 1 MiB control / 8 MiB render limits. Worker extraction drains pending transport writes above 128 KiB, with a five-second timeout; synchronous parser callbacks reject reentrant commands during this drain. `WorkerProcess` waits for a protected bootstrap ping before reporting the Windows worker ready.
|
||||
|
||||
## Private profile and runtime storage
|
||||
|
||||
Creating an AppContainer also creates writable private storage. That default is insufficient for a read-only parser. The launcher replaces DACLs only on its newly generated profile and broker-created runtime copies: the owner retains full access, the package receives read/execute access, and explicit package deny entries block file creation, writes, deletion, ACL changes, and ownership changes. Existing descendant entries are treated similarly. Reparse points and files with multiple hard links are rejected. The profile filesystem is checked again while the child is suspended.
|
||||
|
||||
The broker briefly impersonates the suspended child's token to obtain its own profile registry HKEY with `GetAppContainerRegistryLocation`, then returns to the broker identity before applying protected DACLs recursively. Package registry access is limited to read; creating keys/links, setting values, deleting keys and changing ACLs/ownership are explicitly denied. Unexpected registry links, oversized trees, and API failures stop launch. The child independently attempts to acquire each write permission on its profile directory and registry root and requires access-denied results. These checks do not create files or values.
|
||||
|
||||
The launcher exposes no writable worker output directory. The profile is deleted on normal `NativeProcess` destruction after Job termination and handle closure; recovery after interrupted broker shutdown still needs native validation. Runtime staging uses a finite DLL/executable manifest with hashes and private owner permissions. It does not copy user font directories or grant access to document parents, user configuration/state, or shared installation directories.
|
||||
|
||||
## Font behavior and remaining validation
|
||||
|
||||
The PDF worker now installs the public `FPDF_SYSFONTINFO` version 2 adapter and requests selected font bytes through `font.map`, `font.read`, and `font.close` on its existing protected IPC transport. It does not reactivate PDFium's default filesystem font provider. Main does not link PDFium or parse SFNT/TTC tables. See the [font broker contract](font-broker-contract.md).
|
||||
|
||||
The source Windows backend builds an OS font index with `EnumFontFamiliesExW`, selects an indexed family using `CreateFontIndirectW` and a thread-owned HDC, verifies `GetTextFaceW`/`GetTextMetricsW`, and takes a bounded snapshot through `GetFontData`. A TTC includes its collection bytes and the selected face offset derived from GDI's collection and table-zero sizes. Only an opaque session ID, selected metadata, and 64 KiB byte chunks reach the worker; HDC/HFONT and paths stay in Main. GDI calls run on dedicated background threads, limited to two across active and revoked services, with 256 MiB of total snapshot charges. A shared LRU can reclaim unused snapshots from either service while protecting issued handles. Revocation drops late replies without joining an in-progress OS call. Variable-font instances are skipped and subsequent static candidates are tried. No extra LPAC font capability or font-directory ACL grant was added.
|
||||
|
||||
This Windows backend passed only a supplementary object-compilation check against Wine declarations and Linux Qt headers. An MSVC/Windows Qt build, actual GDI selection and TTC behavior, font RPC through LPAC, Japanese fallback, glyph metrics, and non-ASCII family names remain **unverified on native Windows**. Linux broker and drawing results are not Windows fallback-font evidence. The implementation follows the pinned [PDFium Windows adapter](https://pdfium.googlesource.com/pdfium/+/a5a7089234f121990b336b3841008009dca143bf/core/fxge/win32/cwin32_platform.cpp) and Microsoft's [GetFontData contract](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getfontdata); their semantics still need native execution tests.
|
||||
|
||||
Native acceptance must first prove successful PDF/ZIP/EPUB operation, then reject source writes and path reopen, sibling/configuration/state reads, external and loopback connections, child creation, unrelated inherited handles, runtime mutation, and writes to **own profile, its Temp descendants, own registry storage, and arbitrary temporary directories**. Tests must check actual API error codes and distinguish denied access from malformed test setup. Also verify memory enforcement, broker termination, watchdog/restart, profile cleanup, non-ASCII paths, resource reparse protection, renderer restrictions, and clean packaged installs. Each protection setup failure must leave the worker stopped.
|
||||
|
||||
## Evidence recorded on the Linux development host
|
||||
|
||||
After the shared bootstrap and libzip handle callback changes: Archive **57 passed**, including reading an unlinked-but-open source, rejecting writable/null sources, source-lifetime failure, and unchanged source hashes; PDF **15 passed** through the production `WorkerProcess` route; Canvas **11 passed** with real sandboxed PDF worker IPC. These exercise the Linux path and platform-independent callback behavior only.
|
||||
|
||||
`windows_sandbox.cpp` also passed a C++ syntax-only check using Linux Qt declarations and Wine Win32 headers. The local Wine headers lack current AppContainer declarations/constants, so documented Microsoft declarations were supplied in a temporary compile-only prefix. This is not a link test, ABI check, Windows Qt build, or native execution, and is not an acceptance gate.
|
||||
|
||||
## API references
|
||||
|
||||
- [Microsoft: Launch an AppContainer and LPAC](https://learn.microsoft.com/en-us/windows/win32/secauthz/implementing-an-appcontainer)
|
||||
- [Microsoft: UpdateProcThreadAttribute](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute)
|
||||
- [Microsoft: GetTokenInformation](https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation)
|
||||
- [Microsoft: QueryInformationJobObject](https://learn.microsoft.com/en-us/windows/win32/api/jobapi2/nf-jobapi2-queryinformationjobobject)
|
||||
- [Microsoft: Job Object extended limits](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_extended_limit_information)
|
||||
- [Microsoft: AppContainer profile folder](https://learn.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getappcontainerfolderpath)
|
||||
- [Microsoft: AppContainer registry location](https://learn.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getappcontainerregistrylocation)
|
||||
- [Microsoft: ImpersonateLoggedOnUser](https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-impersonateloggedonuser)
|
||||
- [Microsoft: SetSecurityInfo](https://learn.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-setsecurityinfo)
|
||||
- [Microsoft: `_open_osfhandle` ownership](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/open-osfhandle?view=msvc-170)
|
||||
- [libzip: seekable source callback](https://libzip.org/documentation/zip_source_function/)
|
||||
Reference in New Issue
Block a user