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

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

もずはっく日記(2015年10月)

2015年10月2日

Flash Playerのせいで犠牲になっている、Firefoxの軽い動作を取り戻しましょう 初回投稿日時: 2015年10月02日22時33分45秒
カテゴリ: Firefox Flash Mozilla Core 雑談
固定リンク: id=2015100200
SNS: (list)

Firefoxの動作が遅い、よく聞く苦情です。その原因のうち、かなりの割合は以前から指摘しているようにパフォーマンスを犠牲にしたアドオンをインストールしていることに起因していると思われます。ですが、もう一つ、大多数の人が無駄にコストを払っているであろう原因があります。それは、Flash Playerです。

Flash Playerが必要なコンテンツがページ内に存在している場合に、Flash Playerをロードするためのplugin-container.exeや、Flash Player内部での保護モード(Windowsのみ)のためのプロセス間通信等、非常に多くの時間、CPUを占有してしまいます。これが、Webページ読み込み時の「重たさ」の原因の一つとなっています。

しかし、意外とこれに対して対策をきちんととっている人は少ないのではないでしょうか?

また、自分のアクセスしているWebサイトでは動画プレイヤーやブラウザゲームぐらいでしかFlash Playerが利用されていないので関係無いと思ってはいないでしょうか?

ここで紹介する設定を行うと驚くと思いますが、思わぬページで"見えない"Flash Playerが存在して、Firefoxのパフォーマンスを落としているのです。しかし、Flash Playerは依然として一部のWebサービスのメインコンテンツとして重要なポジションを確立していますので、もちろん、完全にアンインストールしたり、無効化したりすることは現実的な解決策ではありません。そこで、Firefoxに搭載しているClick-to-Playを利用します。

まず、パネルにある「アドオン」をクリックします。

パネルを開いた時に表示される「アドオン」のスクリーンショット

続いて、表示されるアドオンマネージャの左側のペインで「プラグイン」を選択し、「Shockwave Flash」という行にある「常に有効化する」をクリックし、「実行時に確認する」に変更します。

アドオンマネージャでShockwave Flashを「実行時に確認にする」に設定しているスクリーンショット

この状態でFlash Playerを利用しているWebページにアクセスすると、以下のような通知バーがページ上部に表示されます。

ページ上部に表示されるClick-to-Playの通知バーのスクリーンショット

そのWebサイト全体でFlash Playerが不要な場合、「ブロックを継続」ボタンを押すと、そのサイトへアクセスした時にこの通知バーが表示されることはありません。

そのWebサイトでFlash Playerを表示する必要がある場合、「許可...」ボタンを押します。すると、次のダイアログがURLバーの左端下に表示されます。

URLバー左側下に表示されたClick-to-Playの許可ダイアログのスクリーンショット

ここにある「常に許可する」を押すと、そのWebサイトでは今まで通り、Flash Playerは常に自動的に実行されるようになります。

「今だけ許可」を押すと、Flash Playerが実行されますが、次回以降にアクセスした場合にはまた問い合わせが表示されます。Flash PlayerがそのWebサイトの機能の一部で必要なものの、毎回必要というわけでもなく、その頻度も低い場合はこちらを選択しておく方が良いでしょう。

この設定はユーザにとって不要なFlash Playerを利用している多くのWebサイトで効果が絶大です。ハングアップやクラッシュ、さらには、セキュリティホールの温床となっているFlash Playerを必要な(逆に言えば信頼しているサイト)以外で無効化させつつ、Flash Playerの利用自体も可能なこの機能、是非、利用してみてください。

2015年10月14日

Bug-org 1209464 Window neutering missing from MessageChannel::WaitForInterruptNotify 初回投稿日時: 2015年10月14日11時07分59秒
最終更新日時: 2015年10月31日10時08分42秒
カテゴリ: Flash Mozilla Core Mozilla42 Mozilla43 Mozilla44 plugin Windows バグ修正
固定リンク: id=2015101400
SNS: (list)

WindowsでFirefox 41にアップグレードしてからFlash Playerでよくハングアップするというバグです。

