Firefox3 独自の HTML5::Canvas TextAPI CanvasRenderingContext2D.mozDrawText に描画されない不具合があるみたい

今日もCanvasネタです。Firefox3にText APIを実装する方法を模索してましたが、そのとき見つけた不具合について書き残します。

Firefox3限定のAPIに、mozPathText(), mozDrawText() というものがあります。

mozDrawText()

mozTextStyle 属性で指定されたテキストスタイルを用いて、指定されたテキストを描画します。コンテキストの現在の fill (塗りつぶし) の色がテキストの色として用いられます。

mozPathText を呼ぶだけで描画されそうな雰囲気ですが、実際にやってみると、

CanvasRenderingContext2D.prototype.fillText = function(text, x, y, maxWidth) {

  this.mozTextStyle = this.font;
  this.translate(x, y);
  this.mozDrawText(text);
};

テキストが描画されません。
ちょっと上にスクロールアウト⇒スクロールインさせるとスクロールアウトした部分だけが描画されているので、明らかに変です。

スクロール以外にも、ウインドウサイズを変更したり、他のタブに切り替えると再描画されます。


Geckoのソースコードを見てみると、Redraw() が呼ばれていないようです。

1551 NS_IMETHODIMP
1552 nsCanvasRenderingContext2D::MozDrawText(const nsAString& textToDraw)
1553 {
1554     const PRUnichar* textdata;
1555     textToDraw.GetData(&textdata);
1556 
1557     PRUint32 textrunflags = 0;
1558 
1559     PRUint32 aupdp;
1560     GetAppUnitsValues(&aupdp, NULL);
1561 
1562     gfxTextRunCache::AutoTextRun textRun;
1563     textRun = gfxTextRunCache::MakeTextRun(textdata,
1564                                            textToDraw.Length(),
1565                                            GetCurrentFontStyle(),
1566                                            mThebesContext,
1567                                            aupdp,
1568                                            textrunflags);
1569 
1570     if(!textRun.get())
1571         return NS_ERROR_FAILURE;
1572 
1573     gfxPoint pt(0.0f,0.0f);
1574 
1575     // Fill color is text color
1576     ApplyStyle(STYLE_FILL);
1577     
1578     textRun->Draw(mThebesContext,
1579                   pt,
1580                   /* offset = */ 0,
1581                   textToDraw.Length(),
1582                   nsnull,
1583                   nsnull,
1584                   nsnull);
1585     return NS_OK;
1586 }

なにか使えないもんか? と、コードを見てみると
fill() はスタイルを適用して、Redraw() するだけのようなので、テキストを描画させるためには、mozPathText() + fill() でいけそうな気がします。

1266 NS_IMETHODIMP
1267 nsCanvasRenderingContext2D::Fill()
1268 {
1269     ApplyStyle(STYLE_FILL);
1270     cairo_fill_preserve(mCairo);
1271     return Redraw();
1272 }

具体的にはこうします。

CanvasRenderingContext2D.prototype.fillText = function(text, x, y, maxWidth) {

  this.mozTextStyle = this.font;
  this.translate(x, y);
  this.mozDrawText(text);
  this.fill(); // ← ここ追加
};

これで、テキストが描画されるようになりました。


ググってみたら、同じようなことを体験した方がいらっしゃるようです。
http://d.hatena.ne.jp/electrolysis/20080123/1201026733

追記

ctx.fill() だとカレントパスが存在する場合に、そちらも塗りつぶされてしまうので、 ctx.fillRect(0,0,0,0) のほうが良いような気がします。

uuCanvas.jsuupaa.js では以下のようにして回避しています。

  ctx.mozDrawText(text);
  ctx.fillRect(0, 0, 0, 0); // force redraw