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