Army of Awesomeで実際に困っている方と連絡をとってみると、保護モードを無効化すると回避できるようではありますが、Firefox側にも修正が入りました。実際にリリースが行われるのか不明ですが、Firefox 41.0.2がリリースされる場合にはこの修正が含まれるようです(といってもあと2週間で42がリリースされてしまう)。

忙しくて更新できていませんでしたが、この修正は結局、41.0.2からはバックアウトされていました。スタックオーバーフローのバグの原因になっていたためです(たまたまクラッシュするメソッドがTSF関係のメソッドだったので私も巻き込まれてましたが……)。

2015年10月31日

Bug-org 1208043 [TSF] MS-IME for Korean inserts composition string to the end of previous textnode when you type text at start of <p> 初回投稿日時: 2015年10月31日10時37分20秒
カテゴリ: IME Mozilla Core Mozilla42 Mozilla43 Mozilla44 TSF Windows バグ修正
固定リンク: id=2015103100
SNS: (list)

contenteditableEnterキーを押した時の動作には2種類あって、<div contenteditable>foo</div>というエディタ上では<br>要素が挿入し、キャレットのその後ろに移動させますが、<div contenteditable><p>foo</p></div>というエディタで(<p>要素内にキャレットがある時に)は新しい<p>要素を生成して、その内部にキャレットを移動させます。このバグは後者の場合に、Enterキーを押した直後、つまり空の<p>要素でハングル文字を入力しようとすると、ひとつ前の<p>要素の最後に入力されてしまうというバグです。

まずそもそも何故このようなことが発生しているのかというと、ハングル用のMS-IMEは非常に特殊な挙動で未確定文字列の入力開始を通知してきている点にありました。普通のTIPは、ITfContextOwnerCompositionSink::OnStartComposition()を呼び出して、明示的に未確定文字列の編集が始まったことをアプリに通知してから、文字の入力や、選択範囲の設定を行います。それに対してハングル用のMS-IMEは、先にITextStoreACP::InsertTextAtSelection()を呼び出し、最後にITfContextOwnerCompositionSink::OnStartComposition()をその時に期待される選択範囲と共に呼び出します。

このような順序のため、TSFTextStoreは、まずテキストの挿入が未確定文字列の編集無しに行われ、その後、別の範囲をターゲットに未確定文字列の編集が開始されたと考えていました。ですので実際に、最初の編集に対してcompositionstartcompositionupdatecompositionendを送信した後、compositionstartが再度送信されるという動作になってしまっていました。

そして、何故、挿入位置がずれてたかというと、現在、GeckoがDOMツリーからIME APIに対して渡すコンテンツの内容は<br>要素のみを改行文字に変更したプレーンテキストになっています(ContentEventHandlerで生成)。このため、<p>foo</p><p></p>というDOMツリーでは、空の<p>要素内にキャレットがある場合のオフセットと、最初の<p>要素の末尾(つまり、fooテキストノードの末尾)のオフセットが同じになってしまいます。未確定文字列が指定された範囲で変換が開始されるこのケースでは選択範囲を再設定しなくてはいけませんが、選択範囲をContentEventHandlerを利用して設定した場合、常に、後者の位置が優先されてしまうため、このようなバグの発生につながっていました。

今回の修正では、未確定文字列の編集が開始される際に、直前に行われてキューに入っている内容を確認し、直前の内容がITfContextOwnerCompositionSink::OnStartComposition()の指定してきた範囲に直接文字を挿入していた場合、compositionstartcompositionupdatecompositionendをキューから取り除き、新たにcompositionstartcompositionupdateをあるべき形でキューに入れ直すことでContentEventHandler側のオフセットの矛盾問題に触れないように修正しました。

Bug-org 1109410 IME candidate window position doesn't honor CSS transform 初回投稿日時: 2015年10月31日10時42分54秒
カテゴリ: CSS IME Mozilla Core Mozilla44 バグ修正
固定リンク: id=2015103101
SNS: (list)

エディタか、その祖先の要素がCSSのtransformプロパティで移動や変形されている場合、IMEの候補ウインドウがその変形を適用前の座標に表示されてしまうというバグです。TweetDeckで新しいツイートを入力する際に候補ウインドウ位置がずれるのはこのバグが原因です。

