/*
    See license.txt in the root of this project.
*/

# ifndef LMT_TEXFONT_H
# define LMT_TEXFONT_H

# include "tex/textypes.h"

/*tex

    In the \WEBC\ infrastructrure there is code that deals with endianness of the machine but in
    \LUAMETATEX\ we don't need this. In \LUATEX\ sharing the format file was already dropped, simply
    because we can also store \LUA\ bytecode in the format. In the other engines font data can end
    up in the format file and that in turn then also can be endian dependent. But in \LUAMETATEX\
    we no longer stored font data, and that is yet another reason why there is no endian related
    code here.

    The ligature and kern structures are for traditional \TEX\ fonts, thise that are handles by the
    built in reference handlers. Although \OPENTYPE\ is more versatile, we should not forget that
    for many (latin) scripts these so called base fonts are quite adequate and efficient. We could
    of course implement base support in \LUA\ but although \LUAMETATEX\ can delegate a lot, we also
    keep the reference implementation available: it is well documented, was for a long time the best
    one could get and doesn't take that much code. So, here come the basic structures:

*/

typedef struct ligatureinfo {
    int type;
    int ligature;
    int adjacent;
    /* alignment */
    int padding;
} ligatureinfo;

typedef struct kerninfo {
    int kern;
    int adjacent;
} kerninfo;

/*tex

    In \LUAMETATEX, at runtime, after a font is loaded via a callback, we only store the little
    information that is needed for basic ligature building and kerning, math rendering (like
    extensibles), and par building which includes protrusion and expansion. We don't need anything
    related to the backend because outpout is delegated to \LUA.

    The most extensive data structures are those related to \OPENTYPE\ math. When passing a font we
    can save memory by using the |hasmath| directive. In \LUAMETATEX\ we can then have a different
    |struct| with 15 fields less than in \LUATEX\ which, combined with other savings, saves some 60
    bytes. The disadvantage is that accessors of those fields also need to act upon that flag, which
    involves more testing. However, because in practice math font access is not that prominent so
    the gain outweights this potential performance hit. For an average \CJK\ font with 5000
    characters we saves 300000 bytes. Because a complete Latin font with various features also can
    have thousands of glyphs, it can save some memory there too. It's changes like this that give
    \LUAMETATEX\ a much smaller memory footprint than its predecessor.

    The next record relates to math extensibles. It is good to realize that traditional \TEX\ fonts
    are handled differently in the math subengine than \OPENTYPE\ math fonts. However, we use the
    more extensive \OPENTYPE\ structure for both type of fonts.

*/

typedef struct extinfo {
    struct extinfo *next;
    int             glyph;
    int             start_overlap;
    int             end_overlap;
    int             advance;
    int             extender;
    /* alignment */
    int             padding;
} extinfo;

/*tex 
    We have dedicated fields for hparts and vparts and their italics. Only avery few fonts actually
    set the italic on the extensible which is why the engine can use the regular italic, which in 
    that case is then the last in the variant list because that is where we put the recipe. Keep in
    mind that in an \OPENTYPE\ fonts we have a base glyph that has a variant list and part recipe 
    while in the engine (in good \TEX\ tradition) we chain the variants (with the next field)) so by 
    the time we arrive at the last one we look at the (h,v) italic there. No fonts (so far) have a 
    horizontal extensible with a set italic correction. 
    
    Actually, because the specification is rather explicit about glyphs only having horizontal or
    vertical extensibles we now have collapsed the two categories into one.
*/

