Back to index

texmacs  1.0.7.15
tex_font.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : tex_font.cpp
00004 * DESCRIPTION: TeX text fonts
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "font.hpp"
00013 #include "Metafont/load_tex.hpp"
00014 #include "translator.hpp"
00015 #include "iterator.hpp"
00016 #include "gui.hpp"
00017 
00018 #define TEX_ANY   0
00019 #define TEX_EC    1
00020 #define TEX_LA    2
00021 #define TEX_CM    3
00022 #define TEX_ADOBE 4
00023 
00024 static void special_initialize ();
00025 
00026 /******************************************************************************
00027 * TeX text fonts
00028 ******************************************************************************/
00029 
00030 struct tex_font_rep: font_rep {
00031   int              status;
00032   string           family;
00033   int              dpi;
00034   int              dsize;
00035   tex_font_metric  tfm;
00036   font_glyphs      pk;
00037   double           unit;
00038 
00039   tex_font_rep (string name, int status,
00040               string family, int size, int dpi, int dsize);
00041 
00042   void get_extents (string s, metric& ex);
00043   void get_xpositions (string s, SI* xpos);
00044   void draw (renderer ren, string s, SI x, SI y);
00045   SI   get_left_correction (string s);
00046   SI   get_right_correction (string s);
00047   glyph get_glyph (string s);
00048   void special_get_extents (string s, metric& ex);
00049   void special_get_xpositions (string s, SI* xpos);
00050   void special_draw (renderer ren, string s, SI x, SI y);
00051   SI   special_get_left_correction (string s);
00052   SI   special_get_right_correction (string s);
00053   void accented_get_extents (string s, metric& ex);
00054   void accented_get_xpositions (string s, SI* xpos);
00055   void accented_draw (renderer ren, string s, SI x, SI y);
00056   SI   accented_get_left_correction (string s);
00057   SI   accented_get_right_correction (string s);
00058 };
00059 
00060 /******************************************************************************
00061 * The implementation of tex_fonts
00062 ******************************************************************************/
00063 
00064 #define conv(x) ((SI) (((double) (x))*unit))
00065 
00066 tex_font_rep::tex_font_rep (string name, int status2,
00067   string family2, int size2, int dpi2, int dsize2):
00068   font_rep (name), status (status2), dsize (dsize2)
00069 {
00070   load_tex (family2, size2, dpi2, dsize, tfm, pk);
00071 
00072   family       = family2;
00073   type         = FONT_TYPE_TEX;
00074   size         = size2;
00075   dpi          = dpi2;
00076   design_size  = tfm->design_size () >> 12;
00077   display_size = (((design_size*dpi)/72)*PIXEL) >> 8;
00078   unit         = ((double) display_size) / ((double) (1<<20));
00079   slope        = tfm->slope ();
00080   spc->def     = conv (tfm->spc ());
00081   spc->min     = spc->def - conv (tfm->spc_shrink ());
00082   spc->max     = spc->def + conv (tfm->spc_stretch ());
00083   extra        = conv (tfm->spc_extra ());
00084   extra->min   = extra->min >> 1;
00085   extra->max   = extra->min << 1;
00086   sep          = ((((dpi*PIXEL)/72)*design_size) >> 8) / 10;
00087 
00088   y1           = conv (-262080);   // -0.25 quad
00089   y2           = y1+ display_size; //  0.75 quad
00090   yx           = conv (tfm->x_height ());
00091   yfrac        = yx >> 1;
00092   ysub_lo_base = -yx/3;
00093   ysub_hi_lim  = (5*yx)/6;
00094   ysup_lo_lim  = yx/2;
00095   ysup_lo_base = (5*yx)/6;
00096   ysup_hi_lim  = yx;
00097   yshift       = yx/6;
00098 
00099   wpt          = (dpi*PIXEL)/72;
00100   wfn          = (wpt*design_size) >> 8;
00101   wline        = wfn/20;
00102   wquad        = conv (tfm->spc_quad ());
00103 
00104   if ((family == "cmr") || (family == "ecrm") || (family == "cmmi")) {
00105     if (size < 8)
00106       wline= wfn / (size==7? 16: (size==6? 14: 12));
00107     else if (size < 10) yfrac += (size * wfn) / 1600;
00108     else if (size <= 14) yfrac += (size * wfn) / 1000;
00109     else {
00110       wline= wfn / (size>16? 28: 24);
00111       yfrac += (size * wfn) / 700;
00112     }
00113   }
00114 
00115   special_initialize ();
00116 }
00117 
00118 /******************************************************************************
00119 * Handle <, > and (in the future?) other special characters
00120 ******************************************************************************/
00121 
00122 static bool special_initialized= false;
00123 static hashmap<string,string> special_translate ("");
00124 
00125 static void
00126 special_initialize () {
00127   if (special_initialized) return;
00128   special_translate ("<less>")= "<";
00129   special_translate ("<gtr>")= ">";
00130   translator trl= load_translator ("larm");
00131   iterator<string> it= iterate (trl->dict);
00132   while (it->busy ()) {
00133     string s= it->next ();
00134     special_translate (s)= string ((char) (unsigned char) trl->dict[s]);
00135   }
00136   special_initialized= true;
00137 }
00138 
00139 void
00140 tex_font_rep::special_get_extents (string s, metric& ex) {
00141   register int i, j;
00142   for (i=0; i<N(s); i++)
00143     if (s[i]=='<') break;
00144   get_extents (s (0, i), ex);
00145   for (j=i+1; j<N(s); j++)
00146     if (s[j]=='>') break;
00147   if (j<N(s)) j++;
00148 
00149   SI x;
00150   metric ey;
00151   int temp= status;
00152   status= TEX_ANY;
00153   string r = s (i, j);
00154   string rr= special_translate[r];
00155   if (N(rr) != 0) r= rr;
00156   get_extents (r, ey);
00157   x= ex->x2;
00158   ex->x1= min (ex->x1, x+ ey->x1); ex->y1= min (ex->y1, ey->y1);
00159   ex->x2= max (ex->x2, x+ ey->x2); ex->y2= max (ex->y2, ey->y2);
00160   ex->x3= min (ex->x3, x+ ey->x3); ex->y3= min (ex->y3, ey->y3);
00161   ex->x4= max (ex->x4, x+ ey->x4); ex->y4= max (ex->y4, ey->y4);
00162   status= temp;
00163   
00164   get_extents (s (j, N(s)), ey);
00165   x= ex->x2;
00166   ex->x1= min (ex->x1, x+ ey->x1); ex->y1= min (ex->y1, ey->y1);
00167   ex->x2= max (ex->x2, x+ ey->x2); ex->y2= max (ex->y2, ey->y2);
00168   ex->x3= min (ex->x3, x+ ey->x3); ex->y3= min (ex->y3, ey->y3);
00169   ex->x4= max (ex->x4, x+ ey->x4); ex->y4= max (ex->y4, ey->y4);
00170 }
00171 
00172 void
00173 tex_font_rep::special_get_xpositions (string s, SI* xpos) {
00174   SI offset= 0;
00175   register int l=0, i, j, n=N(s);
00176   while (l<n) {
00177     for (i=l; i<n; i++)
00178       if (s[i]=='<') break;
00179     if (l<i) {
00180       get_xpositions (s (l, i), xpos + l);
00181       for (j=l+1; j<=i; j++) xpos[j] += offset;
00182       if (i==n) break;
00183       offset= xpos[i];
00184     }
00185 
00186     for (j=i+1; j<n; j++) {
00187       xpos[j]= offset;
00188       if (s[j]=='>') break;
00189     }
00190     if (j<n) j++;
00191     metric ey;
00192     int temp= status;
00193     status= TEX_ANY;
00194     string r= s (i, j);
00195     string rr= special_translate[r];
00196     if (N(rr) != 0) r= rr;
00197     get_extents (r, ey);
00198     status= temp;
00199     offset += ey->x2;
00200     xpos[j]= offset;
00201     l= j;
00202   }
00203 }
00204 
00205 void
00206 tex_font_rep::special_draw (renderer ren, string s, SI x, SI y) {
00207   register int i, j;
00208   metric ex;
00209   for (i=0; i<N(s); i++)
00210     if (s[i]=='<') break;
00211   draw (ren, s (0, i), x, y);
00212   get_extents (s (0, i), ex);
00213   x += ex->x2;
00214   for (j=i+1; j<N(s); j++)
00215     if (s[j]=='>') break;
00216   if (j<N(s)) j++;
00217 
00218   int temp= status;
00219   status= TEX_ANY;
00220   string r= s (i, j);
00221   string rr= special_translate[r];
00222   color c= ren->get_color ();
00223   if (N(rr) != 0) r= rr;
00224   else ren->set_color (red);
00225   draw (ren, r, x, y);
00226   ren->set_color (c);
00227   get_extents (r, ex);
00228   x += ex->x2;
00229   status= temp;
00230   
00231   draw (ren, s (j, N(s)), x, y);
00232 }
00233 
00234 SI
00235 tex_font_rep::special_get_left_correction (string s) {
00236   int i= 0;
00237   tm_char_forwards (s, i);
00238   string r= special_translate (s (0, i));
00239   if (N(r)!=0) return (SI) (slope * conv (tfm->d ((QN) r[0])));
00240   return (SI) (slope * conv (tfm->d ((QN) '<')));
00241 }
00242 
00243 SI
00244 tex_font_rep::special_get_right_correction (string s) {
00245   int n= N(s), i= n;
00246   tm_char_backwards (s, i);
00247   string r= special_translate (s (i, n));
00248   if (N(r)!=0) return conv (tfm->i ((QN) r[0]));
00249   return conv (tfm->i ((QN) '>'));
00250 }
00251 
00252 /******************************************************************************
00253 * Handle accents
00254 ******************************************************************************/
00255 
00256 static char CM_unaccented[128]= {
00257   'A', ' ', 'C', 'C', 'D', 'E', ' ', 'G',
00258   'L', 'L', ' ', 'N', 'N', ' ', 'O', 'R',
00259   'R', 'S', 'S', 'S', 'T', 'T', 'U', 'U',
00260   'Y', 'Z', 'Z', 'Z', ' ', 'I', 'd', ' ',
00261   'a', ' ', 'c', 'c', 'd', 'e', ' ', 'g',
00262   'l', 'l', ' ', 'n', 'n', ' ', 'o', 'r',
00263   'r', 's', 's', 's', 't', 't', 'u', 'u',
00264   'y', 'z', 'z', 'z', ' ', 60 , 62 , ' ',
00265   'A', 'A', 'A', 'A', 'A', 'A', 29 , 'C',
00266   'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
00267   'D', 'N', 'O', 'O', 'O', 'O', 'O', 30 ,
00268   31 , 'U', 'U', 'U', 'U', 'Y', ' ', ' ',
00269   'a', 'a', 'a', 'a', 'a', 'a', 26 , 'c',
00270   'e', 'e', 'e', 'e', 16 , 16 , 16 , 16 ,
00271   'd', 'n', 'o', 'o', 'o', 'o', 'o', 27 ,
00272   28 , 'u', 'u', 'u', 'u', 'y', ' ', 25
00273 };
00274 
00275 static char CM_accents[128]= {
00276   21 , ' ', 19 , 20 , 20 , 20 , ' ', 21 ,
00277   19 , 39 , ' ', 19 , 20 , ' ', 125, 19 ,
00278   20 , 19 , 20 , 24 , 20 , 24 , 125, 23 ,
00279   127, 19 , 20 , 95 , ' ', 95 , 22 , ' ',
00280   21 , ' ', 19 , 20 , 20 , 20 , ' ', 21 ,
00281   19 , 39 , ' ', 19 , 20 , ' ', 125, 19 ,
00282   20 , 19 , 20 , 24 , 20 , 24 , 125, 23 ,
00283   127, 19 , 20 , 95 , ' ', ' ', ' ', ' ',
00284   18 , 19 , 94 , 126, 127, 23 , ' ', 24 ,
00285   18 , 19 , 94 , 127, 18 , 19 , 94 , 127,
00286   22 , 126, 18 , 19 , 94 , 126, 127, ' ',
00287   ' ', 18 , 19 , 94 , 127, 19 , ' ', ' ',
00288   18 , 19 , 94 , 126, 127, 23 , ' ', 24 ,
00289   18 , 19 , 94 , 127, 18 , 19 , 94 , 127,
00290   22 , 126, 18 , 19 , 94 , 126, 127, ' ',
00291   ' ', 18 , 19 , 94 , 127, 19 , ' ', ' '
00292 };
00293 
00294 static char ADOBE_unaccented[128]= {
00295   'A', 'A', 'C', 'C', 'D', 'E', 'E', 'G',
00296   'L', 'L', 232, 'N', 'N', ' ', 'O', 'R',
00297   'R', 'S', 'S', 'S', 'T', 'T', 'U', 'U',
00298   'Y', 'Z', 'Z', 'Z', ' ', 'I', 'd', 167,
00299   'a', 'a', 'c', 'c', 'd', 'e', 'e', 'g',
00300   'l', 'l', 248, 'n', 'n', ' ', 'o', 'r',
00301   'r', 's', 's', 's', 't', 't', 'u', 'u',
00302   'y', 'z', 'z', 'z', ' ', 161, 191, 163,
00303   'A', 'A', 'A', 'A', 'A', 'A', 225, 'C',
00304   'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
00305   'D', 'N', 'O', 'O', 'O', 'O', 'O', 30 ,
00306   233, 'U', 'U', 'U', 'U', 'Y', ' ', ' ',
00307   'a', 'a', 'a', 'a', 'a', 'a', 241, 'c',
00308   'e', 'e', 'e', 'e', 245, 245, 245, 245,
00309   'd', 'n', 'o', 'o', 'o', 'o', 'o', 250,
00310   249, 'u', 'u', 'u', 'u', 'y', ' ', 251
00311 };
00312 
00313 static char ADOBE_accents[128]= {
00314   198, 206, 194, 207, 207, 207, 206, 198,
00315   194, 39 , ' ', 194, 207, ' ', 205, 194,
00316   207, 194, 207, 203, 207, 203, 205, 202,
00317   200, 194, 207, 199, ' ', 199, 197, ' ',
00318   198, 206, 194, 207, 207, 207, 206, 198,
00319   194, 39 , ' ', 194, 207, ' ', 205, 194,
00320   207, 194, 207, 203, 207, 203, 205, 202,
00321   200, 194, 207, 199, ' ', ' ', ' ', ' ',
00322   193, 194, 195, 196, 200, 202, ' ', 203,
00323   193, 194, 195, 200, 193, 194, 195, 200,
00324   197, 196, 193, 194, 195, 196, 200, ' ',
00325   ' ', 193, 194, 195, 200, 194, ' ', ' ',
00326   193, 194, 195, 196, 200, 202, ' ', 203,
00327   193, 194, 195, 200, 193, 194, 195, 200,
00328   197, 196, 193, 194, 195, 196, 200, ' ',
00329   ' ', 193, 194, 195, 200, 194, ' ', ' '
00330 };
00331 
00332 static char* the_unaccented;
00333 static char* the_accents;
00334 
00335 #define ACCENTS_PREPARE \
00336   if (status==TEX_CM) { \
00337     the_unaccented= CM_unaccented; \
00338     the_accents   = CM_accents; \
00339   } \
00340   else { \
00341     the_unaccented= ADOBE_unaccented; \
00342     the_accents   = ADOBE_accents; \
00343   }
00344 
00345 static string
00346 get_unaccented (string s) {
00347   int i;
00348   string r(N(s));
00349   for (i=0; i<N(s); i++)
00350     if ((s[i] & 128) == 0) r[i]= s[i];
00351     else {
00352       char c= the_unaccented[s[i] & 127];
00353       if (c==' ') r[i]= s[i];
00354       else r[i]= the_unaccented[s[i] & 127];
00355     }
00356   return r;
00357 }
00358 
00359 static string
00360 get_accents (string s) {
00361   int i;
00362   string r(N(s));
00363   for (i=0; i<N(s); i++)
00364     if ((s[i] & 128) == 0) r[i]= ' ';
00365     else r[i]= (char) the_accents [s[i] & 127];
00366   return r;
00367 }
00368 
00369 void
00370 tex_font_rep::accented_get_extents (string s, metric& ex) {
00371   int old_status= status;
00372   status= TEX_ANY;
00373 
00374   register int i;
00375   string acc= get_accents (s);
00376   s= get_unaccented (s);
00377   get_extents (s, ex);
00378 
00379   for (i=0; i<N(acc); i++)
00380     if (acc[i] != ' ') {
00381       SI xx, yy;
00382       char c= acc[i];
00383       metric ey, ez;
00384       get_extents (s(0,i+1), ey); xx= ey->x2;
00385       get_extents (s[i], ey);
00386       get_extents (c, ez);
00387       xx -= (((ey->x2 - ey->x1) + (ez->x2 - ez->x1)) >> 1);
00388       yy  = ey->y2- yx;
00389       if (c == 24) yy=PIXEL;
00390       else if (c == ((char) 203)) yy= 0;
00391       else if (c == ((char) 206)) {
00392        yy= 0;
00393        if ((s[i] == 'a') || (s[i] == 'A')) xx += (ey->x2 - ey->x1) / 3;
00394        else xx += (ey->x2 - ey->x1) / 5;
00395       }
00396       else xx += (SI) (((double) yy) * slope);
00397       ex->x3 = min (ex->x3, xx + ez->x3);
00398       ex->y3 = min (ex->y3, yy + ez->y3);
00399       ex->x4 = max (ex->x4, xx + ez->x4);
00400       ex->y4 = max (ex->y4, yy + ez->y4);
00401     }
00402 
00403   status= old_status;
00404 }
00405 
00406 void
00407 tex_font_rep::accented_get_xpositions (string s, SI* xpos) {
00408   int old_status= status;
00409   status= TEX_ANY;
00410   string acc= get_accents (s);
00411   s= get_unaccented (s);
00412   get_xpositions (s, xpos);
00413   status= old_status;
00414 }
00415 
00416 void
00417 tex_font_rep::accented_draw (renderer ren, string s, SI x, SI y) {
00418   int old_status= status;
00419   status= TEX_ANY;
00420 
00421   register int i;
00422   string acc= get_accents (s);
00423   s= get_unaccented (s);
00424   draw (ren, s, x, y);
00425 
00426   for (i=0; i<N(acc); i++)
00427     if (acc[i] != ' ') {
00428       SI xx, yy;
00429       char c= acc[i];
00430       metric ey, ez;
00431       get_extents (s(0,i+1), ey); xx= ey->x2;
00432       get_extents (s[i], ey);
00433       get_extents (c, ez);
00434       xx -= (((ey->x2 - ey->x1) + (ez->x2 - ez->x1)) >> 1);
00435       yy  = ey->y2- yx;
00436       if (c == 24) yy=PIXEL;
00437       else if (c == ((char) 203)) yy= 0;
00438       else if (c == ((char) 206)) {
00439        yy= 0;
00440        if ((s[i] == 'a') || (s[i] == 'A')) xx += (ey->x2 - ey->x1) / 3;
00441        else xx += (ey->x2 - ey->x1) / 5;
00442       }
00443       else xx += (SI) (((double) yy) * slope);
00444       draw (ren, string (c), x+ xx, y+ yy);
00445     }
00446 
00447   status= old_status;
00448 }
00449 
00450 SI
00451 tex_font_rep::accented_get_left_correction (string s) {
00452   s= get_unaccented (s);
00453   return (SI) (slope * conv (tfm->d ((QN) s[0])));
00454 }
00455 
00456 SI
00457 tex_font_rep::accented_get_right_correction (string s) {
00458   s= get_unaccented (s);
00459   return conv (tfm->i ((QN) s[N(s)-1]));
00460 }
00461 
00462 /******************************************************************************
00463 * The general case
00464 ******************************************************************************/
00465 
00466 void
00467 tex_font_rep::get_extents (string s, metric& ex) {
00468   register int i;
00469   switch (status) {
00470   case TEX_ANY:
00471     break;
00472   case TEX_EC:
00473   case TEX_LA:
00474     for (i=0; i<N(s); i++)
00475       if (s[i]=='<') {
00476        special_get_extents (s, ex);
00477        return;
00478       }
00479     break;
00480   case TEX_CM:
00481   case TEX_ADOBE:
00482     for (i=0; i<N(s); i++) {
00483       if (s[i]=='<') {
00484        special_get_extents (s, ex);
00485        return;
00486       }
00487       if ((s[i] & 128) != 0) {
00488        ACCENTS_PREPARE;
00489        accented_get_extents (s, ex);
00490        return;
00491       }
00492     }
00493     break;
00494   }
00495 
00496   int n= N(s);
00497   int m= (n+16) << 1;
00498   STACK_NEW_ARRAY (s_copy, int, n);
00499   STACK_NEW_ARRAY (buf, int, m);
00500   STACK_NEW_ARRAY (ker, int, m);
00501   for (i=0; i<n; i++) s_copy[i]= ((QN) s[i]);
00502   tfm->execute (s_copy, n, buf, ker, m);
00503 
00504   SI x1= 0;
00505   SI x2= 0;
00506   SI x3= PLUS_INFINITY;
00507   SI x4= MINUS_INFINITY;
00508   SI y1= PLUS_INFINITY;
00509   SI y2= MINUS_INFINITY;
00510   SI y3= PLUS_INFINITY;
00511   SI y4= MINUS_INFINITY;
00512 
00513   for (i=0; i<m; i++) {
00514     int c= buf[i];
00515     glyph gl= pk->get (c);
00516     if (is_nil (gl)) continue;
00517     
00518     y1= min (y1, -conv (tfm->d(c)));
00519     y2= max (y2,  conv (tfm->h(c)));
00520     x3= min (x3, x2- ((int) gl->xoff) * PIXEL);
00521     x4= max (x4, x2+ ((int) (gl->width- gl->xoff)) * PIXEL);
00522     y3= min (y3, ((int) (gl->yoff- gl->height)) * PIXEL);
00523     y4= max (y4, ((int) gl->yoff) * PIXEL);
00524     x2 += conv (tfm->w(c)+ ker[i]);
00525   }
00526 
00527   if ((x3 == PLUS_INFINITY) || (x4 == MINUS_INFINITY) ||
00528       (y3 == PLUS_INFINITY) || (y4 == MINUS_INFINITY))
00529     {
00530       x1= x3= x2= x4= 0;
00531       y3= y1= 0; y4= y2= yx;
00532     }
00533 
00534   ex->x1= x1;
00535   ex->x2= x2;
00536   ex->x3= x3 - 2*PIXEL;
00537   ex->x4= x4 + 2*PIXEL;
00538   ex->y1= y1;
00539   ex->y2= y2;
00540   ex->y3= y3 - 2*PIXEL;
00541   ex->y4= y4 + 2*PIXEL;
00542 
00543   STACK_DELETE_ARRAY (s_copy);
00544   STACK_DELETE_ARRAY (buf);
00545   STACK_DELETE_ARRAY (ker);
00546 }
00547 
00548 void
00549 tex_font_rep::get_xpositions (string s, SI* xpos) {
00550   register int i, n= N(s);
00551   if (n == 0) return;
00552 
00553   switch (status) {
00554   case TEX_ANY:
00555     break;
00556   case TEX_EC:
00557   case TEX_LA:
00558     for (i=0; i<n; i++)
00559       if (s[i]=='<') {
00560        special_get_xpositions (s, xpos);
00561        return;
00562       }
00563     break;
00564   case TEX_CM:
00565   case TEX_ADOBE:
00566     for (i=0; i<n; i++) {
00567       if (s[i]=='<') {
00568        special_get_xpositions (s, xpos);
00569        return;
00570       }
00571       if ((s[i] & 128) != 0) {
00572        ACCENTS_PREPARE;
00573        accented_get_xpositions (s, xpos);
00574        return;
00575       }
00576     }
00577     break;
00578   }
00579 
00580   STACK_NEW_ARRAY (s_copy, int, n);
00581   for (i=0; i<n; i++) s_copy[i]= ((QN) s[i]);
00582   tfm->get_xpositions (s_copy, n, unit, xpos);
00583   STACK_DELETE_ARRAY (s_copy);
00584 }
00585 
00586 void
00587 tex_font_rep::draw (renderer ren, string s, SI ox, SI y) {
00588   register int i;
00589   switch (status) {
00590   case TEX_ANY:
00591     break;
00592   case TEX_EC:
00593   case TEX_LA:
00594     for (i=0; i<N(s); i++)
00595       if (s[i]=='<') {
00596        special_draw (ren, s, ox, y);
00597        return;
00598       }
00599     break;
00600   case TEX_CM:
00601   case TEX_ADOBE:
00602     for (i=0; i<N(s); i++) {
00603       if (s[i]=='<') {
00604        special_draw (ren, s, ox, y);
00605        return;
00606       }
00607       if ((s[i] & 128) != 0) {
00608        ACCENTS_PREPARE;
00609        accented_draw (ren, s, ox, y);
00610        return;
00611       }
00612     }
00613     break;
00614   }
00615 
00616   SI  x= ox;
00617   int n= N(s);
00618   int m= (n+16) << 1;
00619   STACK_NEW_ARRAY (str, int, n);
00620   STACK_NEW_ARRAY (buf, int, m);
00621   STACK_NEW_ARRAY (ker, int, m);
00622   for (i=0; i<n; i++) str[i]= ((QN) s[i]);
00623   tfm->execute (str, n, buf, ker, m);
00624 
00625   for (i=0; i<m; i++) {
00626     register int c= buf[i];
00627     glyph gl= pk->get (c);
00628     if (is_nil (gl)) continue;
00629     ren->draw (c, pk, x, y);
00630     x += conv (tfm->w(c)+ ker[i]);
00631   }
00632   STACK_DELETE_ARRAY (str);
00633   STACK_DELETE_ARRAY (buf);
00634   STACK_DELETE_ARRAY (ker);
00635 }
00636 
00637 SI
00638 tex_font_rep::get_left_correction (string s) {
00639   if (N(s) == 0) return 0;
00640   switch (status) {
00641   case TEX_ANY:
00642     break;
00643   case TEX_EC:
00644   case TEX_LA:
00645     if (s[0] == '<') return special_get_left_correction (s);
00646     break;
00647   case TEX_CM:
00648   case TEX_ADOBE:
00649     if (s[0] == '<') return special_get_left_correction (s);
00650     if ((s[0] & 128) != 0) {
00651       ACCENTS_PREPARE;
00652       return accented_get_left_correction (s);
00653     }
00654   }
00655   return (SI) (slope * conv (tfm->d ((QN) s[0])));
00656 }
00657 
00658 SI
00659 tex_font_rep::get_right_correction (string s) {
00660   if (N(s) == 0) return 0;
00661   switch (status) {
00662   case TEX_ANY:
00663     break;
00664   case TEX_EC:
00665   case TEX_LA:
00666     if (s[N(s)-1] == '>') return special_get_right_correction (s);
00667     break;
00668   case TEX_CM:
00669   case TEX_ADOBE:
00670     if (s[N(s)-1] == '>') return special_get_right_correction (s);
00671     if ((s[N(s)-1] & 128) != 0) {
00672       ACCENTS_PREPARE;
00673       return accented_get_right_correction (s);
00674     }
00675   }
00676   return conv (tfm->i ((QN) s[N(s)-1]));
00677 }
00678 
00679 glyph
00680 tex_font_rep::get_glyph (string s) {
00681   register int i;
00682   switch (status) {
00683   case TEX_ANY:
00684     break;
00685   case TEX_EC:
00686   case TEX_LA:
00687     if (s == "<less>") s= "<";
00688     if (s == "<gtr>") s= ">";
00689     break;
00690   case TEX_CM:
00691   case TEX_ADOBE:
00692     if (s == "<less>") s= "<";
00693     if (s == "<gtr>") s= ">";
00694     for (i=0; i<N(s); i++)
00695       if ((s[i] & 128) != 0)
00696        return font_rep::get_glyph (s);
00697     break;
00698   }
00699   if (N(s)!=1) return font_rep::get_glyph (s);
00700   int c= ((QN) s[0]);
00701   glyph gl= pk->get (c);
00702   if (is_nil (gl)) return font_rep::get_glyph (s);
00703   return gl;
00704 }
00705 
00706 #undef conv
00707 
00708 /******************************************************************************
00709 * Interface
00710 ******************************************************************************/
00711 
00712 font
00713 tex_font (string family, int size, int dpi, int dsize) {
00714   string name= "tex:" * family * as_string (size) * "@" * as_string(dpi);
00715   return make (font, name,
00716     tm_new<tex_font_rep> (name, TEX_ANY, family, size, dpi, dsize));
00717 }
00718 
00719 font
00720 tex_cm_font (string family, int size, int dpi, int dsize) {
00721   string name= "cm:" * family * as_string (size) * "@" * as_string(dpi);
00722   return make (font, name,
00723     tm_new<tex_font_rep> (name, TEX_CM, family, size, dpi, dsize));
00724 }
00725 
00726 font
00727 tex_ec_font (string family, int size, int dpi, int dsize) {
00728   string name= "ec:" * family * as_string (size) * "@" * as_string(dpi);
00729   return make (font, name,
00730     tm_new<tex_font_rep> (name, TEX_EC, family, size, dpi, dsize));
00731 }
00732 
00733 font
00734 tex_la_font (string family, int size, int dpi, int dsize) {
00735   string name= "la:" * family * as_string (size) * "@" * as_string(dpi);
00736   return make (font, name,
00737     tm_new<tex_font_rep> (name, TEX_LA, family, size, dpi, dsize));
00738 }
00739 
00740 font
00741 tex_adobe_font (string family, int size, int dpi, int dsize) {
00742   string name= "adobe:" * family * as_string (size) * "@" * as_string(dpi);
00743   return make (font, name,
00744     tm_new<tex_font_rep> (name, TEX_ADOBE, family, size, dpi, dsize));
00745 }