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

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

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

2014年4月8日

Windows 8.1のシステムイメージに関するメモ 初回投稿日時: 2014年04月08日00時14分42秒
最終更新日時: 2014年04月08日00時16分30秒
カテゴリ: Memo Windows 雑談
固定リンク: id=2014040800
SNS: (list)

何度かのシステムドライブのトラブル時に全然役に立たなかった、Windows 8.1のシステムイメージによるバックアップについて、気付いたことを書いておきます。さほど厳密に検証した訳ではないので、間違った情報を含んでることを前提に、参考にしてもらえれれば良いかと思います。

回復ドライブは、そのシステムに必要なドライバ類がインストールされたイメージではない

復旧時に様々なユーティリティを起動するために、回復ドライブの作成を推奨されますが、これには、そのシステムの認識に必要な全てのドライバが含められていません。

バックアップイメージのあるドライブが、拡張カード経由接続されている場合(例えばeSATAのカード増設してるとか)だと、そのドライバのインストールイメージ(インストーラ形式ではなく、.INFファイルと、生のドライバ)を回復ドライブに、手動でコピーしておく必要があります。

ちなみに、zipすら解凍できませんてので要注意。

eSATAのポートマルチプライヤはバックアップドライブに使えない?

詳しく検証していませんが、ポートマルチプライヤで接続したドライブは、拡張カードのドライバをインストール後も認識しませんでした(プライマリのHDD以外がアクティブにならず)。

バックアップデータが、一台のHDDで収まらない容量のシステムだと、ハードウェアRAID内蔵の外付けケースを利用した外付けHDDにするしかなさそうです。

記憶域が認識できるかは不明

私は、eSATA+ポートマルチプライヤで、4台のHDDを接続し、それをひとつの記憶域として構築していましたが、上記の理由で、HDD自体が認識されなかったため、記憶域が回復ドライブからアクセスできるのかは未知数です。

システムドライブ交換時に、回復ドライブで起動して、Cドライブのイメージを新しいドライブに書き戻せない

これが一番致命的なのですが、システムドライブの物理的な故障により、システムドライブを新品のドライブに交換した場合、回復ドライブから、書き戻すことができません。おそらく、ライセンス認証の都合等だと思うのですが、これは実際問題、使い物にならない感じがします。

おそらく、一度、Windows 8.1を新しいドライブにクリーンインストールしてからの書き戻しなら大丈夫なのだと思われます(そういう形で復旧した記憶はぼんやりとあり)。

ただ、Windows 8.1をWindows 8からのアップグレードでインストールした場合、そもそも、Windows 8.1のインストールディスクそのものが無いので、メチャクチャ不便な訳です。

こんな感じで困ったことになってしまったので、システムイメージからの復旧はあきらめ、旧システムドライブから、これでDO台を利用した、ハードコピーという、力技での解決になりました。もちろん、旧システムドライブが完全に死んでいる場合にはこの手段は使えませんし、ファイルシステム的には空の領域のコピーも行わなくてはいけないため、時間はかかるわ、SSDの書き込み寿命を無駄に消費するわと、良いことはありません。

未だにWindowsのシステムドライブ交換のスマートな方法は見つけられていませんが、今回の教訓は、

  • 回復ドライブには外付けHDDのアクセスに必要なドライバをコピーしておく
  • システムイメージはできればHDD単体に保存。それができない場合は、ハードウェアRAIDを搭載したHDDケースを用意するのが吉
  • システムドライブ以外の復旧には、システムイメージはやはり強力なソリューションなので、バックアップは定期的にとっておく方が安心

といった感じです。

2014年4月9日

Bug-org 984271 Rename nsEventStateManager to mozilla::EventStateManager 初回投稿日時: 2014年04月09日13時11分44秒
カテゴリ: Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014040901
SNS: (list)

nsEventStateManager関連のリネームです。以下のように変更されました。

  • ホイールイベント処理のユーティリティメソッド → mozilla::WheelHandlingUtilsのメソッドに変更
  • nsScrollbarsForWheelmozilla::ScrollbarsForWheel
  • nsMouseWheelTransactionmozilla::WheelTransaction
  • nsEventStateManagermozilla::EventStateManager
  • OverOutElementsWrappermozilla::OverOutElementsWrapper
  • nsUITimerCallbackmozilla::UITimerCallback

mozilla::WheelHandlingUtilsmozilla::ScrollbarsForWheelmozilla::WheelTransactionは、dom/events/WheelHandlingHelper.(cpp|h)に分離されました。このヘッダファイルはエクスポートされていません。