typedef struct mathinfo {
    /*tex
       Optional code points for next smaller in size, right2left and flat accent glyphs.
    */
    halfword  smaller;     
    halfword  mirror;      
    halfword  flat_accent; 
    halfword  next;
    /*tex 
        The top anchor is provides by the font and is also known as topaccent while the bottom 
        anchor is one set by (in our case) \CONTEXT.  
    */
    scaled    top_anchor;              
    scaled    bottom_anchor;           
    /*tex 
        A set of pointers to variable size arrays which is why we also have the number of slots 
        stored. 
    */
    int       top_left_math_kerns;        
    int       top_right_math_kerns;       
    int       bottom_right_math_kerns;    
    int       bottom_left_math_kerns;     
    scaled   *top_left_math_kern_array;    
    scaled   *top_right_math_kern_array;
    scaled   *bottom_right_math_kern_array;
    scaled   *bottom_left_math_kern_array;
    /*tex 
        Here come the extensible recipes. Because we haven't seen both in one glyph we can share 
        the pointer and put a h/v flag in the tag field. For the moment we keep them both because
        we might want to play with a two dimensional extensible some day. 
    */
    extinfo  *extensible_recipe;        
    scaled    extensible_italic;         
    /*tex These are for specific (script) anchoring. */
    scaled    top_left_kern;
    scaled    bottom_left_kern;
    scaled    top_right_kern;
    scaled    bottom_right_kern;
    /*tex These four are used in accents. */
    scaled    left_margin;
    scaled    right_margin;
    scaled    top_margin;
    scaled    bottom_margin;
    /*tex As are the following. */
    scaled    top_overshoot;
    scaled    bottom_overshoot;
    /*tex These are for degrees in radicals. */
    scaled    inner_x_offset; 
    scaled    inner_y_offset; 
} mathinfo;

typedef struct charinfo {
    /*tex
        This is what \TEX\ uses when it calculates the dimensions needed for building boxes and
        breaking paragraphs into lines. The italic correction is part of that as it has a primitive
        that needs the value.
    */
    scaled        width;
    scaled        height;
    scaled        depth;
    scaled        italic;
    /*tex
        The next three variables relate to expansion and protrusion, properties introduced in the
        \PDFTEX\ engine. Handling of protrusion and expansion is the only features that we inherit
        from this important extension to traditional \TEX. 

        We can make the next four into a a pointer which saves on large fonts and only a subset 
        of characters has protrusion or expansion, if used at all. That way we delegate some memory 
        consumption to usage (of course allocated blobs also have overhead).  
    */
    scaled        expansion;    
    scaled        compression;
    scaled        leftprotrusion;
    scaled        rightprotrusion;
    /*tex
        The tag and remainder are used in a \TFM\ file for signaling ligatures. They are also used 
        for math extensions in traditional \TEX\ fonts. We used to pack the tag and remainder
        in an integer: 2 bits is enough for the tag (but we get some more) and the remainder (aka 
        next) fits in 21 bits. So we had |tagrem| for quite a while. 

        But we now use a 32 bit tag field and use proper next field that has been moved to the math 
        blob so that we can have a compression field here without padding. 
    */
    halfword      tag; 
    /*tex
        Traditional \TEX\ fonts use these two lists for ligature building and inter-character
        kerning and these are now optional (via pointers). By also using an indirect structure for
        math data we save quite a bit of memory when we have no math font.

        We could combine math and ligatures and save two slots but then we cannot have a hybrid base
        font so ... not now. 
    */
    kerninfo     *kerns;
    mathinfo     *math;       
    ligatureinfo *ligatures;  
} charinfo;

/*
    An option is to make this a pointer to a structure but then we also waste a slot. When we 
    never support it in math then we can actually go smaller: 
    
    charinfo: 8 * 4 : width height depth italic tag *[text or math] *kerns padding 
    textinfo: 4 * 4 : expansion leftprotrusion rightprotrusion *ligatures
    mathinfo: 2 * 4 : next padding ... n * 4 

    But ... given the amount of fields that \CONTEXT\ adds to the basic character data anyway 
    there is no real reason to spend much time in saving some bytes here.  

*/

/*tex
    We can just abuse the token setters and getters here.
*/

//define charinfo_tag    token_cmd
//define charinfo_rem    token_chr
//define charinfo_tagrem token_val

/*tex

    For a font instance we only store the bits that are used by the engine itself. Of course more
    data can (and normally will be) be kept at the \TEX\ cq.\ \LUA\ end.

    We could store a scale (/1000) and avoid copying a font but then we also need to multiply
    width, height, etc. when queried (extra overhead). A bit tricky is then dealing with (virtual)
    commands. It is not that big a deal in \CONTEXT\ so I might actually add this feature but only
    very few documents use many font instances so in the end the gain is neglectable (we only save
    some memory). Also, we then need to adapt the math processing quite a bit which is always kind
    of tricky.

    Again, compared to \LUATEX\ there is less data stored here because we don't need to control the
    backend. Of course in \CONTEXT\ we keep plenty of data at the \LUA\ end, but we did that already
    anyway.

*/

