1 
2 /******************************************************************************
3 * MODULE     : tex_font.cpp
4 * DESCRIPTION: TeX text fonts
5 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11 
12 #include "font.hpp"
13 #include "Metafont/load_tex.hpp"
14 #include "translator.hpp"
15 #include "iterator.hpp"
16 #include "gui.hpp"
17 
18 #define TEX_ANY   0
19 #define TEX_EC    1
20 #define TEX_LA    2
21 #define TEX_GR    3
22 #define TEX_CM    4
23 #define TEX_ADOBE 5
24 
25 static void special_initialize ();
26 
27 /******************************************************************************
28 * TeX text fonts
29 ******************************************************************************/
30 
31 struct tex_font_rep: font_rep {
32   int              status;
33   string           family;
34   int              dpi;
35   int              dsize;
36   tex_font_metric  tfm;
37   font_glyphs      pk;
38   double           unit;
39   bool             exec;             // execute ligature and kerning program?
40 
41   tex_font_rep (string name, int status,
42 		string family, int size, int dpi, int dsize);
43 
44   bool raw_supports (unsigned char c);
45   bool supports (string c);
46   void get_extents (string s, metric& ex);
47   void get_xpositions (string s, SI* xpos, bool ligf);
48   void get_xpositions (string s, SI* xpos);
49   void draw_fixed (renderer ren, string s, SI x, SI y);
50   font magnify (double zoom);
51   SI   get_left_correction (string s);
52   SI   get_right_correction (string s);
53   glyph get_glyph (string s);
54   void special_get_extents (string s, metric& ex);
55   void special_get_xpositions (string s, SI* xpos, bool ligf);
56   void special_draw (renderer ren, string s, SI x, SI y);
57   SI   special_get_left_correction (string s);
58   SI   special_get_right_correction (string s);
59   void accented_get_extents (string s, metric& ex);
60   void accented_get_xpositions (string s, SI* xpos, bool ligf);
61   void accented_draw (renderer ren, string s, SI x, SI y);
62   SI   accented_get_left_correction (string s);
63   SI   accented_get_right_correction (string s);
64 };
65 
66 /******************************************************************************
67 * The implementation of tex_fonts
68 ******************************************************************************/
69 
70 #define conv(x) ((SI) (((double) (x))*unit))
71 
tex_font_rep(string name,int status2,string family2,int size2,int dpi2,int dsize2)72 tex_font_rep::tex_font_rep (string name, int status2,
73   string family2, int size2, int dpi2, int dsize2):
74   font_rep (name), status (status2), dsize (dsize2)
75 {
76   load_tex (family2, size2, dpi2, dsize, tfm, pk);
77 
78   family       = family2;
79   type         = FONT_TYPE_TEX;
80   size         = size2;
81   dpi          = dpi2;
82   design_size  = tfm->design_size () >> 12;
83   display_size = (((design_size*dpi)/72)*PIXEL) >> 8;
84   unit         = ((double) display_size) / ((double) (1<<20));
85   slope        = tfm->slope ();
86   spc->def     = conv (tfm->spc ());
87   spc->min     = spc->def - conv (tfm->spc_shrink ());
88   spc->max     = spc->def + conv (tfm->spc_stretch ());
89   extra        = conv (tfm->spc_extra ());
90   extra->min   = extra->min >> 1;
91   extra->max   = extra->min << 1;
92   sep          = ((((dpi*PIXEL)/72)*design_size) >> 8) / 10;
93   exec         = ! ends (family, "tt");
94 
95   y1           = conv (-262080);   // -0.25 quad
96   y2           = y1+ display_size; //  0.75 quad
97   yx           = conv (tfm->x_height ());
98   yfrac        = yx >> 1;
99   ysub_lo_base = -yx/3;
100   ysub_hi_lim  = (5*yx)/6;
101   ysup_lo_lim  = yx/2;
102   ysup_lo_base = (5*yx)/6;
103   ysup_hi_lim  = yx;
104   yshift       = yx/6;
105 
106   wpt          = (dpi*PIXEL)/72;
107   wfn          = (wpt*design_size) >> 8;
108   wline        = wfn/20;
109   wquad        = conv (tfm->spc_quad ());
110 
111   if ((family == "cmr") || (family == "ecrm") || (family == "cmmi")) {
112     if (size < 8)
113       wline= wfn / (size==7? 16: (size==6? 14: 12));
114     else if (size < 10) yfrac += (size * wfn) / 1600;
115     else if (size <= 14) yfrac += (size * wfn) / 1000;
116     else {
117       wline= wfn / (size>16? 28: 24);
118       yfrac += (size * wfn) / 700;
119     }
120   }
121 
122   special_initialize ();
123 }
124 
125 /******************************************************************************
126 * Handle <, > and (in the future?) other special characters
127 ******************************************************************************/
128 
129 static bool special_initialized= false;
130 static hashmap<string,string> special_translate ("");
131 
132 static void
special_initialize(string enc)133 special_initialize (string enc) {
134   translator trl= load_translator (enc);
135   iterator<string> it= iterate (trl->dict);
136   while (it->busy ()) {
137     string s= it->next ();
138     special_translate (s)= string ((char) (unsigned char) trl->dict[s]);
139     if (N(s) > 2 && s(0,2) == "<#") {
140       string sl= locase_all (s), su= upcase_all (s);
141       special_translate (sl)= string ((char) (unsigned char) trl->dict[s]);
142       special_translate (su)= string ((char) (unsigned char) trl->dict[s]);
143     }
144   }
145 }
146 
147 static void
special_initialize()148 special_initialize () {
149   if (special_initialized) return;
150   special_translate ("<less>")= "<";
151   special_translate ("<gtr>")= ">";
152   special_initialize ("larm");
153   special_initialize ("grmn");
154   special_initialized= true;
155 }
156 
157 void
special_get_extents(string s,metric & ex)158 tex_font_rep::special_get_extents (string s, metric& ex) {
159   register int i, j;
160   for (i=0; i<N(s); i++)
161     if (s[i]=='<') break;
162   get_extents (s (0, i), ex);
163   for (j=i+1; j<N(s); j++)
164     if (s[j]=='>') break;
165   if (j<N(s)) j++;
166 
167   SI x;
168   metric ey;
169   int temp= status;
170   status= TEX_ANY;
171   string r = s (i, j);
172   string rr= special_translate[r];
173   if (N(rr) != 0) r= rr;
174   get_extents (r, ey);
175   x= ex->x2;
176   ex->x1= min (ex->x1, x+ ey->x1); ex->y1= min (ex->y1, ey->y1);
177   ex->x2= max (ex->x2, x+ ey->x2); ex->y2= max (ex->y2, ey->y2);
178   ex->x3= min (ex->x3, x+ ey->x3); ex->y3= min (ex->y3, ey->y3);
179   ex->x4= max (ex->x4, x+ ey->x4); ex->y4= max (ex->y4, ey->y4);
180   status= temp;
181 
182   get_extents (s (j, N(s)), ey);
183   x= ex->x2;
184   ex->x1= min (ex->x1, x+ ey->x1); ex->y1= min (ex->y1, ey->y1);
185   ex->x2= max (ex->x2, x+ ey->x2); ex->y2= max (ex->y2, ey->y2);
186   ex->x3= min (ex->x3, x+ ey->x3); ex->y3= min (ex->y3, ey->y3);
187   ex->x4= max (ex->x4, x+ ey->x4); ex->y4= max (ex->y4, ey->y4);
188 }
189 
190 void
special_get_xpositions(string s,SI * xpos,bool ligf)191 tex_font_rep::special_get_xpositions (string s, SI* xpos, bool ligf) {
192   SI offset= 0;
193   register int l=0, i, j, n=N(s);
194   while (l<n) {
195     for (i=l; i<n; i++)
196       if (s[i]=='<') break;
197     if (l<i) {
198       get_xpositions (s (l, i), xpos + l, ligf);
199       for (j=l+1; j<=i; j++) xpos[j] += offset;
200       if (i==n) break;
201       offset= xpos[i];
202     }
203 
204     for (j=i+1; j<n; j++) {
205       xpos[j]= offset;
206       if (s[j]=='>') break;
207     }
208     if (j<n) j++;
209     metric ey;
210     int temp= status;
211     status= TEX_ANY;
212     string r= s (i, j);
213     string rr= special_translate[r];
214     if (N(rr) != 0) r= rr;
215     get_extents (r, ey);
216     status= temp;
217     offset += ey->x2;
218     xpos[j]= offset;
219     l= j;
220   }
221 }
222 
223 void
special_draw(renderer ren,string s,SI x,SI y)224 tex_font_rep::special_draw (renderer ren, string s, SI x, SI y) {
225   register int i, j;
226   metric ex;
227   for (i=0; i<N(s); i++)
228     if (s[i]=='<') break;
229   draw_fixed (ren, s (0, i), x, y);
230   get_extents (s (0, i), ex);
231   x += ex->x2;
232   for (j=i+1; j<N(s); j++)
233     if (s[j]=='>') break;
234   if (j<N(s)) j++;
235 
236   int temp= status;
237   status= TEX_ANY;
238   string r= s (i, j);
239   string rr= special_translate[r];
240   pencil pen= ren->get_pencil ();
241   if (N(rr) != 0) r= rr;
242   else ren->set_pencil (red);
243   draw_fixed (ren, r, x, y);
244   ren->set_pencil (pen);
245   get_extents (r, ex);
246   x += ex->x2;
247   status= temp;
248 
249   draw_fixed (ren, s (j, N(s)), x, y);
250 }
251 
252 SI
special_get_left_correction(string s)253 tex_font_rep::special_get_left_correction (string s) {
254   int i= 0;
255   tm_char_forwards (s, i);
256   string r= special_translate (s (0, i));
257   if (N(r)!=0) return (SI) (slope * conv (tfm->d ((QN) r[0])));
258   return (SI) (slope * conv (tfm->d ((QN) '<')));
259 }
260 
261 SI
special_get_right_correction(string s)262 tex_font_rep::special_get_right_correction (string s) {
263   int n= N(s), i= n;
264   tm_char_backwards (s, i);
265   string r= special_translate (s (i, n));
266   if (N(r)!=0) return conv (tfm->i ((QN) r[0]));
267   return conv (tfm->i ((QN) '>'));
268 }
269 
270 /******************************************************************************
271 * Handle accents
272 ******************************************************************************/
273 
274 static char CM_unaccented[128]= {
275     'A', ' ', 'C', 'C',   'D',   'E',   ' ',   'G',
276     'L', 'L', ' ', 'N',   'N',   ' ',   'O',   'R',
277     'R', 'S', 'S', 'S',   'T',   'T',   'U',   'U',
278     'Y', 'Z', 'Z', 'Z',   ' ',   'I',   'd',   ' ',
279     'a', ' ', 'c', 'c',   'd',   'e',   ' ',   'g',
280     'l', 'l', ' ', 'n',   'n',   ' ',   'o',   'r',
281     'r', 's', 's', 's',   't',   't',   'u',   'u',
282     'y', 'z', 'z', 'z',   ' ', '\74', '\76',   ' ',
283     'A', 'A', 'A', 'A',   'A',   'A', '\35',   'C',
284     'E', 'E', 'E', 'E',   'I',   'I',   'I',   'I',
285     'D', 'N', 'O', 'O',   'O',   'O',   'O', '\36',
286   '\37', 'U', 'U', 'U',   'U',   'Y',   ' ',   ' ',
287     'a', 'a', 'a', 'a',   'a',   'a', '\32',   'c',
288     'e', 'e', 'e', 'e', '\20', '\20', '\20', '\20',
289     'd', 'n', 'o', 'o',   'o',   'o',   'o', '\33',
290   '\34', 'u', 'u', 'u',   'u',   'y',   ' ', '\31'
291 };
292 
293 static char CM_accents[128]= {
294    '\25',    ' ',  '\23',  '\24',  '\24',  '\24',    ' ',  '\25',
295    '\23',  '\47',    ' ',  '\23',  '\24',    ' ', '\175',  '\23',
296    '\24',  '\23',  '\24',  '\30',  '\24',  '\30', '\175',  '\27',
297   '\177',  '\23',  '\24', '\137',    ' ', '\137',  '\26',    ' ',
298    '\25',    ' ',  '\23',  '\24',  '\24',  '\24',    ' ',  '\25',
299    '\23',  '\47',    ' ',  '\23',  '\24',    ' ', '\175',  '\23',
300    '\24',  '\23',  '\24',  '\30',  '\24',  '\30', '\175',  '\27',
301   '\177',  '\23',  '\24', '\137',    ' ',    ' ',    ' ',    ' ',
302    '\22',  '\23', '\136', '\176', '\177',  '\27',    ' ',  '\30',
303    '\22',  '\23', '\136', '\177',  '\22',  '\23', '\136', '\177',
304    '\26', '\176',  '\22',  '\23', '\136', '\176', '\177',    ' ',
305      ' ',  '\22',  '\23', '\136', '\177',  '\23',    ' ',    ' ',
306    '\22',  '\23', '\136', '\176', '\177',  '\27',    ' ',  '\30',
307    '\22',  '\23', '\136', '\177',  '\22',  '\23', '\136', '\177',
308    '\26', '\176',  '\22',  '\23', '\136', '\176', '\177',    ' ',
309      ' ',  '\22',  '\23', '\136', '\177',  '\23',    ' ',    ' '
310 };
311 
312 static char ADOBE_unaccented[128]= {
313      'A', 'A',    'C', 'C',    'D',    'E',    'E',    'G',
314      'L', 'L', '\350', 'N',    'N',    ' ',    'O',    'R',
315      'R', 'S',    'S', 'S',    'T',    'T',    'U',    'U',
316      'Y', 'Z',    'Z', 'Z',    ' ',    'I',    'd', '\247',
317      'a', 'a',    'c', 'c',    'd',    'e',    'e',    'g',
318      'l', 'l', '\370', 'n',    'n',    ' ',    'o',    'r',
319      'r', 's',    's', 's',    't',    't',    'u',    'u',
320      'y', 'z',    'z', 'z',    ' ', '\241', '\277', '\243',
321      'A', 'A',    'A', 'A',    'A',    'A', '\341',    'C',
322      'E', 'E',    'E', 'E',    'I',    'I',    'I',    'I',
323      'D', 'N',    'O', 'O',    'O',    'O',    'O',  '\36',
324   '\351', 'U',    'U', 'U',    'U',    'Y',    ' ',    ' ',
325      'a', 'a',    'a', 'a',    'a',    'a', '\361',    'c',
326      'e', 'e',    'e', 'e', '\365', '\365', '\365', '\365',
327      'd', 'n',    'o', 'o',    'o',    'o',    'o', '\372',
328   '\371', 'u',    'u', 'u',    'u',    'y',    ' ', '\373'
329 };
330 
331 static char ADOBE_accents[128]= {
332   '\306', '\316', '\302', '\317', '\317', '\317', '\316', '\306',
333   '\302',  '\47',    ' ', '\302', '\317',    ' ', '\315', '\302',
334   '\317', '\302', '\317', '\313', '\317', '\313', '\315', '\312',
335   '\310', '\302', '\317', '\307',    ' ', '\307', '\305',    ' ',
336   '\306', '\316', '\302', '\317', '\317', '\317', '\316', '\306',
337   '\302',  '\47',    ' ', '\302', '\317',    ' ', '\315', '\302',
338   '\317', '\302', '\317', '\313', '\317', '\313', '\315', '\312',
339   '\310', '\302', '\317', '\307',    ' ',    ' ',    ' ',    ' ',
340   '\301', '\302', '\303', '\304', '\310', '\312',    ' ', '\313',
341   '\301', '\302', '\303', '\310', '\301', '\302', '\303', '\310',
342   '\305', '\304', '\301', '\302', '\303', '\304', '\310',    ' ',
343      ' ', '\301', '\302', '\303', '\310', '\302',    ' ',    ' ',
344   '\301', '\302', '\303', '\304', '\310', '\312',    ' ', '\313',
345   '\301', '\302', '\303', '\310', '\301', '\302', '\303', '\310',
346   '\305', '\304', '\301', '\302', '\303', '\304', '\310',    ' ',
347      ' ', '\301', '\302', '\303', '\310', '\302',    ' ',    ' '
348 };
349 
350 static char* the_unaccented;
351 static char* the_accents;
352 
353 #define ACCENTS_PREPARE \
354   if (status==TEX_CM) { \
355     the_unaccented= CM_unaccented; \
356     the_accents   = CM_accents; \
357   } \
358   else { \
359     the_unaccented= ADOBE_unaccented; \
360     the_accents   = ADOBE_accents; \
361   }
362 
363 static string
get_unaccented(string s)364 get_unaccented (string s) {
365   int i;
366   string r(N(s));
367   for (i=0; i<N(s); i++)
368     if ((s[i] & 128) == 0) r[i]= s[i];
369     else {
370       char c= the_unaccented[s[i] & 127];
371       if (c==' ') r[i]= s[i];
372       else r[i]= the_unaccented[s[i] & 127];
373     }
374   return r;
375 }
376 
377 static string
get_accents(string s)378 get_accents (string s) {
379   int i, n= N(s);
380   string r (n);
381   for (i=0; i<n; i++) {
382     if ((s[i] & 128) == 0) r[i]= ' ';
383     else r[i]= (char) the_accents [s[i] & 127];
384   }
385   return r;
386 }
387 
388 void
accented_get_extents(string s,metric & ex)389 tex_font_rep::accented_get_extents (string s, metric& ex) {
390   int old_status= status;
391   status= TEX_ANY;
392 
393   register int i;
394   string acc= get_accents (s);
395   s= get_unaccented (s);
396   get_extents (s, ex);
397 
398   for (i=0; i<N(acc); i++)
399     if (acc[i] != ' ') {
400       SI xx, yy;
401       char c= acc[i];
402       metric ey, ez;
403       get_extents (s(0,i+1), ey); xx= ey->x2;
404       get_extents (s[i], ey);
405       get_extents (c, ez);
406       xx -= (((ey->x2 - ey->x1) + (ez->x2 - ez->x1)) >> 1);
407       yy  = ey->y2- yx;
408       if (c == 24) yy=PIXEL;
409       else if (c == ((char) 203)) yy= 0;
410       else if (c == ((char) 206)) {
411         yy= 0;
412         if ((s[i] == 'a') || (s[i] == 'A')) xx += (ey->x2 - ey->x1) / 3;
413         else xx += (ey->x2 - ey->x1) / 5;
414       }
415       else xx += (SI) (((double) yy) * slope);
416       ex->x3 = min (ex->x3, xx + ez->x3);
417       ex->y3 = min (ex->y3, yy + ez->y3);
418       ex->x4 = max (ex->x4, xx + ez->x4);
419       ex->y4 = max (ex->y4, yy + ez->y4);
420     }
421 
422   status= old_status;
423 }
424 
425 void
accented_get_xpositions(string s,SI * xpos,bool ligf)426 tex_font_rep::accented_get_xpositions (string s, SI* xpos, bool ligf) {
427   int old_status= status;
428   status= TEX_ANY;
429   string acc= get_accents (s);
430   s= get_unaccented (s);
431   get_xpositions (s, xpos, ligf);
432   status= old_status;
433 }
434 
435 void
accented_draw(renderer ren,string s,SI x,SI y)436 tex_font_rep::accented_draw (renderer ren, string s, SI x, SI y) {
437   int old_status= status;
438   status= TEX_ANY;
439 
440   register int i;
441   string acc= get_accents (s);
442   s= get_unaccented (s);
443   draw_fixed (ren, s, x, y);
444 
445   for (i=0; i<N(acc); i++)
446     if (acc[i] != ' ') {
447       SI xx, yy;
448       char c= acc[i];
449       metric ey, ez;
450       get_extents (s(0,i+1), ey); xx= ey->x2;
451       get_extents (s[i], ey);
452       get_extents (c, ez);
453       xx -= (((ey->x2 - ey->x1) + (ez->x2 - ez->x1)) >> 1);
454       yy  = ey->y2- yx;
455       if (c == 24) yy=PIXEL;
456       else if (c == ((char) 203)) yy= 0;
457       else if (c == ((char) 206)) {
458         yy= 0;
459         if ((s[i] == 'a') || (s[i] == 'A')) xx += (ey->x2 - ey->x1) / 3;
460         else xx += (ey->x2 - ey->x1) / 5;
461       }
462       else xx += (SI) (((double) yy) * slope);
463       draw_fixed (ren, string (c), x+ xx, y+ yy);
464     }
465 
466   status= old_status;
467 }
468 
469 SI
accented_get_left_correction(string s)470 tex_font_rep::accented_get_left_correction (string s) {
471   s= get_unaccented (s);
472   return (SI) (slope * conv (tfm->d ((QN) s[0])));
473 }
474 
475 SI
accented_get_right_correction(string s)476 tex_font_rep::accented_get_right_correction (string s) {
477   s= get_unaccented (s);
478   return conv (tfm->i ((QN) s[N(s)-1]));
479 }
480 
481 /******************************************************************************
482 * The general case
483 ******************************************************************************/
484 
485 bool
raw_supports(unsigned char c)486 tex_font_rep::raw_supports (unsigned char c) {
487   glyph gl= pk->get ((int) c);
488   return !is_nil (gl);
489 }
490 
491 bool
supports(string s)492 tex_font_rep::supports (string s) {
493   switch (status) {
494     case TEX_ANY:
495       if (s == "<less>") return raw_supports ('<');
496       else if (s == "<gtr>") return raw_supports ('>');
497       else if (N(s) == 1) return raw_supports (s[0]);
498       else return false;
499     case TEX_EC:
500     case TEX_LA:
501     case TEX_GR:
502       return N(s) == 1 || s == "<less>" || s == "<gtr>";
503     case TEX_CM:
504     case TEX_ADOBE:
505       if (N(s) != 1) return s == "<less>" || s == "<gtr>";
506       else if (((unsigned int) s[0]) < ((unsigned int) 128)) return true;
507       else {
508         ACCENTS_PREPARE;
509         return get_accents (s) != " ";
510       }
511   }
512   return false;
513 }
514 
515 void
get_extents(string s,metric & ex)516 tex_font_rep::get_extents (string s, metric& ex) {
517   register int i;
518   switch (status) {
519     case TEX_ANY:
520       break;
521     case TEX_EC:
522     case TEX_LA:
523     case TEX_GR:
524       for (i=0; i<N(s); i++)
525         if (s[i]=='<') {
526           special_get_extents (s, ex);
527           return;
528         }
529       break;
530     case TEX_CM:
531     case TEX_ADOBE:
532       for (i=0; i<N(s); i++) {
533         if (s[i]=='<') {
534           special_get_extents (s, ex);
535           return;
536         }
537         if ((s[i] & 128) != 0) {
538           ACCENTS_PREPARE;
539           accented_get_extents (s, ex);
540           return;
541         }
542       }
543       break;
544   }
545 
546   int n= N(s);
547   int m= (n+16) << 1;
548   STACK_NEW_ARRAY (s_copy, int, n);
549   STACK_NEW_ARRAY (buf, int, m);
550   STACK_NEW_ARRAY (ker, int, m);
551 
552   if (exec) {
553   for (i=0; i<n; i++) s_copy[i]= ((QN) s[i]);
554   tfm->execute (s_copy, n, buf, ker, m);
555   } else {
556     m = n;
557     for (i=0; i<m; ++i) {
558       buf[i]= s[i] & 255;
559       ker[i]= 0;
560     }
561   }
562 
563   SI x1= 0;
564   SI x2= 0;
565   SI x3= PLUS_INFINITY;
566   SI x4= MINUS_INFINITY;
567   SI y1= PLUS_INFINITY;
568   SI y2= MINUS_INFINITY;
569   SI y3= PLUS_INFINITY;
570   SI y4= MINUS_INFINITY;
571 
572   for (i=0; i<m; i++) {
573     int c= buf[i];
574     glyph gl= pk->get (c);
575     if (is_nil (gl)) continue;
576 
577     y1= min (y1, -conv (tfm->d(c)));
578     y2= max (y2,  conv (tfm->h(c)));
579     x3= min (x3, x2- ((int) gl->xoff) * PIXEL);
580     x4= max (x4, x2+ ((int) (gl->width- gl->xoff)) * PIXEL);
581     y3= min (y3, ((int) (gl->yoff- gl->height)) * PIXEL);
582     y4= max (y4, ((int) gl->yoff) * PIXEL);
583     x2 += conv (tfm->w(c)+ ker[i]);
584   }
585 
586   if ((x3 == PLUS_INFINITY) || (x4 == MINUS_INFINITY) ||
587       (y3 == PLUS_INFINITY) || (y4 == MINUS_INFINITY))
588     {
589       x1= x3= x2= x4= 0;
590       y3= y1= 0; y4= y2= yx;
591     }
592 
593   ex->x1= x1;
594   ex->x2= x2;
595   ex->x3= x3 - 2*PIXEL;
596   ex->x4= x4 + 2*PIXEL;
597   ex->y1= y1;
598   ex->y2= y2;
599   ex->y3= y3 - 2*PIXEL;
600   ex->y4= y4 + 2*PIXEL;
601 
602   STACK_DELETE_ARRAY (s_copy);
603   STACK_DELETE_ARRAY (buf);
604   STACK_DELETE_ARRAY (ker);
605 }
606 
607 void
get_xpositions(string s,SI * xpos,bool ligf)608 tex_font_rep::get_xpositions (string s, SI* xpos, bool ligf) {
609   register int i, n= N(s);
610   if (n == 0) return;
611 
612   switch (status) {
613     case TEX_ANY:
614       break;
615     case TEX_EC:
616     case TEX_LA:
617     case TEX_GR:
618       for (i=0; i<n; i++)
619         if (s[i]=='<') {
620           special_get_xpositions (s, xpos, ligf);
621           return;
622         }
623       break;
624     case TEX_CM:
625     case TEX_ADOBE:
626       for (i=0; i<n; i++) {
627         if (s[i]=='<') {
628           special_get_xpositions (s, xpos, ligf);
629           return;
630         }
631         if ((s[i] & 128) != 0) {
632           ACCENTS_PREPARE;
633           accented_get_xpositions (s, xpos, ligf);
634           return;
635         }
636       }
637       break;
638   }
639 
640   STACK_NEW_ARRAY (s_copy, int, n);
641   for (i=0; i<n; i++) s_copy[i]= ((QN) s[i]);
642   tfm->get_xpositions (s_copy, n, unit, xpos, ligf);
643   STACK_DELETE_ARRAY (s_copy);
644 }
645 
646 void
get_xpositions(string s,SI * xpos)647 tex_font_rep::get_xpositions (string s, SI* xpos) {
648   get_xpositions (s, xpos, true);
649 }
650 
651 void
draw_fixed(renderer ren,string s,SI ox,SI y)652 tex_font_rep::draw_fixed (renderer ren, string s, SI ox, SI y) {
653   register int i;
654   switch (status) {
655     case TEX_ANY:
656       break;
657     case TEX_EC:
658     case TEX_LA:
659     case TEX_GR:
660       for (i=0; i<N(s); i++)
661         if (s[i]=='<') {
662           special_draw (ren, s, ox, y);
663           return;
664         }
665       break;
666     case TEX_CM:
667     case TEX_ADOBE:
668       for (i=0; i<N(s); i++) {
669         if (s[i]=='<') {
670           special_draw (ren, s, ox, y);
671           return;
672         }
673         if ((s[i] & 128) != 0) {
674           ACCENTS_PREPARE;
675           accented_draw (ren, s, ox, y);
676           return;
677         }
678       }
679       break;
680   }
681 
682   SI  x= ox;
683   int n= N(s);
684   int m= (n+16) << 1;
685   STACK_NEW_ARRAY (str, int, n);
686   STACK_NEW_ARRAY (buf, int, m);
687   STACK_NEW_ARRAY (ker, int, m);
688 
689   if (exec) {
690   for (i=0; i<n; i++) str[i]= ((QN) s[i]);
691   tfm->execute (str, n, buf, ker, m);
692   } else {
693     m = n;
694     for (i=0; i<m; ++i) {
695       buf[i]= s[i] & 255;
696       ker[i]= 0;
697     }
698   }
699 
700   for (i=0; i<m; i++) {
701     register int c= buf[i];
702     glyph gl= pk->get (c);
703     if (is_nil (gl)) continue;
704     ren->draw (c, pk, x, y);
705     x += conv (tfm->w(c)+ ker[i]);
706   }
707   STACK_DELETE_ARRAY (str);
708   STACK_DELETE_ARRAY (buf);
709   STACK_DELETE_ARRAY (ker);
710 }
711 
712 font
magnify(double zoom)713 tex_font_rep::magnify (double zoom) {
714   int ndpi= (int) tm_round (dpi * zoom);
715   switch (status) {
716   case TEX_ANY:
717     return tex_font (family, size, ndpi, dsize);
718   case TEX_EC:
719     return tex_ec_font (family, size, ndpi, dsize);
720   case TEX_LA:
721     return tex_la_font (family, size, ndpi, dsize);
722   case TEX_GR:
723     return tex_gr_font (family, size, ndpi, dsize);
724   case TEX_CM:
725     return tex_cm_font (family, size, ndpi, dsize);
726   case TEX_ADOBE:
727     return tex_adobe_font (family, size, ndpi, dsize);
728   }
729   return tex_font (family, size, ndpi, dsize);
730 }
731 
732 SI
get_left_correction(string s)733 tex_font_rep::get_left_correction (string s) {
734   if (N(s) == 0) return 0;
735   switch (status) {
736   case TEX_ANY:
737     break;
738   case TEX_EC:
739   case TEX_LA:
740   case TEX_GR:
741     if (s[0] == '<') return special_get_left_correction (s);
742     break;
743   case TEX_CM:
744   case TEX_ADOBE:
745     if (s[0] == '<') return special_get_left_correction (s);
746     if ((s[0] & 128) != 0) {
747       ACCENTS_PREPARE;
748       return accented_get_left_correction (s);
749     }
750   }
751   return (SI) (slope * conv (tfm->d ((QN) s[0])));
752 }
753 
754 SI
get_right_correction(string s)755 tex_font_rep::get_right_correction (string s) {
756   if (N(s) == 0) return 0;
757   switch (status) {
758   case TEX_ANY:
759     break;
760   case TEX_EC:
761   case TEX_LA:
762   case TEX_GR:
763     if (s[N(s)-1] == '>') return special_get_right_correction (s);
764     break;
765   case TEX_CM:
766   case TEX_ADOBE:
767     if (s[N(s)-1] == '>') return special_get_right_correction (s);
768     if ((s[N(s)-1] & 128) != 0) {
769       ACCENTS_PREPARE;
770       return accented_get_right_correction (s);
771     }
772   }
773   return conv (tfm->i ((QN) s[N(s)-1]));
774 }
775 
776 glyph
get_glyph(string s)777 tex_font_rep::get_glyph (string s) {
778   register int i;
779   switch (status) {
780   case TEX_ANY:
781     break;
782   case TEX_EC:
783   case TEX_LA:
784   case TEX_GR:
785     if (s == "<less>") s= "<";
786     if (s == "<gtr>") s= ">";
787     break;
788   case TEX_CM:
789   case TEX_ADOBE:
790     if (s == "<less>") s= "<";
791     if (s == "<gtr>") s= ">";
792     for (i=0; i<N(s); i++)
793       if ((s[i] & 128) != 0)
794 	return font_rep::get_glyph (s);
795     break;
796   }
797   if (N(s)!=1) return font_rep::get_glyph (s);
798   int c= ((QN) s[0]);
799   glyph gl= pk->get (c);
800   if (is_nil (gl)) return font_rep::get_glyph (s);
801   return gl;
802 }
803 
804 #undef conv
805 
806 /******************************************************************************
807 * Interface
808 ******************************************************************************/
809 
810 font
tex_font(string family,int size,int dpi,int dsize)811 tex_font (string family, int size, int dpi, int dsize) {
812   string name= "tex:" * family * as_string (size) * "@" * as_string(dpi);
813   return make (font, name,
814     tm_new<tex_font_rep> (name, TEX_ANY, family, size, dpi, dsize));
815 }
816 
817 font
tex_cm_font(string family,int size,int dpi,int dsize)818 tex_cm_font (string family, int size, int dpi, int dsize) {
819   string name= "cm:" * family * as_string (size) * "@" * as_string(dpi);
820   return make (font, name,
821     tm_new<tex_font_rep> (name, TEX_CM, family, size, dpi, dsize));
822 }
823 
824 font
tex_ec_font(string family,int size,int dpi,int dsize)825 tex_ec_font (string family, int size, int dpi, int dsize) {
826   string name= "ec:" * family * as_string (size) * "@" * as_string(dpi);
827   return make (font, name,
828     tm_new<tex_font_rep> (name, TEX_EC, family, size, dpi, dsize));
829 }
830 
831 font
tex_la_font(string family,int size,int dpi,int dsize)832 tex_la_font (string family, int size, int dpi, int dsize) {
833   string name= "la:" * family * as_string (size) * "@" * as_string(dpi);
834   return make (font, name,
835     tm_new<tex_font_rep> (name, TEX_LA, family, size, dpi, dsize));
836 }
837 
838 font
tex_gr_font(string family,int size,int dpi,int dsize)839 tex_gr_font (string family, int size, int dpi, int dsize) {
840   string name= "gr:" * family * as_string (size) * "@" * as_string(dpi);
841   return make (font, name,
842     tm_new<tex_font_rep> (name, TEX_GR, family, size, dpi, dsize));
843 }
844 
845 font
tex_adobe_font(string family,int size,int dpi,int dsize)846 tex_adobe_font (string family, int size, int dpi, int dsize) {
847   string name= "adobe:" * family * as_string (size) * "@" * as_string(dpi);
848   return make (font, name,
849     tm_new<tex_font_rep> (name, TEX_ADOBE, family, size, dpi, dsize));
850 }
851