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

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

もずはっく日記(2012年8月)

2012年8月8日

Bug-org 775414 InitKeyEvent() should decide input string instead of InitKeyPressEvent() 初回投稿日時: 2012年08月08日16時42分50秒
最終更新日時: 2012年08月08日16時53分38秒
カテゴリ: Mac Mozilla Core Mozilla17 バグ修正
固定リンク: id=2012080800
SNS: (list)

Bug-org 758420の修正のクリーンナップです。

KeyboardEvent.keyと、KeyboardEvent.charを実装する際に、keydownや、keyupでも入力される文字を特定しなくてはいけないので、そのコードがInitKeyPressEvent()メソッドに、しかもハッキーな設計込み、というのは非常に困るので、必要な部分を分離して、全キーイベントの初期化メソッドであるInitKeyEvent()に移動し、InitKeyPressEvent()には結果だけをパラメータで渡すという形にしました。

これによる動作の変化はありません。

Bug-org 768742 OS/2 IME level3 support 初回投稿日時: 2012年08月08日16時52分54秒
最終更新日時: 2012年08月08日16時53分22秒
カテゴリ: Events Mozilla Core Mozilla16 バグ修正
固定リンク: id=2012080801
SNS: (list)

これは私の修正ではないですが、感動したので紹介しておきます。

OS/2版はボランティア開発者のみでメンテされているのですが、メンテナがメンテし切れていない部分のコードを一度削除しました。この時にIME関係のコードはまるごと削除されていたのですが、16で突然、書き直してくれた方がいらっしゃいました。KO Myung-Hunさんという方です。この、OS/2版をメンテされてる方達にはほんとに頭が下がります。

で、投入されたパッチをチェックしたところ、DOM3 CompositionEventの発生順序、タイミングが間違っていました。そこで、それを指摘したところ、またしても修正してくれています。

ただ、現在のコードを見ると、複数の文節を入力した時の表示が間違っているように思います。例えば、文節が二つある場合でも、常に全体が選択されたように表示されるのではないかと思います。OS/2版をお使いの方で、確認できた方が居たら、是非Bugzillaにバグ報告しておいてください。KOさんは、報告があれば対処するとおっしゃってますので。

2012年8月16日

Bug-org 719320 Implement DOM3 wheel event #2 初回投稿日時: 2012年08月16日13時01分29秒
最終更新日時: 2012年08月16日13時01分53秒
カテゴリ: Events GTK IE Mac Mozilla Core Mozilla17 Windows バグ修正
固定リンク: id=2012081600
SNS: (list)

4月あたりにほぼ完成していたD3E WheelEventの実装がようやく終わりました。実に、29のパッチに分割され、私個人では最高記録です。

この変更により、各widgetのコードは、ネイティブイベントの伝達に、nsMouseScrollEventではなく、mozilla::widget::WheelEventを利用するようになり、widget側のコードが非常にシンプルになっています。特に、high resolution scrollをサポートしているWindowsとMacでは、生成するイベントの回数が、最大で半分、もしくは1/4にまで減っているので若干のパフォーマンスの向上も期待できます。

Webアプリから見ると、この変更により、IE9以降とコードを共通化できるようになっています。もう、DOMMouseScrollや、MozMousePixelScrollといった、Geckoの複雑な独自イベントを処理する必要はありません。単に、wheelイベントを処理するだけで良いのです。

簡単なサンプルを書いておくと、こんな感じです。

var customScrollableElement = document.getElementById("scrollableElement");
var lineHeight = 16;
var pageWidth = 100;
var pageHeight = 100;
customScrollableElement.addEventListener("wheel", function (event) {
  // the event might be consumed.
  if (event.defaultPrevented) {
    return; // shouldn't do anything
  }

  // consume the event for preventing default action such as scroll.
  event.preventDefault();

  var deltaInPixels = { x: 0, y: 0 };
  switch (event.deltaMode) {
    case WheelEvent.DOM_DELTA_PIXEL:
      // delta values are number of pixels to scroll
      deltaInPixels.x = event.deltaX;
      deltaInPixels.y = event.deltaY;
      break;
    case WheelEvent.DOM_DELTA_LINE:
      // delta values are number of lines to scroll
      deltaInPixels.x = event.deltaX * lineHeight;
      deltaInPixels.y = event.deltaY * lineHeight;
      break;
    case WheelEvent.DOM_DELTA_PAGE:
      // delta values are number of pages to scroll
      deltaInPixels.x = event.deltaX * pageWidth;
      deltaInPixels.y = event.deltaY * pageHeight;
      break;
    }
  }
  if (!deltaInPixels.x && !deltaInPixels.y) {
    return;
  }
  // do scroll here!
}, true);

