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

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

もずはっく日記(2011年11月)

2011年11月18日

preventDefault()で何が抑制できるのか? 初回投稿日時: 2011年11月18日16時23分52秒
最終更新日時: 2011年11月25日11時42分21秒
カテゴリ: Firefox Google Chrome IE Javascript Opera Safari
固定リンク: id=2011111800
SNS: (list)

stopPropagation()や、preventDefault()について調査中ですが、prentDefault()の実装が割と適当に感じます。

  • normal text
  • anchor text
  • scrollbars

2011年11月20日

Bug-org 159346 Scrollbar not working when moving mouse out and in again 初回投稿日時: 2011年11月20日15時46分30秒
カテゴリ: Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011112000
SNS: (list)

スクロールバーのボタンの上でマウスのボタンを押して、一度マウスカーソルをボタン外に出すと、カーソルを戻してもスクロールしないというバグです。

スクロールバーのボタンがキャプチャすることでスクロールを再開するように修正しました。また、Linuxではネイティブの動作にあわせて、ボタン外にカーソルがある間もスクロールし続けるように修正しています。

Macでは反対側のボタンの上にカーソルを移動すると、そのボタンの方向へのスクロールに切り替わるのですが、これはまだ実装できていません。

2011年11月23日

Bug-org 704049 Radio button shouldn't be checked by prevented default click event when any radio buttons in same group are not checked 初回投稿日時: 2011年11月23日08時42分36秒
カテゴリ: Google Chrome Javascript Mozilla Core Mozilla11 Safari バグ修正
固定リンク: id=2011112300
SNS: (list)

clickイベントをpreventDefault()していても、選択されたものがないラジオボタンのグループ内では、そのクリックしたラジオボタンにチェックが選択されてしまうというバグです。

Geckoではスタイル処理の問題から、DOMイベントを発行する前にチェックボックスやラジオボタンは一度選択状態にし、DOMイベントを発行し終わった後にdefaultPreventedtrueだった場合には状態を元に戻す、という処理を行っています。この戻すときの処理に問題があり、一度選択状態にする際に直前に選択されていたラジオボタンを記憶しておくのですが、これが復元時にnullだった場合に、ラジオボタンとして処理せず、選択状態を復元していませんでした。

ちなみに、全く同じバグがWebKitにも存在しているのでWebKitも全く同じミスをしているのかもしれません。WebKitな方は報告されると良いと思います。

2011年11月26日

Bug 6800 stopPropagation()でonmousedownイベントを停止するとマウスドラッグによるスクロールが不可能になる 初回投稿日時: 2011年11月26日10時17分08秒
カテゴリ: Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011112600
SNS: (list)

コンテンツがmousedownイベントの、(preventDefault()ではなく)stopPropagation()を呼んだときにブラウザのデフォルトアクションであるスクロールバーの操作が妨害されるのはおかしい、というバグです。

Geckoは内部で、二つのイベントループを行っています。最初にイベントが発行されるのが、Webコンテンツが受け取れる、通常グループ、その後で発行されるのがシステムグループ。defaultPreventedの値はシステムグループに受け継がれますが、stopPropagation()でイベントをWebコンテンツが止めてしまっても、システムグループでは再びstopPropagation()が呼び出されるまで発行される仕組みになっています。

スクロールバーのサムのドラッグのためのマウスイベントのハンドリングは通常グループの方にリスナを登録していたため、このような問題が発生してしまっていました。調査したところ、他にもいくつか似た内容のバグを発見しているため、これらの修正を容易にするためにnsIDOMEventTarget::addSystemEventGroup()を新設していたので修正に時間がかかってしまいました。この新しいメソッドはaddEventListener()と全く同じパラメータ、挙動をとりますが、バイナリを持った拡張では利用することができますが、scriptableではありません。

2011年11月27日

Bug-org 674770 contenteditable breaks middle-click to open links when middlemouse.paste=true 初回投稿日時: 2011年11月27日10時06分24秒
最終更新日時: 2011年11月27日10時20分00秒
カテゴリ: Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011112700
SNS: (list)

中クリックでの貼り付けが有効になっていると、contenteditableな要素のあるドキュメント内では編集不能なa要素であっても、中クリックでリンク先を開けないというバグです。

HTMLエディタのインスタンスはドキュメントごとにひとつしかなく、ドキュメントにイベントリスナを登録して全てのHTMLエディタの処理を行っています。例えば、

<body>
<p id="p1" contenteditable="true">Here is an editable paragraph.</p>
<p id="p2" contenteditable="true">Here is another editable pragraph.</p>
</body>

この例では、#p1にフォーカスが移動した場合は、DOM selectionのrange (つまり、キャレットや選択範囲)をその中に移し、入力イベントはそのrangeに対して実行します。#p2にフォーカスが移動すると、やはりrangeを#p2内に移動して同様に処理しています。