以前、Army of Awesomeでこのバグを知ったときには適切なAPIが内部になく、修正が簡単では無さそうだったので放置して忘れてしまっていましたが、nsLayoutUtilsにこれを解決するAPIが用意されていたので、今回、修正を行いました。

Bug-org 1211352 [e10s][IMM] composition string on windowless plugin should be positioned at left-bottom of the plugin 初回投稿日時: 2015年10月31日10時57分59秒
カテゴリ: Flash IME Mozilla Core Mozilla44 plugin Windows バグ修正
固定リンク: id=2015103102
SNS: (list)

e10sモードでは、windowlessモードで動作するFlash Player上でIMEを使用した場合、未確定文字列が昔のように画面左上に表示されていました。これを現在の非e10sモード時のように、プラグインコンテンツの左下に表示すべきというバグです。

今回の修正により、IMEContentObserverはプラグインがフォーカスを持っている間にも生成されるようになりました。ただし、通常の各プラットフォーム用のwidgetはプラグインがフォーカスを持つ場合にはどの通知も要求しませんので、非e10sモードでは存在するだけという形になります。それに対してPuppetWidgetはレイアウトや位置変更の通知のみを要求します。これにより、ContentCacheInParentにエディタの矩形(プラグインがフォーカスを持つ場合にはプラグインコンテンツ全体の矩形)がキャッシュされるようになりましたので、IMMHandlerがこのキャッシュを利用できるようになり、非e10sモードの時と同様に動作するようになっています。

Bug-org 376679 WM_MOUSEWHEEL and WM_MOUSEHWHEEL messages should be delivered to windowless plugins 初回投稿日時: 2015年10月31日11時22分13秒
カテゴリ: Flash Mozilla Core Mozilla44 plugin Windows バグ修正
固定リンク: id=2015103103
SNS: (list)

Windowsでは、windowlessプラグインに対してWM_MOSUEWHEELメッセージや、WM_MOUSEHWHEELメッセージが送信されていないため、windowlessプラグイン上でマウスホイールが使えないというバグです。

調べてみると、そもそも、WidgetWheelEventにネイティブのメッセージをそのまま挿入していませんでした。しかし、単純にこれを行えば修正できるという話でもありません。なぜならGeckoは高解像度スクロールに完全に対応しているため、WidgetWheelEventWM_MOSUEWHEELWM_MOUSEHWHEELを受信した時に必ず送信している訳ではないからです(小数の端数による問題のため)。また、Flash Playerやその他のプラグインも高解像度スクロールに完全に対応しているのか怪しいという点もあります。少なくとも昔、Logitechのエンジニアからの要請でGeckoに高解像度スクロールを実装した際にテストした時には、当時のFlash Playerは非対応でした。

そこで、今回はトリックを使って(この点に関しては)簡単に実装してしまうことにしました。

WidgetWheelEventには、DOMMouseScrollイベントの発火に利用するためのlineOrPageDeltaXlineOrPageDeltaYというメンバがあります。これらは、それぞれの方向へのスクロール量が整数で表現できるようになった時にだけ値がセットされます。例えばWindowsの場合、0.5行ずつのWM_MOUSEWHEELメッセージが連続して来た場合、最初のWidgetWheelEvent::lineOrPageDelatYは1で、二つ目は0、三つ目は再び1、となり、delta値の合計とつじつまが合うようになっています。

これを利用し、この値からWM_MOUSEWHEELメッセージやWM_MOUSEHWHEELメッセージのwParamを計算することで常に、整数行のスクロールが発生するデルタ値のメッセージをwindowlessプラグインに対して送信するようにし、互換性問題を低くしています(ひょっとするとWHEEL_DELTA値で送信しないとスクロールが早すぎるという古くて、当時でも間違っていた実装方法のままのプラグインもあるかもしれませんが……)。

