『テキストにぶつかるまでネイティブで』を読んで、Pure Go の PDF を思い出した
ネイティブ SDK で行ける所まで行ってテキストで Web に逃げた話。Pure Go PDF で逃げずに済んだ理由を考えます。
今朝の Hacker News に「Native all the way, until you need text」という記事が流れていました。SwiftUI と AppKit でチャット UI を書いていた開発者が、Markdown のリッチテキストレンダリングで Apple のテキスト API の限界にぶつかり、最終的に WebView に逃げた、というネイティブ実装者の告白記事です。読みながら、自分が Pure Go で PDF を書いているときに見ている景色とよく似ているな、と思いました。
テキストはどの処理系でも一番遠い場所にある
記事の論点は「ネイティブ SDK は矩形・色・アニメーションには強いが、テキストレイアウトの自由度が一段低い」というところに収束しています。これは Apple 固有の話ではなく、ほぼあらゆるグラフィックス処理系で同じ構造をしているはずです。Web が強いのは、テキスト系の最後の砦である CSS とフォントメトリクスと組版アルゴリズムを踏みにいった結果で、ブラウザは事実上「世界一汎用なテキストレンダリングエンジン」を内蔵したアプリケーションランタイムです。
私が gpdf を Pure Go ・ゼロ依存で書こうとしたとき、最後まで残った難所はやはり PDF のテキスト周りでした。TrueType/OpenType フォントのサブセット化、CJK のグリフテーブル、字形バリエーション、フォントエンベッドの圧縮。PDF オブジェクトの直列化や FlateDecode は仕様書通りに書けば終わりますが、テキストは仕様書通りに書いてもまだ足りません。
壁にぶつかった人は、だいたい二通りの逃げ方をする
記事の著者は1つめの逃げ方を選びました。「ネイティブで行けるところまで行って、テキストで Webview に切り替える」というやり方です。これは賢い判断だと思っています。閉じたランタイムの中で世界中のテキスト表現に対応するより、CSS の上に乗ったほうが速いです。
もう1つの逃げ方は、問題の表面そのものを狭めることです。私が gpdf で取った方針はこちらでした。「世界中の任意の Markdown を任意のフォントで美しくレンダリングする」のは Pure Go では無理ですが、「PDF を生成する」というクローズドな問題に絞れば、入力フォントと文字集合が呼び出し側のコードで決まります。入力が制御可能になると、テキストは突然解けます。これが Pure Go で PDF を書いた理由 の一番奥にある判断でした。
それでも工数の半分はテキストだった
gpdf v1.0 をリリースする直前、コード量で見るとテキスト系の重みが目立つことに気づきました。線・矩形・画像描画と PDF オブジェクトモデル全部を合わせたぐらいのコードが、フォントとテキストレイアウト周辺に集まっています。書いている本人としても、線描画の倍ぐらいの時間を CJK フォントの埋め込みに使った気がしています。
「テキストにぶつかるまでネイティブで」の著者が WebView に切り替えた瞬間と、私が CGO で harfbuzz を呼ぶ選択肢を捨てた瞬間は、たぶん同じ温度の決断でした。違うのは、彼が「ここから先はネイティブの仕事じゃない」と判断したのに対し、私は「ここから先こそ Pure Go の仕事だ」と判断した、という方向だけです。どちらが正しいかは、配布形態と読者層によって変わります。彼のアプリは利用者の Mac の中で動けばそれでよく、gpdf は 単一バイナリで配布される ことが価値なので、CGO で外部ライブラリを引っ張ってきた瞬間にその価値が消えます。
質問への応答
CGO で harfbuzz を呼べば全て解決したのでは?
そのとおりで、それは知っています。harfbuzz は世界で最も完成されたテキストシェーピングエンジンの1つで、CJK のリガチャやインド系の複雑な字形変換まで吸収してくれます。それでもやらなかったのは、Pure Go の単一バイナリ配布という土台が崩れるからです。CGO を入れた瞬間に「go build 一発で Linux/macOS/Windows の amd64・arm64 を出せる」というデプロイの軽さがなくなります。私はテキスト品質より配布の容易さを取りました。ユーザーが PDF を見て「もう少し綺麗だったらな」と思う頻度より、サーバーに1ファイル放り込んで動くことの利益のほうが、micro SaaS としては大きいと感じています。
今朝の他に読むべき記事
- Voice AI Systems Are Vulnerable to Hidden Audio Attacks (IEEE Spectrum) 人間に聞こえない音声で音声 AI に不正コマンドを 79〜96% の成功率で実行させられるという研究。電話自動応答や音声アシスタントを業務に組み込む前に読んでおきたい話です。
- Agora-1: The Multi-Agent World Model (Hacker News) 複数の人間と AI エージェントが同じ生成世界を共有できる学習型ゲームエンジンの発表。シミュレーションとレンダリングを分離した設計が興味深いです。
- The tyranny of single page apps (Hacker News) SPA のルーティング複雑性と SEO ペナルティに対する辛辣な批判。micro SaaS のフロントエンドを SSR や HTML ファーストに戻すかどうかを再考させられる記事です。
- The most important Design System in 2026 that designers missed was built by a developer (Medium) shadcn/ui が Figma を経由せず GitHub と AI ツール経由でデファクトになった経緯の分析。コードベース駆動のデザインシステムが何を意味するかについては 昨日の記事 で別角度から書きました。
- Context is the new component library (Substack) AI エージェントに使わせるならコンポーネントだけでは足りず、設計意図のコンテキスト文書化が必要、という主張です。
- Elon Musk has lost his lawsuit against Sam Altman and OpenAI (TechCrunch) カリフォルニア州陪審員が全員一致で時効切れと判断。OpenAI の IPO への法的障害が大きく一つ消えた、という意味で読みました。
- Anthropic acquires Stainless (Anthropic) SDK 自動生成と MCP サーバ生成の会社 Stainless を Anthropic が買収。エージェント時代に SDK 品質が AI 普及のボトルネックになる、という読みが透けます。
次に gpdf の text shaping を触るとき、Apple ネイティブで WebView に切り替えた人がいた朝のことを、たぶん思い出します。