typedef struct texfont {
    /*tex the range of (allocated) characters */
    int         first_character;
    int         last_character;
    /*tex the (sparse) character (glyph) array */
    sa_tree     characters;
    charinfo   *chardata;
    int         chardata_count;
    int         chardata_size;
    /*tex properties used in messages */
    int         size;
    int         design_size;
    char       *name;
    char       *original;
    /*tex for experimental new thingies */
    int         compactmath;
    /*tex this controls the engine */
    int         mathcontrol;
    int         textcontrol;
    /*tex expansion */
    int         max_shrink;
    int         max_stretch;
    int         step;
    /*tex special characters, see \TEX book */
    int         hyphen_char;
    int         skew_char;
    /*tex all parameters, although only some are used */
    int         parameter_count;
    scaled     *parameter_base;
    /*tex also special */
    charinfo   *left_boundary;
    charinfo   *right_boundary;
    /*tex all math parameters */
    scaled     *math_parameter_base;
    int         math_parameter_count;
    /* zero is alignment */
    int         mathscales[3];
} texfont;

/*tex

    Instead of global variables we store some properties that are shared between the different components
    in a dedicated struct.

*/

typedef struct font_state_info {
    texfont     **fonts;
    halfword      adjust_stretch;
    halfword      adjust_shrink;
    halfword      adjust_step;
    int           padding;
    memory_data   font_data;
} font_state_info ;

extern font_state_info lmt_font_state;

# define font_size(a)                   lmt_font_state.fonts[a]->size
# define font_name(a)                   lmt_font_state.fonts[a]->name
# define font_original(a)               lmt_font_state.fonts[a]->original
# define font_design_size(a)            lmt_font_state.fonts[a]->design_size
# define font_first_character(a)        lmt_font_state.fonts[a]->first_character
# define font_last_character(a)         lmt_font_state.fonts[a]->last_character
# define font_compactmath(a)            lmt_font_state.fonts[a]->compactmath
# define font_mathcontrol(a)            lmt_font_state.fonts[a]->mathcontrol
# define font_textcontrol(a)            lmt_font_state.fonts[a]->textcontrol
# define font_hyphen_char(a)            lmt_font_state.fonts[a]->hyphen_char
# define font_skew_char(a)              lmt_font_state.fonts[a]->skew_char
# define font_max_shrink(a)             (lmt_font_state.adjust_step > 0 ? lmt_font_state.adjust_shrink  : lmt_font_state.fonts[a]->max_shrink)
# define font_max_stretch(a)            (lmt_font_state.adjust_step > 0 ? lmt_font_state.adjust_stretch : lmt_font_state.fonts[a]->max_stretch)
# define font_step(a)                   (lmt_font_state.adjust_step > 0 ? lmt_font_state.adjust_step    : lmt_font_state.fonts[a]->step)
# define font_mathscale(a,b)            lmt_font_state.fonts[a]->mathscales[b]

# define set_font_size(a,b)             lmt_font_state.fonts[a]->size = b
# define set_font_name(a,b)             lmt_font_state.fonts[a]->name = b
# define set_font_original(a,b)         lmt_font_state.fonts[a]->original = b
# define set_font_design_size(a,b)      lmt_font_state.fonts[a]->design_size = b
# define set_font_first_character(a,b)  lmt_font_state.fonts[a]->first_character = b
# define set_font_last_character(a,b)   lmt_font_state.fonts[a]->last_character = b
# define set_font_compactmath(a,b)      lmt_font_state.fonts[a]->compactmath = b
# define set_font_mathcontrol(a,b)      lmt_font_state.fonts[a]->mathcontrol = b
# define set_font_textcontrol(a,b)      lmt_font_state.fonts[a]->textcontrol = b
# define set_font_hyphen_char(a,b)      lmt_font_state.fonts[a]->hyphen_char = b
# define set_font_skew_char(a,b)        lmt_font_state.fonts[a]->skew_char = b
# define set_font_max_shrink(a,b)       lmt_font_state.fonts[a]->max_shrink = b
# define set_font_max_stretch(a,b)      lmt_font_state.fonts[a]->max_stretch = b
# define set_font_step(a,b)             lmt_font_state.fonts[a]->step = b

# define set_font_textsize(a,b)         lmt_font_state.fonts[a]->mathscales[0] = b
# define set_font_scriptsize(a,b)       lmt_font_state.fonts[a]->mathscales[1] = b
# define set_font_scriptscriptsize(a,b) lmt_font_state.fonts[a]->mathscales[2] = b

