Mozilla アクセシビリティ・アーキテクチャー

Aaron Leventhal へのフィードバック- aaronleventhal@ m o o n s e t  . net にお願いします。

1. 始めに

2. アクセス可能なノードと インターフェイス
アクセシビリティのツリーは DOM ツリーのサブセット (Subset)
アクセシビリティ API モジュール・ディレクトリー構造
ツールキットに固有のコードを置く場所
アクセシビリティ API モジュール・クラスの継承図(キーボード操作可能!)

3. アクセス可能なツリーと探索
探索呼出しシーケンス
探索メソッドのオーバーロード

4. アクセシビリティのイベント
Gecko イベントからアクセシビリティ・イベントへの翻訳リスト
DOM ミューテーションイベント - 多重的使用
MSAA における一意の 32 ビット識別子

5. アクセシビリティのキャッシュ
なぜアクセシビリティ・キャッシュが必要か
アクセシビリティ・キャッシュの 3 つのレベル
nsAccessNode の役割
nsAccessNode::Init()
nsAccessNode::Shutdown()
アクセシビリティ・キャッシュの課題

6. 将来の方向性

1. 始めに

この資料は 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、レイアウトオブジェクト・ツリーの概念に通じていることが必要です。

2. アクセシビリティのノードとインターフェイス

各オペレーティングシステムのアクセシビリティ 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 ツリーの下位のノードのみから成る

すべの 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 で求められる補助テクノロジーの全てを提供できると考えています。

アクセシビリティ API モジュール・ディレクトリー構造

ディレクトリー構造の一般規則:


ディレクトリー
目的
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/ 現在サポートされていないプラットフォーム上でビルドが機能不全にならないための、プラットフォームの特定クラスの空実装。

ツールキットに固有のコードを置く場所

ATK と MSAA とは、共通部分が 75% しかない、異なるアクセシビリティ API ツールキットなので、多数あるツールキット固有のコードをどこかに置かなければなりません。以前に、これは集合単位で存在しました。ひとつは、accessible/src に、もう一つは widget/src に、二つの別のオブジェクトのツリーが確保されました。しかし、アクセシビリティ・キャッシュを実装するとき、このことで多くの障害が発生する可能性があったので、コードは各ツールキットに固有のソースデイレクトリーの中の「Wrap」クラスへと移動されました。

nsTextAccessibleWrap と nsDocAccessibleWrap など、名前に「Wrap」が含まれるクラスは、名前に「Wrap」が含まれない似た名前のクロスプラットフォームのクラスを継承します。これらのクラスは、Init() と Shutdown() などのメソッドをオーバライドでき、所定のツールキットのみが必要とするインターフェイスをサポートする他のメソッドを追加できます。例えば、nsAccessibleWrap は IAccessible のメソッドを実装しますが、それもまた nsAccessible であるので、必要情報を参照するために、「this」 によって nsAccessible のメソッドを呼び込むだけで十分です。

クラスの継承図

ズーム可能: 拡大や縮小するために Netscape や Mozilla では Ctrl+Plus と Ctrl+Minus を押す

クラスの名前にフォーカスがある時、タイプする:

nsAccessNode
nsIAccessNode を実装
重要なデーターメンバ:
nsCOMPtr<nsIDOMNode> mDOMNode;
nsWeakPtr mWeakShell;
 
nsAccessNodeWrap
COM interface である ISimpleDOMNode (MSAA のみ)を実装. アクセスできないノード上のこの interface をサポートすることが、nsAccessNode と nsAccessNodeWrap を必要とする理由
 
nsAccessible
アクセス速度に重要なメンバ:
nsIAccessible *mParent、*mNextSibling、*mFirstChild;
PRInt16 mAccChildCount; // -1 は初期化されていないという意味
 
nsAccessibleWrap
COM interface である IAccessible (MSAA) と IENUMVariant (MSAA を高速化)を実装
すべてのアクセシビリティの特有のクラスは最終的にこのクラスを継承し、またこのように、すべてのクラスのルーツにある nsAccessNode を含めて上記にリストされた 3 つのクラスを継承する。そして、アクセシビリティが連携する DOM ノードを保持する。
 
nsAccessibilityService
- クラス階層外に存在する -
nsIAccessibilityService を実装:要求に応じてこの図表のすべての型へのアクセシビリティを作り出す働きをする単独のクラス
この機能を使用するとアクセシビリティのモジュールがロードされる。また、アプリケーションの終了を監視して終了の際は、ShutdownAccessibility() を呼び出す。
is ancestor of
nsFormControlAccessible
フォーム制御用の名前と状態を取得するための一般規則を実装する。子を許可しないと言う点において、リーフアクセシブルのように動作する。

