<commit_before>! Copyright (C) 2005, 2009 <NAME>.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.accessors alien.c-types arrays io kernel libc
math math.vectors namespaces opengl opengl.gl opengl.sprites assocs
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 fonts memoize ;
IN: ui.text.freetype

SINGLETON: freetype-renderer

M: freetype-renderer finish-text-rendering drop ;

: freetype-error ( n -- )
    0 = [ "FreeType error" throw ] unless ;

DEFER: init-freetype

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

TUPLE: freetype-font < identity-tuple
ascent descent height handle widths ;

M: freetype-font hashcode* drop freetype-font hashcode* ;

M: freetype-renderer free-fonts ( world -- )
    values [ free-sprites ] each ;

: ttf-name ( font -- name )
    [ [ name>> ] [ bold?>> ] [ italic?>> ] tri ] output>array H{
        { { "monospace" f f } "VeraMono" }
        { { "monospace" t f } "VeraMoBd" }
        { { "monospace" t t } "VeraMoBI" }
        { { "monospace" f t } "VeraMoIt" }
        { { "sans-serif" f f } "Vera" }
        { { "sans-serif" t f } "VeraBd" }
        { { "sans-serif" t t } "VeraBI" }
        { { "sans-serif" f t } "VeraIt" }
        { { "serif" f f } "VeraSe" }
        { { "serif" t f } "VeraSeBd" }
        { { "serif" t t } "VeraBI" }
        { { "serif" f t } "VeraIt" }
    } at [ "No such font" throw ] unless* ;

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

MEMO: ttf-font ( font -- contents length )
    ttf-name ttf-path malloc-file-contents ;

: open-face ( font -- 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 ] dip ttf-font 0 f <void*>
    [ FT_New_Memory_Face freetype-error ] keep *void* ;

SYMBOL: dpi

72 dpi set-global

: ft-floor ( m -- n ) -6 shift ; inline

: ft-ceil ( m -- n ) 63 + -64 bitand -6 shift ; inline

: font-units>pixels ( n font -- n )
    face-size face-size-y-scale FT_MulFix ;

: init-ascent ( font face -- font )
    [ face-y-max ] keep font-units>pixels >>ascent ; inline

: init-descent ( font face -- font )
    [ face-y-min ] keep font-units>pixels >>descent ; inline

: init-font ( font -- font )
    dup handle>> init-ascent
    dup handle>> init-descent
    dup [ ascent>> ] [ descent>> ] bi - ft-ceil >>height ; inline

: set-char-size ( open-font size -- open-font )
    [ dup handle>> 0 ] dip
    6 shift dpi get-global dup FT_Set_Char_Size freetype-error ;

MEMO: (open-font) ( font -- open-font )
    freetype-font new
        H{ } clone >>widths
        over open-face >>handle
        swap size>> set-char-size
        init-font ;

GENERIC: open-font ( font -- open-font )

M: font open-font
    clone f >>background f >>foreground (open-font) ;

: load-glyph ( font char -- glyph )
    [ handle>> dup ] dip 0 FT_Load_Char
    freetype-error face-glyph ;

: char-width ( open-font char -- w )
    swap [ widths>> ] keep
    [ swap load-glyph glyph-hori-advance ft-ceil ] curry cache ;

M: freetype-renderer string-width ( font string -- w )
    [ [ 0 ] dip open-font ] dip [ char-width + ] with each ;

M: freetype-renderer string-height ( font string -- h )
    drop open-font height>> ;

: glyph-size ( glyph -- dim )
    [ glyph-hori-advance ft-ceil ]<commit_msg>Fix ui.text.freetype to work across image save/reload<commit_after>! Copyright (C) 2005, 2009 <NAME>.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.accessors alien.c-types arrays io kernel libc
math math.vectors namespaces opengl opengl.gl opengl.sprites assocs
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 fonts memoize ;
IN: ui.text.freetype

SINGLETON: freetype-renderer

M: freetype-renderer finish-text-rendering drop ;

: freetype-error ( n -- )
    0 = [ "FreeType error" throw ] unless ;

DEFER: init-freetype

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

TUPLE: freetype-font < identity-tuple
ascent descent height handle widths ;

M: freetype-font hashcode* drop freetype-font hashcode* ;

M: freetype-renderer free-fonts ( world -- )
    values [ free-sprites ] each ;

: ttf-name ( font -- name )
    [ [ name>> ] [ bold?>> ] [ italic?>> ] tri ] output>array H{
        { { "monospace" f f } "VeraMono" }
        { { "monospace" t f } "VeraMoBd" }
        { { "monospace" t t } "VeraMoBI" }
        { { "monospace" f t } "VeraMoIt" }
        { { "sans-serif" f f } "Vera" }
        { { "sans-serif" t f } "VeraBd" }
        { { "sans-serif" t t } "VeraBI" }
        { { "sans-serif" f t } "VeraIt" }
        { { "serif" f f } "VeraSe" }
        { { "serif" t f } "VeraSeBd" }
        { { "serif" t t } "VeraBI" }
        { { "serif" f t } "VeraIt" }
    } at [ "No such font" throw ] unless* ;

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

MEMO: ttf-font ( font -- contents length )
    ttf-name ttf-path malloc-file-contents ;

: open-face ( font -- 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 ] dip ttf-font 0 f <void*>
    [ FT_New_Memory_Face freetype-error ] keep *void* ;

SYMBOL: dpi

72 dpi set-global

: ft-floor ( m -- n ) -6 shift ; inline

: ft-ceil ( m -- n ) 63 + -64 bitand -6 shift ; inline

: font-units>pixels ( n font -- n )
    face-size face-size-y-scale FT_MulFix ;

: init-ascent ( font face -- font )
    [ face-y-max ] keep font-units>pixels >>ascent ; inline

: init-descent ( font face -- font )
    [ face-y-min ] keep font-units>pixels >>descent ; inline

: init-font ( font -- font )
    dup handle>> init-ascent
    dup handle>> init-descent
    dup [ ascent>> ] [ descent>> ] bi - ft-ceil >>height ; inline

: set-char-size ( open-font size -- open-font )
    [ dup handle>> 0 ] dip
    6 shift dpi get-global dup FT_Set_Char_Size freetype-error ;

MEMO: (open-font) ( font -- open-font )
    freetype-font new
        H{ } clone >>widths
        over open-face >>handle
        swap size>> set-char-size
        init-font ;

GENERIC: open-font ( font -- open-font )

M: font open-font
    freetype drop clone f >>background f >>foreground (open-font) ;

: load-glyph ( font char -- glyph )
    [ handle>> dup ] dip 0 FT_Load_Char
    freetype-error face-glyph ;

: char-width ( open-font char -- w )
    swap [ widths>> ] keep
    [ swap load-glyph glyph-hori-advance ft-ceil ] curry cache ;

M: freetype-renderer string-width ( font string -- w )
    [ [ 0 ] dip open-font ] dip [ char-width + ] with each ;

M: freetype-renderer string-height ( font string -- h )
    drop open-font height>> ;

: glyph-size ( glyph -- dim )
    [ glyph-hori-advance ft-ceil ]
{'fraction_non_alphanumeric': 0.13836038052602126, 'fraction_numerical': 0.006155567991046447, 'mean_word_length': 2.5461309523809526, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 91, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4996444', 'n_tokens_mistral': 2633, 'n_tokens_neox': 2540, 'n_words': 718}