/*tex
    These are bound to a font. There might be a few more in the future. An example is collapsing
    hyphens. One can do that using (in context speak) tlig feature but actually it is some very
    \TEX\ thing, that happened to be implemented using ligatures. In \LUAMETATEX\ it's also a bit
    special because, although it is not really dependent on a language, hyphen handling in \TEX\
    is very present in the hyphenator (also sequences of them). So, naturally it moved there. But
    users who don't want it can disable it per font.
*/

typedef enum text_control_codes {
    text_control_collapse_hyphens = 0x00001,
    text_control_base_ligaturing  = 0x00002,
    text_control_base_kerning     = 0x00004,
    text_control_none_protected   = 0x00008,
} text_control_codes;

# define has_font_text_control(f,c)  ((font_textcontrol(f) & c) == c)

/*tex
    These are special codes that are used in the traditional ligature builder. In \OPENTYPE\
    fonts we don't see these. Maybe this will be dropped at some point. 
*/

typedef enum boundarychar_codes {
    left_boundary_char  = -1,
    right_boundary_char = -2,
    non_boundary_char   = -3,
} boundarychar_codes;

# define font_left_boundary(a)        lmt_font_state.fonts[a]->left_boundary
# define font_right_boundary(a)       lmt_font_state.fonts[a]->right_boundary

# define font_has_left_boundary(a)    (font_left_boundary(a))
# define font_has_right_boundary(a)   (font_right_boundary(a))

# define set_font_left_boundary(a,b)  { if (font_left_boundary(a))  { lmt_memory_free(font_left_boundary(a));  } font_left_boundary(a)  = b; }
# define set_font_right_boundary(a,b) { if (font_right_boundary(a)) { lmt_memory_free(font_right_boundary(a)); } font_right_boundary(a) = b; }

/*tex
    The math engine can benefit from these properties. For instance we use them for optimizing 
    the positioning of the degree in a (left) radical. These properties are not stored in the 
    tag (for a short while we had a variable).
*/

/*tex
    In traditional \TEX\ there are just over a handful of font specific parameters for text fonts
    and some more in math fonts. Actually, these parameters were stored in a way that permitted
    adding  more at runtime, something that made no real sense, but can be abused for creeating
    more dimensions than the 256 that traditional \TEX\ provides.
*/

# define font_parameter_count(a)           lmt_font_state.fonts[a]->parameter_count
# define font_parameter_base(a)            lmt_font_state.fonts[a]->parameter_base
# define font_parameter(a,b)               lmt_font_state.fonts[a]->parameter_base[b]

# define font_math_parameter_count(a)      lmt_font_state.fonts[a]->math_parameter_count
# define font_math_parameter_base(a)       lmt_font_state.fonts[a]->math_parameter_base
# define font_math_parameter(a,b)          lmt_font_state.fonts[a]->math_parameter_base[b]

# define set_font_parameter_base(a,b)      lmt_font_state.fonts[a]->parameter_base = b;
# define set_font_math_parameter_base(a,b) lmt_font_state.fonts[a]->math_parameter_base = b;

/*tex
    These font parameters could be adapted at runtime but one should really wonder if that is such
    a good idea nowadays.
 */

//define set_font_parameter(f,n,b)         { if (font_parameter_count(f)      < n) { tex_set_font_parameters(f, n);      } font_parameter(f, n)      = b; }
// # define set_font_math_parameter(f,n,b)    { if (font_math_parameter_count(f) < n) { tex_set_font_math_parameters(f, n); } font_math_parameter(f, n) = b; }

extern void tex_set_font_parameters      (halfword f, int b);
extern void tex_set_font_math_parameters (halfword f, int b);
extern int  tex_get_font_max_id          (void);
extern int  tex_get_font_max_id          (void);

extern halfword tex_checked_font_adjust (
    halfword adjust_spacing,
    halfword adjust_spacing_step,
    halfword adjust_spacing_shrink,
    halfword adjust_spacing_stretch
);

/*tex
    Font parameters are sometimes referred to as |slant(f)|, |space(f)|, etc. These numbers are
    also the font dimen numbers.
*/

typedef enum font_parameter_codes {
    slant_code = 1,
    space_code,
    space_stretch_code,
    space_shrink_code,
    ex_height_code,
    em_width_code,
    extra_space_code,
} font_parameter_codes;

