この日記はMozillaのプロダクトへの貢献者としての私の成果を中心に、気になったバグやWeb界隈の話題について書いていますが、 断り書きがある場合を除き、いかなる団体のオフィシャルな見解ではありません。あくまでも個人的なものです。 Mozilla Foundation、Mozilla Corporation、及び関連企業の公式情報ではないことに注意してください。

現在、XHTML 1.0 (もどき)から、HTML5なコンテンツに修正中です。古い日記は修正が完了していませんので表示が崩れます。 順次、修正していく予定ですのでしばらくお待ちください。

もずはっく日記(2014年3月)

2014年3月8日

Bug-org 961704 [TSF] Add an option for nsTextStateManager can ignore text change and selection change which are caused by composition 初回投稿日時: 2014年03月08日20時32分12秒
カテゴリ: Mozilla Core Mozilla30 TSF Windows バグ修正
固定リンク: id=2014030800
SNS: (list)

TSFは、IMEによるコンテンツの変更をTSFに通知してはいけないという仕様になっているのを、nsTextStore内でフラグを用いて管理していましたが、未確定文字列の変更等によって発生するDOMイベントからエディタのコンテンツが変更されたことか、IMEの操作による変更なのかの見分けがつかないという問題がありました。

Bug-org 960866の修正により、mozilla::TextCompositionに問い合わせれば、エディタがWidgetTextEventを処理中かどうか、つまり、IMEの未確定文字の変更、もしくは確定での変更が発生したのか、他の要因でエディタの内容が変更されたのかを、nsTextStateManagerで判断できるようになりましたので、これを利用し、TSFでは、エディタがWidgetTextEventを処理中に発生した変更は無視することができるようになりました。

ただし、nsTextStore側にはまだ対応をきちんと入れていないため、未確定文字列の変更等の最中にJSから加えられた変更は、まだ、TSFには通知されません。

Bug-org 975688 nsDOM*Event classes into mozilla::dom namespace and rename them to same as standard spec's name (i.e., nsDOM*Event -> mozilla::dom::*Event) 初回投稿日時: 2014年03月08日20時40分46秒
カテゴリ: Mozilla Core Mozilla30 バグ修正
固定リンク: id=2014030801
SNS: (list)

content/events配下のファイルは全て、dom/eventsに移動されましたが、ファイルの内容はそのままの移動でした。このフォルダ配下のファイルはほとんどが古くから存在しているものなので、nsプレフィックス付きのクラス・ファイル名を利用しているため、ヘッダファイル内では、引数の型の定義が名前空間の付与で長くなりがちで、ソースコードの80桁制限のため、読みづらいところが多いのが問題になっていました。そこで、これらのファイル内のクラスを全て、mozilla::domか、mozilla名前空間に移動させ、モダンなクラス名に変更することにしました。

このバグでは、nsDOM*Eventという名前で定義されていたクラスを全て、mozilla::dom::*Eventという名前に変更しています。