ただし、この修正だけだと、マウスホイールでページ全体をスクロール中にwindowlessプラグインがカーソルの下へ移動してくると、全てのマウスホイールイベントをそのwindowlessプラグインに消費されてしまいます。つまり、スクロールが止まってしまうというバグが発生します。これを防ぐために、windowlessプラグインにマウスホイールのメッセージを送信するのはeWheelイベントのデフォルトアクションという扱いにすることにしました。これにより、マウスホイールトランザクションが活用可能になりますので、直前のスクロールが優先されることになります。

ただし、マウスホイールトランザクションで救えないケース、例えばwindowlessプラグイン上でマウスホイールの操作を開始した場合には、そのwindowlessプラグインが実際にホイールを処理しているか否かに関わらず、そのプラグインに消費されてしまいます。つまり、見た目からページ全体のスクロールを期待しているとバグっているように見えます。しかし、これは別プロセスで動くwindowlessプラグインからホイールの処理が必要だったかどうか、その結果を受けとる仕組みが存在しないので解決不能な問題です。

Bug-org 1213811 [TSF] Bug 1208043 can be reproduced with TavultesoftKeyman90 or TavultesoftKeyman80 初回投稿日時: 2015年10月31日11時28分25秒
カテゴリ: IME Mozilla Core Mozilla42 Mozilla43 Mozilla44 TSF Windows バグ修正
固定リンク: id=2015103104
SNS: (list)

Bug-org 1208043で報告されているバグが、TavultesoftKeyman90とTavultesoftKeyman80というテキストサービスを利用したTIPでも再現するというバグです。

Bug-org 1208043は前述の通り修正済みですが、Betaである42では万全を期すため、報告されているTIPがアクティブな場合のみ、新しい動作を行うようにしていました。そこで、このバグではアクティブなTIPが問題となっているテキストサービスを利用している場合にも修正が適用されるようにホワイトリストへの追加を行いました。

Bug-org 1215434 APZC shouldn't handle eWheel event when the event will be handled by plugin 初回投稿日時: 2015年10月31日11時42分26秒
カテゴリ: e10s Flash Mozilla Core Mozilla44 plugin バグ修正
固定リンク: id=2015103105
SNS: (list)

e10sモードが有効になっているNightlyではAPZCがデフォルトで有効になっていますが、この場合、Bug-org 376679の修正がAPZCによって無視され、windowlessプラグインにホイールイベントが伝達されません。

単純にAPZCにイベントが伝達された後にもwindowlessプラグインにホイールイベントを渡すように修正しても、windowlessプラグイン、ページ全体共にスクロールする、ダブルアクションな状況になってしまったので、APZCの担当であるMarkus Stange [:mstange]に聞いてみたところ、APZCはDisplayListからホイールイベントを消費する可能性のある要素の範囲を予めキャッシュしておくことでスクロールの非同期をスムーズに行っているので、そのチェックの際にwindowlessプラグインも対象として含めないといけないとのことでした。

似たような修正をされる方はこのバグに添付したパッチを参考にしてみてたください。

Bug-org 1215517 Add tests for eSetSelection, eQueryTextContent and eQuerySelectedText 初回投稿日時: 2015年10月31日11時48分42秒
カテゴリ: IME Mozilla Core Mozilla44 TSF Windows バグ修正
固定リンク: id=2015103106
SNS: (list)

Bug-org 1208043の解説記事で述べたように、現在のContentEventHandlerの仕様には問題があります。そして、ハングル用のMS-IMEにTSFモードで完全に対応するにはこの問題を完全に解決する必要があることが別のバグ報告から分かりました。そのため、このバグで先行して、ContentEventHandlercontenteditableエディタがフォーカスを持っている場合の挙動のテストを大量に追加しました。

このテストで分かりましたが、エッジケースでは特にバグが多々存在しています。

Bug-org 1215816 nsContentIterator::Init(nsIDOMRange*) shouldn't include end node if it's an empty element and end offset is 0 when mPre == true 初回投稿日時: 2015年10月31日11時57分18秒
カテゴリ: Mozilla Core Mozilla44 バグ修正
固定リンク: id=2015103107
SNS: (list)