extern scaled   tex_get_font_slant            (halfword f);
extern scaled   tex_get_font_space            (halfword f);
extern scaled   tex_get_font_space_stretch    (halfword f);
extern scaled   tex_get_font_space_shrink     (halfword f);
extern scaled   tex_get_font_ex_height        (halfword f);
extern scaled   tex_get_font_em_width         (halfword f);
extern scaled   tex_get_font_extra_space      (halfword f);
extern scaled   tex_get_font_parameter        (halfword f, halfword code);
extern void     tex_set_font_parameter        (halfword f, halfword code, scaled v);
                
extern scaled   tex_get_scaled_slant          (halfword f);
extern scaled   tex_get_scaled_space          (halfword f);
extern scaled   tex_get_scaled_space_stretch  (halfword f);
extern scaled   tex_get_scaled_space_shrink   (halfword f);
extern scaled   tex_get_scaled_ex_height      (halfword f);
extern scaled   tex_get_scaled_em_width       (halfword f);
extern scaled   tex_get_scaled_extra_space    (halfword f);
extern scaled   tex_get_scaled_parameter      (halfword f, halfword code);
extern void     tex_set_scaled_parameter      (halfword f, halfword code, scaled v);

extern halfword tex_get_scaled_glue           (halfword f);
extern halfword tex_get_scaled_parameter_glue (quarterword p, quarterword s);
extern halfword tex_get_parameter_glue        (quarterword p, quarterword s);

extern halfword tex_get_font_identifier       (halfword fs);

/*tex
    The \OPENTYPE\ math fonts have four edges and reference points for kerns. Here we go:
*/

typedef enum font_math_kern_codes {
    top_right_kern = 1,
    bottom_right_kern,
    bottom_left_kern,
    top_left_kern,
} font_math_kern_codes;

extern charinfo *tex_get_charinfo     (halfword f, int c);
extern int       tex_char_exists      (halfword f, int c);
extern void      tex_char_process     (halfword f, int c);
extern int       tex_math_char_exists (halfword f, int c, int size);
extern int       tex_get_math_char    (halfword f, int c, int size, scaled *scale, int direction);

/*tex 
    These used to be small integers, bit 22 upto 31, but now we have a 32 bit set. We actually don't 
    really need the granularity but by having these flags we can actually add a bit of control, like 
    having kerns but still blocking them. The numbers here are no longer reflective of what a tfm 
    file provides. We assume tfm files to be converted anyway. 

    Not all are needed but at least we now can keep some state. We can actually use them to something
    if we really want to (like when we runt tests). However, that is a rather drastic measure for 
    shared fonts. Tracing is another application and at some point it will be used for this. 
*/

typedef enum char_tag_codes {
    no_tag           = 0x00000, /*tex vanilla character */
    ligatures_tag    = 0x00001, /*tex character has a ligature program, not used */ 
    kerns_tag        = 0x00002, /*tex character has a kerning program, not used */ 
    list_tag         = 0x00004, /*tex character has a successor in a charlist */  
    callback_tag     = 0x00010,
    extensible_tag   = 0x00020, /*tex character is extensible, we can unset it in order to block */
    horizontal_tag   = 0x00040, /*tex horizontal extensible */
    vertical_tag     = 0x00080, /*tex vertical extensible */
    inner_left_tag   = 0x00100, /*tex anchoring */
    inner_right_tag  = 0x00200, /*tex anchoring */
    inner_top_tag    = 0x00400, /*tex anchoring */ 
    inner_bottom_tag = 0x00800, /*tex anchoring */ 
    extend_last_tag  = 0x01000, /*tex auto scale last variant */
    italic_tag       = 0x02000, 
    n_ary_tag        = 0x04000, 
    radical_tag      = 0x08000, 
    punctuation_tag  = 0x10000, 
    keep_base_tag    = 0x20000, 
} char_tag_codes;

/*tex
    These low level setters are not publis and used in helpers. They might become functions
    when I feel the need.
*/

# define set_charinfo_width(ci,val)                        ci->width  = val;
# define set_charinfo_height(ci,val)                       ci->height = val;
# define set_charinfo_depth(ci,val)                        ci->depth  = val;
# define set_charinfo_italic(ci,val)                       ci->italic = val;
# define set_charinfo_expansion(ci,val)                    ci->expansion = val;
# define set_charinfo_compression(ci,val)                  ci->compression = val;
# define set_charinfo_leftprotrusion(ci,val)               ci->leftprotrusion = val;
# define set_charinfo_rightprotrusion(ci,val)              ci->rightprotrusion = val;