is ancestor of nsRadioButtonAccessible
is ancestor of nsXULRadioButtonAccessible
is ancestor of nsHTMLRadioButtonAccessible
is ancestor of nsXULColorPickerTileAccessible
is ancestor of nsXULDropmarkerAccessible
is ancestor of nsXULProgressMeterAccessible
is ancestor of nsXULCheckboxAccessible
is ancestor of nsHTMLCheckboxAccessible
is ancestor of nsHTMLTextFieldAccessible
is ancestor of nsHTMLButtonAccessible
<input> タグによってつくられるボタン用で、簡単なラベルを備えることが出来る。また nsHTML4ButtonAccessible を参照のこと
is ancestor of
nsLinkableAccessible
リンク用およびリンクの子がある時のため。リンクの状態と名前をサポート
is ancestor of nsTextAccessible
子は認められない
is ancestor of nsXULTextAccessible
is ancestor of nsHTMLTextAccessible
is ancestor of nsHTMLLabelAccessible
is ancestor of nsHTMLImageAccessible
is ancestor of nsHTMLAreaAccessible
イメージマップ <area>用。DOM の別の部分に在るが、画像の子として nsHTMLImageAccessible によって作られる。
is ancestor of nsHTMLLinkAccessible
is ancestor of
nsBlockAccessible
オーバラップする子を処理可能であり、特定のピクセル位置のアクセス可能な子を返す AccGetAt() が呼ばれた時、最も小さい子を返す。
is ancestor of
nsDocAccessible
nsIAccessibleDocument を実装する。ドキュメントにおいて、すべての nsAccessNode(したがって nsアクセシビリティも) のキャッシュを含む。
is ancestor of nsDocAccessibleWrap
ISimpleDOMDocument (MSAA のみ) を実装。ツールキットイベントを起動する
is ancestor of nsRootAccessible
最上層のウインドウにつき一つ。nsCaretAccessible を保持。 DOM イベント用にツールキットイベントを起動する。
is ancestor of nsHTMLTableAccessible
is ancestor of nsHTMLTableCellAccessible
is ancestor of nsOuterDocAccessible
新しいドキュメントを発生させるエレメント用: <iframe>、<browser> および <editor>
is ancestor of nsXULMenuPopupAccessible
is ancestor of nsXULMenubarAccessible
is ancestor of
nsXULMenuitemAccessible
is ancestor of nsXULSelectOptionAccessible
is ancestor of nsXULListitemAccessible
is ancestor of nsXULMenuSeperatorAccessible
is ancestor of
nsXULSelectableAccessible
is ancestor of nsXULListboxAccessible
is ancestor of nsXULComboboxAccessible
is ancestor of nsXULTreeAccessible
is ancestor of nsXULSelectListAccessible
is ancestor of
nsHTMLSelectableAccessible
is ancestor of nsHTMLSelectListAccessible is ancestor of nsHTMLComboboxListAccessible
is ancestor of nsHTMLComboboxAccessible
is ancestor of
nsLeafAccessible
子は認められない
is ancestor of nsHTMLSelectOptionAccessible is ancestor of nsHTMLSelectOptGroupAccessible
is ancestor of nsHTMLComboboxTextfieldAccessible
is ancestor of nsHTMLComboboxButtonAccessible
is ancestor of nsCaretAccessible
最上層ウインドウにひとつ。nsRootAccessible に所有される。自らを nsISelectionListener として附属させ、ツールキットイベントのカレット移動を起動する。
is ancestor of nsHTML4ButtonAccessible
開始と終了タグ間で任意のコンテンツを備えることができる<ボタン>タグによって作られるボタン用である。また nsHTMLButtonAccessible を参照のこと。
is ancestor of nsHTMLHRAccessible
is ancestor of nsXULToolbarSeparatorAccessible
is ancestor of nsXULTabAccessible
is ancestor of nsXULTooltipAccessible
is ancestor of nsXULTreeitemAccessible
is ancestor of nsXULTreeColumnitemAccessible
is ancestor of nsHTMLGroupboxAccessible
is ancestor of nsHTMLTableCaptionAccessible
is ancestor of nsHTMLWin32ObjectAccessible
is ancestor of nsXULGroupboxAccessible
is ancestor of nsXULButtonAccessible
is ancestor of nsXULRadioGroupAccessible
is ancestor of nsXULStatusBarAccessible
is ancestor of nsXULToolbarAccessible
is ancestor of nsXULTabBoxAccessible
is ancestor of nsXULTabPanelsAccessible
is ancestor of nsXULTabsAccessible
is ancestor of nsXULTreeColumnsAccessible