wheelイベントはブラウザが拡大解釈せず、できるだけネイティブイベントの情報をそのまま伝達できるように設計されていますので、deltaMode属性値が、deltaXdeltaYdeltaZの値の単位を示します。Windowsでは、WheelEvent.DOM_DELTA_LINEか、WheelEvent.DOM_DELTA_PAGEになります。Macでは、WheelEvent.DOM_DELTA_PIXELか、WheelEvent.DOM_DELTA_LINEになります。どちらになるかは、使用しているデバイスのドライバや、その設定に依存します。これら以外のプラットフォームではWheelEvent.DOM_DELTA_LINEのみです。

deltaXdeltaYdeltaZは整数ではなく、小数を返します。たとえば、一回のイベントで、一行の三分の一だけスクロールする場合、deltaModeWheelEvent.DOM_DELTA_LINEで、delta値が0.3333...になります。正の値が、下方向、もしくは右方向で、負の値が、上方向、もしくは左方向を意味します。つまり、そのまま座標に可算できます。

deltaZは、今のところ、どのプラットフォームでも常にゼロとなります。Mac(Cocoa)のネイティブイベントにはZ軸方向のdelta値も存在するのですが、これを活用しているデバイスがないため、ネイティブイベントの符号と、DOMイベントの符号を同一のものとするか、反転させるべきなのか、その判断がつかないためです。

ちなみに、Macのみ、ネイティブイベント一つで斜め方向のスクロールが表現できるため、deltaXdeltaYが同時に非ゼロになることがあるので注意してください。

if (event.deltaX) {

} else if (event.deltaY) {

}

このようなコードを書いてしまうと、多くのイベントを捨てることになり、レスポンスの悪いアプリケーションになってしまいます。

このため、今までの垂直方向と、水平方向を同時に指定できていたユーザ設定は再利用不能になりました。また、最近のネイティブホイールイベントは操作速度に応じて、様々な大きさの値をデルタ値に指定してきますので、今までのデルタ値をそのまま固定した値で置換してしまう設定もすでに時代遅れとなっています。

この問題を解決するため、また、ESR10とprofileを共有しても問題が出ないように、全ての設定が新設されました。

まず、モディファイアキーを指定する部分の名前が変わりました。defaultwith_altwith_controlwith_metawith_shiftwith_winとなっています。二つ以上のモディファイアキーを同時押ししている場合は、defaultになります。MacのCommandキーはwith_metaになります。

各イベントのデフォルトアクションは、mousewheel.(モディファイアキー).actionで指定できます。値も以前とは変更されていて、0は「何もしない」、1は「スクロール」、2は「履歴を戻る、もしくは進む」、3は「ズーム」となっています。

デルタ値のカスタマイズは係数を設定で指定し、ネイティブイベントのデルタ値に掛けるようになりました。mousewheel.(モディファイアキー).delta_multiplier_xmousewheel.(モディファイアキー).delta_multiplier_ymousewheel.(モディファイアキー).delta_multiplier_zでその係数を指定します。値は、1001.0を意味します。-200と指定すると、-2.0倍されるため、スクロール方向は逆になり、速度も倍になります。また、この設定は、DOMのwheelイベントのdeltaXdeltaYdeltaZの値も書き換えますので注意してください。現在、100未満、-100より大きい数値には対応していません

ちなみに、今までのレガシーイベントDOMMouseScrollイベントと、MozMousePixelScrollイベントも、これまでとできる限り同じタイミングで発生します。イベントの発生順序は、

  1. wheelイベントが通常イベントグループで
  2. 垂直方向のDOMMouseScrollイベントが両方のイベントグループで、ただし、wheelイベントがpreventDefault()で消費されておらず、wheelイベントが1行以上のスクロールの場合に限る
  3. 垂直方向のMozMousePixelScrollイベントが両方のイベントグループで、ただし、wheelイベントがpreventDefault()で消費されておらず、wheelイベントが1ピクセル以上のスクロールの場合に限る
  4. 水平方向のDOMMouseScrollイベントが両方のイベントグループで、ただし、wheelイベントがpreventDefault()で消費されておらず、wheelイベントが1行以上のスクロールの場合に限る
  5. 水平方向のMozMousePixelScrollイベントが両方のイベントグループで、ただし、wheelイベントがpreventDefault()で消費されておらず、wheelイベントが1ピクセル以上のスクロールの場合に限る
  6. wheelイベントがシステムイベントグループで

となっています。システムイベントグループは、Webコンテンツからは登録できないグループで、通常イベントグループでイベントが全て伝播した後に、再び全ての要素のシステムイベントグループのイベントリスナにイベントが配信されます。これは、通常イベントグループでstopPropagation()が呼び出されていても行われるので、デフォルトアクションの実装に最適です。

ですので、アドオン作者の方は、システムイベントグループでwheelイベントのリスナを登録することで、レガシーイベントが処理されたかどうかを確認してからwheelイベントを処理することが可能になっています。

Bug-org 782552 Nightly not responding properly to left/right trackpad swipes 初回投稿日時: 2012年08月16日13時12分46秒
カテゴリ: Mac Mozilla Core Mozilla17 バグ修正
固定リンク: id=2012081602
SNS: (list)

