package provide Freetype 0.1
package provide Freetype::freetype 0.1

if {![info exists _source([file tail [info script]])]} {
package require Freetype::ft2build
package require $FT_TYPES
package require $FT_ERRORS


ft::struct define FT_Glyph_Metrics {
    {width        int - FT_Pos 1 FT_Pos}
    {height       int - FT_Pos 1 FT_Pos}
    {horiBearingX int - FT_Pos 1 FT_Pos}
    {horiBearingY int - FT_Pos 1 FT_Pos}
    {horiAdvance  int - FT_Pos 1 FT_Pos}
    {vertBearingX int - FT_Pos 1 FT_Pos}
    {vertBearingY int - FT_Pos 1 FT_Pos}
    {vertAdvance  int - FT_Pos 1 FT_Pos}
}

ft::struct define FT_Bitmap_Size {
    {height  int - FT_Short 1 FT_Short}
    {width   int - FT_Short 1 FT_Short}
    {size    int - FT_Pos   1 FT_Pos}
    {x_ppem  int - FT_Pos   1 FT_Pos}
    {y_ppem  int - FT_Pos   1 FT_Pos}
}

ft::struct define FT_Library {
}

ft::struct define FT_Module {
}

ft::struct define FT_Driver {
}

ft::struct define FT_Renderer {
}


ffidl::typedef FT_Encoding int

set FT_ENCODING_NONE      [FT_MAKE_TAG "" "" "" ""]
set FT_ENCODING_MS_SYMBOL [FT_MAKE_TAG "s" "y" "m" "b"]
set FT_ENCODING_UNICODE   [FT_MAKE_TAG "u" "n" "i" "c"]
set FT_ENCODING_SJIS      [FT_MAKE_TAG "s" "j" "i" "s"]
set FT_ENCODING_GB2312    [FT_MAKE_TAG "g" "b" " " " "]
set FT_ENCODING_BIG5      [FT_MAKE_TAG "b" "i" "g" "5"]
set FT_ENCODING_WANSUNG   [FT_MAKE_TAG "w" "a" "n" "s"]
set FT_ENCODING_JOHAB     [FT_MAKE_TAG "j" "o" "h" "a"]
# for backwards compatibility
set FT_ENCODING_MS_SJIS    $FT_ENCODING_SJIS
set FT_ENCODING_MS_GB2312  $FT_ENCODING_GB2312
set FT_ENCODING_MS_BIG5    $FT_ENCODING_BIG5
set FT_ENCODING_MS_WANSUNG $FT_ENCODING_WANSUNG
set FT_ENCODING_MS_JOHAB   $FT_ENCODING_JOHAB

set FT_ENCODING_ADOBE_STANDARD [FT_MAKE_TAG "A" "D" "O" "B"]
set FT_ENCODING_ADOBE_EXPERT   [FT_MAKE_TAG "A" "D" "B" "E"]
set FT_ENCODING_ADOBE_CUSTOM   [FT_MAKE_TAG "A" "D" "B" "C"]
set FT_ENCODING_ADOBE_LATIN_1  [FT_MAKE_TAG "l" "a" "t" "1"]

set FT_ENCODING_OLD_LATIN_2    [FT_MAKE_TAG "l" "a" "t" "2"]

set FT_ENCODING_APPLE_ROMAN    [FT_MAKE_TAG "a" "r" "m" "n"]

set ft_encoding_none           $FT_ENCODING_NONE
set ft_encoding_unicode        $FT_ENCODING_UNICODE
set ft_encoding_symbol         $FT_ENCODING_MS_SYMBOL
set ft_encoding_latin_1        $FT_ENCODING_ADOBE_LATIN_1
set ft_encoding_latin_2        $FT_ENCODING_OLD_LATIN_2
set ft_encoding_sjis           $FT_ENCODING_SJIS
set ft_encoding_gb2312         $FT_ENCODING_GB2312
set ft_encoding_big5           $FT_ENCODING_BIG5
set ft_encoding_wansung        $FT_ENCODING_WANSUNG
set ft_encoding_johab          $FT_ENCODING_JOHAB


set ft_encoding_adobe_standard $FT_ENCODING_ADOBE_STANDARD
set ft_encoding_adobe_expert   $FT_ENCODING_ADOBE_EXPERT
set ft_encoding_adobe_custom   $FT_ENCODING_ADOBE_CUSTOM
set ft_encoding_apple_roman    $FT_ENCODING_APPLE_ROMAN

ft::struct define FT_CharMap {
    {face        object * FT_Face   1 pointer}
    {encoding    int    - int       1 int}
    {platform_id int    - FT_UShort 1 FT_UShort}
    {encoding_id int    - FT_UShort 1 FT_UShort}
}

ft::struct define FT_Face {
    {num_faces           int    - FT_Long        1 FT_Long}
    {face_index          int    - FT_Long        1 FT_Long}
    {face_flags          int    - FT_Long        1 FT_Long}
    {style_flags         int    - FT_Long        1 FT_Long}
    {num_glyphs          int    - FT_Long        1 FT_Long}
    {family_name         string * char           1 pointer}
    {style_name          string * char           1 pointer}
    {num_fixed_sizes     int    - FT_Int         1 FT_Int}
    {available_sizes     object * FT_Bitmap_Size 1 pointer}
    {num_charmaps        int    - FT_Int         1 FT_Int}
    {charmaps            int    - pointer        1 pointer}
    {generic             object - FT_Generic     1 FT_Generic}
    {bbox                object - FT_BBox        1 FT_BBox}
    {units_per_EM        int    - FT_UShort      1 FT_UShort}
    {ascender            int    - FT_Short       1 FT_Short}
    {descender           int    - FT_Short       1 FT_Short}
    {height              int    - FT_Short       1 FT_Short}
    {max_advance_width   int    - FT_Short       1 FT_Short}
    {max_advance_height  int    - FT_Short       1 FT_Short}
    {underline_position  int    - FT_Short       1 FT_Short}
    {underline_thickness int    - FT_Short       1 FT_Short}
    {glyph               object * FT_GlyphSlot   1 pointer}
    {size                object * FT_Size        1 pointer}
    {charmap             object * FT_CharMap     1 pointer}
    {driver              object * FT_Driver      1 pointer}
    {memory              object * FT_Memory      1 pointer}
    {stream              object * FT_Stream      1 pointer}
    {size_list           object - FT_List        1 FT_List}
    {autohint            object - FT_Generic     1 FT_Generic}
    {extensions          int    - pointer        1 pointer}
    {internal            int    - pointer        1 pointer}
}

oo::define FT_Face method get {varName} {
    # object pointer arrays
    if {$varName eq "charmaps"} {
        set n [next "num_charmaps"]
        set ptr [next "charmaps"]
        set size [ffidl::info sizeof "pointer"]
        set ret [list]
        for {set i 0} {$i < $n} {incr i} {
            lappend ret [FT_CharMap new [::ft::get_pointer_pointer $ptr]]
            incr ptr $size
        }
        return $ret
    }
    # object arrays
    if {$varName eq "available_sizes"} {
        set num [next "num_fixed_sizes"]
        set obj [next $varName]
        set ptr [$obj getPointer]
        set tcltype [my getInfo $varName tcltype]
        set ffidltype [my getInfo $varName ffidltype]
    
        return [my _get_tcl_list_value $num $ptr $tcltype $ffidltype]
    }
    next $varName
}

oo::define FT_Face method set {varName varValue} {
    if {$varName eq "charmaps"} {
        error "$varName is readonly"
    }
    next $varName $varValue
}

set FT_FACE_FLAG_SCALABLE          [expr 1 <<  0]
set FT_FACE_FLAG_FIXED_SIZES       [expr 1 <<  1]
set FT_FACE_FLAG_FIXED_WIDTH       [expr 1 <<  2]
set FT_FACE_FLAG_SFNT              [expr 1 <<  3]
set FT_FACE_FLAG_HORIZONTAL        [expr 1 <<  4]
set FT_FACE_FLAG_VERTICAL          [expr 1 <<  5]
set FT_FACE_FLAG_KERNING           [expr 1 <<  6]
set FT_FACE_FLAG_FAST_GLYPHS       [expr 1 <<  7]
set FT_FACE_FLAG_MULTIPLE_MASTERS  [expr 1 <<  8]
set FT_FACE_FLAG_GLYPH_NAMES       [expr 1 <<  9]
set FT_FACE_FLAG_EXTERNAL_STREAM   [expr 1 << 10]
set FT_FACE_FLAG_HINTER            [expr 1 << 11]
set FT_FACE_FLAG_CID_KEYED         [expr 1 << 12]
set FT_FACE_FLAG_TRICKY            [expr 1 << 13]
set FT_FACE_FLAG_COLOR             [expr 1 << 14]

proc FT_HAS_HORIZONTAL {face} {
    upvar FT_FACE_FLAG_HORIZONTAL flag
    return [expr {[$face get face_flags] & $flag}]
}

proc FT_HAS_VERTICAL {face} {
    upvar FT_FACE_FLAG_VERTICAL flag
    return [expr {[$face get face_flags] & $flag}]
}

proc FT_HAS_KERNING {face} {
    upvar FT_FACE_FLAG_KERNING flag
    return [expr {[$face get face_flags] & $flag}]
}

proc FT_IS_FIXED_WIDTH {face} {
    upvar FT_FACE_FLAG_FIXED_WIDTH flag
    return [expr {[$face get face_flags] & $flag}]
}

proc FT_HAS_FIXED_SIZES {face} {
    upvar FT_FACE_FLAG_FIXED_SIZES flag
    return [expr {[$face get face_flags] & $flag}]
}

proc FT_HAS_FAST_GLYPHS {face} {return 0}


proc FT_HAS_GLYPH_NAMES {face} {
    upvar FT_FACE_FLAG_GLYPH_NAMES flag
    return [expr {[$face get face_flags] & $flag}]
}

proc FT_HAS_MULTIPLE_MASTERS {face} {
    upvar FT_FACE_FLAG_MULTIPLE_MASTERS flag
    return [expr {[$face get face_flags] & $flag}]
}

proc FT_IS_CID_KEYED {face} {
    upvar FT_FACE_FLAG_CID_KEYED flag
    return [expr {[$face get face_flags] & $flag}]
}

proc FT_IS_TRICKY {face} {
    upvar FT_FACE_FLAG_TRICKY flag
    return [expr {[$face get face_flags] & $flag}]
}

proc FT_HAS_COLOR {face} {
    upvar FT_FACE_FLAG_COLOR flag
    return [expr {[$face get face_flags] & $flag}]
}

set FT_STYLE_FLAG_ITALIC  [expr 1 << 0]
set FT_STYLE_FLAG_BOLD    [expr 1 << 1]

ft::struct define  FT_Size_Metrics {
    {x_ppem      int - FT_UShort 1 FT_UShort}
    {y_ppem      int - FT_UShort 1 FT_UShort}
    {x_scale     int - FT_Fixed  1 FT_Fixed}
    {y_scale     int - FT_Fixed  1 FT_Fixed}
    {ascender    int - FT_Pos    1 FT_Pos}
    {descender   int - FT_Pos    1 FT_Pos}
    {height      int - FT_Pos    1 FT_Pos}
    {max_advance int - FT_Pos    1 FT_Pos}
}

ft::struct define FT_Size {
    {face     object * FT_Face         1 pointer}
    {generic  object - FT_Generic      1 FT_Generic}
    {metrics  object - FT_Size_Metrics 1 FT_Size_Metrics}
    {internal int    - pointer         1 pointer}
}

ft::struct define  FT_GlyphSlot {
    {library           object * FT_Library       1 pointer}
    {face              object * FT_Face          1 pointer}
    {next              object * FT_GlyphSlot     1 pointer}
    {reserved          int    - FT_UInt          1 FT_UInt}
    {generic           object - FT_Generic       1 FT_Generic}
    {metrics           object - FT_Glyph_Metrics 1 FT_Glyph_Metrics}
    {linearHoriAdvance int    - FT_Fixed         1 FT_Fixed}
    {linearVertAdvance int    - FT_Fixed         1 FT_Fixed}
    {advance           object - FT_Vector        1 FT_Vector}
    {format            int    - FT_Glyph_Format  1 FT_Glyph_Format}
    {bitmap            object - FT_Bitmap        1 FT_Bitmap}
    {bitmap_left       int    - FT_Int           1 FT_Int}
    {bitmap_top        int    - FT_Int           1 FT_Int}
    {outline           object - FT_Outline       1 FT_Outline}
    {num_subglyphs     int    - FT_UInt          1 FT_UInt}
    {subglyphs         int    - pointer          1 pointer}
    {control_data      int    - pointer          1 pointer}
    {control_len       int    - long             1 long}
    {lsb_delta         int    - FT_Pos           1 FT_Pos}
    {rsb_delta         int    - FT_Pos           1 FT_Pos}
    {other             int    - pointer          1 pointer}
    {internal          int    - pointer          1 pointer}
}

::ffidl::callout _FT_Init_FreeType {pointer-var} int \
    [::ffidl::symbol $::ft::lib FT_Init_FreeType]
proc FT_Init_FreeType {libraryVarName} {
    set p [::ft::_bytearray_from_pointer 0]
    set result [_FT_Init_FreeType p]
    uplevel [list set $libraryVarName [FT_Library new [::ft::_bytearray_to_pointer $p]]]
    return $result
}
::ffidl::callout _FT_Done_FreeType {pointer} int \
    [::ffidl::symbol $::ft::lib FT_Done_FreeType]
proc FT_Done_FreeType {library} {
    set result [_FT_Done_FreeType [$library getPointer]]
    return $result
}
set FT_OPEN_MEMORY    [expr 0x01]
set FT_OPEN_STREAM    [expr 0x02]
set FT_OPEN_PATHNAME  [expr 0x04]
set FT_OPEN_DRIVER    [expr 0x08]
set FT_OPEN_PARAMS    [expr 0x10]

set ft_open_memory    $FT_OPEN_MEMORY
set ft_open_stream    $FT_OPEN_STREAM
set ft_open_pathname  $FT_OPEN_PATHNAME
set ft_open_driver    $FT_OPEN_DRIVER
set ft_open_params    $FT_OPEN_PARAMS

ft::struct define FT_Parameter {
    {tag  int - FT_ULong 1 FT_ULong}
    {data int - pointer  1 pointer}
}

ft::struct define FT_Open_Args {
    {flags       int    - FT_UInt      1 FT_UInt}
    {memory_base int    - pointer      1 pointer}
    {memory_size int    - pointer      1 FT_Long}
    {pathname    string * char         1 pointer}
    {stream      object * FT_Stream    1 pointer}
    {driver      object * FT_Module    1 pointer}
    {num_params  int    - FT_Int       1 FT_Int}
    {params      object * FT_Parameter 1 FT_Parameter}
}

::ffidl::callout _FT_New_Face {pointer pointer int pointer-var} int \
    [::ffidl::symbol $::ft::lib FT_New_Face]
proc FT_New_Face {library filepath face_index faceVarName} {
    set p [::ft::_bytearray_from_pointer 0]
    set filepath_bin [encoding convertto [encoding system] $filepath]
    append filepath_bin \x00
    ::ft::get_bytearray_pointer filepath_bin filepath_adr len
    set result [_FT_New_Face [$library getPointer] $filepath_adr $face_index p]
    set obj [FT_Face new [::ft::_bytearray_to_pointer $p]]
    uplevel [list set $faceVarName $obj]
    return $result
}

::ffidl::callout _FT_New_Memory_Face {pointer pointer int int pointer-var} int \
    [::ffidl::symbol $::ft::lib FT_New_Memory_Face]
proc FT_New_Memory_Face {library file_base file_size face_index faceVarName} {
    set p [::ft::_bytearray_from_pointer 0]
    set result [_FT_New_Memory_Face [$library getPointer] $file_base \
        $file_size $face_index p]
    set obj [FT_Face new [::ft::_bytearray_to_pointer $p]]
    uplevel [list set $faceVarName $obj]
    return $result
}

::ffidl::callout _FT_Open_Face {pointer pointer int pointer-var} int \
    [::ffidl::symbol $::ft::lib FT_Open_Face]
proc FT_Open_Face {library args face_index faceVarName} {
    set p [::ft::_bytearray_from_pointer 0]
    set result [_FT_Open_Face [$library getPointer] [$args getPointer] $face_index p]
    set obj [FT_Face new [::ft::_bytearray_to_pointer $p]]
    uplevel [list set $faceVarName $obj]
    return $result
}

::ffidl::callout _FT_Attach_File {pointer pointer} int \
    [::ffidl::symbol $::ft::lib FT_Attach_File]
proc FT_Attach_File {library filepath} {
    set filepath_bin [encoding convertto [encoding system] $filepath]
    ::ft::get_bytearray_pointer filepath_bin filepath_adr len

    set result [_FT_Attach_File [$library getPointer] $filepath_adr]
    return $result
}

::ffidl::callout _FT_Attach_Stream {pointer pointer-var} int \
    [::ffidl::symbol $::ft::lib FT_Attach_Stream]
proc FT_Attach_Stream {face args} {
    set result [_FT_Attach_Stream [$face getPointer] [$args getPointer]]
    return $result
}

if {[catch {::ffidl::symbol $::ft::lib FT_Reference_Face} _symbol] == 0} {
::ffidl::callout _FT_Reference_Face {pointer} int $_symbol
proc FT_Reference_Face {face} {
    set result [_FT_Reference_Face [$face getPointer]]
    return $result
}
}

::ffidl::callout _FT_Done_Face {pointer} int \
    [::ffidl::symbol $::ft::lib FT_Done_Face]
proc FT_Done_Face {face} {
    set result [_FT_Done_Face [$face getPointer]]
    return $result
}

::ffidl::callout _FT_Select_Size {pointer int} int \
    [::ffidl::symbol $::ft::lib FT_Select_Size]
proc FT_Select_Size {face strike_index} {
    set result [_FT_Select_Size [$face getPointer] $strike_index]
    return $result
}

set FT_SIZE_REQUEST_TYPE_NOMINAL  0
set FT_SIZE_REQUEST_TYPE_REAL_DIM 1
set FT_SIZE_REQUEST_TYPE_BBOX     2
set FT_SIZE_REQUEST_TYPE_CELL     3
set FT_SIZE_REQUEST_TYPE_SCALES   4
set FT_SIZE_REQUEST_TYPE_MAX      5

ffidl::typedef FT_Size_Request_Type int

ft::struct define FT_Size_Request {
    {type           int - int     1 int}
    {width          int - FT_Long 1 FT_Long}
    {height         int - FT_Long 1 FT_Long}
    {horiResolution int - FT_UInt 1 FT_UInt}
    {vertResolution int - FT_UInt 1 FT_UInt}
}

::ffidl::callout _FT_Request_Size {pointer pointer} int \
    [::ffidl::symbol $::ft::lib FT_Request_Size]
proc FT_Request_Size {face req} {
    set result [_FT_Request_Size [$face getPointer] [$req getPointer]]
    return $result
}

::ffidl::callout _FT_Set_Char_Size {pointer FT_F26Dot6 FT_F26Dot6 FT_UInt FT_UInt} int \
    [::ffidl::symbol $::ft::lib FT_Set_Char_Size]
proc FT_Set_Char_Size {face char_width char_height horz_resolution vert_resolution} {
    set result [_FT_Set_Char_Size [$face getPointer] \
                $char_width $char_height \
                $horz_resolution $vert_resolution]
    return $result
}

::ffidl::callout _FT_Set_Pixel_Sizes {pointer unsigned unsigned} int \
    [::ffidl::symbol $::ft::lib FT_Set_Pixel_Sizes]
proc FT_Set_Pixel_Sizes {face pixel_width pixel_height} {
   set result [_FT_Set_Pixel_Sizes [$face getPointer] $pixel_width $pixel_height]
   return $result
}

::ffidl::callout _FT_Load_Glyph {pointer unsigned int} int \
    [::ffidl::symbol $::ft::lib FT_Load_Glyph]
proc FT_Load_Glyph {face glyph_index load_flags} {
    set result [_FT_Load_Glyph [$face getPointer] $glyph_index $load_flags]
    return $result
}
::ffidl::callout _FT_Load_Char {pointer {unsigned long} int} int \
    [::ffidl::symbol $::ft::lib FT_Load_Char]
proc FT_Load_Char {face char_code load_flags} {
    set result [_FT_Load_Char [$face getPointer] $char_code $load_flags]
    return $result
}

set FT_RENDER_MODE_NORMAL 0
set FT_RENDER_MODE_LIGHT  1
set FT_RENDER_MODE_MONO   2
set FT_RENDER_MODE_LCD    3
set FT_RENDER_MODE_LCD_V  4
set FT_RENDER_MODE_MAX    5
set ft_render_mode_normal $FT_RENDER_MODE_NORMAL
set ft_render_mode_mono   $FT_RENDER_MODE_MONO
ffidl::typedef FT_Render_Mode int

set FT_LOAD_DEFAULT                      [expr 0x00]
set FT_LOAD_NO_SCALE                     [expr 1 << 0]
set FT_LOAD_NO_HINTING                   [expr 1 << 1]
set FT_LOAD_RENDER                       [expr 1 << 2]
set FT_LOAD_NO_BITMAP                    [expr 1 << 3]
set FT_LOAD_VERTICAL_LAYOUT              [expr 1 << 4]
set FT_LOAD_FORCE_AUTOHINT               [expr 1 << 5]
set FT_LOAD_CROP_BITMAP                  [expr 1 << 6]
set FT_LOAD_PEDANTIC                     [expr 1 << 7]
set FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH  [expr 1 << 9]
set FT_LOAD_NO_RECURSE                   [expr 1 << 10]
set FT_LOAD_IGNORE_TRANSFORM             [expr 1 << 11]
set FT_LOAD_MONOCHROME                   [expr 1 << 12]
set FT_LOAD_LINEAR_DESIGN                [expr 1 << 13]
set FT_LOAD_NO_AUTOHINT                  [expr 1 << 15]
# Bits 16..19 are used by `FT_LOAD_TARGET_'
set FT_LOAD_COLOR                        [expr 1 << 20]
# used internally only by certain font drivers! 
set FT_LOAD_ADVANCE_ONLY                 [expr 1 << 8]
set FT_LOAD_SBITS_ONLY                   [expr 1 << 14]

set FT_LOAD_TARGET_NORMAL  [expr ($FT_RENDER_MODE_NORMAL & 15) << 16]
set FT_LOAD_TARGET_LIGHT   [expr ($FT_RENDER_MODE_LIGHT  & 15) << 16]
set FT_LOAD_TARGET_MONO    [expr ($FT_RENDER_MODE_MONO   & 15) << 16]
set FT_LOAD_TARGET_LCD     [expr ($FT_RENDER_MODE_LCD    & 15) << 16]
set FT_LOAD_TARGET_LCD_V   [expr ($FT_RENDER_MODE_LCD_V  & 15) << 16]

proc FT_LOAD_TARGET_MODE {x} {
    return [expr {($x >> 16 ) & 15}]
}

::ffidl::callout _FT_Set_Transform {pointer pointer pointer} void \
    [::ffidl::symbol $::ft::lib FT_Set_Transform]
proc FT_Set_Transform {face matrix delta} {
    if {$matrix eq {}} {set matrix [FT_Matrix new 0]}
    if {$delta  eq {}} {set delta  [FT_Vector new 0]}
    _FT_Set_Transform [$face getPointer] [$matrix getPointer] [$delta getPointer]
    return
}

::ffidl::callout _FT_Render_Glyph {pointer int} int \
    [::ffidl::symbol $::ft::lib FT_Render_Glyph]
proc FT_Render_Glyph {slot render_mode} {
    set result [_FT_Render_Glyph [$slot getPointer] $render_mode]
    return $result
}

ffidl::typedef FT_Kerning_Mode int
set FT_KERNING_DEFAULT  0
set FT_KERNING_UNFITTED 1
set FT_KERNING_UNSCALED 2
set ft_kerning_default  $FT_KERNING_DEFAULT
set ft_kerning_unfitted $FT_KERNING_UNFITTED
set ft_kerning_unscaled $FT_KERNING_UNSCALED

::ffidl::callout _FT_Get_Kerning {pointer FT_UInt FT_UInt FT_UInt pointer} int \
    [::ffidl::symbol $::ft::lib FT_Get_Kerning]
proc FT_Get_Kerning {face left_glyph right_glyph kern_mode kerningVarName} {
    set vec [FT_Vector new]
    set result [_FT_Get_Kerning [$face getPointer] $left_glyph $right_glyph $kern_mode [$vec getPointer]]
    if {$result == 0} {
        uplevel [list set $kerningVarName $vec]
    } else {
        $vec destroy
    }
    return $result
}

::ffidl::callout _FT_Get_Track_Kerning {pointer FT_Fixed FT_Int pointer-var} int \
    [::ffidl::symbol $::ft::lib FT_Get_Track_Kerning]
proc FT_Get_Track_Kerning {face pointer_size degree kerningVarName} {
    set p [::ft::_bytearray_from FT_Fixed 0]
    set result [_FT_Get_Track_Kerning [$face getPointer] $pointer_size $degree p]
    if {$result == 0} {
        uplevel [set $kerningVarName [::ft::_bytearray_to FT_Fixed $p]]
    }
    return $result
}

::ffidl::callout _FT_Get_Glyph_Name {pointer int pointer int} int \
    [::ffidl::symbol $::ft::lib FT_Get_Glyph_Name]
proc FT_Get_Glyph_Name {face glyph_index bufferVarName} {
    set p [::ffidl::malloc 256]
    set result [_FT_Get_Glyph_Name [$face getPointer] $glyph_index $p 100]
    uplevel [list set $bufferVarName [ffidl::new-string $p -1]]
    ffidl::free $p
}

::ffidl::callout _FT_Get_Postscript_Name {pointer} pointer \
    [::ffidl::symbol $::ft::lib FT_Get_Postscript_Name]
proc FT_Get_Postscript_Name {face} {
    set p [_FT_Get_Postscript_Name [$face getPointer]]
    return [ffidl::new-string $p -1]
}

::ffidl::callout _FT_Select_Charmap {pointer int} int \
    [::ffidl::symbol $::ft::lib FT_Select_Charmap]
proc FT_Select_Charmap {face encoding} {
    set result [_FT_Select_Charmap [$face getPointer] $encoding]
    return $result
}

::ffidl::callout _FT_Set_Charmap {pointer pointer} int \
    [::ffidl::symbol $::ft::lib FT_Set_Charmap]
proc FT_Set_Charmap {face charmap} {
    set result [_FT_Set_Charmap [$face getPointer] [$charmap getPointer]]
    return $result
}

::ffidl::callout _FT_Get_Charmap_Index {pointer} int \
    [::ffidl::symbol $::ft::lib FT_Get_Charmap_Index]
proc FT_Get_Charmap_Index {charmap} {
    set idx [_FT_Get_Charmap_Index [$charmap getPointer]]
    return $idx
}

::ffidl::callout _FT_Get_Char_Index {pointer FT_ULong} FT_UInt \
    [::ffidl::symbol $::ft::lib FT_Get_Char_Index]
proc FT_Get_Char_Index {face charcode} {
    set idx [_FT_Get_Char_Index [$face getPointer] $charcode]
    return $idx
}

::ffidl::callout _FT_Get_First_Char {pointer pointer-var} FT_ULong \
    [::ffidl::symbol $::ft::lib FT_Get_First_Char]
proc FT_Get_First_Char {face glyphIndexVarName} {
    set p [::ft::_bytearray_from_unit32 0]
    set idx [_FT_Get_First_Char [$face getPointer] p]
    set gidx [::ft::_bytearray_to_uint32 $p]
    uplevel set $glyphIndexVarName $gidx
    return $idx
}

::ffidl::callout _FT_Get_Next_Char {pointer FT_ULong pointer-var} FT_ULong \
    [::ffidl::symbol $::ft::lib FT_Get_Next_Char]
proc FT_Get_Next_Char {face char_code glyphIndexVarName} {
    set p [::ft::_bytearray_from_unit32 0]
    set idx [_FT_Get_Next_Char [$face getPointer] $char_code p]
    set gidx [::ft::_bytearray_to_uint32 $p]
    uplevel set $glyphIndexVarName $gidx
    return $idx
}

::ffidl::callout _FT_Get_Name_Index {pointer pointer} FT_UInt \
    [::ffidl::symbol $::ft::lib FT_Get_Name_Index]
proc FT_Get_Name_Index {face glyph_name} {
    append glyph_name \0
    ::ft::get_bytearray_pointer glyph_name adr len
    set idx [_FT_Get_Name_Index [$face getPointer] $adr]
    return $idx
}

set FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS                 1
set FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES             2
set FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID               4
set FT_SUBGLYPH_FLAG_SCALE                          8
set FT_SUBGLYPH_FLAG_XY_SCALE             [expr 0x040]
set FT_SUBGLYPH_FLAG_2X2                  [expr 0x080]
set FT_SUBGLYPH_FLAG_USE_MY_METRICS       [expr 0x200]

::ffidl::callout _FT_Get_SubGlyph_Info {pointer uint32 pointer pointer
    pointer pointer pointer} int [::ffidl::symbol $::ft::lib FT_Get_SubGlyph_Info]
proc FT_Get_SubGlyph_Info {glyph sub_index indexVarName flagsVarName
    arg1VarName arg2VarName transformVarName} {
    upvar $indexVarName index
    upvar $flagsVarName flags
    upvar $arg1VarName arg1
    upvar $arg2VarName arg2
    upvar $transformVarName transform
    set p_index [::ft::_bytearray_from_int32  0]
    set p_flags [::ft::_bytearray_from_unit32 0]
    set p_arg1  [::ft::_bytearray_from_int32  0]
    set p_arg2  [::ft::_bytearray_from_int32  0]
    set p_transform [::ft::_bytearray_from_pointer  0]

    set result [FT_Get_SubGlyph_Info [$glyph getPointer] $sub_index \
        $p_index $p_flags $p_arg1 $p_arg2 $p_transform]
    if {$result == 0} {
        set index [::ft::_bytearray_to_int32  $p_index]
        set flags [::ft::_bytearray_to_uint32 $p_flags]
        set arg1  [::ft::_bytearray_to_int32  $p_arg1]
        set arg2  [::ft::_bytearray_to_int32  $p_arg2]
        set transform [FT_Matrix new [::ft::_bytearray_to_pointer $p_transform]]
    }
    return $result
}

set FT_FSTYPE_INSTALLABLE_EMBEDDING         [expr 0x0000]
set FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING  [expr 0x0002]
set FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING   [expr 0x0004]
set FT_FSTYPE_EDITABLE_EMBEDDING            [expr 0x0008]
set FT_FSTYPE_NO_SUBSETTING                 [expr 0x0100]
set FT_FSTYPE_BITMAP_EMBEDDING_ONLY         [expr 0x0200]

if {[catch {::ffidl::symbol $::ft::lib FT_Get_FSType_Flags} _symbol] == 0} {
::ffidl::callout _FT_Get_FSType_Flags {pointer} FT_UShort $_symbol
proc FT_Get_FSType_Flags {face} {
    set result [_FT_Get_FSType_Flags [$face getPointer]]
    return $result
}
}

if {[catch {::ffidl::symbol $::ft::lib FT_Face_GetCharVariantIndex} _symbol] == 0} {
::ffidl::callout _FT_Face_GetCharVariantIndex {pointer FT_ULong FT_ULong} FT_UInt $_symbol
proc FT_Face_GetCharVariantIndex {face charcode variantSelector} {
    set result [_FT_Face_GetCharVariantIndex [$face getPointer] \
        $charcode $variantSelector]
    return $result
}
}

if {[catch {::ffidl::symbol $::ft::lib FT_Face_GetCharVariantIsDefault} _symbol] == 0} {
::ffidl::callout _FT_Face_GetCharVariantIsDefault {pointer FT_ULong FT_ULong} FT_Int $_symbol
proc FT_Face_GetCharVariantIsDefault {face charcode variantSelector} {
    set result [_FT_Face_GetCharVariantIsDefault [$face getPointer] \
        $charcode $variantSelector]
    return $result
}
}

if {[catch {::ffidl::symbol $::ft::lib FT_Face_GetVariantSelectors} _symbol] == 0} {
::ffidl::callout _FT_Face_GetVariantSelectors {pointer} int $_symbol
proc FT_Face_GetVariantSelectors {face} {
    set adr [_FT_Face_GetVariantSelectors [$face getPointer]]
    if {$adr == 0} {return {}}
    set bin [::ft::_bytearray_from_address $adr FT_UInt32 -1]
    return [::ft::_bytearray_to_list $bin FT_UInt32]
}
}

if {[catch {::ffidl::symbol $::ft::lib FT_Face_GetVariantsOfChar} _symbol] == 0} {
::ffidl::callout _FT_Face_GetVariantsOfChar {pointer FT_ULong} int $_symbol
proc FT_Face_GetVariantsOfChar {face charcode} {
    set adr [_FT_Face_GetVariantsOfChar [$face getPointer] $charcode]
    set bin [::ft::_bytearray_from_address $adr FT_UInt32 -1]
    return [::ft::_bytearray_to_list $bin FT_UInt32]
}
}

if {[catch {::ffidl::symbol $::ft::lib FT_Face_GetCharsOfVariant} _symbol] == 0} {
::ffidl::callout _FT_Face_GetCharsOfVariant {pointer FT_ULong} int $_symbol
proc FT_Face_GetCharsOfVariant {face variantSelector} {
    set adr [_FT_Face_GetCharsOfVariant [$face getPointer] $variantSelector]
    set bin [::ft::_bytearray_from_address $adr FT_UInt32 -1]
    return [::ft::_bytearray_to_list $bin FT_UInt32]
}
}


::ffidl::callout FT_MulDiv {FT_Long FT_Long FT_Long} FT_Long [::ffidl::symbol $::ft::lib FT_MulDiv]
::ffidl::callout FT_MulFix   {FT_Long FT_Long} FT_Long [::ffidl::symbol $::ft::lib FT_MulFix]
::ffidl::callout FT_DivFix   {FT_Long FT_Long} FT_Long [::ffidl::symbol $::ft::lib FT_DivFix]
::ffidl::callout FT_RoundFix {FT_Fixed} FT_Fixed [::ffidl::symbol $::ft::lib FT_RoundFix]
::ffidl::callout FT_CeilFix  {FT_Fixed} FT_Fixed [::ffidl::symbol $::ft::lib FT_CeilFix]
::ffidl::callout FT_FloorFix {FT_Fixed} FT_Fixed [::ffidl::symbol $::ft::lib FT_FloorFix]
::ffidl::callout _FT_VectorTransform {pointer pointer} void \
    [::ffidl::symbol $::ft::lib FT_Vector_Transform]
proc FT_VectorTransform {vec matrix} {
    _FT_VectorTransform [$vec getPointer] [$matrix getPointer]
}

::ffidl::callout _FT_Library_Version {pointer pointer-var pointer-var pointer-var} void \
    [::ffidl::symbol $::ft::lib FT_Library_Version]
proc FT_Library_Version {library majorVarName minorVarName patchVarName} {
        set mj [::ft::_bytearray_from_pointer 0]
        set mn [::ft::_bytearray_from_pointer 0]
        set pt [::ft::_bytearray_from_pointer 0]
        set result [_FT_Library_Version [$library getPointer] mj mn pt]
        uplevel [list set $majorVarName [::ft::_bytearray_to_pointer $mj]]
        uplevel [list set $minorVarName [::ft::_bytearray_to_pointer $mn]]
        uplevel [list set $patchVarName [::ft::_bytearray_to_pointer $pt]]
        return $result
}

if {[catch {::ffidl::symbol $::ft::lib FT_Face_CheckTrueTypePatents} _symbol] == 0} {
::ffidl::callout _FT_Face_CheckTrueTypePatents {pointer} FT_Bool $_symbol
proc FT_Face_CheckTrueTypePatents {face} {
    set result [_FT_Face_CheckTrueTypePatents [$face getPointer]]
    return $result
}
}

if {[catch {::ffidl::symbol $::ft::lib FT_Face_SetUnpatentedHinting} _symbol] == 0} {
::ffidl::callout _FT_Face_SetUnpatentedHinting {pointer FT_Bool} FT_Bool $_symbol
proc FT_Face_SetUnpatentedHinting {face value} {
    set result [_FT_Face_SetUnpatentedHinting [$face getPointer] $value]
    return $result
}
}

#FT_Init_FreeType lib
#FT_New_Face $lib  "D:/Fonts/msmincho.ttc" 1 face
#
#FT_New_Face $lib  "D:/Fonts/KozGoPr6N-Medium.otf" 0 face
#FT_Load_Glyph $face 10 0
#FT_Load_Char $face 10 0

#set result [FT_Get_Kerning $face 63 64 1 kern]
#set result [FT_Get_Track_Kerning $face 14 2 kern]
#
#
#puts r=$result
#puts k=[$kern getPointer]
#puts x=[$kern get x]
#puts y=[$kern get y]

#FT_Get_Glyph_Name $face 1000 str; puts str=$str; unset str

#puts [FT_Get_Postscript_Name $face]
#puts [FT_Get_Name_Index $face "abc"]

#FT_Done_Face $face
#FT_Done_FreeType $lib


set _source([file tail [info script]]) 1
}