# define set_charinfo_tag(ci,val)                          ci->tag |= val;
# define set_charinfo_next(ci,val)                         if (ci->math) { ci->math->next = val; }

# define has_charinfo_tag(ci,p)                            (ci->tag) & (p) == (p)) 
# define get_charinfo_tag(ci)                              ci->tag

# define set_charinfo_ligatures(ci,val)                    { lmt_memory_free(ci->ligatures); ci->ligatures = val; }
# define set_charinfo_kerns(ci,val)                        { lmt_memory_free(ci->kerns);     ci->kerns     = val; }
# define set_charinfo_math(ci,val)                         { lmt_memory_free(ci->math);      ci->math      = val; }

# define set_charinfo_top_left_math_kern_array(ci,val)     if (ci->math) { lmt_memory_free(ci->math->top_left_math_kern_array);     ci->math->top_left_math_kern_array = val; }
# define set_charinfo_top_right_math_kern_array(ci,val)    if (ci->math) { lmt_memory_free(ci->math->top_right_math_kern_array);    ci->math->top_left_math_kern_array = val; }
# define set_charinfo_bottom_right_math_kern_array(ci,val) if (ci->math) { lmt_memory_free(ci->math->bottom_right_math_kern_array); ci->math->top_left_math_kern_array = val; }
# define set_charinfo_bottom_left_math_kern_array(ci,val)  if (ci->math) { lmt_memory_free(ci->math->bottom_left_math_kern_array);  ci->math->top_left_math_kern_array = val; }

//define set_charinfo_options(ci,val)                      if (ci->math) { ci->math->options = val; }

# define set_ligature_item(f,b,c,d)                        { f.type = b; f.adjacent = c; f.ligature = d; }
# define set_kern_item(f,b,c)                              { f.adjacent = b; f.kern = c; }

# define set_charinfo_left_margin(ci,val)                  if (ci->math) { ci->math->left_margin = val; }
# define set_charinfo_right_margin(ci,val)                 if (ci->math) { ci->math->right_margin = val; }
# define set_charinfo_top_margin(ci,val)                   if (ci->math) { ci->math->top_margin = val; }
# define set_charinfo_bottom_margin(ci,val)                if (ci->math) { ci->math->bottom_margin = val; }

# define set_charinfo_smaller(ci,val)                      if (ci->math) { ci->math->smaller = val; }
# define set_charinfo_mirror(ci,val)                       if (ci->math) { ci->math->mirror = val; }
# define set_charinfo_extensible_italic(ci,val)            if (ci->math) { ci->math->extensible_italic = val; }
# define set_charinfo_top_anchor(ci,val)                   if (ci->math) { ci->math->top_anchor = val; }
# define set_charinfo_bottom_anchor(ci,val)                if (ci->math) { ci->math->bottom_anchor = val; }
# define set_charinfo_flat_accent(ci,val)                  if (ci->math) { ci->math->flat_accent = val; }

# define set_charinfo_inner_x_offset(ci,val)               if (ci->math) { ci->math->inner_x_offset = val; }
# define set_charinfo_inner_y_offset(ci,val)               if (ci->math) { ci->math->inner_y_offset = val; }

# define set_charinfo_top_left_kern(ci,val)                if (ci->math) { ci->math->top_left_kern = val; }
# define set_charinfo_top_right_kern(ci,val)               if (ci->math) { ci->math->top_right_kern = val; }
# define set_charinfo_bottom_left_kern(ci,val)             if (ci->math) { ci->math->bottom_left_kern = val; }
# define set_charinfo_bottom_right_kern(ci,val)            if (ci->math) { ci->math->bottom_right_kern = val; }

# define set_charinfo_top_overshoot(ci,val)                if (ci->math) { ci->math->top_overshoot = val; }
# define set_charinfo_bottom_overshoot(ci,val)             if (ci->math) { ci->math->bottom_overshoot = val; }

# define proper_char_index(f, c) (c >= font_first_character(f) && c <= font_last_character(f))

/*tex Setters: */

void             tex_set_lpcode_in_font                 (halfword f, halfword c, halfword i);
void             tex_set_rpcode_in_font                 (halfword f, halfword c, halfword i);
void             tex_set_efcode_in_font                 (halfword f, halfword c, halfword i);
void             tex_set_cfcode_in_font                 (halfword f, halfword c, halfword i);