3. アクセシビリティのツリー構造と探索

アクセシビリティのツリーは要求に応じて、構築されます。最初のアクセシビリティの要求は普通、開かれた一つのウインドウ内のドキュメントへのアクセシビリティです。widget/src/gtk2 や widget/src/windows 内のコードはこのドキュメントアクセシビリティを返さなければなりません。最初にドキュメントの子アクセシビリティが要求されたとしても、ドキュメントアクセシビリティが最初に作られることになります。というのは、ドキュメント内に作られるどんなアクセシビリティでもキャッシュされる必要があるからです。

ドキュメントアクセシビリティが要求されると、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 ツールキット探索メソッド calls into
nsAccessible 探索メソッド calls into
DOM & 匿名コンテンツを探索する nsAccessibleTreeWalker method calls into
コンテンツノードを使う nsIAccessibilityService::GetAccessible()calls into
    nsDocAccessible::GetCachedAccessNode() 成功なら返し、さもなくば、 calls into
    nsIAccessibleProvider::GetAccessible() (if XUL) さもなくば calls into
    nsIFrame::GetAccessible() (if HTML)、何も返さないか、さもなくばcall into
nsIAccessibilityService::Create[InsertTypeNameHere]Accessible() which uses
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 および他のアクセシビリティの実装において、通常されているように、これらの子を得るメソッドをオーバーライドして何も返さないこともまた有益です。リーフやテキストオブジェクトに何も返さないことも、ツリーの構築と探索を高速化するのに役立ちます。

4. アクセシビリティのイベント

アクセシビリティのイベントは nsIAccessibleEventReceiver.idl にリスト表示されている、連続したイベント番号を使用して、所定のプラットフォームのイベントメカニズムへと翻訳される DOM イベントです。アクセシビリティのクライアントは、どんな種類のイベントが発生し、どのアクセシビリティノード上でイベントが発生したかを見出すことができます。

Gecko イベントからアクセシビリティ・イベントへの翻訳一覧表

アクセシビリティのドキュメントは、内部にあるノード上の DOM イベントを監視します。その結果、正しいアクセシビリティのイベントを起動します。これは、HandleEvent() の中で発生します。

Note: この表は途中までしかありませんので、全部見たい方は HandleEvent() メソッドを参照して下さい。

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 ミューテーションイベント - 多重的使用

DOM ミューテーションイベントはすばらしいものです。ドキュメント内のノードが作成、移動、また変更されるときはいつも、これらのイベントは、Gecko によって起動されます。ミューテーションの存在する共通の理由はウェブページ・スクリプトとエディター内のユーザーのアクションのためです。

いくつかの理由のために DOM ミューテーション・イベントは監視されます:

2003 年 5 月現在、私たちはまだ、DOMAttrModied を使用してノード上の属性の変更を監視していません。属性の変更の中には、キャッシュの一部分を無効化する必要性を信号で伝達する可能性のあるものが存在するので、変更を監視する必要があります。例えば、アンカーエレメント上の名前や href 属性が変わったり、img のユーズマップ属性が変わるかどうかについてです。これらのケースはごくまれですが、万が一発生する可能性のある場所では、現実的なシナリオを考えておくべきです。これに対応するならば、コードは nsDocAccessible::AttrModified() に保持されることになります。

MSAA における一意の 32 ビット識別子

MSAA では、ターゲットの各アクセシビリティへ一意の 32 ビットの子番号をイベントを使って渡す必要があります。この値を得るために、私たちは現在、DOM ノードへポインターを持って行き、整数へ変え、さらに、ネゲートします。 MSAA クライアントが、AccessibleObjectFromEvent() を使用して、アクセシビリティのノードを呼び戻すと、Windows はその子 ID 番号付きの子のドキュメントアクセシビリティを要求します。これは nsDocAccessibleWrap::get_accChild() において処理され、そこで私たちは、負の子番号をチェックし、アクセシビリティキャッシュ を使用して正しいオブジェクトを返します。

5. アクセシビリティキャッシュ

アクセシビリティモジュールは一連のハッシュテーブルとして実装されたキャッシュを保持します--ドキュメントあたり一つ。ハッシュキーは各アクセシビリティ用の DOM ノードへのポインターです。このようにすれば、 DOM ノードに同じアクセシビリティオブジェクトが二回作られる必要が一切ありません。

