コア描画の実装
0.3.0には描画のキャッシュと描画クロージャを導入しないことにしたので、全ての描画はdrawopのlistに一旦変換されることになる。cairo contextの確保と解放はライブラリ側で隠蔽し、ビットマップオブジェクトの確保と解放はユーザ側に任せる。
たとえばWin32 windowへの描画を行うためにビットマップを確保する = Windowを開く という風に対応づけることができるため、ユーザはこれといって描画オブジェクトの確保/解放を意識する必要はない。もちろん、drawopのlistはSchemeオブジェクトなので自動的に回収される。
描画命令のemit
描画命令を発行するための分岐にはとりあえず*1matchを使う。
(match e (('move-to x y) (cairo_move_to ctx (inexact x) (inexact y))) (('line-to x y) (cairo_line_to ctx (inexact x) (inexact y))) (('hline-to x) (cairo_line_to ctx (inexact x) (cur-y))) (('vline-to y) (cairo_line_to ctx (cur-x) (inexact y))) (('quad-to x0 y0 x1 y1) (let ((xx0 (cur-x)) (yy0 (cur-y)) (xx1 (inexact x0)) (yy1 (inexact y0)) (xx2 (inexact x1)) (yy2 (inexact y1))) (cairo_curve_to ctx (/ (+ xx0 (* 2.0 xx1)) 3.0) ; 1st (/ (+ yy0 (* 2.0 yy1)) 3.0) (/ (+ xx2 (* 2.0 xx1)) 3.0) ; 2nd (/ (+ yy2 (* 2.0 yy1)) 3.0) xx2 ; end yy2))) ...
(truetypeとかで使われるような)2次ベジェはcairoには存在しないので、変換する必要がある。単に2:1で加重平均を取ればよい。
一般に、この手のAPIでは直線や曲線の始点を指示することはない(なぜなら、通常のシチュエーションでは"前の線分の続き"を描くから)ので、曲線のフォーマットを修正する必要があるときは始点を取得する必要がある。
環境
描画リストの中には(Schemeのモノではない)独自の環境への参照を持つものがある。これは、一種のラベル&ループとして機能し、一つのpathを複数回ストロークするようなケースで利用される。
(line-to* 10.0 10.0) (save-path my-line) (path my-line) (pen my-pen0) (stroke) (path my-path) (pen my-pen1) (stroke)
環境はpen、path、paint(塗り色)、image(GPUにロードされたビットマップ)、mask(未実装)のいづれかのオブジェクトを持つ。
環境はcanvasオブジェクトに関連づけられ、環境中のオブジェクトは、canvasコンテキストが解放されると同時(= 描画されたタイミング)にすべて解放される。少なくとも、cairoではこれらのオブジェクトの生成コストはほぼゼロ(mallocと同等)なので大きな問題ではない。
リスト中には実際のビットマップなどは持たず、あくまでシンボルでアクセスする点が重要となる。
*1:この手の"リストを変換してeval"は共通のインフラが有った方がいいかもしれない。