extern void      tex_add_charinfo_math_kern             (charinfo *ci, int type, scaled ht, scaled krn);
extern int       tex_get_charinfo_math_kerns            (charinfo *ci, int id);
extern void      tex_set_charinfo_extensible_recipe     (charinfo *ci, extinfo *ext);
extern void      tex_append_charinfo_extensible_recipe  (charinfo *ci, int glyph, int startconnect, int endconnect, int advance, int repeater);

/*tex Checkers: */

int              tex_char_has_math                      (halfword f, halfword c);
int              tex_has_ligature                       (halfword f, halfword c);
int              tex_has_kern                           (halfword f, halfword c);

/*tex Getters: */

# define MATH_KERN_NOT_FOUND 0x7FFFFFFF

extern scaled    tex_font_x_scaled                      (scaled v);
extern scaled    tex_font_y_scaled                      (scaled v);

extern scaled    tex_char_width_from_font               (halfword f, halfword c); /* math + maincontrol */
extern scaled    tex_char_height_from_font              (halfword f, halfword c); /* math + maincontrol */
extern scaled    tex_char_depth_from_font               (halfword f, halfword c); /* math + maincontrol */
extern scaled    tex_char_total_from_font               (halfword f, halfword c); /* math */
extern scaledwhd tex_char_whd_from_font                 (halfword f, halfword c); /* math + maincontrol */
extern scaled    tex_char_italic_from_font              (halfword f, halfword c); /* math + maincontrol */
extern scaled    tex_char_ef_from_font                  (halfword f, halfword c); /* packaging + maincontrol */
extern scaled    tex_char_cf_from_font                  (halfword f, halfword c); /* packaging + maincontrol */
extern scaled    tex_char_lp_from_font                  (halfword f, halfword c); /* packaging + maincontrol */
extern scaled    tex_char_rp_from_font                  (halfword f, halfword c); /* packaging + maincontrol */
extern halfword  tex_char_tag_from_font                 (halfword f, halfword c); /* math */
extern halfword  tex_char_next_from_font                (halfword f, halfword c); /* math */
extern halfword  tex_char_has_tag_from_font             (halfword f, halfword c, halfword tag); 
extern void      tex_char_reset_tag_from_font           (halfword f, halfword c, halfword tag); 
extern int       tex_char_checked_tag                   (halfword tag);
extern scaled    tex_char_inner_x_offset_from_font      (halfword f, halfword c);
extern scaled    tex_char_inner_y_offset_from_font      (halfword f, halfword c);
extern scaled    tex_char_top_left_kern_from_font       (halfword f, halfword c); /* math */
extern scaled    tex_char_top_right_kern_from_font      (halfword f, halfword c); /* math */
extern scaled    tex_char_bottom_left_kern_from_font    (halfword f, halfword c); /* math */
extern scaled    tex_char_bottom_right_kern_from_font   (halfword f, halfword c); /* math */
extern halfword  tex_char_extensible_italic_from_font   (halfword f, halfword c);
extern halfword  tex_char_flat_accent_from_font         (halfword f, halfword c);
extern halfword  tex_char_top_anchor_from_font          (halfword f, halfword c);
extern halfword  tex_char_bottom_anchor_from_font       (halfword f, halfword c);
extern scaled    tex_char_left_margin_from_font         (halfword f, halfword c);
extern scaled    tex_char_right_margin_from_font        (halfword f, halfword c);
extern scaled    tex_char_top_margin_from_font          (halfword f, halfword c);
extern scaled    tex_char_bottom_margin_from_font       (halfword f, halfword c);
extern scaled    tex_char_top_overshoot_from_font       (halfword f, halfword c);
extern scaled    tex_char_bottom_overshoot_from_font    (halfword f, halfword c);
extern extinfo  *tex_char_extensible_recipe_from_font   (halfword f, halfword c);
extern extinfo  *tex_char_extensible_recipe_front_last  (halfword f, halfword c);

extern halfword  tex_char_unchecked_top_anchor_from_font    (halfword f, halfword c);
extern halfword  tex_char_unchecked_bottom_anchor_from_font (halfword f, halfword c);