この際に、Event.hEventクラス等、あまりに一般的すぎる名前になるため、ヘッダファイルの方は、あえてすべてエクスポートし、mozilla/dom/*Event.hでインクルードするように修正しています。

文字にするとこれだけですが、30クラスぐらいあった上に、一番ベースのコンクリートクラスである、nsDOMEventmozilla::dom::Event化には苦労させられました……

Bug-org 974318 WidgetTextEvent should store text ranges with a class inherited from nsTArray 初回投稿日時: 2014年03月08日20時59分51秒
最終更新日時: 2014年03月08日21時02分22秒
カテゴリ: Mozilla Core Mozilla30 バグ修正
固定リンク: id=2014030802
SNS: (list)

GeckoのIMEまわりのコードを見たことある人は分かると思いますが、現在のGeckoでは、widget側で様々なルールに則ってイベントを発行しなければエディタが正確にハンドリングできない上、DOMイベントの発生順序等にもプラットフォーム毎にバグが混入する可能性があります。そこで、これを簡素化し、プラットフォーム間の違いが発生しにくいように再設計することにしました。

このバグではまず、リファクタリングを行いやすい様に、WidgetTextEventの保持する文節情報をnsTArrayの派生クラスで処理しやすくし、また、Netscape時代から続く、WidgetTextEventの未確定文字列の文節情報をnsDOMTextEventでコピーする、という無駄で分かり難い設計を改善することをゴールにしました。

この修正により、WidgetTextEventは、新たに定義された、TextRangeArrayクラスのインスタンスを必要な場合にのみヒープに確保して、それへの参照を保持するようになりました。このため、スタックに文節情報を保存し、メモリの断片化を抑えるという手法が使えなくなりましたが、TextRangeArrayは、nsAutoTArray<TextRange, 10>の派生クラスで、9文節とキャレットの情報、または10文節の情報を、再アロケーション無しで取り扱えるため、今回の修正による新たなメモリ断片化は起きづらいのでは無いかと思います。

またこのクラスは動的にアロケーションし、参照カウンタで管理するようになっています。このため、nsDOMTextEvent内でコピーを作成する必要が無くなり、その結果、nsDOMTextEvent、その固有のインターフェースであるnsIPrivateTextEvent、文節の情報をXPCOMとして表現するnsIPrivateTextRange、これを配列として表現するnsIPrivateTextRangeList、そしてこれらのコンクリートクラスである、nsPrivateTextRangensPrivateTextRangeを削除することができました。

そして、TextRangeArrayは、TextCompositionnsEditorの代わりに保存するようになりしました。これにより、文節情報にはエディタ外からでも簡単に参照可能になっています。これにより、nsEditorと、IMETextTxnクラスの関係を今までよりも疎遠にすることに成功しています。

言葉では非常に伝わりにくいですが、興味のある方はパッチを参照してみてください。かなり、エディタやイベント周りのコードがシンプルになったことが分かると思います。

2014年3月10日

来週リリースのFirefox 28、Mac版で、ブックマークツールバーをマウスだけで操作したい人は便利になります 初回投稿日時: 2014年03月10日20時48分38秒
カテゴリ: Firefox Mac Mozilla28
固定リンク: id=2014031000
SNS: (list)

来週リリース予定のFirefox 28、Mac版でブックマークツールバーを使っている人には良いリリースになると思います。

Mac版では長年にわたり、ブックマークツールバーのサブフォルダを開いた状態、つまり、ブックマークツールバー上に作成したフォルダを開き、そこに表示されたブックマークアイテム上で右クリックをしても、コンテキストメニューが表示されませんでした。このため、新しいタブで開くにはアイテムをタブバーにドラッグしたり、キーボードでCommandキーを押しながらクリックしなければいけない、等、ちょっとした作業が中々に面倒でしたし、アイテムの編集等、どうしようもできないこともありました。

Bug-org 930900の修正により、他のプラットフォームと同じように、コンテキストメニューを利用できるようになっていますので、是非、試してみて下さい。

Bug-org 978023 Rename nsIMEStateManager and nsTextStateManager and move into mozilla:: 初回投稿日時: 2014年03月10日22時55分30秒
カテゴリ: Mozilla Core Mozilla30 バグ修正
固定リンク: id=2014031001
SNS: (list)

dom/events配下のクラスのリネームバグです。このバグでは、nsIMEStateManagermozilla::IMEStateManagerに、nsTextStateManagerIMEContentObserverに名前を変更し、後者は、nsIMEStateManager.cppから、独立したIMEContentObserver.cppと、IMEContentObserver.hに分離しています。

このバグで指摘されたのですが、ファイルを分割する場合、分割元のファイルをhg copyで複製後に不要な部分を削除することで、変更履歴が引き継げるらしいです。

実例: dom/events/IMEContentObserver.cppのannotation

2014年3月11日

Bug-org 981947 Use PeekMessage() instead of GetMessage() when we try removing found message with PeekMessage(PM_NOREMOVE) 初回投稿日時: 2014年03月11日12時28分37秒
カテゴリ: Mozilla Core Mozilla28 Mozilla29 Mozilla30 Windows バグ修正
固定リンク: id=2014031100
SNS: (list)

mozilla::widget::NativeKey::RemoveFollowingCharMessage()は、WM_KEYDOWNメッセージのハンドリング中に呼び出され、生成されているWM_CHAR等をキューから取り除くメソッドなのですが、この最中に想定外のことがあると、テキスト入力はおかしくなるものの、バグ報告が来ないことが予想され、また、そうそう起きないであろうケースと踏んで、MOZ_CRASH()を利用して、クラッシュレポートで想定外のバグを調査できるようにしていました。

しかし、このクラッシュが予想外に大量に発生しているということで、対応を続けています。クラッシュレポートでも、有益なコメントが付けられているものはほとんど無いのですが、原因のひとつには、Doragon Naturally Speakingというソフトがあるようです。このアプリは、音声からキー入力イベントを生成しているようですが、どうもその生成が下手なようで、他のアプリでもうまく動かないものがあるというコメントも見られました。

このバグは、オリジナルであるBug-org 962140での取り扱いに限界が出たため、分割登録しなおした最初のバグです。

これまでは、PeekMessage()WM_*CHARを発見した場合、GetMessage()で見つけたメッセージを取得していましたが、PeekMessage()PM_REMOVEとセットで呼び出した場合の挙動の違いが事態をややこしくしている可能性がありましたので、PeekMessage()PM_NOREMOVEを利用して呼び出した後には、必ず、PeekMessage()PM_REMOVEを利用するようにしました。

また、実際にバグ修正のヒントとなるであろう、メッセージキューの情報を、MOZ_CRASH()を呼び出す直前に取得して、リポートにログを追加するようにしました。

Bug-org 981951 We should remove following char message immediately after we find it at handling keydown message 初回投稿日時: 2014年03月11日12時44分28秒
カテゴリ: Mozilla Core Mozilla28 Mozilla29 Mozilla30 Windows バグ修正
固定リンク: id=2014031101
SNS: (list)

mozilla::widget::NativeKey::RemoveFollowingCharMessage()は、keypressイベントの生成処理の流れの中で、自然なタイミングで呼び出されてました。しかし、このメソッドがメッセージ処理の最中に、ありえない状況が発生しているということは、他のスレッド等からメッセージキューに変更が加えられている可能性があります。そこで、メッセージを発見してから削除するまでの魔の時間を可能な限り短くするため、mozilla::widget::NativeKeyGetFollowingCharMessage()というメソッドに改名し、メッセージの存在を確認した直後に、それをキューから削除し、戻り値として引数経由でその削除したメッセージを返し、必要としているメソッドへ引数として渡すように修正しました。

なお、PeekMessage()でメッセージを削除する際に、キーメッセージにその対象を限定していても、WM_NULLが削除されるという不思議な挙動がMetroFirefox上でのみ見られたので、PeekMessage()WM_NULLを削除した場合には最高で5回までリトライするようにしています(その後のクラッシュレポートのログを見た限りでは2回以上していることは無さそうですが)。

なお、この修正により、クラッシュのシグネチャが[@ mozilla::widget::NativeKey::GetFollowingCharMessage(tagMSG&)]に変更されていることに注意してください。

Bug-org 981954 Sometimes we remove a char message whose scan code is different from found message 初回投稿日時: 2014年03月11日12時51分04秒
最終更新日時: 2014年03月11日12時51分25秒
カテゴリ: Mozilla Core Mozilla28 Mozilla29 Mozilla30 Windows バグ修正
固定リンク: id=2014031102
SNS: (list)

WM_*CHARPeekMessage()で発見後に、実際に削除を行った後、想定外な状況がおきていないか、取得したメッセージが発見していたメッセージと同一のものか確認し、違っていた場合には、暗っ氏レポートにログを吐いた後、MOZ_CRASH()でクラッシュさせていました。

このバグは、そのクラッシュで、WM_*CHARlParam内のスキャンコードが別のキーのものに置き換わっているというものです。

原因は分かっていませんが、メッセージキューの仕様から考えると、WM_*KEYDOWNWM_*CHARの前に割り込んだ後に、メッセージを削除すると、スキャンコードが差し込まれたキーメッセージのもので上書きされているのではないか、と推測しています。

現在、このスキャンコードで何らかの処理を行っている訳ではないので、この修正では、スキャンコードのみが変わっている場合、クラッシュせずにその違いを無視するようにしています。

Bug-org 981958 PeekMessage() sometimes fails (returns false) at removing found char message on MetroFirefox 初回投稿日時: 2014年03月11日13時02分52秒
カテゴリ: Mozilla Core Mozilla28 Mozilla29 Mozilla30 Windows バグ修正
固定リンク: id=2014031103
SNS: (list)

発見済みのWM_*CHARメッセージをPeekMessage()で削除する際に、時々、falseを返して失敗し、MOZ_CRASH()でクラッシュしているケースがクラッシュレポートのログから発見されました。残るクラッシュの大半の原因はこれのようです。

この修正では、PeekMessage()でのメッセージ削除に失敗した場合、ウインドウを限定せずにキーメッセージを再度調査し、メッセージキューから発見済みのメッセージが発見できなかった場合にはクラッシュせず、keypressイベントの生成自体を行わないように修正しました。原因として、フォーカスの移動等による、メッセージの宛先の変更や、外部アプリによるメッセージ削除、後ほど再生成されて、keypressイベントが発行されるといったことが考えられるので、keypressイベントをこの状況下では生成すべきでは無いと考えたからです。

2014年3月20日

Bug-org 977959 Redesign native key bindings handling 初回投稿日時: 2014年03月20日21時34分46秒
カテゴリ: GTK Mac Mozilla Core Mozilla30 バグ修正
固定リンク: id=2014032000
SNS: (list)

Mac版と、Linux (GTK)版では、OSのネイティブウイジットのショートカットキーを可能な限りエミュレートするために、エディタがキーイベントを処理しなかった場合に、nsINativeKeyBindingsのサービスを利用しています。

しかし、e10sではネイティブイベントを子プロセスに渡すことはできないので、どうするかが問題になります。これに対応するため、まずは、その結果を保存しておきやすいように、結果は、XULのコマンドの文字列ではなく、enumで保存しておけるようにしました。これにより、キャッシュする配列を作成するコストが大きく削減されます。

次に、構造をシンプルにするために、nsINativeKeyBindingsのインターフェース、サービス共に廃止し、これらの実装は、各widget内の、ただのシングルトンのクラスに変更しました。XPのコードからは、nsIWidgetのメソッドで結果を問い合わせるように抽象化しています。

Bug-org 981226 Rename nsContentEventHandler to mozilla::ContentEventHandler 初回投稿日時: 2014年03月20日21時38分24秒
カテゴリ: Mozilla Core Mozilla30 バグ修正
固定リンク: id=2014032001
SNS: (list)

サマリの通り、nsContentEventHandlerを、mozilla::ContentEventHandlerに改名し、ファイル名も、nsを削除して、ContentEventHandler.(cpp|h)に変更しています。

現在、このヘッダファイルは他のモジュールから直接参照されていませんので、エクスポートされていません。ですので、単に、#include "ContentEventHandler.h"と記述することになります。

Bug-org 970141 The value of deltaX and deltaY of WheelEvent should be in CSS pixels if its deltaMode is DOM_DELTA_PIXEL 初回投稿日時: 2014年03月20日21時46分18秒
カテゴリ: Events Mac Mozilla Core Mozilla30 バグ修正
固定リンク: id=2014032002
SNS: (list)

MacのRetinaディスプレイモデルを使用していると、WheelEventdeltaXdeltaYが、ディスプレイの物理ピクセル数で返されるため、Javascriptで実装された、独自のスクロール可能な要素のスクロールスピードが速すぎる、というバグです。

この修正により、WheelEventは物理ピクセル値ではなく、CSSピクセル値で返すようになりました(deltaModeDOM_DELTA_PIXELの場合の話です、もちろん)。

なお、ピクセル単位でのスクロールは、現在のところ、Macでしか発生しませんので、結果的にはMac固有の修正になっています。

そして、ピクセル単位のホイールイベントは、あくまでも、デバイスピクセルの単位でスクロール量を算出しています。つまり、200%にズームした場合、100ピクセルのスクロールが発生した場合、CSSピクセルでは50ピクセルしかスクロールしません。ですので、Retinaディスプレイを使用していなくても、ズームしている際の、JS実装の独自スクロール可能な要素のスクロール量はこの修正の影響を受け、デフォルトアクションのスクロール量に統一されるはずです。

なお、行単位、もしくはページ単位のスクロールは従来通りです。デフォルトアクションでもこれらはズーム後の行やページのサイズを参考に、スクロール量が算出されますので、ピクセルとの挙動の違いに注意してください。

Bug-org 982602 Move nsAsyncDOMEvent into mozilla:: namespace and rename it 初回投稿日時: 2014年03月20日21時52分17秒
カテゴリ: Mozilla Core Mozilla30 バグ修正
固定リンク: id=2014032003
SNS: (list)

nsAsyncDOMEventが、より、このクラスの動作を表した名前のmozilla::AsyncEventDispatcherに変更されました。これにより、ファイル名もAsyncEventDispatcher.(cpp|h)に変更されています。

ヘッダファイルはエクスポートされていますので、#include "mozilla/AsyncEventDispatcher.h"と書くべきです。

Bug-org 981261 Rename nsEventListener* to mozilla::EventListener* 初回投稿日時: 2014年03月20日22時01分09秒
カテゴリ: Mozilla Core Mozilla30 バグ修正
固定リンク: id=2014032004
SNS: (list)

この修正により、各クラス名や型名が以下のように変更されました。

  • nsEventListenerInfomozilla::EventListenerInfo
  • nsEventListenerServicemozilla::EventListenerService
  • nsEventListenerManagermozilla::EventListenerManager
  • nsListenerStructmozilla::EventListenerManager::Listener
  • nsListenerTypemozilla::EventListenerManager::Listener::ListenerType
  • mozilla::dom::EventListenerFlagsmozilla::EventListenerFlags

ファイル名もそれぞれ、EventListenerService.(cpp|h)と、EventListenerManager.(cpp|h)に変更され、EventListenerService.hはエクスポートされていません。EventListenerManager.hはエクスポートされていますので、#include "mozilla/EventListenerManager.h"と記述すべきです。

Bug-org 983049 Rename nsEventDispatcher to mozilla::EventDispatcher 初回投稿日時: 2014年03月20日22時08分13秒
最終更新日時: 2014年03月20日22時09分21秒
カテゴリ: Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014032005
SNS: (list)

この修正により、各クラス名は以下のように変更されています。

  • nsEventChainVisitormozilla::EventChainVisitor
  • nsEventChainPreVisitormozilla::EventChainPreVisitor
  • nsEventChainPostVisitormozilla::EventChainPostVisitor
  • nsDispatchingCallbackmozilla::EventDispatchingCallback
  • nsEventDispatchermozilla::EventDispatcher
  • ELMCreationDetectormozilla::ELMCreationDetector
  • nsEventTargetChainItemmozilla::EventTargetChainItem

ファイル名は、EventDispatcher.(cpp|h)で、ヘッダはエクスポートされていますので、#include "mozilla/EventDispatcher.h"と記述すべきです。

2014年3月31日

Bug-org 981963 PeekMessage() may remove char message which is really different from found message (wParam of WM_DEADCHAR becomes 0) 初回投稿日時: 2014年03月31日20時42分35秒
カテゴリ: Mozilla Core Mozilla29 Mozilla30 Mozilla31 Windows バグ修正
固定リンク: id=2014033100
SNS: (list)

PeekMessage()で、発見済みのWM_DEADCHARwParamが0に変化してしまっているというバグです。

原因はまだはっきりしていませんが、ひとまず、wParamが0ということは、文字入力が発生しないわけですから、この場合、WM_KEYDOWNに続く、WM_CHARメッセージは発見できなかったことにして、処理するように修正しています。

Bug-org 981960 PeekMessage(PM_REMOVE) sometimes fails to remove found char message (returns false) even if the message still in the queue 初回投稿日時: 2014年03月31日20時46分49秒
カテゴリ: Mozilla Core Mozilla29 Mozilla30 Mozilla31 Windows バグ修正
固定リンク: id=2014033101
SNS: (list)

メッセージキュー上に、WM_CHARメッセージがあるにも関わらず、PeekMessage()でそのメッセージを削除できないことがある、というバグです。

原因は分かりませんが、PeekMessage()で再び存在確認をしてみて、存在している場合、GetMesage()で取得するように修正してみました。

特に根拠のない修正でしたが、このパッチを投入後、このケースでのクラッシュレポートがゼロになりましたので、PeekMessage()PM_REMOVEを指定している場合の動作に、なんらかのバグがあるように思えます。

Bug-org 964718 MOZ_CRASH(WidgetQueryContentEvent doesn't support Duplicate()) at ../../dist/include/mozilla/TextEvents.h:333 初回投稿日時: 2014年03月31日20時55分21秒
最終更新日時: 2014年04月17日12時32分00秒
カテゴリ: Events Mozilla Core Mozilla29 Mozilla30 Mozilla31 バグ修正
固定リンク: id=2014033102
SNS: (list)

Geckoが内部処理用に発行したイベントが、何らかの理由でWebコンテンツにキャッチされ、サポートしていないDOMイベントのコピー処理が走って、クラッシュする、というバグです。

内部処理用のイベントは、匿名のDOMイベントの発火も伴います。しかし、イベントが匿名であるが故に、DOMイベント用の処理は不要なはずなので、そのような想定外のことが発生した場合には、クラッシュするようにしておいたところ、クラッシュするケースが発見されました。

発見されたケースでは、開発者向けツールで、イベントを捕捉するようにすることが条件となっていました。Smaugによると、nsIEventListenerServiceを利用すれば、全てのイベントを捕まえることが可能なので、それが原因かもしれない、とのことでしたが、確認はとれていません。

今回の修正で、DOMイベントの発火が内部処理でも不要なものに関しては、DOMイベント自体の生成をスキップするように修正しました。このため、IME利用時のパフォーマンスが若干改善していると思われます(体感はできないと思いますが、バッテリの浪費を防ぐという意味で)。

また、匿名のイベントを今の設計では発火させざるを得ないものに関しては、そのまま発火させ、DOMイベント用の処理を実装し、クラッシュしないように修正しています。

AuroraとBetaにもパッチが入ったため、29以降で修正されたことになります。