らんだむな記憶

blogというものを体験してみようか!的なー

fontforgeデバッグ(3)

一晩寝たので、整数丸めの箇所をデバッガで丁寧に追う。まずはデータがおかしくなる箇所を1ヶ所ピックアップ。

      <point x="466.1" y="409.5" type="curve" smooth="yes"/>
      <point x="449.7" y="409.3"/>
      <point x="436.3" y="408.7"/>
      <point x="435.8" y="408.2" type="curve" smooth="yes"/>
      <point x="434.6" y="407"/>
      <point x="433.7" y="396.1"/>
      <point x="431.1" y="354.5" type="curve" smooth="yes"/>

      <point x="466" y="410" type="curve" smooth="yes"/>
      <point x="450" y="410"/>
      <point x="436" y="408" type="line" smooth="yes"/> 君はカーブだろ?CPは??
      <point x="435" y="407"/>
      <point x="434" y="396"/>
      <point x="431" y="354" type="curve" smooth="yes"/>

に化けるところが比較的早く現れている。
ここを追いかける。

[splinechar.c]

 765if ( sp->selected || !onlysel )
 766│                     SplinePointRound(sp,factor);
 767if ( sp->prev!=NULL )
 768│                     SplineRefigure(sp->prev);

の部分をステップ実行しながら中身を見てみる。

(gdb) p *sp
$28 = {me = {x = 435.7998046875, y = 408.2001953125}, nextcp = {x = 434.599609375, y = 407}, prevcp = {x = 436.2998046875, y =
408.7001953125}, nonextcp = 0, noprevcp = 0, nextcpdef = 0, prevcpdef = 0, selected = 0, nextcpselected = 0, prevcpselected = 0
, pointtype = 0, isintersection = 0, flexy = 0, flexx = 0, roundx = 0, roundy = 0, dontinterpolate = 0, ticked = 0, watched = 0
, ptindex = 0, ttfindex = 65534, nextcpindex = 65534, next = 0x904a20, prev = 0x904b00, hintmask = 0x0, name = 0x0}
(gdb) p *sp->prev
$29 = {islinear = 0, isquadratic = 0, isticked = 1, isneeded = 0, isunneeded = 0, exclude = 0, ishorvert = 0, knowncurved = 1,
knownlinear = 0, order2 = 0, touched = 0, leftedge = 0, rightedge = 0, acceptableextrema = 0, from = 0x904a90, to = 0x9049b0, s
plines = {{a = 9.9013671875, b = 8.9970703125, c = -49.1982421875, d = 466.099609375}, {a = 0.4990234375, b = -1.1982421875, c
= -0.6005859375, d = 409.5}}, approx = 0x0}
(gdb) n
(gdb) p *sp
$31 = {me = {x = 436, y = 408}, nextcp = {x = 435, y = 407}, prevcp = {x = 436, y = 408}, nonextcp = 0, noprevcp = 1, nextcpdef
 = 0, prevcpdef = 0, selected = 0, nextcpselected = 0, prevcpselected = 0, pointtype = 0, isintersection = 0, flexy = 0, flexx
= 0, roundx = 0, roundy = 0, dontinterpolate = 0, ticked = 0, watched = 0, ptindex = 0, ttfindex = 65534, nextcpindex = 65534,
next = 0x904a20, prev = 0x904b00, hintmask = 0x0, name = 0x0}
(gdb) n
(gdb) n
(gdb) p *sp->prev
$32 = {islinear = 0, isquadratic = 0, isticked = 1, isneeded = 0, isunneeded = 0, exclude = 0, ishorvert = 0, knowncurved = 1,
knownlinear = 0, order2 = 0, touched = 0, leftedge = 0, rightedge = 0, acceptableextrema = 0, from = 0x904a90, to = 0x9049b0, s
plines = {{a = 12, b = 6, c = -48, d = 466}, {a = 4, b = -6, c = 0, d = 410}}, approx = 0x0}

$28->$31が座標を丸める前後。$29->$32は線の種別情報? $30は大して面白くない情報が出たから編集して消した。($でMathJaxが発動してしまう...。Unicodeで指定しても発動する...)
おかしくなっている箇所は丸めた後に、meとprevcpが同一座標になっているのが気になるね。

$28 = {me = {x = 435.7998046875, y = 408.2001953125}, prevcp = {x = 436.2998046875, y =408.7001953125},
$31 = {me = {x = 436, y = 408}, prevcp = {x = 436, y = 408},

これに着目して丸めている処理をステップ実行すると、座標の変更だけじゃなくて、CPの有無のフラグも変更していることが分かる。ここで、まずい箇所では noprevcp つまり、手前のCPがないという扱いになっているな。要するに座標を丸めてハンドル長が0になる場合、CPがないことにされるのだがそれは変だろう。バグだな。そもそもハンドル長が異常に短いデータというのがまずいというのはあるのだが、この処理だとそういうデータに対して不正なフォントを吐き出すことになる。
ま、こうしたところで、内部的に長さ0のハンドルができてしまうことが避けられないので、一旦小数座標で吐き出せておいて、別のツールで最低でも長さが1になるように丸めないと厳しいかもしれないな。まぁ、長さが0でも多分それほど実害はないと思うけど。

void SplinePointRound(SplinePoint *sp,real factor) {
    ...

    if ( sp->nextcp.x==sp->me.x && sp->nextcp.y==sp->me.y )
    sp->nonextcp = true;
    if ( sp->prevcp.x==sp->me.x && sp->prevcp.y==sp->me.y )
    sp->noprevcp = true; // ここが実行されている。
}