コア描画の実装

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"は共通のインフラが有った方がいいかもしれない。