dom/events/nsEventStateManager.(cpp|h)は、dom/events/EventStateManager.(cpp|h)にリネームされ、ヘッダは、mozilla/EventStateManager.hとしてエクスポートされています。

Bug-org 984253 Rename nsJSEventListener to mozilla::JSEventListener 初回投稿日時: 2014年04月09日13時21分01秒
カテゴリ: Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014040902
SNS: (list)

nsJSEventListenerまわりの整理です。nsIJSEventListenerインターフェースは廃止・統合され、新たに、コンクリートクラスである、mozilla::JSEventHandlerがインターフェースとしても動作するようになっています。Listenerが、Handlerに変更されていることに注意してください。

  • nsIJSEventListenermozilla::JSEventHandlerに統合
  • nsEventHandlermozilla::TypedEventHandler
  • nsJSEventListenermozilla::JSEventHandler

mozilla::TypedEventHandlerは、nsIJSEventListener.hの廃止に伴い、JSEventHandler.hに移動しています。

dom/events/nsJSEventListener.(cpp|h)は、dom/events/JSEventHandler.(cpp|h)に改名され、ヘッダは、mozilla/JSEventHandler.hとしてエクスポートされています。

Bug-org 984269 Rename nsDOMEventTargetHelper to mozilla::dom::EventTargetHelper or something 初回投稿日時: 2014年04月09日13時25分19秒
最終更新日時: 2014年04月09日13時25分50秒
カテゴリ: Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014040903
SNS: (list)

nsDOMEventTargetHelperが、mozilla::DOMEventTargetHelperにリネームされました。これに伴い、dom/events/nsDOMEventTargetHelper.(cpp|h)が、dom/events/DOMEventTargetHelper.(cpp|h)にリネームされ、ヘッダは、mozilla/DOMEventTargetHelper.hとしてエクスポートされています。

Bug-org 989214 Rename nsPaintRequest to mozilla::dom::PaintRequest 初回投稿日時: 2014年04月09日13時29分47秒
カテゴリ: Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014040904
SNS: (list)

nsPaintRequest関連のリネームです。

  • nsPaintRequestmozilla::PaintRequest
  • nsPaintRequestListmozilla::PaintRequestList

dom/events/nsPaintRequest.(cpp|h)は、dom/events/PaintRequest.(cpp|h)にリネームされ、ヘッダは、mozilla/dom/PaintRequest.hとしてエクスポートされています。

Bug-org 989212 Rename nsEventStates to mozilla::EventStates 初回投稿日時: 2014年04月09日13時34分40秒
カテゴリ: Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014040905
SNS: (list)

nsEventStatesは、mozilla::EventStatesにリネームされ、ファイル名も、dom/events/nsEventStates.hから、dom/events/EventStates.hにリネームされました。また、mozilla/EventStates.hとしてエクスポートされています。

ただし、このヘッダ内にある、NS_EVENT_STATE_*は、マクロのまま放置されています。mozilla::ネームスペース内で定義された、定数の方が望ましいと思いますが、パッチの数が膨大になることと、リファクタリングに疲れたので、今回はノータッチです。どなたか、やりたい方が居たら、練習にやってみてはどうでしょうか?

Bug-org 990855 Remove dom/events from local includes 初回投稿日時: 2014年04月09日13時38分36秒
カテゴリ: Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014040906
SNS: (list)