ContentEventHandlerの修正をしていて発見したnsContentIteratorのバグです。NS_NewPreContentIterator()でインスタンスを生成した場合、指定した範囲のルートとなる要素から最初の葉ノードまで列挙していく、開始タグを列挙する動作になりますが、この場合に指定した範囲の最後のノードが子ノードを持たず、ノード内のオフセットが0の場合に、その要素自身を列挙してしまうというバグです。

例えば、<p>[<br>]<br></p>の"[]"の選択範囲を表現しようとした場合、開始位置が最初の<br>要素のオフセット0、終了位置が二つ目の<br>要素のオフセット0という形もあり得ます。この場合、最初の<br>要素のみが列挙されるべきという話です。

Bug-org 1215798 nsContentIterator::Init(nsIDOMRange*) ignores start node of the range if it's empty node like <br> when mPre == true 初回投稿日時: 2015年10月31日12時02分44秒
最終更新日時: 2015年10月31日12時03分47秒
カテゴリ: Mozilla Core Mozilla44 バグ修正
固定リンク: id=2015103108
SNS: (list)

ContentEventHandlerの修正をしていて発見したnsContentIteratorのバグです。NS_NewPreContentIterator()でインスタンスを生成した場合、指定した範囲のルートとなる要素から最初の葉ノードまで列挙していく、開始タグを列挙する動作になりますが、この際、指定した範囲の開始位置が空要素のオフセット0だと、その開始要素を無視してしまうというバグです。

例えば、[<br>text]nodeの"[]"部分を指定したい場合、開始位置が<br>要素のオフセット0、終了位置がtextnodeのオフセット4というケースがありますが、この場合、textnodeのみが列挙されていました。

Bug-org 1217275 [IMM] MS-IME for Japanese on WinXP SP3 hangs up at inputting first Kana character 初回投稿日時: 2015年10月31日12時12分56秒
カテゴリ: IME Mozilla Core Mozilla42 Mozilla43 Mozilla44 Windows バグ修正
固定リンク: id=2015103109
SNS: (list)

Windows XPのMS-IMEが、一文字目のかなを入力した時点でハングアップしたり、Firefoxがクラッシュするというバグです。Aliceさんが報告してくれた上に、regression範囲を調査してくれたところ、奇妙なことにその原因となっているのはnsIMM32Handlermozilla::widget::IMMHandlerにリネームしたバグでした。

さらにAliceさんがその時のログを提出してくれたおかげで、IMR_DOCUMENTFEEDの結果を返したところでハングアップが発生しているところまで分かりました。そこで注意深くソースを見てみると、MOZ_LOG()内の不要な\nを削除した置換の際に、誤って、\nを検索しているコードまで置換してしまっていることに気付きました。そのため、空文字列を検索して(どのような数値が返ってきているのか分かりませんが)、その奇妙な値のせいでその後の処理がおかしくなってしまっていました。

ラッキーなことに、ギリギリで、42のRCビルドに入れてもらうことができました。

Bug-org 1184890 [e10s][GTK][TSF] cannot input composing string on comment of articles on Facebook 初回投稿日時: 2015年10月31日12時23分47秒
カテゴリ: e10s GTK IME Mozilla Core Mozilla44 TSF バグ修正
固定リンク: id=2015103110
SNS: (list)

Bug-org 1189396と同じ話のe10sモード版です。

e10sモードでは、compositionstartイベントハンドラでコンテンツの変化が発生した場合、その選択範囲の変化通知が未確定文字列が存在している時点で(未確定文字列が存在する前の)通知を受け取ることになります。この場合、GTK版とWindowsのTSFモードでは、未確定文字列を強制的に確定していました。

しかし、そのためにFacebookという有名サイトで問題が発生していたため、TSF版はオフセットが変化している場合には挙動がおかしくなってしまうものの、ひとまず問題が無いように強引に修正しています。

今回は単純に、選択範囲の変化が未確定文字列がエディタ上に存在しているかそうではなかったかを示すフラグを新たに追加し、未確定文字列が存在する場合に、未確定文字列が存在していなかった時の選択範囲の変更通知を受け取った場合に強制確定を行わないように修正しました。