ですので、以前、キーイベントやIMEイベントで修正した様に、HTMLエディタは、処理内容によっては編集可能な要素がターゲットとなったイベントかどうかを確認しなくてはいけません。中クリックでの貼り付け、というのはもちろん、編集可能な要素がターゲットになっている場合にのみ実行しなくてはいけませんので、そのように修正しました。

ちなみに、

<html>
  <head></head>
  <body contenteditable="true"></body>
</html>

このように、ルート要素は編集可能ではないものの、body要素が編集可能な場合に、ルート要素をターゲットにしたマウスイベントが来た場合、上記の判定を行う前にターゲットをbody要素だと読み替えて処理を行います。ですので、body要素の高さを確保しなくてはマウスでキャレットを移したり、中クリックでの貼り付けができない、ということはありません。

2011年11月29日

Bug-org 697842 cancelling compositonstart causes unexpected result 初回投稿日時: 2011年11月29日09時28分19秒
カテゴリ: Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011112900
SNS: (list)

compositionstartイベントのstopPropagation()を呼び出すとHTMLエディタ内で未確定文字列が変になるというバグです。

これもやはりシステムイベントグループにイベントリスナを登録していないことが問題でした。ちなみに、compositionupdatecompositionendは今のところエディタの内部処理では利用していないので、これらのイベントではこのような問題は起こりえません。

Bug-org 703186 image map's focus outline may not be painted correctly if focus/blur event's stopPropagation() is called 初回投稿日時: 2011年11月29日09時51分16秒
カテゴリ: Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011112901
SNS: (list)

focusイベントやblurイベントがstopPropagation()で中断されると、イメージマップ内でのフォーカスリングが描画されなかったり、フォーカスを失った後でも描画されていたり、といったことが発生するというバグです。

これもシステムイベントグループでイベントリスナを登録することで解決しています。

Bug-org 685395 Redesign IME APIs of nsIWidget for mobile devices 初回投稿日時: 2011年11月29日10時06分50秒
カテゴリ: Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011112902
SNS: (list)

nsIWidgetのIME関連のAPIの整理です。

SetIMEEnabled()GetIMEEnabled()はFx4以降、動作しなくなっていましたが、完全に削除されました。

SetInputMode()GetInputMode()SetInputContext()GetInputContext()に改名され、そのパラメータのInputContextからはmReasonが削除され、代わりにSetInputContext()に追加のパラメータで、その呼び出し理由となったユーザのアクション、もしくはコンテンツの変化を通知するようになりました。これにより、実際には保証されていなかった、GetIMEEnabled()で最後に変更があった際の理由を取得するという機能は取り除かれました。

SetIMEOpenState()GetIMEOpenState()はそれぞれ、SetInputContext()GetInputContext()に統合されたため、削除されました。

これらの変更で、APIの形をnsIContent側と共通化できたので、nsIContentで定義されていたIMEの状態を示すフラグは全て廃止され、content側のコードでもwidget側で定義したmozilla::widget::IMEStateを利用するようになりました。これで、二つの状態フラグの存在によるイージーミスを防止することができます。

Bug-org 507987 [Maemo] [N8x0] virtual keyboard not shown by selecting an input field after forcing it to hide 初回投稿日時: 2011年11月29日10時12分31秒
最終更新日時: 2011年11月29日10時12分46秒
カテゴリ: Fennec Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011112903
SNS: (list)

サマリにはプラットフォームが書かれていますが、実際にはモバイル共通のバグで、フォーカスを持ったエディタ内でタップしてもソフトウェアキーボードを開くことができない、というバグです。

IME APIの整理時に同時に修正されています。

なお、タップはマウスのクリックイベントを生成しているため、通常のPCをターゲットにしたWebアプリでもアクセシビリティを確保できるように、あえてpreventDefault()されたクリックイベントでもソフトウェアキーボードを開けるようになっています。Webアプリ側で、編集可能な要素上でソフトウェアキーボードの表示を抑止することは今のところ不可能です。

2011年11月30日

Bug-org 703500 Cannot drop file to <input type="file"/> if drop event is called stopPropagation() 初回投稿日時: 2011年11月30日12時13分10秒
最終更新日時: 2011年11月30日12時13分32秒
カテゴリ: Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011113001
SNS: (list)

<input type="file"/>に対して、ドラッグアンドドロップでファイルを指定しようとしても、dropイベントのstopPropagation()が呼ばれていると動作しないというバグです。

他にもいくつか、イベントハンドラがdropイベントと同様に通常グループで登録していたので、そちらもあわせて修正しました。これによって他の動作も何らかの不具合があって、解消されているかもしれません。

Bug-org 703210 tooltip is not shown if stopPropagation() of mousemove event is called 初回投稿日時: 2011年11月30日12時19分17秒
カテゴリ: Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011113002
SNS: (list)