dom/events配下のクラス名、ファイル名の整理が全て終了し、外部から参照されるヘッダファイルは全てエクスポートしましたので、dom/events配下のヘッダファイルは、mozilla/*.h、もしくは、mozilla/dom/*.hとしてインクルードされるべきです。このため、LOCAL_INCLUDESから、dom/eventsへの参照を全て削除しました。

2014年4月11日

Bug-org 993234 Implement D3E KeyboardEvent.isComposing 初回投稿日時: 2014年04月11日15時54分58秒
カテゴリ: Events Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014041100
SNS: (list)

今週頭に、以前からW3Cに提案していた、KeyboardEvent.isComposingが採用され、ドラフトに追加されましたので、早速、実装してしまいました。

ただし、Geckoはバグがある場合を除き、compositionstartからcompositionendの間は、キーイベントは今のところ発生しませんので、この属性が実際に利用されるのは、Bug-org 354358の修正後になるかと思います。

Bug-org 993253 Implement D3E InputEvent interface with isComposing 初回投稿日時: 2014年04月11日16時05分47秒
カテゴリ: Events Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014041101
SNS: (list)

こちらは、inputイベントや、D3Eで提案されているbeforeinputのための、InputEventインターフェースを、isComposing属性のみでひとまず実装しようというバグです。

こちらのInputEvent.isComposingはGeckoでも使いやすいものとなっています。例えば、テキストが変更される度に、その文字列を使って、何らかの処理を行いたい場合で、未確定文字列の変化は無視したい場合、これまでは、

var target = document.getElementById("foo");
var isComposing = false;
target.addEventListener("compositionstart", function (event) { isComposing = true; }, false);
target.addEventListener("compositionend", function(event) { isComposing = false; }, false);
target.addEventListener("input",
  function (event) {
    if (!isComposing) {
      doSomething(target.value);
    }
  }, false);

と、フラグをひとつ設け、管理しなくてはいけませんでした。この処理では、ブラウザにバグがあり、compositionstartcompositionendが適切に発生しないケースがあると破綻していました。

しかし、InputEvent.isComposingを利用することで、

var target = document.getElementById("foo");
target.addEventListener("input",
  function (event) {
    if (!event.isComposing) {
      doSomething(target.value);
    }
  }, false);

このような、シンプルなコードで同様のことが実現可能になりました。

2014年4月16日

Bug-org 930893 Implement D3E KeyboardEvent constructor 初回投稿日時: 2014年04月16日00時48分07秒
最終更新日時: 2014年04月25日16時27分06秒
カテゴリ: Events Javascript Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014041600
SNS: (list)

D3Eで定義された、KeyboardEventのコンストラクタを実装しよう、というバグです。

このバグの修正により、コンストラクタを利用して、全ての属性を初期化しつつ、untrustedイベントを生成することができます。

var keydown =
  new KeyboardEvent("keydown", { bubbles: true, cancelable: true,
                                 view: window, detail: 0,
                                 keyCode: 65, charCode: 0, which: 65,
                                 key: "a", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD };
var keypress =
  new KeyboardEvent("keypress", { bubbles: true, cancelable: true,
                                  view: window, detail: 0,
                                  keyCode: 0, charCode: 97, which: 97,
                                  key: "a", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD };
var keyup =
  new KeyboardEvent("keyup", { bubbles: true, cancelable: true,
                               view: window, detail: 0,
                               keyCode: 65, charCode: 0, which: 65,
                               key: "a", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD };

例えば、この例では、Geckoのaキーを押した時と同じイベントを生成しています。これを利用して、エディタ等を更新することはできませんが、Webアプリのイベントハンドラの自動テストには使いやすいかと思います。

なお、あわせて、このバグの修正時に、D3Eで定義されている、KeyboardEvent.initKeyboardEvent()も一応、実装しておきました。これの実装義務はもはや無いので、あくまでも、IE向けのコードとの互換性のためでしかありません。ですが、このメソッドはブラウザ毎に仕様が異なっているので要注意です。ちなみに、Geckoには昔から、KeyEvent.initKeyEvent()というメソッドも存在していますので、あわせて紹介しておきましょう。

ブラウザ実装しているメソッド
DOM Level 3 Events
void initKeyboardEvent(DOMString typeArg,
                       boolean canBubbleArg,
                       boolean cancelableArg,
                       window? viewArg,
                       long detailArg,
                       DOMString keyArg,
                       unsigned long locationArg,
                       DOMString modifiersListArg,
                       boolean repeatArg)
Gecko
void initKeyEvent(DOMString typeArg,
                  boolean canBubbleArg,
                  boolean cancelableArg,
                  window? viewArg,
                  boolean ctrlKeyArg,
                  boolean altKeyArg,
                  boolean shiftKeyArg,
                  boolean metaKeyArg,
                  unsigned long keyCodeArg,
                  unsigned long charCodeArg)
void initKeyboardEvent(DOMString typeArg,
                       boolean canBubbleArg,
                       boolean cancelableArg,
                       window? viewArg,
                       long detailArg,
                       DOMString keyArg,
                       unsigned long locationArg,
                       DOMString modifiersListArg,
                       boolean repeatArg)
IE
void initKeyboardEvent(DOMString typeArg,
                       boolean canBubbleArg,
                       boolean cancelableArg,
                       window? viewArg,
                       long detailArg,
                       DOMString keyArg,
                       unsigned long locationArg,
                       DOMString modifiersListArg,
                       boolean repeatArg,
                       DOMString localeArg)
Blink
void initKeyboardEvent(DOMString typeArg,
                       boolean canBubbleArg,
                       boolean cancelableArg,
                       window? viewArg,
                       DOMString keyIdentifierArg,
                       boolean ctrlKeyArg,
                       boolean altKeyArg,
                       boolean shiftKeyArg,
                       boolean metaKeyArg,
                       boolean altGraphKeyArg)
WebKit

このように、互換性は最悪な状況です。IEは、D3Eにかつて存在していた、locale属性を初期化する引数が、現在の標準仕様の最後に追加されている形になっています。この引数を指定した場合でも、Geckoでは、エラーなく動くことは確認済みで、自動テストにも含めていますので、IE向けのコードはGeckoでそのまま動きます。ただし、Geckoはlocale属性をサポートしていませんので、この引数は無視されます。

Blink/WebKitでは、過去の仕様案に従っているのか、現在からは考えられないような引数構成になっています。detail属性は初期化できない上、key属性ではなく、独自のkeyIdentifier属性を初期化する引数があり、さらに、AltGrキーの状態を指定する引数が最後にあります。

幸い、Blinkでは、コンストラクタをサポートしていることを確認していますので、コンストラクタが存在しない場合に、try-catchを利用して、フォールバックしていく以外に、スマートなやり方はなさそうです。

最後に、keyCodecharCodewhich属性の値について、注意があるので書いておきます。

これらのレガシー属性は、Blinkのコンストラクタを利用しても初期化できないことは確認しています。つまり、今のところ、これらの属性値を初期化できるのは、Geckoのみということになります。

ですが、Geckoにも少し、癖があります。まず、コンストラクタで初期化した場合、初期化時に指定した値がそのままセットされます。未指定時には初期値の0になります。

それに対し、initKeyEventで初期化した場合、keyCode属性は、イベントのtype属性値が、keydownもしくはkeyupでない場合、無視され、0がセットされます。ただし、keypressの場合は、charCodeがゼロの場合のみ、無視されません。

同様に、initKeyEventで初期化した場合、charCode属性は、イベントのtype属性値が、keypress以外の場合、無視され、0がセットされます。

initKeyEventで初期化した場合、which属性値は直接初期化できませんが、keyCode属性値、もしくは、charCode属性値と同じものがセットされます。type属性値が、keydown、もしくは、keyupの場合は、keyCode属性値がセットされ、keypressの場合は、keyCode値が、DOM_VK_RETURN (0x0D)、もしくは、DOM_VK_BACK_SPACE (0x08)の場合は、keyCode属性値がセットされ、それ以外の場合は、charCode属性値がセットされます。type属性値がこれらのいずれでもない場合は、常に0となります。

initKeyEvent()で初期化した場合の挙動は、trustedイベントの挙動と全く同じものなので、この様に、複雑なものとなっています。今回の修正で単純化も考えましたが、そもそも、このようなレガシーなメソッドを利用しているコードの互換性を壊すのも意味が無いことなので、コンストラクタでの初期化時のみ、その動作を単純化しています。

KeyboardEvent.initKeyboardEvent()の実装は取りやめになりました。IEのものと互換性が無いことが分かったため、feature detectionを完全に壊してしまうことがその理由です。GeckoとIEでは、コンストラクタを利用し、WebKitとBlinkでは、非標準のinitKeyboardEvent()を利用するようにしてください。

2014年4月23日

Firefox 29で修正したバグ 初回投稿日時: 2014年04月23日02時24分28秒
最終更新日時: 2014年04月23日02時25分46秒
カテゴリ: Firefox Mozilla29
固定リンク: id=2014042300
SNS: (list)

いよいよ、Firefox 29のリリースがいよいよ来週に迫ってきましたが、来週は書き込めるチャンスが無さそうなので、今のうちに、私が修正した、コアの改善点を紹介しておきます。

ちなみに、UI面ではAustralisと呼ばれる新UIが来ますが、あれで十分な人には良いリリースになるかと思います。あれでは拡張性が足りない、という人は、Classic Theme Restorerをインストールして、カスタマイズ性を取り戻せば、特に問題ないかと思います。

Windows版で、Flash Playerがwindowlessモードで動作している場合と、Mac版でFlash Playerが動いている場合、IMEの未確定文字列はインラインでは表示されず、フローティングウインドウに表示されますが、この表示位置がプラグインのすぐ下に表示され、より、見やすくなります。特に、Macユーザには満足してもらえる修正じゃないかと思います。

Windows版FirefoxのwindowlessモードのFlash Player
スクリーンショット
Mac版FirefoxのFlash Player
スクリーンショット

Windowsでは、多くのノートPCのタッチパッドで、ドロップダウンリストをスクロールしようとすると、ドロップダウンが閉じてしまい、ページ全体がスクロールする、という問題がありました。これは、タッチパッドのドライバ側の問題なのですが、回避策を見つけることができたので、Firefox側で対処しています。このバグにイライラさせられていた方も多いのではないかと思います。

最後に、KeyboardEvent.keyの実装が一段階、前進しました。デッドキーの対応はまだですが、文字入力キーのイベントの値が、MozPrintableKey等から、仕様通りになっています。また、一部、キー名も最新の仕様にあわせて削除されました。まだこれから、最新のドラフトにあわせて、キー名の修正が入りますので、実用には厳しい状況ですが、興味のある方はテストしてみてください。

他にも、GTK3版や、WindowsのTSFモードが大きく改善されていますが、こちらは一般のユーザや開発者の方には関係ないので、個別に確認してもらえれれば、と思います。

2014年4月25日

Bug-org 810179 Make IMEContentObserver cycle collectable 初回投稿日時: 2014年04月25日16時38分44秒
最終更新日時: 2014年04月25日16時40分50秒
カテゴリ: Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014042500
SNS: (list)

mozilla::IMEContentObserver (旧称: nsTextStateManager)をサイクルコレクターに入れて管理しようというバグです。

この修正により、コンテンツをIMEContentObserverが監視中は、そのnsPresContextに紐付いているmozilla::EventStateManagerに登録し、ESMから管理する形になりました。

ただし、mozilla::IMEStateManagerは引き続き、static変数で同時に管理していますので、論理的なバグがある場合にはリークはあり得ると思います。その場合は盛大に挙動がバグっているとは思いますが。

この修正によって、IMEContentObserverもDOMノードのキャッシュ等が安全にできるようになりますので、今後、mozilla::ContentEventHandlerのキャッシュを利用した高速化につながると思います。

2014年4月30日

Bug-org 999645 KeyboardEvent.initKeyboardEvent requires too many arguments 初回投稿日時: 2014年04月30日21時05分06秒
最終更新日時: 2014年04月30日21時08分46秒
カテゴリ: Events Firefox Google Chrome IE Mozilla Core Mozilla31
固定リンク: id=2014043000
SNS: (list)

Bug-org 930893の修正で実装したKeyboardEvent.initKeyboardEvent()ですが、実際に1Passwordのfeature detectionが壊れたという報告が来ました。BlinkやWebKitでは、大半の引数がオプションなので、省略して呼び出している所でエラーとなるようになったようです。

さらに、実装時には気付かなかったIEとの非互換問題も存在していました。そのため、実装する意義が無いということで、バックアウトしました。IEとGeckoでは、コンストラクタを仕様することを強く推奨します。

Bug-org 998188 ContentEventHandler::OnQueryCaretRect() converts native text offset with wrong node 初回投稿日時: 2014年04月30日23時39分35秒
最終更新日時: 2014年04月30日23時40分36秒
カテゴリ: Mozilla Core Mozilla31 バグ修正
固定リンク: id=2014043001
SNS: (list)

デバッグビルドでTwitter等、contenteditable等で作成されたリッチテキストエディタでIMEを使っていると、mozilla::ContentEventHandler内でオフセットの異常を検知して強制終了するというバグです。

このバグの原因は、Metro版Firefoxのchromeのコードから、nsIDOMWindowUtils.sendQueryContentEvent()を呼び出す際に、JS上で取得した文字列のオフセットを利用して、キャレットの位置を取得できるようにするために、アドホックな修正を入れてたことで混入していました。

ただし、デバッグビルドで発生する異常検知も、エディタ内のテキストノードが複数存在する場合にのみ検知できていたので、これまで、バグの混入に誰も気付いていなかったという感じです。IMEを利用した場合、未確定文字列が独立したテキストノードとして挿入されているので、この条件が整っていたわけです。

今回の修正では、まず、アドホックな修正そのものを取り除き、nsIDOMWindowUtils.sendQueryContentEvent()と、nsIDOMWindowUtils.sendSelectionSetEvent()の引数にフラグを追加し、指定するオフセットや、長さ、前者の戻り値のオフセット、長さ、文字列それぞれが、改行文字列が、JSで扱いやすい\nのみXPモードと、ネイティブAPIとの通信に必要な、ネイティブの改行文字列、例えばWindowsでは\r\nであるネイティブモードを選択可能にしました。

nsIDOMWindowUtils.sendSelectionSetEvent()には注意が必要で、最後にあったbooleanの引数は削除され、新設したフラグの一つとなっています。互換性を失っていますが、これは、addons.mozilla.orgに登録されているアドオンのソースコードを横断検索し、利用しているアドオンが存在しないことを確認した上でのことです。ですので、自前のWebサイト等で配布されている、いわゆる、野良拡張や、企業等で組織内での利用のために作成されたアドオンがこのメソッドを利用していると、動作が壊れている可能性があることに注意してください(ただし、その引数がfalseの場合は問題なく、利用していたとしても、falseであることが通常のはず)。