summaryrefslogtreecommitdiff
path: root/source/luametatex/source/tex/texfont.h
blob: a13c6e13d6454852208aef22f31b0f0cc2fe0ece (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
/*
    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;

// typedef enum math_font_options {
//     math_font_ignore_italic_option = 0x01,
// } math_font_options;
//
// # define math_font_option(options,option) ((options & option) == option)

typedef struct mathinfo {
    scaled    vertical_italic;
    scaled    top_accent;
    scaled    bottom_accent;
    int       smaller;
    scaled    scale;
    int       flat_accent;
    int       top_left_math_kerns;
    int       top_right_math_kerns;
    int       bottom_right_math_kerns;
    int       bottom_left_math_kerns;
    extinfo  *horizontal_parts;
    extinfo  *vertical_parts;
    scaled   *top_left_math_kern_array;
    scaled   *top_right_math_kern_array;
    scaled   *bottom_right_math_kern_array;
    scaled   *bottom_left_math_kern_array;
    /* these are for specific (script) anchoring */
    scaled   top_left_kern;
    scaled   bottom_left_kern;
    scaled   top_right_kern;
    scaled   bottom_right_kern;
    scaled   left_margin;
    scaled   right_margin;
    scaled   top_margin;
    scaled   bottom_margin;
} 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.
    */
    scaled        expansion;
    scaled        leftprotrusion;
    scaled        rightprotrusion;
 /* halfword  padding; */  /* when we pack |tag| and |remainder| we can safe 4 bytes */
    /*tex
        These two are used in a \TFM\ file for signaling ligatures. They are also used for math
        extensions in traditional \TEX\ fonts, so we just keep them.
    */
 /* halfword      tag;       */ /*  2 bits is enough (flags)   */
 /* halfword      remainder; */ /* 21 bits is enough (unicode) */
    halfword      tagrem;       /* just an integer, less (arm) alignment hassle that way */
    /*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.
    */
    ligatureinfo *ligatures;
    kerninfo     *kerns;
    mathinfo     *math;
} charinfo;

/*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 default to false when MathConstants not seen */
    int         oldmath;
    /*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;
    /* */
    int         padding;
    /*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_touched(a)                font_state.fonts[a]->touched */
# define font_oldmath(a)                lmt_font_state.fonts[a]->oldmath
# 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_touched(a,b)          font_state.fonts[a]->touched = b */
# define set_font_oldmath(a,b)          lmt_font_state.fonts[a]->oldmath = 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_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.

*/

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

/*tex These are pointers, so: |NULL|  */

# 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

    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_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);

/*tex

    Here is a quick way to test if a glyph exists, when you are already certain the font |f| exists,
    and that the |c| is a regular glyph id, not one of the two special boundary objects. Contrary
    to traditional \TEX\ we store character information in a hash table instead of an array. Keep
    in mind that we talk \UNICODE: plenty of characters in the code space, but less so in a font,
    so we can best be sparse.

*/

# define quick_char_exists(f,c) (sa_get_item_4(lmt_font_state.fonts[f]->characters,c).int_value)

/*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_leftprotrusion(ci,val)               ci->leftprotrusion = val;
# define set_charinfo_rightprotrusion(ci,val)              ci->rightprotrusion = val;

# define set_charinfo_tag(ci,tag)                          ci->tagrem = charinfo_tagrem(charinfo_tag(ci->tagrem) | tag,charinfo_rem(ci->tagrem));
# define set_charinfo_remainder(ci,rem)                    ci->tagrem = charinfo_tagrem(charinfo_tag(ci->tagrem),rem);

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

# 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_vertical_italic(ci,val)              if (ci->math) { ci->math->vertical_italic = val; }
# define set_charinfo_top_accent(ci,val)                   if (ci->math) { ci->math->top_accent = val; }
# define set_charinfo_bottom_accent(ci,val)                if (ci->math) { ci->math->bottom_accent = val; }
# define set_charinfo_flat_accent(ci,val)                  if (ci->math) { ci->math->flat_accent = 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; }

/*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);

extern void      tex_set_charinfo_extensible            (charinfo *ci, int top, int bottom, int middle, int extender);
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_horizontal_parts      (charinfo *ci, extinfo *ext);
extern void      tex_set_charinfo_vertical_parts        (charinfo *ci, extinfo *ext);
extern void      tex_add_charinfo_vertical_part         (charinfo *ci, extinfo *ext);
extern void      tex_add_charinfo_horizontal_part       (charinfo *ci, extinfo *ext);
extern extinfo  *tex_new_charinfo_part                  (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_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 scaled    tex_char_italic_from_font              (halfword f, halfword c); /* math + maincontrol */
//     halfword  tex_char_options_from_font             (halfword f, halfword c);
extern scaled    tex_char_ef_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_remainder_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); 
//     int       tex_char_has_option_from_font          (halfword g, halfword c, int option);

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 scaledwhd tex_char_whd_from_font                 (halfword f, halfword c); /* math + maincontrol */

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

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 */
//     int       tex_char_options_from_glyph            (halfword g);
extern scaled    tex_char_width_italic_from_glyph       (halfword g); /* x/y scaled */
//     int       tex_char_has_option_from_glyph         (halfword g, int option);

extern scaledwhd tex_char_whd_from_glyph                (halfword g); /* x/y scaled */

extern halfword  tex_char_vertical_italic_from_font     (halfword f, halfword c);
extern halfword  tex_char_top_accent_from_font          (halfword f, halfword c);
extern halfword  tex_char_bot_accent_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_bot_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 extinfo  *tex_char_vertical_parts_from_font      (halfword f, halfword c);
extern extinfo  *tex_char_horizontal_parts_from_font    (halfword f, halfword c);
                                                       
/*     scaled    tex_math_kern_at                       (halfword f, int c, int side, int v); */
/*     scaled    tex_find_math_kern                     (halfword l_f, int l_c, halfword r_f, int r_c, int cmd, scaled shift); */
                                                       
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 */

/*
    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)

/*
    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)

/* Remainders and related flags: */

typedef enum math_extension_modes {
    math_extension_normal,
    math_extension_repeat,
} math_extension_modes;

/* Expansion */

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;
*/

/* Tags: */

typedef enum tag_codes {
    no_tag          = 0x00, /*tex vanilla character */
    ligature_tag    = 0x01, /*tex character has a ligature/kerning program */
    list_tag        = 0x02, /*tex character has a successor in a charlist */
    extension_tag   = 0x04, /*tex character is extensible */
    callback_tag    = 0x08,
    extend_last_tag = 0x10,
} tag_codes;

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