HTMLの要素のtitle属性にテキストを指定しておくと、マウスカーソルがその要素の上に移動した際にそのテキストがツールチップとして表示されますが、mousemoveイベントがstopPropagation()で止められてしまうと、表示されなくなってしまうというバグです。

これもやはり、システムイベントグループでイベントリスナを登録して解決しています。

CSS仕様における行高とオーバーフロー 初回投稿日時: 2011年11月30日17時04分56秒
最終更新日時: 2011年11月30日19時18分43秒
カテゴリ: CSS Mozilla Core
固定リンク: id=2011113003
SNS: (list)

最近、いくつか似た様な話を見かけたので、久々にCSSの基本的な部分を解説しておきます。

p {
  font-size: 16px;
  line-height: 16px;
}

このようなスタイルを指定した場合、p要素の行高は何ピクセルになるでしょうか? 16ピクセルと思った人はCSSのレイアウト仕様をもう一度読んだ方が良いです。正解は『16ピクセル以上だけど、分からない』です。

ブロックレベルの要素に対してline-heightを指定した場合、それはそのブロックレベル要素内の行の高さを指定しているのではなく、最低限の行高を指定していることになります。つまり、フォントによっては16ピクセル以上の高さになる可能性があります。また、例えインラインレベルの要素に対してline-heightを指定したとしても、表示しきれない部分がオーバーフローし、それが内容領域の高さに含まれることに注意してください。

ですので、以下の様なスタイルを書くと、文字の一部や、下線は表示されないかもしれません。

p {
  font-size: 16px;
  line-height: 16px;
  height: 16px;
  overflow: hidden;
  text-decoration: underline;
}

グリフの主要な部分は、16ピクセルの高さの中に表示されますが、文字の中心から離れているグリフの端は16ピクセル以上の領域を必要とするかもしれません。

下線もディセンダに十分な余裕がない場合、行の外側に描画されますので、オーバーフローしているかもしれません。

さて、ここでひとつ、Geckoの内部事情を知らないと理解できない挙動があります。例えば以下の様なスタイルを書いた場合、Windows版のGeckoではドラッグによってスクロールすることができます(実例)。

p {
  font-family: "MS PGothic";
  font-size: 8px;
  line-height: 8px;
  height: 8px;
  overflow: auto;
}

これは下線が書かれる場所を、text-decoration: underline;が指定されていなくても確保しているためです。MS PGothicは下線の位置指定がおかしいフォントの一つで、Geckoでは下線位置を推測して決めますが、この際にこのフォントのこのサイズでは十分なディセンダが無いために、行の外側に描くことを決断しています。ちなみに、この下線描画領域を確保をしておかないと、:hoverで下線の有無を変更された際などにHTMLの構造によってはかなりの再レイアウトが必要になり、CPU負荷を高めてしまいます。

結果的に、この下線の描画部分がオーバーフローを引き起こし、内容がスクロール可能になっています。現在のCSS仕様ではWebデザイナにこれを防ぐ手段はありません。なぜならオーバーフローした矩形のサイズを指定する手段が無いからです。

ちなみに、overflow: hidden;とすれば、スクロールされることはありません。ですが、

p {
  font-family: "MS PGothic";
  font-size: 8px;
  line-height: 8px;
  height: 8px;
  overflow: hidden;
  text-decoration: underline;
}

というスタイルであっても、下線は表示されません(実例)。overflow: hidden;によって切り取られているからです。

昔から何度も書いていますが、テキストを含めたレイアウトでタイトなレイアウトはCSSでは不可能です。テキストがどのようなサイズで描画されるのかはフォントや、各プラットフォームのAPIに依存しますし、テキストは読めないと話にならないのでブラウザはオーバーフローさせてでも内容の描画に努めます。ですので、Webデザイナはこういった無謀なチャレンジをすべきではありません。

Bug-org 392159 Middle-click paste doesn't work under Mac OS X when middlemouse.paste is true 初回投稿日時: 2011年11月30日21時15分10秒
カテゴリ: Mozilla Core Mozilla11 バグ修正
固定リンク: id=2011113005
SNS: (list)

MacOS Xでは、middlemouse.pastetrueにしていても中クリックで貼り付けが有効にならないというバグです。

editorのコードで#ifdefでプラットフォーム毎に決め打ちでprimary selectionを利用するか、クリップボードを利用するか決めるコードになっていました。Macにはprimary selectionは無いのですが、primary selectionを利用する側のコードが用いられていたため、何も貼り付けられない、という形になっていました。

nsIClipboardにはこれをきちんと調べるメソッドがあるので、それを利用してランタイムに処理することで問題がない実装に書き換えました。とにかく、プラットフォームを条件にした#ifdefは徹底的にcontentlayoutからは消していかなくては。