extern scaled    tex_char_width_from_glyph              (halfword g); /* x/y scaled */
extern scaled    tex_char_height_from_glyph             (halfword g); /* x/y scaled */
extern scaled    tex_char_depth_from_glyph              (halfword g); /* x/y scaled */
extern scaled    tex_char_total_from_glyph              (halfword g); /* x/y scaled */
extern scaled    tex_char_italic_from_glyph             (halfword g); /* x/y scaled */
extern scaled    tex_char_width_italic_from_glyph       (halfword g); /* x/y scaled */
extern scaledwhd tex_char_whd_from_glyph                (halfword g); /* x/y scaled */
                                                       
extern int       tex_valid_kern                         (halfword left, halfword right);            /* returns kern */
extern int       tex_valid_ligature                     (halfword left, halfword right, int *slot); /* returns type */
                                                       
extern scaled    tex_calculated_char_width              (halfword f, halfword c, halfword ex);
extern scaled    tex_calculated_glyph_width             (halfword g, halfword ex); /* scale */

/*tex
    Kerns: the |otherchar| value signals \quote {stop}. These are not really public and only
    to be used in the helpers. But we keep them as reference.
*/

# define end_kern            0x7FFFFF

# define charinfo_kern(b,c)  b->kerns[c]

# define kern_char(b)       (b).adjacent
# define kern_kern(b)       (b).kern
# define kern_end(b)        ((b).adjacent == end_kern)
# define kern_disabled(b)   ((b).adjacent > end_kern)

/*tex
    Ligatures: the |otherchar| value signals \quote {stop}. These are not really public and only
    to be used in the helpers. But we keep them as reference.
*/

# define end_of_ligature_code    0x7FFFFF

# define charinfo_ligature(b,c)  b->ligatures[c]

# define ligature_is_valid(a)    ((a).type != 0)
# define ligature_type(a)        ((a).type >> 1)
# define ligature_char(a)        (a).adjacent
# define ligature_replacement(a) (a).ligature
# define ligature_end(a)         ((a).adjacent == end_of_ligature_code)
# define ligature_disabled(a)    ((a).adjacent > end_of_ligature_code)

/*tex Extension specific: */

typedef enum math_extension_modes {
    math_extension_normal,
    math_extension_repeat,
} math_extension_modes;

/*tex Expansion and protrusion: */

typedef enum adjust_spacing_modes {
    adjust_spacing_off,
    adjust_spacing_unused,
    adjust_spacing_full,
    adjust_spacing_font,
} adjust_spacing_modes;

typedef enum protrude_chars_modes {
    protrude_chars_off,
    protrude_chars_unused,
    protrude_chars_normal,
    protrude_chars_advanced,
} protrude_chars_modes;

/*
typedef enum math_extension_locations {
    extension_top,
    extension_bottom,
    extension_middle,
    extension_repeat,
} math_extension_locations;
*/

extern halfword      tex_checked_font          (halfword f);
extern int           tex_is_valid_font         (halfword f);
extern int           tex_raw_get_kern          (halfword f, int lc, int rc);
extern int           tex_get_kern              (halfword f, int lc, int rc);
extern ligatureinfo  tex_get_ligature          (halfword f, int lc, int rc);
extern int           tex_new_font              (void);
extern int           tex_new_font_id           (void);
extern void          tex_font_malloc_charinfo  (halfword f, int num);
extern void          tex_char_malloc_mathinfo  (charinfo *ci);
extern void          tex_dump_font_data        (dumpstream f);
extern void          tex_undump_font_data      (dumpstream f);
extern void          tex_create_null_font      (void);
extern void          tex_delete_font           (int id);
extern int           tex_read_font_info        (char *cnom, scaled s);
extern int           tex_fix_expand_value      (halfword f, int e);

extern halfword      tex_handle_glyphrun       (halfword head, halfword group, halfword direction);
extern halfword      tex_handle_ligaturing     (halfword head, halfword tail);
extern halfword      tex_handle_kerning        (halfword head, halfword tail);

extern void          tex_set_cur_font          (halfword g, halfword f);
extern int           tex_tex_def_font          (int a);

extern void          tex_char_warning          (halfword f, int c);

extern void          tex_initialize_fonts      (void);

extern void          tex_set_font_name         (halfword f, const char *s);
extern void          tex_set_font_original     (halfword f, const char *s);

extern scaled        tex_get_math_font_scale   (halfword f, halfword size);

extern void          tex_run_font_spec         (void);

# endif