なぜアクセシビリティ・キャッシュが必要か

アクセシビリティ・キャッシュにはたくさんの目的があります:

アクセシビリティ・キャッシュの 3 つのレベル

アクセシビリティ・キャッシュには 3 つのレベルがあります:

このアーキテクチャーのお陰で、ドキュメントアクセシビリティのキャッシュを破棄するだけで、ドキュメントが消される時、ドキュメント全部のキャッシュノード量を迅速に除去することが出来ます。

しかし、DOM ノードのキャッシュされたアクセシビリティを取得するには二段階が必要です。まず最初に、ノードのドキュメント用のグローバルキャッシュからドキュメントアクセシビリティを取得する必要があり、次に、ドキュメントアクセシビリティの特定のキャッシュを使って dom ノードへのエントリーをチェックします。この事は、毎回新しいアクセシビリティを作成するよりはるかに高速な工程なので大きな問題とはなりません。この二段階は nsAccessibilityService::GetCachedAccessible(domNode) において実装されます。

子の数、親、最初の子、および次の兄弟の記録を保持しているメンバー変数のお陰で、すでに訪問されたアクセシビリティのノードへはたちどころに探索ができます。

nsAccessNode の役割

もしあなたが、私たちのアクセシビリティ・モジュールの ATK 部門で作業することが多いならば、 nsAccessNode の目的が分からないかもしれません。それを使用するインターフェイスが存在しないからです。事実上、nsAccessNode は ISimpleDOMNode を MSAA へ拡張するために存在しており、そしてそれは nsAccessNodeWrap において実装されます。ISimpleDOMNode は補助テクノロジーによって使用され、「アクセスが」可能であるか不可能である個々の DOM ノードについての情報へアクセスします。

nsAccessNode は、「アクセスでき」ない DOM ノードも含め、すべての DOM モードを指し示すことが可能なので、nsAccessible になることも、またならないこともあります。つまり、私たちがキャッシュしなければならない最低の共通分母が nsAccessNode です。

nsAccessNode::Init()

nsAccessibilityService::GetAccessible() が新しく作られたアクセシビリティを取得する時、新オブジェクト上に nsIAccessNode::Init() を呼出します。そしてこれが、新オブジェクトをドキュメントアクセシビリティ用のキャッシュへ追加します。各 nsAccessNode はオブジェクト用の dom ノードと weak pres shell を保持します。weak pres shell はハッシュキーを作成するのに使われ gGlobalDocAccessibleCache よりドキュメントアクセシビリティを取得します。dom ノードポインターは新しいハッシュキーを作成し、ドキュメントアクセシビリティの mAccessNodeCache へ nsIAccessNode* を加えるのに使用されます。

Init() メソッドもまた仮想的で、アクセシビリティの多くがそのメソッドをオーバーライドして自分自身の特別な初期化を行います。オーバーライドするならば、完了時に、親クラスの Init() メソッドも呼び込む必要があります。

nsAccessNode::Shutdown()

Shutdown() は、所定の nsAccessNode/nsAccessible 用の dom ノードがもはや存在しない時、使用されます。その呼び出され方は様々です:

アクセシビリティ・キャッシュの課題

アクセシビリティ・キャッシュを扱う時用心しなければならない問題があります:

6. 将来の方向性

概ね、アクセシビリティの API モジュールの仕事は、いまや結論に向かうべき時です。不幸にして、私たちは今もなお、市場の主要なスクリーンリーダーや、スクリーン拡大鏡や、音声検出器について、全面的な協力関係にありません。この状況を早く変えて、主要ベンダー(および Linux/UNIX のGnopernicus) と協力してこの目標を達成したいと思っています。

いずれにしても、当面 Windows 上の唯一の計画は補助テクノロジーベンダーからのフィードバック情報に基づいた細かいバグの修正のためのものです。Linux と UNIX では、新しいアーキテクチャー(「Wrap」クラスをもっと多く使用するなど)の注入に対してもっと多くの仕事が必要となるでしょう。

Macintosh アクセシビリティ API、Windows の将来のバージョン用に Microsoft によって開発されつつある新 API、または、クロスプラットフォームや小型装置での利用のために開発されたその他の新しい API をサポートすると決めると、さらなる作業が生まれます。私たちの全体的なアクセシビリティ・アーキテクチャーが、大きな困難を伴わずに、これらの API をサポートできることを願ってやみません。