この資料は Mozilla の アクセシビリティ API モジュールを理解したい人々に向けて、プラットフォームのアクセシビリティ API へのサポートを提供します。アクセシビリティ API はスクリーンリーダー、スクリーン拡大鏡、音声検知ソフトウエアーなどサードパーティのソフトウエアーによって使用されますが、この事で、フォーカスの変更のような重要なイベントについてだけでなく、ドキュメントの内容についての情報や UI のコントロールについての情報が必要になります。Mozilla は Windows 上の MSAA や Linux/Unix 上の ATK という二つのアクセシビリティ API をサポートします。しかし Apple の OS X用の Carbon アクセシビリティ・モデルは現在サポートしていません。
MSAA を実装するためのドキュメントのサーバーが変更になりました。また、どのように MSAA クライアントが Gecko のサポートを利用できるかについて、第三者ソフトウエアー・ベンダー向け手引書である Gecko Info for Windows Accessibility Vendors を読むことも可能です。もし、Linux や UNIX のアクセシビリティに興味をお持ちならば、Mozilla ATK プロジェクトページ をお調べ下さい。
この資料の読者はインターフェイス、W3C DOM、XUL、レイアウトオブジェクト・ツリーの概念に通じていることが必要です。
各オペレーティングシステムのアクセシビリティ API は、次のような点について固有の前提を備えてます: 最も重要な情報は何か、Mozilla のようなアクセシビリティ・サーバが API のプログラム・インターフェースをどのように使用して、この情報をアクセシビリティ・クライアント(補助テクノロジー)に渡すべきかといった点についてです。各プラットフォームのアクセシビリティ API は、異なる条件を備えていますが、共通の特徴が数多くあります。たとえばすべて、各オブジェクトのアクセシビリティの名前や、テキスト表示を公表し、限定されたリストから列挙整数値を使用して、オブジェクトの役割を公表します。アクセシビリティの役割の定数は、ROLE_BUTTON、ROLE_CHECKBOX および ROLE_LIST であり、各 API によって名前や数値が少し異なる可能性はあります。一般的に、アクセシビリティの API は類似する概念を備えますが、メソッド、定数、インターフェイスなどの名前は異なります。
アクセシビリティ API ツールキット間に共通性が高いことを考えると、クロスプラットフォーム風にコードについて書いてから、一貫した方法でプラットフォームの違いを処理すると自然です。 公表したいオブジェクトの情報を返す標準の XPCOM のインターフェイスによって、共通化されたコードがツールキット特有のコードへ適応可能となります。フォーカス可能なすべてのノード、テーブル、テキストには、アクセシビリティのインターフェイスがあります。これらのオブジェクトは「アクセシビリティのノード」と呼ばれます。これらの各ノードは、最低でも、標準のクロスプラットフォームなアクセシビリティ・インターフェイスである nsIAccessible (テキストの名前、列挙された役割識別子、状態フラグ一式を提供します)と、時には追加のインターフェイスをサポートします。たとえば、テーブルは nsIAccessibleTable を、テキストは nsIAccessibleText を、エディット・ボックスは nsIEditableText をサポートします。ただし、nsIAccessible は現在 Windows で使用されていないために、ATK の特定のデイレクトリーに移動しています。私たちは、複数あるリッチな ATK インターフェイスを Windows 上でサポートする可能性を排除するつもりはありません。
ツールキット特有のクラスはその結果、XPCOM インターフェイスを使用して、公表したいオブジェクトについての情報を収集し、必要な変更を行い、そして、Windows 上で Microsofit COM や、Linux/Unix上で GTK2 の ATK API を使用します。
補助テクノロジーはその時、この情報を様々に使用することが出来ます。ドキュメント全部をすぐに読み込む、最近のイベント関連のドキュメントのみを見る、あるいは画面の位置に基づいてアクセシビリティのオブジェクト・モデルを探索するなどです。
すべの DOM ノードがアクセシビリティ API ツールキットによって公表されるわけではなく、ツールキットの開発者が重要であるとみなすもののみが、公表されます。Mozilla は独自のアクセシビリティ・オブジェクトを維持しています。これは DOM ツリーに似ていますが、完全に同じような構造を保っているわけではありません。
上記:MSAA ツリーを示す図は、DOM ツリーの下位集合です。他のアクセシビリティ API の状況も同様です。
補助テクノロジー・ベンダーが知りたいのに、公表されていない DOM ノードがあるとすればどうなる ? というのは問題です。CSS 規則、タグの名前と属性などの DOM 情報を知りたいのに、MSAA の IAccessible が提供していなければどうなる ? というのも問題です。
Windows 上では、MSAA の IAccessible を飛び越してすべての DOM ノード用の追加インターフェイスをサポートすることで、私たちはこの問題を解決します。QueryInterface() は、二つのインターフェイス間を切り替えるのに使用することが出来ます。DOM ノード用に MSAA のノードが存在しないならば、 pAccessible -> QueryInterface(IID_IAccessible) が null を返します。さらに、テキストノードよりも小さなテキストの断片(例:単語)の情報とサポートの提供を私たちに依頼して来たベンダーもありました。そして、このために Mozilla が ISimpleDOMText をサポートします。
ATK では、現実の DOM 情報を取得するインターフェイスはありません。Mozilla の ATK サポートを管理している Sun Microsystems は、ATK が十分にリッチで、Sun Microsystems で求められる補助テクノロジーの全てを提供できると考えています。
| ディレクトリー |
目的 |
|---|---|
| accessible/public | すべてのツールキットにある共用インターフェイス |
| accessible/public/msaa | MSAA の IAccessible を拡張するのに使用される Custom COM インターフェイス |
| accessible/public/atk | 内部 XPCOM ATK インターフェイス |
| accessible/src/base | HTML と XUL の実装によって共用化される共通の実装 |
| accessible/src/html/ | ドキュメント と HTML オブジェクトの実装 |
| accessible/src/xul/ | ユーザーインターフェイスと XUL オブジェクトの実装 |
| accessible/src/msaa/ | Windows の実装 |
| accessible/src/atk/ | ATK の実装は最終的には Linux と Unix 以外のプラットフォームで使用されるかもしれない。 |
| accessible/src/mac/ |
OS X 用プラットフォーム特定クラスの空実装。これらの実装は後に埋められるかもしれない。 |
| accessible/src/other/ | 現在サポートされていないプラットフォーム上でビルドが機能不全にならないための、プラットフォームの特定クラスの空実装。 |
ズーム可能: 拡大や縮小するために Netscape や Mozilla では Ctrl+Plus と Ctrl+Minus を押す
クラスの名前にフォーカスがある時、タイプする:
ドキュメントアクセシビリティが要求されると、PresShell に到達するイベントが起動されます。PresShell はその時、accessibility service singleton(nsIAccessibilityService) を使用してドキュメントアクセシビリティを作りウィジェットコードへ返します。なぜドキュメントアクセシビリティがそれを必要としてるコードの中で直接作成されないかという理由は、何の nsIDOMNode が現在のウインドウのドキュメントオブジェクトと連携しているかウィジェットコードが知らないためです。pres shell がウィジェットコード用のドキュメントアクセシビリティを作るために、現在のウィジェット (nsWindow/nsIWidget) 用のドキュメントがなくてはなりません。
この方法のよい点のひとつは、accessibility.dll/libaccessibility.so が 実際にアクセシビリティの働きが使用されるまでは、ロードされる必要がないことであり、ほとんどのユーザーはロードすることはまずありません。
個々のオブジェクトの他のアクセシビリティも同様に、要求に応じて作られます。補助テクノロジーは、最初に深さ(または幅)の検索を使用して、ツリー全体を得る事を選択できますし、フォーカスのようなイベントに基づくだけで、アクセシビリティを得ることを選択できます。また、画面の特定の位置でアクセシビリティを得ることもできます。どのように補助テクノロジーのクライアントがデーターを要求しても、所定のノード用のアクセシビリティは一度しか作成されません。アクセシビリティのキャッシュは、所定の dom ノード用に既に作成されたアクセシビリティを読み出すために使用されます。
このツリーの探索はツールキットを使った特別な呼出しによってなされます。最終的に nsIAccessible メソッドの呼出しとなり、GetAccParent()、GetAccNextSibling()、GetAccPreviousSibling()、GetAccFirstChild()、GetAccLastChild()、GetAccChildCount() および GetChildAt(childNum) などが呼び出されます。探索では、ATK は MSAA よりもっと便利なメソッドを備えており、例えば、nsIAccessibleTable::CellRefAt() を使用することで、テーブルの特定の行や列へのアクセシビリティへ直接到達することが出来ます。
アクセシビリティのノードへアクセス可能な子の数を計算するのに使用されるアルゴリズムは高価です。現在のアクセシビリティのノードにおいて、すべてのアクセス可能な子が、直下の子か孫か何世代後の子から来ているかを推定することは出来ません。従って、あたかもすべてのアクセス可能な子を作っているかのように、ツリーを繰り返し下って、下りながら、全体数に追加しなければなりません。
この作業を安価にすませるために、子のカウントや子へのアクセスが1度要求されると、子のカウントとすべての子のカウントが共に、同時に計算されそしてキャッシュされることで、この高価な処理を二度以上実行することが避けられます。
上述の nsIAccessible GetAccBlah() 探索メソッドはすべて、nsAccessible において実装が初期設定されています。初期設定実装は nsAccessibleTreeWalker と呼ばれるクラスを使用し、実際の仕事をします。 nsAccessibleTreeWalker は DOM とドキュメント内の匿名のコンテンツを歩き、各ノードへのアクセシビリティの取得を nsIAccessibilityService::GetAccessible() に依頼します。もしアクセシビリティがキャッシュにあれば、返されます。XUL エレメントは、アクセシビリティを返すことができる nsIAccessibleProvider インターフェイスのサポートをチェックされます。HTML エレメントはノードの最初のフレームに nsIFrame::GetAccessible() によってアクセシビリティの取得を依頼します。もし、nsnull が返されると tree walker は、下位レベルの最初の並びにある次のノードをチェックします。
アクセシビリティのノードが nsIAccessible の探索メソッドによって返される方法
ATK/MSAA ツールキット探索メソッドnsAccessible 探索メソッド
DOM & 匿名コンテンツを探索する nsAccessibleTreeWalker method
コンテンツノードを使う nsIAccessibilityService::GetAccessible()
nsDocAccessible::GetCachedAccessNode() 成功なら返し、さもなくば、
nsIAccessibleProvider::GetAccessible() (if XUL) さもなくば
nsIFrame::GetAccessible() (if HTML)、何も返さないか、さもなくば
nsIAccessibilityService::Create[InsertTypeNameHere]Accessible()
operator new によってオブジェクトが最終的にコンストラクトされる。
nsIAccessibleProvider::GetAccessible() か nsIFrame::GetAccessible() のいずれか経由で、accessibility service へと呼び戻したり、アクセシビリティの各型を作る特定のメソッドを使うことによって、新しいアクセシビリティは作られます。たとえば、nsHTMLTableCellFrame::GetAccessible() は最終的に nsIAccessibilityService::CreateHTMLTableCellAccessible() を呼出し、これは |new nsHTMLTableCellAccessible(domNode、weakPresShell) を使用します;
アクセスできる必要な子がノード用の DOM 従ツリーに存在しない場合があります。このようなケースとして:
これらのアクセシビリティの実装において、nsIAccessible::GetAccChildCount()、::GetAccFirstChild() および ::GetAccLastChild() がオーバライドされます。こうすれば、通常の探索メソッドである nsAccessibleTreeWalker を使わずに、私たちが欲するどのような子アクセシビリティでも作られます。nsHTMLComboboxAccessible と nsXULTreeItemAccessible の場合のように、各アクセシビリティに DOM ノードがない時は、Shutdown() メソッドをオーバライドして、親が終了された時にメモリーから子が取り除かれるようにします。この場合はまた、DOM の無い子用に ::GetAccNextSibling()、 ::GetAccPreviousSibling() をオーバーライドします。そうしないと、子たちはお互いどのように見つけてよいか分かりません。
必ず子を持ちたくないような nsLeafAccessible、nsTextAccessible および他のアクセシビリティの実装において、通常されているように、これらの子を得るメソッドをオーバーライドして何も返さないこともまた有益です。リーフやテキストオブジェクトに何も返さないことも、ツリーの構築と探索を高速化するのに役立ちます。
| Gecko イベント (または呼び戻し) |
イベント型 |
アクセシビリティ・イベント |
|---|---|---|
| フォーカス、選択 |
標準 HTML DOM イベント |
EVENT_FOCUS |
| DOMMenuItemActive、 DOMMenuBarActive | Mozilla DOM |
EVENT_FOCUS |
| DOMNodeInserted | W3C DOM ミューテーションイベント |
EVENT_CREATE (ATK) EVENT_REORDER (MSAA) |
| DOMSubtreeModified | W3C DOM ミューテーションイベント |
EVENT_REORDER |
| DOMNodeRemoved |
W3C DOM ミューテーションイベント |
EVENT_DESTROY (ATK) EVENT_REORDER (MSAA) |
| CheckboxStateChange、
RadioStateChange |
Mozilla DOM | EVENT_STATE_CHANGE |
| ポップアップ表示 |
Mozilla DOM | EVENT_MENUSTART |
| ポップアップ待避 |
Mozilla DOM |
EVENT_MENUEND |
| nsDocAccessible::ScrollPositionDidChange()、
then nsDocAccessible::ScrollTimerCallback() |
nsIScrollPositonListener と
nsITimer 呼び戻し |
EVENT_SCROLLINGEND (クイックタイマーは、余分なイベントが起動されるのを避けるために、いつスクロールを一次停止するかまたは停止するかを決めるのに使用される。) |
| nsDocAccessible::OnStateChange()、
:nsDocAccessible:OnLocationChange() |
nsIWebProgressListener 呼び戻し |
EVENT_STATE_CHANGE (MSAA) EVENT_REORDER (ATK) |
DOM ミューテーションイベントはすばらしいものです。ドキュメント内のノードが作成、移動、また変更されるときはいつも、これらのイベントは、Gecko によって起動されます。ミューテーションの存在する共通の理由はウェブページ・スクリプトとエディター内のユーザーのアクションのためです。
いくつかの理由のために DOM ミューテーション・イベントは監視されます:
アクセシビリティ・キャッシュにはたくさんの目的があります:
アクセシビリティ・キャッシュには 3 つのレベルがあります:
このアーキテクチャーのお陰で、ドキュメントアクセシビリティのキャッシュを破棄するだけで、ドキュメントが消される時、ドキュメント全部のキャッシュノード量を迅速に除去することが出来ます。
しかし、DOM ノードのキャッシュされたアクセシビリティを取得するには二段階が必要です。まず最初に、ノードのドキュメント用のグローバルキャッシュからドキュメントアクセシビリティを取得する必要があり、次に、ドキュメントアクセシビリティの特定のキャッシュを使って dom ノードへのエントリーをチェックします。この事は、毎回新しいアクセシビリティを作成するよりはるかに高速な工程なので大きな問題とはなりません。この二段階は nsAccessibilityService::GetCachedAccessible(domNode) において実装されます。
子の数、親、最初の子、および次の兄弟の記録を保持しているメンバー変数のお陰で、すでに訪問されたアクセシビリティのノードへはたちどころに探索ができます。
もしあなたが、私たちのアクセシビリティ・モジュールの ATK 部門で作業することが多いならば、 nsAccessNode の目的が分からないかもしれません。それを使用するインターフェイスが存在しないからです。事実上、nsAccessNode は ISimpleDOMNode を MSAA へ拡張するために存在しており、そしてそれは nsAccessNodeWrap において実装されます。ISimpleDOMNode は補助テクノロジーによって使用され、「アクセスが」可能であるか不可能である個々の DOM ノードについての情報へアクセスします。
nsAccessNode は、「アクセスでき」ない DOM ノードも含め、すべての DOM モードを指し示すことが可能なので、nsAccessible になることも、またならないこともあります。つまり、私たちがキャッシュしなければならない最低の共通分母が nsAccessNode です。
Init() メソッドもまた仮想的で、アクセシビリティの多くがそのメソッドをオーバーライドして自分自身の特別な初期化を行います。オーバーライドするならば、完了時に、親クラスの Init() メソッドも呼び込む必要があります。
Shutdown() は、所定の nsAccessNode/nsAccessible 用の dom ノードがもはや存在しない時、使用されます。その呼び出され方は様々です:
アクセシビリティ・キャッシュを扱う時用心しなければならない問題があります:
概ね、アクセシビリティの API モジュールの仕事は、いまや結論に向かうべき時です。不幸にして、私たちは今もなお、市場の主要なスクリーンリーダーや、スクリーン拡大鏡や、音声検出器について、全面的な協力関係にありません。この状況を早く変えて、主要ベンダー(および Linux/UNIX のGnopernicus) と協力してこの目標を達成したいと思っています。
いずれにしても、当面 Windows 上の唯一の計画は補助テクノロジーベンダーからのフィードバック情報に基づいた細かいバグの修正のためのものです。Linux と UNIX では、新しいアーキテクチャー(「Wrap」クラスをもっと多く使用するなど)の注入に対してもっと多くの仕事が必要となるでしょう。
Macintosh アクセシビリティ API、Windows の将来のバージョン用に Microsoft によって開発されつつある新 API、または、クロスプラットフォームや小型装置での利用のために開発されたその他の新しい API をサポートすると決めると、さらなる作業が生まれます。私たちの全体的なアクセシビリティ・アーキテクチャーが、大きな困難を伴わずに、これらの API をサポートできることを願ってやみません。