     [ ] [ length ] ?if ;
 
 M:: freetype-renderer offset>x ( n font string -- x )
-    font open-font string n head string-width ;
+    font string n head-slice string-width ;
+
+M: freetype-renderer line-metrics ( font string -- metrics )
+    [ string-width ]
+    [ drop open-font [ ascent>> ft-ceil ] [ descent>> ft-ceil ] bi 0 ] 2bi
+    metrics boa ;
+
+: init-freetype ( -- )
+    global [
+        f <void*> dup FT_Init_FreeType freetype-error
+        *void* \ freetype set
+        \ (open-font) reset-memoized
+        \ ttf-font reset-memoized
+    ] bind ;
 
 freetype-renderer font-renderer set-global

sequences io.files continuations freetype
ui.gadgets.worlds ui.text ui.text.private ui.backend
byte-arrays accessors locals specialized-arrays.direct.uchar
combinators.smart ;
IN: ui.text.freetype

SINGLETON: freetype-renderer

SYMBOL: open-fonts

: freetype-error ( n -- )
    zero? [ "FreeType error" throw ] unless ;

DEFER: freetype

: init-freetype ( -- )
    global [
        f <void*> dup FT_Init_FreeType freetype-error
        *void* \ freetype set
        H{ } clone open-fonts set
    ] bind ;

: freetype ( -- alien )
    \ freetype get-global expired? [ init-freetype ] when

: char-widths ( open-font string -- widths )
    [ char-width ] with { } map-as ;

: sums ( seq -- seq )
    0 [ + ] accumulate nip ;

: font-sprites ( font world -- sprites )
    fonts>> [ drop H{ } clone ] cache ;

: draw-background ( widths open-font -- )
    [ sum ] [ height>> ] bi* 2array gl-fill-rect ;

:: draw-selection ( widths open-font line -- )
    line color>> gl-color
    widths line start>> head-slice sum 0 2array [
        line [ start>> ] [ end>> ] bi widths <slice> sum
        open-font height>> 2array gl-fill-rect
    ] with-translation ;

M:: freetype-renderer draw-string ( font line loc -- )
    line dup selection? [ string>> ] when :> string
    font open-font :> open-font
    open-font world get font-sprites :> sprites
    open-font string char-widths :> widths
    GL_TEXTURE_2D [
        loc [
            font background>> gl-color
            widths open-font draw-background
            line selection? [ widths open-font line draw-selection ] when
            font foreground>> gl-color
            string widths sums [ [ open-font sprites ] 2dip draw-char ] 2each
        ] with-translation
    ] do-enabled ;

: run-char-widths ( open-font string -- widths )
    char-widths [ sums ] [ 2 v/n ] bi v+ ;

M: freetype-renderer x>offset ( x font string -- n )
    [ open-font ] dip
