 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 ;
+combinators.smart fonts memoize ;
 IN: ui.text.freetype
 
 SINGLETON: freetype-renderer
 
-SYMBOL: open-fonts
+M: freetype-renderer finish-text-rendering drop ;
 
 : 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 ;
+    0 = [ "FreeType error" throw ] unless ;
+
+DEFER: init-freetype
 
 : freetype ( -- alien )
     \ freetype get-global expired? [ init-freetype ] when

        { { "serif" t f } "VeraSeBd" }
        { { "serif" t t } "VeraBI" }
        { { "serif" f t } "VeraIt" }
    } at ;

: ttf-path ( name -- string )
    "resource:fonts/" ".ttf" surround ;

: (open-face) ( path length -- face )
    #! We use FT_New_Memory_Face, not FT_New_Face, since
    #! FT_New_Face only takes an ASCII path name and causes
    #! problems on localized versions of Windows
    [ freetype ] 2dip 0 f <void*> [
        FT_New_Memory_Face freetype-error
    ] keep *void* ;

: open-face ( font -- face )
    ttf-name ttf-path malloc-file-contents (open-face) ;

SYMBOL: dpi


    [ ] [ length ] ?if ;

M:: freetype-renderer offset>x ( n font string -- x )
    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
