一晩寝たので、整数丸めの箇所をデバッガで丁寧に追う。まずはデータがおかしくなる箇所を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]
765│ if ( sp->selected || !onlysel ) 766│ SplinePointRound(sp,factor); 767│ if ( 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; // ここが実行されている。 }