MacOS X 10.7と、MacOS X 10.8で、二本指スワイプで、「戻る」「進む」ができなくなったというバグで、もちろん、Bug-org 719320の修正によるregressionです。

nsEventStateManagerは、mozilla::widget::WheelEventの後処理で、デフォルトアクションがスクロールだった場合に、スクロールに実際に利用しなかったデルタ値を、overflowDeltaXと、overflowDeltaYというメンバにセットします。

ですが、そのwheelイベントでスクロールできる要素が見つからなかった場合、これをセットせずに処理を終了してしまっていました。正しくはdeltaXと、deltaYの値をそのままセットすることで、widget側は、全くスクロールされなかったので、履歴の移動に利用しよう、となるわけです。

Bug-org 422132 font size 0px on div with scrollbars disables mouse wheel scrolling 初回投稿日時: 2012年08月16日13時23分28秒
カテゴリ: Mozilla Core Mozilla17 バグ修正
固定リンク: id=2012081603
SNS: (list)

font-size: 0;のスクロール可能な要素では、ホイールによってスクロールできない、というバグです。実際には、キーボードの矢印キーでもスクロールできませんでした。

nsIScrollableFrame::GetScrollLineAmount()がフォントサイズを元に、行高を返してくるので、この値を元にスクロール処理を行うのですが、中途半端なことに、このメソッドはfont-size: 0;の場合に、1 app unitを返してきていました。これは、Gecko内部では、60分の1pxとなりますので結果、スクロールしないという形になっていました。

このバグの修正で、mousewheel.min_line_scroll_amountという設定を追加しました。nsIScrollableFrame::GetScrollLineAmount()は、この設定値(意味はピクセル数)より、計算した戻り値が小さい場合、この設定値と同じ意味の値を返すようになります。

また、ホイールイベントは、0.1行ずつスクロール、といったことが普通にありますので、その修正だけではまだスクロールできません。このため、nsEventStateManager::DeltaAccumulatorで、スクロールに利用されなかった端数を記録しておくようにしました。このため、スクロール量が小さい場合でも、ホイールを回し続ければ、トータルでは期待通りのスクロールスピードでスクロールするようになっています。

Bug-org 659071 Ctrl + scrollwheel doesn't zoom when hovering a <video> element 初回投稿日時: 2012年08月16日13時28分07秒
カテゴリ: Mozilla Core Mozilla17 バグ修正
固定リンク: id=2012081604
SNS: (list)

<video>要素の上にカーソルがある時に、Ctrl+ホイールでズームを行おうとしても、ズームできないというバグです。

内部的には、<video>要素内のパーツはXULの要素を組み合わせているため、XUL要素上ではズームしない、というチェックに引っかかってしまっていました。

カーソル下の要素がXULの要素かどうか確認するのではなく、要素がXUL documentに属しているかどうかで判断するように変更して、修正しています。

Bug-org 310003 ESM mousewheel code should use AppendLiteral instead of Append for appending strings 初回投稿日時: 2012年08月16日13時31分58秒
カテゴリ: Mozilla Core Mozilla17 バグ修正
固定リンク: id=2012081605
SNS: (list)

nsEventStateManagerがホイール関連の設定を読み込むために、設定名を変数上で組み立てて行く時、nsCAString::AppendLiteral()を使うべき状況でも使っていなかったというバグです。

Bug-org 719320の修正であわせて修正しました。

Bug-org 782739 mouse wheel zoom is lost after tab switch 初回投稿日時: 2012年08月16日13時47分13秒
カテゴリ: Mozilla Core Mozilla17 バグ修正
固定リンク: id=2012081606
SNS: (list)

Bug-org 719320の修正の、漏れです。マウスホイールでズームした場合、タブを切り替えたときに、ズーム量を忘れてしまうというものです。

browserのコードは、サイト毎にズーム量を記憶するため、マウスホイールのイベントを監視して、ズームを行うイベントが来た場合には、そのイベント直後にズーム量を記憶するようなことを行っていました。この、ズームを行うイベント、かどうかを判断するために、設定を読んでいたのですが、それが古い設定のままだったので、ズーム量が変化していることに気付かず、そのタブに戻ってきた時にズーム量変更前の値に戻してしまう、ということになってしまっていました。

ただ、このような設計は全然駄目なので、そのうち、落ち着いたら、ズーム量の変化があった場合にカスタムイベントを発行するようにして、安全にハンドルできるように修正するつもりです。現に、SpecialPowers.setFullZoom()に対応できていないため、本来ならあり得ないテスト失敗が発生する要因になってしまっていますので。

2012年8月20日

Bug-org 782175 delta_multiplier_(x|y|z) should support less than 100 value and larger than -100 value 初回投稿日時: 2012年08月20日19時06分08秒
カテゴリ: Mozilla Core Mozilla17 バグ修正
固定リンク: id=2012082000
SNS: (list)

mousewheel.default.delta_multiplier_x等の設定で、99から-99の値が当初は指定できませんでしたが、bug-org 422132の修正で、超低速スクロール時にも対応可能になったので、修正が終わりました。