Download - GeckoのDOMイベント処理の実装 (Gecko Inside ver.)
![Page 1: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/1.jpg)
![Page 2: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/2.jpg)
中野雅之
•肩書き
•正式: Mozilla Japan 国際化担当マネージャ
•非公式: Mozilla Japan 大阪支部長
•大阪の自宅で、自宅警備しながら仕事してます
![Page 3: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/3.jpg)
中野雅之
•色んなアカウント
•メールアドレス: [email protected]
• Skype: masayuki-nakano
• Twitter: @d_toybox
• Blog: 「もずはっく日記」で検索
![Page 4: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/4.jpg)
アジェンダ
•簡単な用語解説
• DOMイベントの基礎知識
• Geckoのイベント処理の実装
•イベントとe10s
![Page 5: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/5.jpg)
簡単な用語解説
• D3E
• DOM Level 3 Events の略
• DOM Level 4 Events にあたる仕様案の名前だった、”UI
Events” に改名され、マージされた
• DOM Level 3 KeyboardEvent key Values
• KeyboardEvent.keyの値を定義した仕様
• 元々は D3E で定義されていたものの分割された
• DOM Level 3 KeyboardEvent code Values
• KeyboardEvent.codeの値を定義した仕様
• 元々は UI Events で定義されていたものが分割された
![Page 6: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/6.jpg)
簡単な用語解説
• Edit Events
• UI Events からinputイベントとbeforeinputイベントを分離した仕様
• しかし、迷走中
• inputイベントとbeforeinputイベントはそれぞれ、editとbeforeeditイベントに改名され、従来のinputイベントとの後方互換性も無い
![Page 7: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/7.jpg)
簡単な用語解説
• PresShell
• “Presentation Shell”の略
• DOM document (window?)ひとつに対して、一つ生成される
• nsPresShell.cpp で PresShellとして実装され、nsIPresShell抽象クラスでインターフェースが定義されている
• ESM
• イベントの前処理や後処理、イベントによって変化するコンテンツの状態管理(:hover状態等)を管理している、EventStateManagerの略
• PresShellに生成され、破棄される
![Page 8: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/8.jpg)
簡単な用語解説
• PresContext
• “Presentation Context”の略
• PresShellに生成され、破棄される
• RefCountable ではないので、クラスのメンバとして保存する時は nsCOMPtr<nsIPresShell>を保存しておき、GetPresContext()で取得する方が安全
![Page 9: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/9.jpg)
簡単な用語解説
• dispatch、fire
•共にイベントを発火する意味で違いは無い
• default action
•イベントが発生した際にブラウザが行う動作、例えば、wheelイベントに対する、スクロールやズーム処理がwheelイベントのdefault action
• consumed
• Event.preventDefault()が呼び出され、default action
がキャンセルされている状態
![Page 10: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/10.jpg)
DOM イベントの基礎
• フェイズと、プロパゲーション
• イベントを捕まえる
• イベントの伝播を抑制する
• ブラウザのイベント処理を妨害する
• Gecko独自のイベントグループ
![Page 11: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/11.jpg)
capturing フェイズ
1. 最初はwindow
2. 次にdocument
3. rootからtargetの親
• targetの決定は、イベント依存
• フォーカス• 発生位置• ……等々
![Page 12: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/12.jpg)
target フェイズ
• targetフェイズは、capturingフェイズの一部でもあり、bubblingフェイズの一部でもある。
• windowやdocumentがtargetの場合も
![Page 13: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/13.jpg)
bubbling フェイズ
1. target の親からroot
2. 次にdocument
3. 最後にwindow
• Event.bubblesが falseの場合、bubblingは発生しない
![Page 14: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/14.jpg)
イベントを捕まえる
• 書式:
• EventTarget.addEventListener(イベント名, ハンドラ, Capture?);
• EventTarget.removeEventListener(イベント名, ハンドラ, Capture?);
• イベント名: イベントの名前 "click" とか、 "keydown"
• ハンドラ: function foo(aEvent) { /* something */ }がお手軽で十分
• Capture?: trueなら、capturing フェイズと、target フェイズ、falseなら、target フェイズと、bubbling フェイズ
![Page 15: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/15.jpg)
イベントを捕まえる
• 単純な例1:
• 全ての要素で発生するkeydownイベントを知りたい
• イベントターゲットより先に知りたい
• removeする必要はない
document.addEventListener("keydown",function (aEvent) { /* something */ },true);
![Page 16: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/16.jpg)
イベントを捕まえる
• 単純な例2:
• 全ての要素で発生するkeydownイベントを知りたい
• イベントターゲットより後に知りたい
• removeする必要がある
function keydownHandler(aEvent) {/* something */
}
document.addEventListener("keydown", keydownHandler, false);
…
document.removeEventListener("keydown", keydownHandler, false);
![Page 17: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/17.jpg)
イベントの伝播を抑制する
• 複数のイベントリスナを登録している場合、あるイベントハンドラで処理済みのイベントを他のイベントハンドラでは無視したい場合が考えられる
• Event.stopPropagation()か、Event.stopImmediatePropagation()を呼ぶと、それ以降のイベント発生を中止できる
• Event.stopPropagation()では、次のEventTarget以降でのイベントハンドラの実行を中止できる
• Event.stopImmediatePropagation()では、同じEventTargetに登録されている未処理のイベントハンドラも含めて、イベントハンドラの実行を中止できる
![Page 18: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/18.jpg)
ブラウザのイベント処理を妨害する
• ブラウザにdefault actionを実行してもらいたくない場合が考えられる
• Event.preventDefault()を呼び出すと、Event.defaultPrevented属性値がtrueになる
• defaultPrevented属性がtrueなら、ブラウザはdefault action
を実行しない(ただし、タブの切替等、セキュリティ上、無視することはある)
• Webアプリは Event.defaultPreventedの値を、処理前に確認することで、Event.stopPropagation()の代用としても使える
![Page 19: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/19.jpg)
Gecko独自のイベントグループ
• GeckoはDOMイベントを捕まえることでデフォルトアクションを実装することがある
• WebコンテンツがEvent.stopPropagation()を呼び出したものの、Event.peventDefault()を呼び出していない場合にdefault
actionを実行する必要がある
• Webコンテンツと同じ様にイベントリスナを登録していると、Event.stopPropagation()の呼び出しだけでdefault actionの実行が抑制されてしまう
• 実はこのバグは多く、私自身も発見しては修正している
![Page 20: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/20.jpg)
Gecko独自のイベントグループ
• GeckoはWebコンテンツの登録するイベントリスナをdefault
event groupに登録する
• Gecko内部や、UIはイベントリスナをSystem Event Groupに登録する(べき)
• 最初にdefault event groupに登録されたリスナが実行され、その後、system event groupに登録されたリスナが実行される、つまり……
![Page 21: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/21.jpg)
Gecko独自のイベントグループ
1. default event groupのcapturing phase
2. default event groupのtarget
3. default event groupのbubbling phase
4. system event groupのcapturing phase
5. system event groupのtarget
6. system event groupのbubbling phase
という順序で実行される
![Page 22: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/22.jpg)
Gecko独自のイベントグループ
• Event.stopPropagation()やEvent.stopImmediatePropagation()は各event group内での伝播を止めるのみ
• default event groupで呼び出していても、system event
groupでの実行は保証されている
• system event group内で呼び出した場合にはdefault event
groupと同様にそれ以降のイベントリスナは呼び出されないのでsystem event groupに登録しているイベントリスナ全てが実行を保証されている訳ではない
![Page 23: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/23.jpg)
Geckoのイベント処理の実装
• OSネイティブなイベントをDOMイベントとしてWebアプリに通知するケースを解説
•図にすると、次のように……
![Page 24: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/24.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 25: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/25.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 26: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/26.jpg)
EventListenerManager
• イベントターゲットで、最初にイベントリスナが登録された時に、インスタンスが生成され、そのノードに保存される
• そのノードに登録された全てのイベントリスナを管理する
• HandleEvent()が呼び出されると、イベントの名前とフェーズ、イベントリスナのグループがマッチするものを探し、マッチした場合に登録されているハンドラを実行する
• stopImmediatePropagation()が呼び出されたら、中断する
![Page 27: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/27.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 28: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/28.jpg)
モジュール間の処理の流れの例
1. widget/ は、各 OS のネイティブイベントをハンドリングするモジュール。ネイティブイベントが発生したら、内部イベントである、Widget*Eventクラスのインスタンスをスタックに作成し、その値を設定する
2. PresShellにイベントを送信、PresShellが target を決定する
![Page 29: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/29.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 30: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/30.jpg)
モジュール間の処理の流れの例
3. EventStateManager::PreHandleEvent()が前処理を行う
• 後ほど詳しく……
![Page 31: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/31.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 32: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/32.jpg)
モジュール間の処理の流れの例
4. PresShellがEventDispatcher::Dispatch()を呼び出す
5. EventDispatcher::CreateEvent()でWidget*Eventのクラスに対応した、dom::*Eventクラスを選択し、そのインスタンスをヒープに作成する
6. EventListenerManagerを列挙した配列を用意し、EventTargetChainItem::HandleEventTargetChain()を呼び出す
![Page 33: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/33.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 34: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/34.jpg)
モジュール間の処理の流れ
7. EventTargetChainItem::HandleEventTargetChain()で、受け取った、各EventListenerManagerのHandleEvent()を実行していく
8. EventListenerManager::HandleEvent()は、そのノードに登録されたイベントリスナを順に実行していく
9. EventTargetChainItem::HandleEventTargetChain()が自身をもう一度呼び出し、デフォルトアクションの実行のため、System Event Groupに登録されたリスナを実行する。
![Page 35: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/35.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 36: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/36.jpg)
モジュール間の処理の流れ
10. EventStateManager::PostHandleEvent()で、デフォルトアクションを実行したり、関連するイベントを生成したりする
![Page 37: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/37.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 38: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/38.jpg)
Widget*Event、Internal*Event
• WidgetEventクラスが全てのイベントクラスの基底クラス
• WidgetMouseEventや、InternalFocusEventといった派生クラスが、イベントごとに定義・実装されている
• 各クラスは、ほぼ構造体であり、メンバのカプセル化はほとんど行われず、メンバにダイレクトにアクセスする (読み書き問わず)
• widgetから生成されるイベントは、Widget*Event、それ以外の場合は、DOMイベントのデータを保存するためだけのものは、Internal*Event と命名されている
![Page 39: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/39.jpg)
Widget*Event、Internal*Event
• widget/
• widget/BasicEvents.h
• widget/ContentEvents.h
• widget/MiscEvents.h
• widget/MouseEvents.h
• widget/TextEvents.h
• widget/TouchEvents.h
• dom/events/
• dom/events/InternalMutationEvent.h
![Page 40: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/40.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 41: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/41.jpg)
PresShell
• イベントの複雑な処理はEventStateManager、表示に関わる部分はnsPresContextに分離されている
• イベント処理では widget で生成されたイベントを受け取り、target の決定と、発火処理を行う
• PresShell::HandleEvent()や、関連メソッドを参照
![Page 42: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/42.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 43: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/43.jpg)
EventStateManager::PreHandleEvent()
• PresShellがイベントを発火する直前に呼び出す
• マウスの操作によって変化する:hoverや、:activeといった要素の状態設定を行う
• マウスのクリックカウント等、状態の保存や、その値のWidget*Eventのメンバへの書き出しを行う
• ホイールの速度等、設定でカスタマイズできる項目を、Widget*Eventのメンバの値を書き換えることで実現してる
![Page 44: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/44.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 45: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/45.jpg)
EventDispatcher::CreateEvent()
• Widget*Eventクラスのインスタンスや、Internal*Eventクラスのインスタンスから、DOMイベントの実装クラスを選択し、インスタンスを生成する
• Javascriptのdocument.createEvent()の実装でもある
• new MouseEvent(…)等は別
• EventListenerManager::HandleEventInternal()が最初のイベントリスナを見つけた時点で呼び出される
![Page 46: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/46.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 47: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/47.jpg)
dom::Event
• DOMイベントの実装クラスは、名前空間 “mozilla::dom“に、標準仕様と同じ名前で定義
• dom::KeyboardEvent、dom::WheelEvent等
• nsIDOMEventインターフェースを必ず継承している
• dom::Eventは、WidgetEventへのポインタを持ち、イベントの属性値はここに保存している
• DOMイベントクラスは、Widget*Eventや Internal*Eventへ、DOMからアクセスするためのラッパクラス
![Page 48: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/48.jpg)
dom::Event
• 古くから実装されているDOMイベントクラスは、固有の、nsIDOM*Eventインターフェースも継承している
• 新規作成時にはほとんど定義されない
• データにアクセスするだけなら、内部イベントクラスにアクセスする方が高速で、実装も単純化される
• nsIDOM*Eventのメソッドは全て、virtual callになるためパフォーマンスが悪い
![Page 49: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/49.jpg)
dom::Event
•内部イベントクラスを定義・実装する必要が無い、シンプルなイベントを実装する際は、webidlで定義したイベントから、実装コードを自動生成することも可能
•自動生成の定義は dom/webidl/moz.build で定義
• dom/bindings/Codegen.py によって、ビルド時にcppファイルが自動的に生成される
![Page 50: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/50.jpg)
dom::Event
•実装例
• dom/events/
• dom/events/Event.cpp
• dom/events/UIEvent.cpp
• dom/events/WheelEvent.cpp
• dom/svg/
• dom/svg/SVGZoomEvent.cpp
![Page 51: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/51.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 52: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/52.jpg)
EventDispatcher::Dispatch()
• PresShellから呼び出される
• 最初に、 targetのPreHandleEvent()を実行する
• windowからtargetノードまで辿り、作成されている全てのEventListenerManagerを列挙し、配列に格納
• EventTargetChainItem::HandleEventTargetChain()にその配列を渡す
• その後、 targetのPostHandleEvent()を実行する
• 発火が終了しても、DOM イベントが JS の変数等から参照されている場合、内部イベントをヒープにコピーする
• 発火処理後、スタックにある内部イベントは破棄されるため
![Page 53: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/53.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 54: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/54.jpg)
EventTargetChainItem::HandleEventTargetChain()
• EventDispatcher::Dispatch()に呼び出される
• 列挙されている、windowからtargetの親ノードまでのEventListenerManagerの、HandleEvent()を実行していく(capturingフェーズ)
• Event.stopPropagation()がHandleEvent()実行中に呼び出されていたら、ループを中断する
![Page 55: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/55.jpg)
EventTargetChainItem::HandleEventTargetChain()
• 次に、targetのEventListenerManagerのHandleEvent()を呼び出す (targetフェーズ)
• Event.stopPropagation()か、Event.stopImmediatePropagation()が既に呼び出されていた場合、実行しない
• Event.stopPropagation()がHandleEvent()実行中に呼び出されていたら、ループを中断する
![Page 56: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/56.jpg)
EventTargetChainItem::HandleEventTargetChain()
• 次に、列挙された、targetの親から、windowまでのEventListenerManagerの、HandleEvent() を実行していく(bubbling フェーズ)
• Event.bubblesがfalseなら実行しない
• Event.stopPropagation()か、Event.stopImmediatePropagation()が既に呼び出されていた場合、実行しない
• Event.stopPropagation()がHandleEvent()実行中に呼び出されていたら、ループを中断する
![Page 57: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/57.jpg)
EventTargetChainItem::HandleEventTargetChain()
• 次に、イベントターゲットが生成した、CSS boxを実装している、nsIFrame::HandleEvent()を呼び出す
• PresShellがEventDispatcher::Dispatch()に渡したcallbackクラス経由で呼び出し
• default actionの実装に利用可能
![Page 58: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/58.jpg)
EventTargetChainItem::HandleEventTargetChain()
• 最後に、System Event Groupのイベントリスナが登録されている場合、capturing、target、bubblingフェーズを再度、処理する
• 通常のWebコンテンツからは登録不可
• Web コンテンツにEvent.stopPropagation()等を呼び出されていても実行される
• default actionの実装に利用可能
• System Event Group 内のリスナで、stopPropagation()等を呼ぶと中断される
![Page 59: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/59.jpg)
Geckoのイベント処理の実装nsDocument
PresShell
widget EventDispatcher
EventStateManager
Widget*Eventdom::*Event
PreHandleEvent() PostHandleEvent()
Dispatch()
CreateEvent()
2
3
4
5
6
EventTargetChainItem
nsINode
EventListenerManager
HandleEvent() handler2handler1
nsINode
EventListenerManager
HandleEvent() handler2handler1
7
810
1
9
![Page 60: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/60.jpg)
EventStateManager::PostHandleEvent()
• PresShellが最後に呼び出す
• イベントの後処理や、default actionを実行
• マウスホイールによるスクロール処理やズーム処理
• mouseupからclickイベントや、dblclickイベントの生成
• mousemoveから、 mouseover、mouseout、mouseenter、mouseleaveイベントの生成
![Page 61: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/61.jpg)
イベントとe10s
PresShell
widget
EventStateManager
PostHandleEvent()
1
2 5
6
TabParent
3 4
PuppetWidget
7
PresShell
9
EventStateManager
EventDispatcher
etc.
11
12
TabChild
8
10
13
![Page 62: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/62.jpg)
イベントとe10s
• e10sではネイティブのイベント入力は全てchromeプロセスで処理し、Widget*Eventをwidget/からdispatchする
• フォーカスを持った要素が子プロセス内にある場合、EventStateManager::PostHandleEvent()がイベントをTabParent経由で子プロセスへ送信する
• 一部例外のイベントもあり(WidgetCompositionEvent等)
• 子要素ではTabChildがイベントを受け取ると、PuppetWidgetへ送信し、PuppetWidgetから子プロセス内のPresShellにイベントを送信し同様に処理される
• つまり……
![Page 63: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/63.jpg)
イベントとe10s
• 子プロセスに送信されるイベントは、親プロセスのdefault
actionの一部
• 子プロセスには非同期で送信されているため、親プロセスはそのイベントがconsumedとなったかどうかを知ることができない
• OS側に非同期でイベントの処理結果を返す方法が無い限り、嘘の結果しか返せない
• 各OSがモダンな結果になることを期待したい
• IMEのみ、即座にコンテンツの情報を返したりする必要があるため、ContentCacheという仕組みを用意している
![Page 64: GeckoのDOMイベント処理の実装 (Gecko Inside ver.)](https://reader037.vdocuments.mx/reader037/viewer/2022102323/5a680cc17f8b9a7e348b4f01/html5/thumbnails/64.jpg)
Text
Q&A?