WWDC21:次世代テキストエンジン「TextKit 2」を発表
※本サイトは、アフィリエイト広告および広告による収益を得て運営しています。購入により売上の一部が本サイトに還元されることがあります。
Appleが、WWDC21において、次世代テキストエンジンについて紹介するセッション「Meet TextKit 2」を公開しています。
これまでのテキストエンジンは「TextKit 1」と呼び、Apple のすべてのプラットフォームでテキストのレイアウトと表示を行うテキスト エンジンです。
UIKit と AppKit のテキスト コントロールは、TextKit 1を使用してストレージを管理し、テキスト コンテンツのレイアウトを制御します。
TextKit 1 は当初の原則に基づいているため、高水準のパフォーマンスを提供しながら、新しいテクノロジーとうまく統合する API を提供することは、年々難しくなっています。
TextKit 2は、一連の将来を見据えた設計原則に基づいて構築された、Apple の次世代テキスト エンジンです。
そして、何を推測しますか?あなたはすでに Mac で TextKit 2 を使用しています。
macOS Big Sur では、バックグラウンドで TextKit 2 を使用するために、OS 全体のテキスト コンポーネントの多くを更新し、ユーザーはmacOS Big Surから TextKit 2 を使用しています。
TextKit 2 は TextKit 1 と共存し、その前身と同様に、TextKit 2 は Foundation、Quartz、および Core Text の上に構築されています。
UIKit と AppKit のテキスト コントロールは、TextKit 2 の上に構築されています。
TextKit 2 も、前身のMVC 設計を大まかに保持しています。
ビュー部分は UIKit と AppKit フレームワークのビュー オブジェクトに残りますが、古い友人であるNSTextStorage と NSLayoutManager の新しいバージョンがあります。
TextKit 2 の中心的な高レベルの設計原則は、正確性、安全性、およびパフォーマンスです。私たちはバランスの取れたアプローチをとりました。
3 つの原則はすべて重要であるため、説明する順序に優先順位はありません。
これらの高レベルの設計原則はそれぞれ、システムの特定の設計変更を通知し、正確を期すために、TextKit 2 はグリフの処理を抽象化しています。
安全のために、TextKit 2 は値のセマンティクスに重点を置き、また、パフォーマンスのために、TextKit 2 はビューポート ベースのレイアウトとレンダリングを使用します。
多くの西洋言語では、通常、1 つのグリフが1 つの文字を表しますが、これは常に正しいとは限りません。
単一の文字を表す複数のグリフを使用することも、その逆にすることもできます。1 つのグリフで複数の文字を表すことができます。
複数の文字を表すために使用されるこの 1 つのグリフは、合字と呼ばれます。
西洋の言語にはあまり多くの合字がなく、通常、テキストの読みやすさに影響を与えることはありません。リガチャーなしでも問題なく読めます。
しかし、それはすべての言語に当てはまるわけではなく、アラビア語やデーバナーガリーなどのスクリプトは、多くの合字を使用しており、読みやすさに影響を与えます。
NSTextSelection のこれらのプロパティは読み取り専用であるため、選択オブジェクトのインスタンスを変更して変更することはありません。
代わりに、NSTextSelectionNavigation のインスタンスを使用してテキスト選択に対するアクションを実行し、結果の選択を表すNSTextSelection の新しいインスタンスを受け取ります。
ナビゲーション オブジェクトに、画面上のポイントでのタップまたはマウスダウン イベントの結果として選択を提供するか、前後に移動した結果として新しい選択を取得するように依頼できます。
これにより、選択範囲を 1 単語前方に拡張して正しい結果を得るなどの操作が容易になり、右から左への言語での双方向テキストに対応します。
次は安全についてで、Swift や SwiftUI などのテクノロジの目標によりよく適合するように、値のセマンティクスに重点を置いてTextKit 2は設計されています。
そして、「値のセマンティクス」と言う場合、値の型について話しているのではありません。NSLayoutManager を構造体にしませんでした。
値型はデータの一意のコピーを保持し、そのデータの変更を防ぎます。これにより、意図しない共有や関連する副作用がなくなるため、コードの安全性と安定性が高まります。ただし、値型だけがこの利点を得る唯一の方法ではありません。
不変クラスには、初期化後に変更できないプロパティがあり、データの変更も防止されます。
これらのクラスは値型のように動作するため、値のセマンティクスを持つものとして参照します。
これらのオブジェクトのいずれかのデータを変更する場合は、新しいインスタンスを作成して元のインスタンスを置き換える必要があり、TextKit 2のクラスの多くは、このように設計されています。
NSTextLayoutManager は、テキスト レイアウト マネージャーは、テキスト レイアウト プロセスを制御します。
NSTextLayoutManager は、TextKit 1 の古い NSLayoutManager に似ていますが、1つの大きな違いがあり、NSTextLayoutManager はグリフを処理しません。
代わりに、NSTextLayoutManager はテキスト要素を受け取り、それらをテキスト コンテナーにレイアウトし、それらの要素のレイアウト フラグメントを生成します。
2つ目のプロパティであるレイアウト フラグメント フレームは、レイアウト フラグメント内のテキストがテキスト コンテナー領域内にどのようにレイアウトされるかを示します。
TextKit 2 では、テキスト レイアウトは基本的に、コンテナー内のレイアウト フラグメント フレームを積み上げます。これらのフレームはタイルのようなものだと考えてください。システムはテキスト コンテナー領域をタイルに分割します。各レイアウト フラグメントは 1 つのタイルです。
一般に、レイアウト フラグメント フレームは、フラグメント コンテンツの近くにUI 内の他のビューを配置したり、テキスト コンテンツの合計の高さを計算したりするのに役立ちます。
現在、このフレームは、テキスト自体を描画するために必要なスペースを正確に表していません。その情報は3つ目のプロパティから取得されます。
パフォーマンスは、テキスト エンジンにとって最大の課題の 1 つで、TextKit 2 は、わずか数行のラベルをすばやくレンダリングすることから、インタラクティブな速度でスクロールする数百メガバイトのドキュメントをレイアウトすることまで、非常に幅広いシナリオで非常に高速です。
これらのシナリオでは、これらの非常に大きなドキュメントを可変速度でスクロールする場合、優れたパフォーマンスを得るには、不連続なテキスト レイアウトが不可欠です。
不連続なレイアウトとは、テキストの一部を文書内の任意の場所に配置できることを意味し、その前にある部分をレイアウトする必要はありません。
ドキュメントの中央までスクロールすると、すぐにその可視領域にレイアウトが行われます。
これにより、画面に表示されるテキストの部分のみにレイアウトを実行し、さらにオーバー スクロール領域を追加することでパフォーマンスが向上し、よりスムーズなスクロール エクスペリエンスが得られます。
TextKit 2 は、可視コンテンツ領域の要素に一貫したレイアウト情報を提供し、その可視領域のレイアウトが更新されると通知します。
この領域はビューポートと呼ばれ、ビューポートを調整または再配置することでビューポートを管理し、ビューポート レイアウトの前、最中、および後にコールバックを受け取ります。
最適なパフォーマンスを得るには、コードでビューポート領域内のレイアウト情報を操作することに集中する必要があり、ビューポートの外側にある要素のレイアウト情報は、可能な限りリクエストしないでください。
ビューポートの外側にある要素のレイアウト情報は、それらの要素に対応するテキスト範囲のレイアウトを確実にするように明示的に要求しない限り、正確ではない可能性があります。
この呼び出しは、特に大きなドキュメントの場合、コストがかかる可能性があります。
UIKit 開発者の場合、UITextField は iOS 15 で TextKit 2 を自動的に使用します。
TextKit 2 を使用した UITextView は、iOS 15 では使用できません。
UITextView を使用するすべてのアプリケーションに対して最大限の互換性を確保するために取り組んでおり、非常に多くのアプリケーションがあります。
それまでの間、UITextView のlayoutManager プロパティを使用するための既存のコードを確認し、TextKit 2 で意図を表現する方法を考えることができます。
これで、利用可能になったときに移行する準備が整います。