1 /*
2 Gri - A language for scientific graphics programming
3 Copyright (C) 2008 Daniel Kelley
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 //#define DEBUG 1
21 #include <vector>
22 #include <string>
23 #include <stack>
24 #include <math.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include "gr.hh"
28 #include "extern.hh"
29 #include "GriPath.hh"
30 #include "superus.hh"
31 #include "defaults.hh"
32 #define NCODES 100
33 // symbol_code (p 604 new PostScript book): (1) define name, (2) Postscript
34 // code, (3) symbol-font crossref code (used for estimage of symbol
35 // size, by index_for_math_symbol() ... a bad idea, really), and (4)
36 // SVG code [broken; need to transcribe the codes from
37 // http://www.w3.org/TR/html4/sgml/entities.html#h-24.3 one by one]
38 static char *symbol_code[NCODES][4] = {
39 // name, code in Table E.11, p604 new ps book, char-equivalent}
40 //
41 // Organization of list below is as in the tables in
42 // Lamport's Latex book
43 //
44 // Table 3.3 Greek Letters
45 // lowercase
46 {(char *)"alpha", (char *)"\\141", (char *)"a", (char *)"α"},
47 {(char *)"beta", (char *)"\\142", (char *)"b", (char *)"β"},
48 {(char *)"gamma", (char *)"\\147", (char *)"g", (char *)"γ"},
49 {(char *)"delta", (char *)"\\144", (char *)"d", (char *)"δ"},
50 {(char *)"epsilon", (char *)"\\145", (char *)"e", (char *)"ε"},
51 // varepsilon
52 {(char *)"zeta", (char *)"\\172", (char *)"z", (char *)"θ"},
53 {(char *)"eta", (char *)"\\150", (char *)"h", (char *)"η"},
54 {(char *)"theta", (char *)"\\161", (char *)"q", (char *)"θ"},
55 {(char *)"vartheta", (char *)"\\112", (char *)"q", (char *)"ϑ"},
56 {(char *)"iota", (char *)"\\151", (char *)"i", (char *)"┻"},
57 {(char *)"kappa", (char *)"\\153", (char *)"k", (char *)"κ"},
58 {(char *)"lambda", (char *)"\\154", (char *)"l", (char *)"λ"},
59 {(char *)"mu", (char *)"\\155", (char *)"m", (char *)"μ"},
60 {(char *)"nu", (char *)"\\156", (char *)"n", (char *)"ν"},
61 {(char *)"xi", (char *)"\\170", (char *)"x", (char *)"ξ"},
62 // o [not needed, really]
63 {(char *)"pi", (char *)"\\160", (char *)"p", (char *)"π"},
64 {(char *)"varpi", (char *)"\\166", (char *)"p", (char *)"π"},
65 {(char *)"rho", (char *)"\\162", (char *)"r", (char *)"ρ"},
66 {(char *)"sigma", (char *)"\\163", (char *)"s", (char *)"σ"}, // or 962
67 {(char *)"varsigma", (char *)"\\126", (char *)"s", (char *)"ς"},
68 {(char *)"tau", (char *)"\\164", (char *)"t", (char *)"τ"},
69 {(char *)"upsilon", (char *)"\\165", (char *)"u", (char *)"υ"},
70 {(char *)"psi", (char *)"\\171", (char *)"y", (char *)"ψ"},
71 {(char *)"chi", (char *)"\\143", (char *)"c", (char *)"χ"},
72 {(char *)"phi", (char *)"\\146", (char *)"f", (char *)"φ"},
73 {(char *)"varphi", (char *)"\\152", (char *)"f", (char *)"φ"}, //?
74 {(char *)"omega", (char *)"\\167", (char *)"w", (char *)"ω"},
75 //
76 // Uppercase
77 {(char *)"Gamma", (char *)"\\107", (char *)"G", (char *)"Γ"},
78 {(char *)"Delta", (char *)"\\104", (char *)"D", (char *)"Δ"},
79 {(char *)"Theta", (char *)"\\121", (char *)"Q", (char *)"Θ"},
80 {(char *)"Lambda", (char *)"\\114", (char *)"L", (char *)"Λ"},
81 {(char *)"Xi", (char *)"\\130", (char *)"X", (char *)"Ξ"},
82 {(char *)"Pi", (char *)"\\120", (char *)"P", (char *)"Π"},
83 {(char *)"Sigma", (char *)"\\123", (char *)"S", (char *)"Σ"},
84 {(char *)"Upsilon", (char *)"\\241", (char *)"Y", (char *)"Υ"},
85 {(char *)"Phi", (char *)"\\106", (char *)"F", (char *)"Φ"},
86 {(char *)"Psi", (char *)"\\131", (char *)"Y", (char *)"Ψ"},
87 {(char *)"Omega", (char *)"\\127", (char *)"W", (char *)"Ω"},
88 // Table 3.4: Binary Operation Symbols
89 {(char *)"pm", (char *)"\\261", (char *)"+", (char *)"±"}, // guess that size is same as +
90 // mp
91 {(char *)"times", (char *)"\\264", (char *)"x", (char *)"×"}, // guess that size is same as x
92 {(char *)"div", (char *)"\\270", (char *)"x", (char *)"÷"}, // guess that size is same as x
93 {(char *)"ast", (char *)"\\052", (char *)"*", (char *)"∗"}, // star
94 {(char *)"circ", (char *)"\\260", (char *)".", (char *)"°"},
95 {(char *)"bullet", (char *)"\\267", (char *)"*", (char *)"•"}, // guess that size is same as *
96 {(char *)"cdot", (char *)"\\327", (char *)",", (char *)"·"}, // ? Georgian comma
97 // cap
98 // cup
99 // uplus
100 // sqcap
101 // sqcup
102 // vee
103 {(char *)"wedge", (char *)"\\331", (char *)"M", (char *)"∧"}, // guess that size is same as M
104 // setminus
105 // wr
106 // diamond
107 // bigtriangleup
108 // bigtriangledown
109 // triangleleft
110 // triangleright
111 // lhd
112 // rhd
113 // unlhd
114 // unrhd
115 {(char *)"oplus", (char *)"\\305", (char *)"o", (char *)"⊕"},
116 // ominus
117 {(char *)"otimes", (char *)"\\304", (char *)"o", (char *)"⊗"},
118 // oslash
119 // odot
120 // bigcirc
121 // dagger
122 // ddagger
123 // amalg
124 //
125 // Table 3.5: Relation Symbols
126 {(char *)"leq", (char *)"\\243", (char *)"<", (char *)"≤"}, // guess that size is same as <
127 // prec
128 // preceq
129 // ll
130 {(char *)"subset", (char *)"\\314", (char *)"<", (char *)"⊂"}, // guess that size is same as <
131 {(char *)"subseteq", (char *)"\\315", (char *)"<", (char *)"⊆"}, // guess that size is same as <
132 // sqsubset
133 // sqsubseteq
134 // MOVE 'in' to after 'infty'
135 // vdash
136 {(char *)"geq", (char *)"\\263", (char *)">", (char *)"≥"},
137 // succ
138 // succeq
139 // gg
140 {(char *)"supset", (char *)"\\311", (char *)">", (char *)"⊃"},
141 {(char *)"supseteq", (char *)"\\312", (char *)">", (char *)"⊇"},
142 // sqsupset
143 // sqsupseteq
144 // ni
145 // dashv
146 {(char *)"equiv", (char *)"\\272", (char *)"=", (char *)"≡"},
147 {(char *)"sim", (char *)"\\176", (char *)"~", (char *)"∼"},
148 // simeq
149 // asymp
150 {(char *)"approx", (char *)"\\273", (char *)"~", (char *)"≆"}, // ?
151 {(char *)"cong", (char *)"\\100", (char *)"=", (char *)"∼"}, // ?
152 {(char *)"neq", (char *)"\\271", (char *)"=", (char *)"≠"},
153 // doteq
154 {(char *)"propto", (char *)"\\265", (char *)"~", (char *)"∝"},
155 // models
156 {(char *)"perp", (char *)"\\136", (char *)"M", (char *)"⊥"},
157 // mid
158 // parallel
159 // bowtie
160 // join
161 // smile
162 // frown
163 //
164 // Table 3.6: Arrow Symbols
165 {(char *)"leftarrow", (char *)"\\254", (char *)"M", (char *)"←"},
166 {(char *)"Leftarrow", (char *)"\\334", (char *)"M", (char *)"⇐"},
167 {(char *)"rightarrow", (char *)"\\256", (char *)"M", (char *)"→"},
168 {(char *)"Rightarrow", (char *)"\\336", (char *)"M", (char *)"⇒"},
169 {(char *)"leftrightarrow", (char *)"\\253", (char *)"M", (char *)"↔"},
170 {(char *)"Leftrightarrow", (char *)"\\333", (char *)"M", (char *)"⇔"},
171 // mapsto
172 // hookleftarrow
173 // leftharpoonup
174 // leftharpoondown
175 // rightleftharpoons
176 // longleftarrow
177 // Longleftarrow
178 // longrightarrow
179 // Longrightarrow
180 // longleftrightarrow
181 // Longleftrightarrow
182 // longmapsto
183 // hookrightarrow
184 // rightharpoonup
185 // rightharpoon down
186 // leadsto
187 {(char *)"uparrow", (char *)"\\255", (char *)"|", (char *)"↑"},
188 {(char *)"Uparrow", (char *)"\\335", (char *)"|", (char *)"⇑"},
189 {(char *)"downarrow", (char *)"\\257", (char *)"|", (char *)"↓"},
190 {(char *)"Downarrow", (char *)"\\337", (char *)"|", (char *)"⇓"},
191 // updownarrow
192 // Updownarrow
193 // neararrow
194 // searrow
195 // swarrow
196 // nwarrow
197 //
198 // Table 3.7: Miscellaneous Symbols
199 {(char *)"aleph", (char *)"\\300", (char *)"M", (char *)"ℵ"}, // ?
200 // hbar
201 // imath
202 // jmath
203 // ell
204 {(char *)"wp", (char *)"\\303", (char *)"M", (char *)"&#;8476"}, // BUG: figure out what this is
205 {(char *)"Re", (char *)"\\302", (char *)"R", (char *)"&#;8476"},
206 {(char *)"Im", (char *)"\\301", (char *)"M", (char *)"ℑ"},
207 // mho
208 {(char *)"prime", (char *)"\\242", (char *)"'", (char *)"′"},
209 {(char *)"emptyset", (char *)"\\306", (char *)"M", (char *)"&#;8709"},
210 {(char *)"nabla", (char *)"\\321", (char *)"M", (char *)"∇"},
211 {(char *)"surd", (char *)"\\326", (char *)"M", (char *)"√"},
212 {(char *)"sqrt", (char *)"\\326", (char *)"M", (char *)"√"},
213 // top
214 {(char *)"bot", (char *)"\\136", (char *)"M", (char *)"&#;8730"}, // BUG: no idea what this is
215 // |
216 {(char *)"angle", (char *)"\\320", (char *)"M", (char *)"∠"},
217 {(char *)"forall", (char *)"\\042", (char *)"M", (char *)"∀"},
218 {(char *)"exists", (char *)"\\044", (char *)"M", (char *)"∃"},
219 {(char *)"neg", (char *)"\\330", (char *)"M", (char *)"¬"},
220 // flat
221 // natural
222 // sharp
223 // backslash
224 {(char *)"partial", (char *)"\\266", (char *)"d", (char *)"∂"},
225 {(char *)"infty", (char *)"\\245", (char *)"M", (char *)"∞"},
226 // Interpose 'int' and 'in' here to avoid clashes with 'infty'
227 {(char *)"int", (char *)"\\362", (char *)"M", (char *)"∫"},
228 {(char *)"in", (char *)"\\316", (char *)"<", (char *)"∈"},
229 // Box
230 // Diamond
231 // triangle
232 {(char *)"clubsuit", (char *)"\\247", (char *)"M", (char *)"♣"},
233 {(char *)"diamondsuit", (char *)"\\340", (char *)"M", (char *)"♦"},
234 // heartsuit
235 {(char *)"spadesuit", (char *)"\\252", (char *)"M", (char *)"♥"},
236 //
237 // Table 3.8 Variable-sized symbols
238 {(char *)"sum", (char *)"\\345", (char *)"M", (char *)"∑"},
239 {(char *)"prod", (char *)"\\325", (char *)"M", (char *)"∏"},
240 // int -- moved up to avoid name clashes
241 // oint
242 // bigcap
243 // bigcup
244 // bigsqcup
245 // bigvee
246 // bigwedge
247 // bigodot
248 // bigotimes
249 // bigoplus
250 // biguplus
251 //
252 // Table 3.10
253 {(char *)"lfloor", (char *)"\\353", (char *)"M", (char *)"⌊"},
254 {(char *)"lceil", (char *)"\\351", (char *)"M", (char *)"⌈"},
255 {(char *)"langle", (char *)"\\341", (char *)"<", (char *)"〈"},
256 {(char *)"rfloor", (char *)"\\373", (char *)"M", (char *)"⌋"},
257 {(char *)"rceil", (char *)"\\371", (char *)"M", (char *)"⌉"},
258 {(char *)"rangle", (char *)"\\361", (char *)">", (char *)"〉"}
259 // backslash SEE ABOVE
260 // \|
261 // uparrow SEE ABOVE
262 // downarrow SEE ABOVE
263 // updownarrow SEE ABOVE
264 // Uparrow SEE ABOVE
265 // Downarrow SEE ABOVE
266 // Updownarrow SEE ABOVE
267 };
268 double gr_current_descender(void);
part_string(const std::string & s)269 std::vector<std::string> part_string(const std::string &s)
270 {
271 using namespace std;
272 string::size_type i, lasti = 0, len = s.size();
273 bool inmath = false;
274 vector<string> parts;
275 for (i = 0; i < len; i++) {
276 if (s[i] == '$') {
277 // \$ escapes but not \\$
278 if (i > 0 && s[i-1] == '\\') {
279 if (!(i > 1 && s[i-2] == '\\'))
280 continue;
281 }
282 if (inmath) i++; // keep the $ at the end
283 parts.push_back(s.substr(lasti, i-lasti));
284 inmath = !inmath;
285 lasti = i;
286 }
287 }
288 parts.push_back(s.substr(lasti, len-lasti));
289 #if 0
290 printf("\n\"%s\"\n", s.c_str());
291 for (unsigned int l = 0; l < parts.size(); l++)
292 printf(" \"%s\"\n", parts[l].c_str());
293 #endif
294 return parts;
295 }
296
297 const char* gr_fontname_from_id(int id);
298
299 #define default_fontID gr_font_Helvetica
300 #define default_encoding font_encoding_isolatin1
301 #define default_fontsize_pt 12.0
302
303 static gr_font CurrentFont = {
304 default_fontID,
305 default_encoding,
306 default_fontsize_pt
307 };
308
309 // Q: should this be done in Moveup() routine? [then what about $N$N though]
310 #define START_NEW_TEXT {\
311 if (_output_file_type == postscript && _grWritePS) { \
312 fprintf(_grPS, "(");\
313 check_psfile();\
314 }\
315 }
316
317 #define STOP_OLD_TEXT {\
318 if (_output_file_type == postscript && _grWritePS) {\
319 fprintf(_grPS, ") sh\n");\
320 check_psfile();\
321 }\
322 }
323
324
325 enum position {Superscript, Subscript, Inline}; // Baseline indicator
326 static std::stack<position> pstack; // baseline position stack
327
328 // Use spacing patterned on results of a TeX example (using Large font). All
329 // quantities are multiples of Mspace.
330 static const double SubSize = 0.75; // relative height of subscripts = 6/8
331 static const double SuperSize = 0.75; // relative height of superscripts = 6/8
332 static const double SuperMoveUp =0.625; // Move up for super = 5/8
333 static const double SubMoveDown =0.375; // Move down for sub = 3/8
334
335
336
337 #define PS_showpage "grestore\nshowpage\n"
338 #define PS_stroke "s\n"
339
340 extern FILE *_grPS;
341 extern FILE *_grSVG;
342 extern bool _grNeedBegin;
343 extern bool _grPathExists;
344 extern bool _grWritePS;
345
346 static void gr_drawstring(const char *s);
347 static void gr_drawchar_svg(char c, double xcm, double ycm, gr_fontID font_id);
348 static void gr_drawsymbol_svg(int index, double xcm, double ycm, gr_fontID font_id);
349 static void gr_drawstring_svg(const char *s, double xcm, double ycm, double angle);
350 //static int index_for_math_symbol(const char *s); // base routine
351 static double gr_charwidth_cm(int c, int font, double fontsize_pt);
352 static void gr_DrawChar(const char *c);
353 static void gr_setfont_fontsize(gr_fontID newID, bool force = false);
354 static void pstack_erase();
355 static void MoveDown(void);
356 static void MoveUp(void);
357 static void MoveUp_svg(double *xcm, double *ycm);
358 static void MoveDn_svg(double *xcm, double *ycm);
359 static void MoveHorizontally(double em_distance);
360 static int symbol_in_math(const char *sPtr, int *inc);
361
362 gr_font_info font_list[] =
363 {
364 {gr_font_Courier, (char *)"Courier"},
365 {gr_font_CourierOblique, (char *)"Courier-Oblique"},
366 {gr_font_CourierBold, (char *)"Courier-Bold"},
367 {gr_font_CourierBoldOblique, (char *)"Courier-BoldOblique"},
368 {gr_font_Helvetica, (char *)"Helvetica"},
369 {gr_font_HelveticaBold, (char *)"Helvetica-Bold"},
370 {gr_font_HelveticaOblique, (char *)"Helvetica-Oblique"},
371 {gr_font_PalatinoRoman, (char *)"Palatino-Roman"},
372 {gr_font_PalatinoItalic, (char *)"Palatino-Italic"},
373 {gr_font_PalatinoBold, (char *)"Palatino-Bold"},
374 {gr_font_PalatinoBoldItalic, (char *)"Palatino-BoldItalic"},
375 {gr_font_Symbol, (char *)"Symbol"},
376 {gr_font_TimesRoman, (char *)"Times-Roman"},
377 {gr_font_TimesItalic, (char *)"Times-Italic"},
378 {gr_font_TimesBold, (char *)"Times-Bold"},
379 {gr_font_TimesBoldItalic, (char *)"Times-BoldItalic"},
380 {gr_font_Century, (char *)"Century"},
381 {gr_font_end_of_list, (char *)""}
382 };
383
384 // Draw text at specified location.
385 void
gr_show_at(char * s,double xcm,double ycm,gr_textStyle style,double angle_deg)386 gr_show_at(/*const*/ char *s, double xcm, double ycm, gr_textStyle style, double angle_deg)
387 {
388 #ifdef DEBUG
389 printf("DEBUG %s:%d gr_show_at(\"%s\",xcm,ycm,style,%f)\n",__FILE__,__LINE__,s,angle_deg);
390 #endif
391 if (0.0 == gr_currentfontsize_pt() || !strlen(s)) {
392 return;
393 }
394 double oldfontsize_pt = gr_currentfontsize_pt();
395 gr_fontID oldfontID = gr_currentfont();
396 double width_cm, ascent_cm, descent_cm;
397 rectangle box;
398 extern bool _warn_offpage;
399 if (_warn_offpage
400 && ( xcm < OFFPAGE_LEFT
401 || xcm > OFFPAGE_RIGHT
402 || ycm < OFFPAGE_BOTTOM
403 || ycm > OFFPAGE_TOP)) {
404 warning("Drawing text at a location that is offpage.");
405 }
406 const char *fn_svg = NULL;
407 double r, g, b;
408 _griState.color_text().getRGB(&r, &g, &b);
409 switch (_output_file_type) {
410 case postscript:
411 break;
412 case svg:
413 switch (CurrentFont.id) {
414 case gr_font_Courier: fn_svg = "Courier"; break;
415 case gr_font_CourierOblique: fn_svg = "Courier-Italic"; break;
416 case gr_font_CourierBold: fn_svg = "Courier-Bold"; break;
417 case gr_font_CourierBoldOblique: fn_svg = "Courier-BoldItalic"; break;
418 case gr_font_Helvetica: fn_svg = "Helvetica"; break;
419 case gr_font_HelveticaOblique: fn_svg = "Helvetica-Italic"; break;
420 case gr_font_HelveticaBold: fn_svg = "Helvetica-Bold"; break;
421 case gr_font_PalatinoRoman:
422 case gr_font_PalatinoItalic:
423 case gr_font_PalatinoBold:
424 case gr_font_PalatinoBoldItalic:
425 fn_svg = "Times";
426 warning("SVG cannot handle Palatino font yet");
427 break;
428 case gr_font_Symbol: fn_svg = "Symbol"; break;
429 case gr_font_TimesRoman: fn_svg = "Times"; break;
430 case gr_font_TimesItalic: fn_svg = "Times-Italic"; break;
431 case gr_font_TimesBold: fn_svg = "Times-Bold"; break;
432 case gr_font_TimesBoldItalic: fn_svg = "Times-BoldItalic"; break;
433 case gr_font_Century: fn_svg = "Century"; break;
434 default:
435 fn_svg = "Times";
436 warning("SVG defaulting to Times font");
437 break;
438 }
439 break;
440 case gif:
441 fprintf(stderr, "INTERNAL error at %s:%d -- nothing known for GIF\n\n", __FILE__, __LINE__);
442 exit(99);
443 break;
444 }
445
446 // if (_output_file_type == svg) {
447 // fprintf(stderr, "%s:%d approximating drawing of '%s' NOTE: subscripts, etc won't work\n", __FILE__, __LINE__, s);
448 // }
449
450 void set_ps_color(char what);
451 set_ps_color('t');
452 gr_setfontsize_pt(oldfontsize_pt);
453 gr_setfont(oldfontID);
454 gr_stringwidth(s, &width_cm, &ascent_cm, &descent_cm);
455 switch (style) {
456 case TEXT_LJUST:
457 gr_moveto_cm(xcm, ycm);
458 if (_output_file_type == postscript) {
459 if (_grWritePS) {
460 if (fabs(angle_deg) > 0.1)
461 fprintf(_grPS, "%.2f rotate ", angle_deg);
462 gr_drawstring(s);
463 }
464 } else if (_output_file_type == svg) {
465 gr_drawstring_svg(s, xcm, ycm, angle_deg);
466 } else {
467 fprintf(stderr, "%s:%d unknown file output type\n",__FILE__,__LINE__);
468 }
469 // This box not tested specifically
470 box.set(0, -descent_cm, width_cm, ascent_cm);
471 box.rotate(angle_deg);
472 box.shift_x(xcm);
473 box.shift_y(ycm);
474 break;
475 case TEXT_RJUST:
476 if (_output_file_type == postscript) {
477 if (_grWritePS) {
478 fprintf(_grPS, "%.1f %.1f m ",
479 PT_PER_CM * (xcm - width_cm * cos(angle_deg / DEG_PER_RAD)),
480 PT_PER_CM * (ycm - width_cm * sin(angle_deg / DEG_PER_RAD)));
481 if (fabs(angle_deg) > 0.1)
482 fprintf(_grPS, "%.2f rotate ", angle_deg);
483 gr_drawstring(s);
484 }
485 } else if (_output_file_type == svg) {
486 if (_grWritePS) {
487 gr_drawstring_svg(s,
488 xcm - width_cm * cos(angle_deg / DEG_PER_RAD),
489 ycm - width_cm * sin(angle_deg / DEG_PER_RAD),
490 angle_deg);
491 }
492 } else {
493 fprintf(stderr, "%s:%d unknown file output type\n",__FILE__,__LINE__);
494 }
495
496 // This box not tested specifically
497 box.set(-width_cm, -descent_cm, 0.0, ascent_cm);
498 box.rotate(angle_deg);
499 box.shift_x(xcm);
500 box.shift_y(ycm);
501 break;
502 case TEXT_CENTERED:
503 if (_output_file_type == postscript) {
504 if (_grWritePS) {
505 #ifdef DEBUG
506 fprintf(_grPS, "%% DEBUG %s:%d '%s' at angle %f\n",__FILE__,__LINE__,s,angle_deg);
507 #endif
508 fprintf(_grPS, "%.1f %.1f m ",
509 PT_PER_CM * (xcm - 0.5 * width_cm * cos(angle_deg / DEG_PER_RAD)),
510 PT_PER_CM * (ycm - 0.5 * width_cm * sin(angle_deg / DEG_PER_RAD)));
511 if (fabs(angle_deg) > 0.1)
512 fprintf(_grPS, "%.2f rotate ", angle_deg);
513 gr_drawstring(s);
514 }
515 } else if (_output_file_type == svg) {
516 if (_grWritePS) {
517 gr_drawstring_svg(s,
518 xcm - 0.5 * width_cm * cos(angle_deg / DEG_PER_RAD),
519 ycm - 0.5 * width_cm * sin(angle_deg / DEG_PER_RAD),
520 angle_deg);
521 }
522 } else {
523 fprintf(stderr, "%s:%d unknown file output type\n",__FILE__,__LINE__);
524 }
525 box.set(-width_cm/2, -descent_cm, width_cm/2, ascent_cm);
526 box.rotate(angle_deg);
527 box.shift_x(xcm);
528 box.shift_y(ycm);
529 break;
530 default:
531 warning("gr_show_at type is UNKNOWN\n");
532 }
533 switch (_output_file_type) {
534 case postscript:
535 if (_grWritePS) {
536 if (fabs(angle_deg) > 0.1)
537 fprintf(_grPS, "%.2f rotate ", -angle_deg);
538 check_psfile();
539 //fprintf(_grPS, "%% gr_show_at() END\n");
540 }
541 break;
542 case svg:
543 //fprintf(_grSVG, "</text>\n");
544 break;
545 case gif:
546 fprintf(stderr, "INTERNAL error at %s:%d -- nothing known for GIF\n\n", __FILE__, __LINE__);
547 exit(99);
548 break;
549 default:
550 fprintf(stderr, "%s:%d unknown file output type\n",__FILE__,__LINE__);
551 break; // BUG: should check filetype here
552 }
553 // Update bounding box
554 bounding_box_update(box);
555 _drawingstarted = true;
556 }
557
558 // gr_drawstring() -- draw string, including font changes &super/subscripts
559 static void
gr_drawstring(const char * s)560 gr_drawstring(const char *s)
561 {
562 char slast = '\0';
563 int slen = strlen(s);
564 bool inmath = false;
565 gr_fontID original_font = gr_currentfont();
566 gr_fontID current_font = original_font;
567 gr_fontID slant_font = original_font; // prevent compiler warning
568 double original_fontsize = gr_currentfontsize_pt();
569 bool know_slant_font = false;
570 #ifdef DEBUG
571 printf("DEBUG %s:%d gr_drawstring(\"%s\")\n",__FILE__,__LINE__,s);
572 #endif
573 if (slen <= 0)
574 return;
575 if (0.0 == gr_currentfontsize_pt())
576 return;
577 // Figure out slant font, if there is an appropriate one
578 switch (original_font) {
579 case gr_font_TimesRoman:
580 slant_font = gr_font_TimesItalic;
581 know_slant_font = true;
582 break;
583 case gr_font_TimesBold:
584 slant_font = gr_font_TimesBoldItalic;
585 know_slant_font = true;
586 break;
587 case gr_font_Helvetica:
588 slant_font = gr_font_HelveticaOblique;
589 know_slant_font = true;
590 break;
591 case gr_font_HelveticaBold:
592 slant_font = gr_font_HelveticaBoldOblique;
593 know_slant_font = true;
594 break;
595 case gr_font_Courier:
596 slant_font = gr_font_CourierOblique;
597 know_slant_font = true;
598 break;
599 case gr_font_CourierBold:
600 slant_font = gr_font_CourierBoldOblique;
601 know_slant_font = true;
602 break;
603 case gr_font_PalatinoRoman:
604 slant_font = gr_font_PalatinoItalic;
605 know_slant_font = true;
606 break;
607 case gr_font_PalatinoBold:
608 slant_font = gr_font_PalatinoBoldItalic;
609 know_slant_font = true;
610 break;
611 case gr_font_Century:
612 slant_font = gr_font_TimesItalic; // BUG: should be Century Italic
613 know_slant_font = true;
614 break;
615 default:
616 know_slant_font = false;
617 }
618 // Scan through whole string.
619 START_NEW_TEXT;
620 while (*s != '\0') {
621 #ifdef DEBUG
622 // printf("DEBUG(%s:%d) *s= '%c'\n",__FILE__,__LINE__,*s);
623 #endif
624 if (*s == '-' && CurrentFont.encoding == font_encoding_isolatin1) {
625 // Use a different character to avoid looking like underscore.
626 if (_grWritePS) {
627 STOP_OLD_TEXT;
628 fprintf(_grPS, "(\\255) sh\n"); // endash
629 check_psfile();
630 START_NEW_TEXT;
631 }
632 s++;
633 continue;
634 }
635 // Figure out whether entering or leaving math mode; enter/leave if
636 // find $ without preceeding \. Thus a$b$ has math but a\$b\$ does
637 // not.
638 if (*s == '$' && slast != '\\') {
639 if (inmath) {
640 #ifdef DEBUG
641 printf("DEBUG(%s:%d) got $ so leave math mode\n",__FILE__,__LINE__);
642 printf("DEBUG(%s:%d) pstack size is %d\n",__FILE__,__LINE__,int(pstack.size()));
643 #endif
644
645 // Were in math; now go back to original font.
646 inmath = false;
647 if (current_font != original_font) {
648 current_font = original_font;
649 STOP_OLD_TEXT;
650 gr_setfont(current_font);
651 START_NEW_TEXT;
652 }
653 if (!pstack.empty()) {
654 warning("a text string ended without completing a mathematical grouping (superscript, subscript, or {block})");
655 pstack_erase();
656 }
657 } else {
658 #ifdef DEBUG
659 printf("DEBUG(%s:%d) got $ so enter math mode\n",__FILE__,__LINE__);
660 #endif
661 // Go to Italic/Oblique font, as case may be. Unfortunately,
662 // PostScript uses different names for this slanted font.
663 inmath = true;
664 if (know_slant_font) {
665 current_font = slant_font;
666 STOP_OLD_TEXT;
667 gr_setfont(current_font);
668 START_NEW_TEXT;
669 }
670 if (!pstack.empty()) {
671 warning("a text string started without an empty mathematical grouping (superscript, subscript, or {block})");
672 pstack_erase();
673 }
674 }
675 slast = *s++;
676 continue;
677 }
678 // Handle math mode. This code is a little kludgy, so be carefull.
679 if (inmath) {
680 if (*s == '^') {
681 // Handle superscripts
682 slast = *s++;
683 if (*s == '\0') {
684 // Odd -- nothing to superscript
685 if (current_font != original_font) {
686 STOP_OLD_TEXT;
687 gr_setfontsize_pt(original_fontsize);
688 gr_setfont(original_font);
689 }
690 return;
691 } else if (*s == '{') {
692 // Several characters to superscript
693 pstack.push(Superscript);
694 #ifdef DEBUG
695 printf("DEBUG(%s:%d) pushed superscript=%d onto stack to make length %d\n",__FILE__,__LINE__,Superscript, int(pstack.size()));
696 #endif
697 MoveUp();
698 } else if (*s == '\\') {
699 // Math character to superscript
700 int inc;
701 int symbol_index = symbol_in_math(s, &inc);
702 if (inc) {
703 gr_fontID oldfontID = gr_currentfont();
704 pstack.push(Superscript);
705 #ifdef DEBUG
706 printf("DEBUG(%s:%d) pushed subscript=%d onto stack to make length %d\n",__FILE__,__LINE__,Superscript, int(pstack.size()));
707 #endif
708 MoveUp();
709 STOP_OLD_TEXT;
710 gr_setfont(gr_font_Symbol);
711 if (_grWritePS) {
712 fprintf(_grPS, "(%s) sh\n", symbol_code[symbol_index][1]);
713 check_psfile();
714 }
715 gr_setfont(oldfontID);
716 START_NEW_TEXT;
717 s += inc;
718 #ifdef DEBUG
719 printf("DEBUG(%s:%d) about to pop stack (was %d) to make length %d\n",__FILE__,__LINE__,pstack.top(), int(pstack.size())-1);
720 #endif
721 MoveDown();
722 pstack.pop();
723 }
724 } else {
725 // Single character to superscript
726 pstack.push(Superscript);
727 #ifdef DEBUG
728 printf("DEBUG(%s:%d) pushed subscript=%d onto stack to make length %d\n",__FILE__,__LINE__,Subscript, int(pstack.size()));
729 #endif
730 MoveUp();
731 // Draw single character in math mode. If it's a digit,
732 // do not do in italics!
733 if (isdigit(*s) || ispunct(*s)) {
734 if (*s == '/' && !isdigit(slast)) {
735 gr_DrawChar(s);
736 } else {
737 STOP_OLD_TEXT;
738 gr_setfont(original_font);
739 START_NEW_TEXT;
740 gr_DrawChar(s);
741 STOP_OLD_TEXT;
742 gr_setfont(slant_font);
743 START_NEW_TEXT;
744 }
745 } else {
746 gr_DrawChar(s);
747 }
748 MoveDown();
749 #ifdef DEBUG
750 printf("DEBUG(%s:%d) about to pop stack (was %d) to make length %d\n",__FILE__,__LINE__,pstack.top(), int(pstack.size())-1);
751 #endif
752 pstack.pop();
753 }
754 } else if (*s == '_') {
755 // Handle subscript
756 slast = *s++;
757 if (*s == '\0') {
758 // Odd -- nothing to subscript
759 if (current_font != original_font) {
760 STOP_OLD_TEXT;
761 gr_setfontsize_pt(original_fontsize);
762 gr_setfont(original_font);
763 }
764 return;
765 } else if (*s == '{') {
766 // Several characters to subscript
767 pstack.push(Subscript);
768 #ifdef DEBUG
769 printf("DEBUG(%s:%d) pushed subscript=%d onto stack to make length %d\n",__FILE__,__LINE__,Subscript, int(pstack.size()));
770 #endif
771 MoveDown();
772 } else if (*s == '\\') {
773 // Math character to subscript
774 int inc;
775 int symbol_index = symbol_in_math(s, &inc);
776 if (symbol_index > -1) {
777 gr_fontID oldfontID = gr_currentfont();
778 pstack.push(Subscript);
779 #ifdef DEBUG
780 printf("DEBUG(%s:%d) pushed subscript=%d onto stack to make length %d\n",__FILE__,__LINE__,Subscript, int(pstack.size()));
781 #endif
782 MoveDown();
783 STOP_OLD_TEXT;
784 gr_setfont(gr_font_Symbol);
785 if (_grWritePS) {
786 fprintf(_grPS, "(%s) sh\n", symbol_code[symbol_index][1]);
787 check_psfile();
788 }
789 gr_setfont(oldfontID);
790 START_NEW_TEXT;
791 s += inc;
792 MoveUp();
793 #ifdef DEBUG
794 printf("DEBUG(%s:%d) about to pop stack (was %d) to make length %d\n",__FILE__,__LINE__,pstack.top(), int(pstack.size())-1);
795 #endif
796 pstack.pop();
797 }
798 } else {
799 // Single character to subscript
800 pstack.push(Subscript);
801 #ifdef DEBUG
802 printf("DEBUG(%s:%d) pushed subscript=%d onto stack to make length %d\n",__FILE__,__LINE__,Subscript, int(pstack.size()));
803 #endif
804 MoveDown();
805 // Draw single character in math mode. If it's a digit,
806 // do not do in italics!
807 if (isdigit(*s) || ispunct(*s)) {
808 if (*s == '/' && !isdigit(slast)) {
809 gr_DrawChar(s);
810 } else {
811 STOP_OLD_TEXT;
812 gr_setfont(original_font);
813 START_NEW_TEXT;
814 gr_DrawChar(s);
815 STOP_OLD_TEXT;
816 gr_setfont(slant_font);
817 START_NEW_TEXT;
818 }
819 } else {
820 gr_DrawChar(s);
821 }
822 MoveUp();
823 #ifdef DEBUG
824 printf("DEBUG(%s:%d) about to pop stack (was %d) to make length %d\n",__FILE__,__LINE__,pstack.top(), int(pstack.size())-1);
825 #endif
826 pstack.pop();
827 }
828 } else if (*s == '{') { // just a grouping, not a baseline shift
829 pstack.push(Inline);
830 #ifdef DEBUG
831 printf("DEBUG(%s:%d) pushed Inline=%d onto stack to make length %d\n",__FILE__,__LINE__,Inline,int(pstack.size()));
832 #endif
833
834 } else if (*s == '}') { // finished with Superscript/Subscript/Inline
835 if (pstack.size() > 0) {
836 position p = pstack.top();
837 if (p == Superscript) {
838 MoveDown();
839 } else if (p == Subscript) {
840 MoveUp();
841 } // ignore inline
842 #ifdef DEBUG
843 printf("DEBUG(%s:%d) about to pop stack (was %d) to make length %d\n",__FILE__,__LINE__,pstack.top(), int(pstack.size())-1);
844 #endif
845 pstack.pop();
846 } else {
847 warning("unmatched \"}\" in a mathematicsal string");
848 }
849 } else if (*s == '\\') {
850 // Substitute math symbol, unless it's
851 // an escaped string
852 if (*(s + 1) == '$') {
853 slast = *s++;
854 } else if (*(s + 1) == ',') {
855 slast = *s++;
856 MoveHorizontally(0.1666666); // thinspace
857 } else if (*(s + 1) == '!') {
858 slast = *s++;
859 MoveHorizontally(-0.1666666); // neg thinspace
860 } else if (*(s + 1) == '"') {
861 slast = *s++;
862 } else if (*(s + 1) == '\\') {
863 slast = *s++;
864 } else if (*(s + 1) == '{' || *(s + 1) == '}') {
865 STOP_OLD_TEXT;
866 gr_setfont(original_font);
867 START_NEW_TEXT;
868 gr_DrawChar(s + 1);
869 STOP_OLD_TEXT;
870 gr_setfont(slant_font);
871 START_NEW_TEXT;
872 slast = *s++;
873 } else {
874 int inc;
875 int symbol_index = symbol_in_math(s, &inc);
876 if (inc) {
877 // math symbol in symbol font
878 gr_fontID oldfontID = gr_currentfont();
879 STOP_OLD_TEXT;
880 gr_setfont(gr_font_Symbol);
881 if (_grWritePS) {
882 fprintf(_grPS, "(%s) sh\n", symbol_code[symbol_index][1]);
883 check_psfile();
884 }
885 gr_setfont(oldfontID);
886 START_NEW_TEXT;
887 s += inc;
888 } else {
889 // Not a known math-mode symbol, so just
890 // draw it. Is this the right thing to do?
891 gr_DrawChar(s + 1);
892 }
893 }
894 } else {
895 // Draw single character in math mode.
896 // If it's a digit, do not use italics.
897 if (isdigit(*s) || ispunct(*s)) {
898 if (*s == '/' && !isdigit(slast)) {
899 gr_DrawChar(s);
900 } else {
901 STOP_OLD_TEXT;
902 gr_setfont(original_font);
903 START_NEW_TEXT;
904 gr_DrawChar(s);
905 STOP_OLD_TEXT;
906 gr_setfont(slant_font);
907 START_NEW_TEXT;
908 }
909 } else {
910 gr_DrawChar(s);
911 }
912 }
913 } else {
914 // draw simple character outside math mode
915 if (*s == '\\') {
916 if (*(s + 1) == '$') {
917 slast = *s++;
918 } else if (*(s + 1) == '"') {
919 slast = *s++;
920 } else if (*(s + 1) == '\\') {
921 slast = *s++;
922 }
923 }
924 gr_DrawChar(s);
925 }
926 slast = *s++;
927 }
928 STOP_OLD_TEXT;
929 gr_setfontsize_pt(original_fontsize);
930 gr_setfont(original_font);
931 _drawingstarted = true;
932 if (!pstack.empty()) {
933 warning("a text string ended without completing a mathematical grouping (superscript, subscript, or {block})");
934 pstack_erase();
935 }
936 return;
937 }
938
gr_fontname_from_id(int id)939 const char* gr_fontname_from_id(int id)
940 {
941 switch (id) {
942 case gr_font_Courier: return("Courier");
943 case gr_font_CourierOblique: return("Courier-Italic");
944 case gr_font_CourierBold: return("Courier-Bold");
945 case gr_font_CourierBoldOblique: return("Courier-BoldItalic");
946 case gr_font_Helvetica: return("Helvetica");
947 case gr_font_HelveticaOblique: return("Helvetica-Italic");
948 case gr_font_HelveticaBold: return("Helvetica-Bold");
949 case gr_font_PalatinoRoman:
950 case gr_font_PalatinoItalic:
951 case gr_font_PalatinoBold:
952 case gr_font_PalatinoBoldItalic:
953 warning("SVG cannot handle Palatino font yet");
954 return("Times");
955 case gr_font_Symbol: return("Symbol");
956 case gr_font_TimesRoman: return("Times");
957 case gr_font_TimesItalic: return("Times-Italic");
958 case gr_font_TimesBold: return("Times-Bold");
959 case gr_font_TimesBoldItalic: return("Times-BoldItalic");
960 case gr_font_Century: return("Century");
961 }
962 warning("SVG defaulting to Times font");
963 return("Times");
964 }
965
gr_drawchar_svg(char c,double xcm,double ycm,gr_fontID font_id)966 static void gr_drawchar_svg(char c, double xcm, double ycm, gr_fontID font_id)
967 {
968 double size = gr_currentfontsize_pt();
969 const char *font_style;
970 //printf("%s:%d | gr_drawchar_svg('%c', ...) decodes to '%c' font_id=.s\n", __FILE__, __LINE__, c, symbol_code[int(c)][1]);//, gr_fontID);
971 if (pstack.size() > 0)
972 size *= SuperSize;
973 if (isdigit(c) || font_id == gr_font_Symbol)
974 font_style = "normal";
975 else
976 font_style = "italic";
977 const char *fill = _griState.color_text().get_hexcolor().c_str();
978 double transparency = _griState.color_text().getT();
979 fprintf(_grSVG, "<g><text x=\"%.1f\" y=\"%.1f\" font-family=\"%s\" font-size=\"%.1f\" font-style=\"%s\" fill=\"%s\" opacity=\"%.2f\" style=\"fill:%s\">%c</text></g>\n",
980 xcm * PT_PER_CM,
981 /*gr_page_height_pt() -*/ -ycm * PT_PER_CM,
982 gr_fontname_from_id(font_id), size, font_style,
983 fill,
984 1.0 - transparency,
985 fill,
986 c);
987 gr_setfont(font_id);
988 char st[2];
989 st[0] = c;
990 st[1] = '\0';
991 double w, a, d;
992 double oldfontsize = gr_currentfontsize_pt();
993 gr_setfontsize_pt(size);
994 gr_stringwidth(st, &w, &a, &d); // BUG: NEED TO SET FONT FIRST
995 gr_setfontsize_pt(oldfontsize);
996 //*xcm += w;
997 }
gr_drawsymbol_svg(int index,double xcm,double ycm,gr_fontID font_id)998 static void gr_drawsymbol_svg(int index, double xcm, double ycm, gr_fontID font_id)
999 {
1000 double size = gr_currentfontsize_pt();
1001 const char *font_style;
1002 //printf("%s:%d | gr_drawchar_svg('%c', ...) decodes to '%c' font_id=.s\n", __FILE__, __LINE__, c, symbol_code[int(c)][1]);//, gr_fontID);
1003 if (pstack.size() > 0)
1004 size *= SuperSize;
1005 if (font_id == gr_font_Symbol)
1006 font_style = "normal";
1007 else
1008 font_style = "italic";
1009 const char *fill = _griState.color_text().get_hexcolor().c_str();
1010 double transparency = _griState.color_text().getT();
1011 if (font_id == gr_font_Symbol) {
1012 fprintf(_grSVG, "<g><text x=\"%.1f\" y=\"%.1f\" font-family=\"%s\" font-size=\"%.1f\" font-style=\"%s\" fill=\"%s\" opacity=\"%.2f\" style=\"fill:%s\">%s</text></g>\n",
1013 xcm * PT_PER_CM,
1014 /*gr_page_height_pt() -*/ -ycm * PT_PER_CM,
1015 gr_fontname_from_id(font_id), size, font_style,
1016 fill,
1017 1.0 - transparency,
1018 fill,
1019 symbol_code[index][3]);
1020 } else {
1021 fprintf(_grSVG, "<g><text x=\"%.1f\" y=\"%.1f\" font-family=\"%s\" font-size=\"%.1f\" font-style=\"%s\" fill=\"%s\" opacity=\"%.2f\" style=\"fill:%s\">%s</text></g>\n",
1022 xcm * PT_PER_CM,
1023 /*gr_page_height_pt() -*/ -ycm * PT_PER_CM,
1024 gr_fontname_from_id(font_id), size, font_style,
1025 fill,
1026 1.0 - transparency,
1027 fill,
1028 "?");
1029 }
1030 gr_setfont(font_id);
1031 char st[2];
1032 st[0] = 'm'; // guess at width
1033 st[1] = '\0';
1034 double w, a, d;
1035 double oldfontsize = gr_currentfontsize_pt();
1036 gr_setfontsize_pt(size);
1037 gr_stringwidth(st, &w, &a, &d); // BUG: NEED TO SET FONT FIRST
1038 gr_setfontsize_pt(oldfontsize);
1039 //*xcm += w; // BUG
1040 }
1041 static void
gr_drawstring_svg(const char * s,double xcm,double ycm,double angle)1042 gr_drawstring_svg(const char *s, double xcm, double ycm, double angle)
1043 {
1044 #ifdef DEBUG
1045 printf("DEBUG %s:%d gr_drawstring_svg(s=\"%s\", xcm=%f, ycm=%f, angle=%f)\n", __FILE__,__LINE__, s, xcm, ycm, angle);
1046 #endif
1047 int slen = strlen(s);
1048 gr_fontID original_font = gr_currentfont();
1049 gr_fontID slant_font = original_font; // prevent compiler warning
1050 double original_fontsize = gr_currentfontsize_pt();
1051 bool know_slant_font = false;
1052 if (slen <= 0)
1053 return;
1054 if (0.0 == gr_currentfontsize_pt())
1055 return;
1056 // Figure out slant font, if there is an appropriate one
1057 switch (original_font) {
1058 case gr_font_TimesRoman:
1059 slant_font = gr_font_TimesItalic;
1060 know_slant_font = true;
1061 break;
1062 case gr_font_TimesBold:
1063 slant_font = gr_font_TimesBoldItalic;
1064 know_slant_font = true;
1065 break;
1066 case gr_font_Helvetica:
1067 slant_font = gr_font_HelveticaOblique;
1068 know_slant_font = true;
1069 break;
1070 case gr_font_HelveticaBold:
1071 slant_font = gr_font_HelveticaBoldOblique;
1072 know_slant_font = true;
1073 break;
1074 case gr_font_Courier:
1075 slant_font = gr_font_CourierOblique;
1076 know_slant_font = true;
1077 break;
1078 case gr_font_CourierBold:
1079 slant_font = gr_font_CourierBoldOblique;
1080 know_slant_font = true;
1081 break;
1082 case gr_font_PalatinoRoman:
1083 slant_font = gr_font_PalatinoItalic;
1084 know_slant_font = true;
1085 break;
1086 case gr_font_PalatinoBold:
1087 slant_font = gr_font_PalatinoBoldItalic;
1088 know_slant_font = true;
1089 break;
1090 case gr_font_Century:
1091 slant_font = gr_font_TimesItalic; // BUG: should be Century Italic
1092 know_slant_font = true;
1093 break;
1094 default:
1095 know_slant_font = false;
1096 }
1097 std::vector<std::string> parts;
1098 parts = part_string(s);
1099 int nparts = parts.size();
1100 double xxcm = xcm, yycm = ycm;
1101 fprintf(_grSVG, "<g transform=\"translate(%.2f,%.2f)\">\n", xxcm*PT_PER_CM,
1102 gr_page_height_pt() - yycm*PT_PER_CM);
1103 xxcm = yycm = 0.0;
1104 fprintf(_grSVG, "<g transform=\"rotate(%.1f)\">\n", -angle);
1105 angle = 0.0; // BUG: not sure if this is the best method
1106 //printf("DEBUG (%s)\n", _griState.color_text().get_hexcolor().c_str());
1107 for (int i = 0; i < nparts; i++) {
1108 double w, a, d;
1109 std::string p = parts[i];
1110 gr_stringwidth(p.c_str(), &w, &a, &d);
1111 //printf(" \"%s\" w=%f a=%f d=%f\n", parts[i].c_str(),w,a,d);
1112 if (p[0] != '$') {
1113 // Normal text
1114 fprintf(_grSVG, "<g><text x=\"%.1f\" y=\"%.1f\" font-family=\"%s\" font-size=\"%.1f\" font-style=\"normal\" fill=\"%s\" opacity=\"%.2f\" style=\"fill:%s\">%s</text></g>\n",
1115 xxcm * PT_PER_CM,
1116 /*gr_page_height_pt() -*/ -yycm * PT_PER_CM,
1117 gr_fontname_from_id(original_font),
1118 original_fontsize,
1119 _griState.color_text().get_hexcolor().c_str(),
1120 1.0 - _griState.color_text().getT(),
1121 _griState.color_text().get_hexcolor().c_str(),
1122 p.c_str());
1123 xxcm += w;
1124 //FIXME: should s/\$/$/ first
1125 } else {
1126 // Math text
1127 unsigned int ic, nc = p.size();
1128 // w = gr_thinspace_cm() / 1.0; // put a bit of space before math
1129 // xxcm += w;
1130 if (p[nc-1] == '$') nc--;
1131 fprintf(_grSVG, "<!-- math mode -->\n<g>\n");
1132 for (ic = 1; ic < nc; ic++) {
1133 #ifdef DEBUG
1134 printf(" -- %d [%c] --\n", ic, p[ic]);
1135 #endif
1136 if (p[ic] == '\\') { // HEREHEREHERE
1137 if (p[ic+1] == '\\') {
1138 gr_drawsymbol_svg(-1, xxcm, yycm, original_font);
1139 ic += 1;
1140 continue;
1141 }
1142 int inc;
1143 int symbol_index = symbol_in_math(p.c_str() + ic, &inc);
1144 if (inc) {
1145 gr_drawsymbol_svg(symbol_index, xxcm, yycm, gr_font_Symbol);
1146 ic += inc;
1147 } else {
1148 gr_drawstring_svg("?", xxcm, yycm, gr_font_Symbol);
1149 }
1150 } else if (p[ic] == '{') {
1151 // ignore
1152 pstack.push(Inline);
1153 ic++;
1154 continue;
1155 } else if (p[ic] == '}') {
1156 if (pstack.size() > 0) {
1157 position p = pstack.top();
1158 if (p == Superscript) {
1159 MoveDn_svg(&xxcm, &yycm);
1160 } else if (p == Subscript) {
1161 MoveUp_svg(&xxcm, &yycm);
1162 }
1163 #ifdef DEBUG
1164 printf("DEBUG(%s:%d) about to pop stack (was %d) to make length %d\n",__FILE__,__LINE__,pstack.top(), int(pstack.size())-1);
1165 #endif
1166 pstack.pop();
1167 } else {
1168 warning("unmatched \"}\" in a mathematical string");
1169 }
1170 } else if (p[ic] == '_') {
1171 pstack.push(Subscript);
1172 MoveDn_svg(&xxcm, &yycm);
1173 if (p[ic+1] != '{') { // BUG: should check for symbol
1174 gr_drawchar_svg(p[ic+1], xxcm, yycm, original_font);
1175 MoveUp_svg(&xxcm, &yycm);
1176 pstack.pop();
1177 }
1178 ic++;
1179 continue;
1180 } else if (p[ic] == '^') {
1181 pstack.push(Superscript);
1182 MoveUp_svg(&xxcm, &yycm);
1183 if (p[ic+1] != '{') { // BUG: should check for symbol
1184 gr_drawchar_svg(p[ic+1], xxcm, yycm, original_font);
1185 MoveDn_svg(&xxcm, &yycm);
1186 pstack.pop();
1187 }
1188 ic++;
1189 continue;
1190 } else {
1191 gr_drawchar_svg(p[ic], xxcm, yycm, original_font);
1192 }
1193 }
1194 fprintf(_grSVG, "</g>\n");
1195 }
1196 }
1197 fprintf(_grSVG, "</g>\n"); // rotate
1198 fprintf(_grSVG, "</g>\n"); // translate
1199 return;
1200 }
1201
1202
1203 // set fontsize in points
1204 void
gr_setfontsize_pt(double fontsize_pt)1205 gr_setfontsize_pt(double fontsize_pt)
1206 {
1207 if (fontsize_pt < 0.0)
1208 CurrentFont.size_pt = default_fontsize_pt;
1209 else
1210 CurrentFont.size_pt = fontsize_pt;
1211 gr_setfont_fontsize(CurrentFont.id);
1212 }
1213
1214 // Set font encoding
1215 void
gr_set_font_encoding(gr_font_encoding encoding)1216 gr_set_font_encoding(gr_font_encoding encoding)
1217 {
1218 CurrentFont.encoding = encoding;
1219 }
1220 // Get font encoding
1221 gr_font_encoding
gr_current_font_encoding()1222 gr_current_font_encoding()
1223 {
1224 return CurrentFont.encoding;
1225 }
1226
1227 /*
1228 * gr_currentfont() -- find current font synopsis int gr_currentfont()
1229 * description: gets the current font,as set by gr_setfont(). return value:
1230 * current font number.
1231 */
1232 gr_fontID
gr_currentfont()1233 gr_currentfont()
1234 {
1235 return CurrentFont.id;
1236 }
1237
1238 /*
1239 * gr_currentfontsize_pt() -- return current fontsize in points
1240 */
1241 double
gr_currentfontsize_pt()1242 gr_currentfontsize_pt()
1243 {
1244 return CurrentFont.size_pt;
1245 }
1246
1247 /*
1248 * gr_setfont() -- set new font. SYNOPSIS void gr_setfont(int new_font)
1249 * DESCRIPTION: Sets the font for future string drawing to 'new_font'. These
1250 * fonts are predefined: TimesRoman Helvetica Courier Symbol Palatino-Roman
1251 * Palatino-Italic.
1252 *
1253 */
1254 void
gr_setfont(gr_fontID newID,bool force)1255 gr_setfont(gr_fontID newID, bool force /* default false */)
1256 {
1257 gr_setfont_fontsize(newID, force);
1258 }
1259
1260 static void
gr_setfont_fontsize(gr_fontID newID,bool force)1261 gr_setfont_fontsize(gr_fontID newID, bool force)
1262 {
1263 int i = 0;
1264 static bool have_set_font = false;
1265 static gr_font last_font;
1266 /* Search the font list */
1267 while (font_list[i].id != gr_font_end_of_list) {
1268 if (newID == font_list[i].id) {
1269 /* Found the font, but ignore request if no change */
1270 if (force
1271 || (!have_set_font
1272 || newID != last_font.id
1273 || CurrentFont.encoding != last_font.encoding
1274 || CurrentFont.size_pt != last_font.size_pt)) {
1275 CurrentFont.id = newID;
1276 if (!_grNeedBegin) {
1277 /*
1278 * Don't try to write if haven't done gr_begin() yet,
1279 * since then will ruin things like
1280 * gr_setup_ps_filename();
1281 */
1282 if (_grWritePS) {
1283 switch (CurrentFont.encoding) {
1284 case font_encoding_standard:
1285 fprintf(_grPS, "/%s findfont ", font_list[i].name);
1286 break;
1287 case font_encoding_isolatin1:
1288 if (CurrentFont.id == gr_font_Symbol)
1289 fprintf(_grPS, "/%s findfont ", font_list[i].name);
1290 else
1291 fprintf(_grPS, "/%s-ISOLatin1 findfont ", font_list[i].name);
1292 break;
1293 }
1294 fprintf(_grPS, "%.2f sc sf\n", CurrentFont.size_pt);
1295 }
1296 have_set_font = true;
1297 last_font.id = newID;
1298 last_font.encoding = CurrentFont.encoding;
1299 last_font.size_pt = CurrentFont.size_pt;
1300 }
1301 }
1302 return;
1303 }
1304 i++;
1305 }
1306 warning("Ignoring request for unknown font.");
1307 }
1308
symbol_in_math(const char * sPtr,int * inc)1309 static int symbol_in_math(const char *sPtr, int *inc) // handle greek letter or symbol in math mode
1310 {
1311 sPtr++;
1312 *inc = 0;
1313 for (int i = 0; i < NCODES; i++) {
1314 int len = strlen(symbol_code[i][0]);
1315 if (!strncmp(sPtr, symbol_code[i][0], len)) {
1316 *inc = len;
1317 return i;
1318 }
1319 }
1320 return -1;
1321 }
1322
1323 // Clear the position stack (doesn't STL do this??)
1324 static void
pstack_erase()1325 pstack_erase()
1326 {
1327 while (!pstack.empty()) {
1328 position p = pstack.top();
1329 if (p == Superscript) {
1330 MoveDown();
1331 } else if (p == Subscript) {
1332 MoveUp();
1333 } // ignore inline
1334 #ifdef DEBUG
1335 if (p == Superscript)
1336 printf("\tcleared Superscript from position stack\n");
1337 else if (p == Subscript)
1338 printf("\tcleared Subscript from position stack\n");
1339 #endif
1340 pstack.pop();
1341 }
1342 }
1343 // Move left/right by indicated number of M spaces
1344 static void
MoveHorizontally(double em_distance)1345 MoveHorizontally(double em_distance)
1346 {
1347 double w, a, d;
1348 gr_stringwidth("M", &w, &a, &d);
1349 STOP_OLD_TEXT;
1350 gr_rmoveto_cm(em_distance * w, 0.0);
1351 START_NEW_TEXT;
1352 }
1353
1354 // MoveUp() -- move up, shifting to smaller/larger size if necessary
MoveUp_svg(double * xcm,double * ycm)1355 static void MoveUp_svg(double *xcm, double *ycm)
1356 {
1357 #ifdef DEBUG
1358 printf("DEBUG(%s:%d) moving text position up one level. Stack size on entry = %d\n", __FILE__,__LINE__,(int)pstack.size());
1359 #endif
1360 if (!pstack.size())
1361 return;
1362 double dy;
1363 // See if already in subscript.
1364 position p = pstack.top();
1365 if (p == Subscript) {
1366 // Moving up from subscript, so enlarge font, then undo last move
1367 // down.
1368 gr_setfontsize_pt(gr_currentfontsize_pt() / SubSize);
1369 dy = SubMoveDown * gr_currentCapHeight_cm();
1370 } else {
1371 // Moving up from inline or superscript, so move up, then reduce font.
1372 dy = SuperMoveUp * gr_currentCapHeight_cm();
1373 gr_setfontsize_pt(gr_currentfontsize_pt() * SuperSize);
1374 } // ignore Inline
1375 *ycm += dy;
1376 }
1377 // MoveDown() -- move down, shifting to smaller/larger size if necessary
MoveDn_svg(double * xcm,double * ycm)1378 static void MoveDn_svg(double *xcm, double *ycm)
1379 {
1380 #ifdef DEBUG
1381 printf("DEBUG(%s:%d) moving text position down one level\n", __FILE__,__LINE__);
1382 #endif
1383 if (!pstack.size())
1384 return;
1385 double dy;
1386 position p = pstack.top();
1387 // See if already in superscript.
1388 if (p == Superscript) {
1389 // Moving down from superscript, so enlarge font, then undo last move up.
1390 gr_setfontsize_pt(gr_currentfontsize_pt() / SuperSize);
1391 dy = -SuperMoveUp * gr_currentCapHeight_cm();
1392 } else {
1393 // Moving down from inline or subscript, so move down, then reduce font.
1394 dy = -SubMoveDown * gr_currentCapHeight_cm();
1395 gr_setfontsize_pt(gr_currentfontsize_pt() * SubSize);
1396 }
1397 *ycm += dy;
1398 }
1399
1400 static void
MoveUp()1401 MoveUp()
1402 {
1403 #ifdef DEBUG
1404 printf("DEBUG(%s:%d) moving text position up one level\n", __FILE__,__LINE__);
1405 #endif
1406 STOP_OLD_TEXT;
1407 // See if already in subscript.
1408 position p = pstack.top();
1409 if (p == Subscript) {
1410 // Moving up from subscript, so enlarge font, then undo last move
1411 // down.
1412 gr_setfontsize_pt(gr_currentfontsize_pt() / SubSize);
1413 gr_rmoveto_pt(0.0, SubMoveDown * gr_currentCapHeight_cm() * PT_PER_CM);
1414 } else {
1415 // Moving up from inline or superscript, so move up, then reduce font.
1416 gr_rmoveto_pt(0.0, SuperMoveUp * gr_currentCapHeight_cm() * PT_PER_CM);
1417 gr_setfontsize_pt(gr_currentfontsize_pt() * SuperSize);
1418 } // ignore Inline
1419 START_NEW_TEXT;
1420 }
1421
1422 // MoveDown() -- move down, shifting to smaller/larger size if necessary
1423 static void
MoveDown()1424 MoveDown()
1425 {
1426 #ifdef DEBUG
1427 printf("DEBUG(%s:%d) moving text position down one level\n", __FILE__,__LINE__);
1428 #endif
1429 STOP_OLD_TEXT;
1430 position p = pstack.top();
1431 // See if already in superscript.
1432 if (p == Superscript) {
1433 // Moving down from superscript, so enlarge font, then undo last move up.
1434 gr_setfontsize_pt(gr_currentfontsize_pt() / SuperSize);
1435 gr_rmoveto_pt(0.0, -SuperMoveUp * gr_currentCapHeight_cm() * PT_PER_CM);
1436 } else {
1437 // Moving down from inline or subscript, so move down, then reduce font.
1438 gr_rmoveto_pt(0.0, -SubMoveDown * gr_currentCapHeight_cm() * PT_PER_CM);
1439 gr_setfontsize_pt(gr_currentfontsize_pt() * SubSize);
1440 }
1441 START_NEW_TEXT;
1442 }
1443
1444 static void
gr_DrawChar(const char * c)1445 gr_DrawChar(const char *c)
1446 {
1447 extern bool _grWritePS;
1448 if (_grWritePS) {
1449 extern FILE *_grPS;
1450 switch (*c) {
1451 case '\\':
1452 fprintf(_grPS, "\\\\");
1453 break;
1454 case '(':
1455 fprintf(_grPS, "\\(");
1456 break;
1457 case ')':
1458 fprintf(_grPS, "\\)");
1459 break;
1460 default:
1461 fprintf(_grPS, "%c", *c);
1462 break;
1463 }
1464 check_psfile();
1465 }
1466 _drawingstarted = true;
1467 }
1468
1469 // Draw indicated text in a "whiteout" box of indicated color, left-right
1470 // centered at the indicated (x,y) locn specified in user-units. The text
1471 // and box will be rotated by gr_currenttextangle_deg() degrees, measured
1472 // counterclockwise from the horizontal.
1473 void
gr_show_in_box(GriString & s,const GriColor & text_color,const GriColor & box_color,double x,double y,double angle_deg)1474 gr_show_in_box(/*const*/GriString &s,
1475 const GriColor& text_color,
1476 const GriColor& box_color,
1477 double x, // cm units
1478 double y,
1479 double angle_deg)
1480 {
1481 GriColor old_text_color = _griState.color_text();
1482 GriColor old_line_color = _griState.color_line();
1483
1484 double width, ascent, descent;
1485 double x0, y0, dx, dy, dx_rot, dy_rot;
1486 double thin_space = gr_thinspace_cm();
1487 if (0.0 == gr_currentfontsize_pt())
1488 return;
1489 gr_stringwidth(s.getValue(), &width, &ascent, &descent);
1490 x0 = x; // save
1491 y0 = y;
1492
1493 // White out below text.
1494 dx = -0.5 * width - thin_space;
1495 dy = -thin_space;
1496 gr_rotate_xy(dx, dy, angle_deg, &dx_rot, &dy_rot);
1497
1498 static GriPath p(5);
1499 p.clear();
1500 p.push_back(x0 + dx_rot, y0 + dy_rot, 'm');
1501
1502 dx = -dx;
1503 gr_rotate_xy(dx, dy, angle_deg, &dx_rot, &dy_rot);
1504 p.push_back(x0 + dx_rot, y0 + dy_rot, 'l');
1505
1506 dx = 0.5 * width + thin_space;
1507 dy = ascent + thin_space;
1508 gr_rotate_xy(dx, dy, angle_deg, &dx_rot, &dy_rot);
1509 p.push_back(x0 + dx_rot, y0 + dy_rot, 'l');
1510
1511 dx = -dx;
1512 gr_rotate_xy(dx, dy, angle_deg, &dx_rot, &dy_rot);
1513 p.push_back(x0 + dx_rot, y0 + dy_rot, 'l');
1514
1515 p.push_back(x0 + dx_rot, y0 + dy_rot, 'l');
1516
1517 _griState.set_color_line(box_color);
1518 p.fill(units_cm);
1519
1520 bounding_box_update(p.bounding_box(units_cm));
1521
1522 // Draw text
1523 _griState.set_color_text(text_color);
1524 dx = -0.5 * width;
1525 dy = 0.0;
1526 gr_rotate_xy(dx, dy, angle_deg, &dx_rot, &dy_rot);
1527 gr_show_at(s.getValue(),
1528 x0 + dx_rot,
1529 y0 + dy_rot,
1530 TEXT_LJUST,
1531 angle_deg);
1532 _griState.set_color_line(old_line_color);
1533 _griState.set_color_text(old_text_color);
1534 _drawingstarted = true;
1535 }
1536
1537 // Rotate (x,y) into (xx,yy), through `angle' degrees counterclockwise.
1538 void
gr_rotate_xy(double x,double y,double angle,double * xx,double * yy)1539 gr_rotate_xy(double x, double y, double angle, double *xx, double *yy)
1540 {
1541 angle /= DEG_PER_RAD; // convert to radians
1542 double c = cos(angle);
1543 double s = sin(angle);
1544 *xx = c * x - s * y;
1545 *yy = s * x + c * y;
1546 }
1547
1548 // Get the width, ascent and descent of string s, in current font.
1549 // BUG: Ascent and descent are inaccurate.
1550 // BUG: Smaller size of super/subscripts not accounted for.
1551 void
gr_stringwidth(const char * s,double * w,double * a,double * d)1552 gr_stringwidth(const char *s, double *w, double *a, double *d)
1553 {
1554 *w = *a = *d = 0.0;
1555 if (strlen(s) == 0)
1556 return;
1557 bool used_supers = false;
1558 bool used_subs = false;
1559 bool inmath = false;
1560 bool oldWritePS = _grWritePS;
1561 double oldfontsize_pt = gr_currentfontsize_pt();
1562 _grWritePS = false;
1563 while (*s != '\0') {
1564 // figure out whether entering or leaving math mode
1565 if (*s == '$' && *(s - 1) != '\\') {
1566 #ifdef DEBUG
1567 printf("DEBUG %s:%d toggling inmath; rest of string is \"%s\"\n",__FILE__,__LINE__,s);
1568 #endif
1569 inmath = (inmath ? false : true);
1570 s++;
1571 continue;
1572 }
1573 // handle math mode differently
1574 // ?? BUG Superscripts and subscripts are printed smaller, but
1575 // ?? BUG their size is assumed to be the same as normal chars.
1576 if (inmath) {
1577 if (*s == '^') // handle superscript
1578 used_supers = true;
1579 else if (*s == '_') // handle subscript
1580 used_subs = true;
1581 else if (*s == '{') // ignore groups while computing string length
1582 ; // EMPTY
1583 else if (*s == '}') // ignore groups
1584 ; // EMPTY
1585 else if (*s == '\\') { // handle synonym
1586 // First catch thinspace commands
1587 if (*(s + 1) == ',') {
1588 // Thinspace = Mwidth/6
1589 *w += gr_charwidth_cm((int)'M', CurrentFont.id, CurrentFont.size_pt) / 6.0;
1590 s += 1;
1591 } else if (*(s + 1) == '!') {
1592 // Negative thinspace = -Mwidth/6
1593 *w -= gr_charwidth_cm((int)'M', CurrentFont.id, CurrentFont.size_pt) / 6.0;
1594 s += 1;
1595 } else {
1596 int inc;
1597 int symbol_index = symbol_in_math(s, &inc);
1598 if (symbol_index > -1) {
1599 gr_fontID oldfontID = CurrentFont.id;
1600 s += inc;
1601 // *w += gr_charwidth_cm("m" symbol_code[symbol_index][1], gr_font_Symbol, CurrentFont.size_pt);
1602 *w += gr_charwidth_cm('m', gr_font_Symbol, CurrentFont.size_pt); // BUG
1603 CurrentFont.id = oldfontID;
1604 } else {
1605 // it's not a known math symbol
1606 *w += gr_charwidth_cm('\\', CurrentFont.id, CurrentFont.size_pt);
1607 }
1608 }
1609 } else {
1610 // We are in math-mode, but it's not a special character. Add
1611 // appropriate amount for either super/subscript or normal
1612 // character.
1613 *w += gr_charwidth_cm((int) *s, CurrentFont.id, CurrentFont.size_pt);
1614 }
1615 } else {
1616 // not inmath
1617 *w += gr_charwidth_cm((int) *s, CurrentFont.id, CurrentFont.size_pt);
1618 }
1619 s++;
1620 }
1621 // Calculate ascent/descent. BUG: doesn't take math chars into acct
1622 *a = gr_currentCapHeight_cm() * (1 + (used_supers ? 1 : 0) *
1623 (SuperSize + SuperMoveUp - 1));
1624 #if 0 // before 2.054
1625 *d = gr_currentCapHeight_cm() * (1.0 + 0.5 * (int) used_subs);
1626 #endif
1627 *d = gr_current_descender() * (1 + (used_subs ? 1.0 : 0.0) *
1628 (SubSize + SubMoveDown - 1));
1629 #ifdef DEBUG
1630 printf("DEBUG %s:%d gr_stringwidth(s=\"%s\",...) RETURNING w=%f, a=%f d=%f\n", __FILE__,__LINE__,s,*w,*a,*d);
1631 #endif
1632 // reset fontsize ... can't do with gr_setfontsize_pt()
1633 // because that would call this function in infinite recursion.
1634 CurrentFont.size_pt = oldfontsize_pt;
1635 _grWritePS = oldWritePS;
1636 }
1637
1638 #if 0
1639 // return index (for size-table) for a character (given as integer)
1640 static int index_for_math_symbol(const char *s)
1641 {
1642 //printf("index_for_math_symbol(%s)\n",s);
1643 if (!s) return (int)'?';
1644 for (int i = 0; i < NCODES; i++) {
1645 //printf(" %3d (%s) (%s)\n", i, symbol_code[i][1],symbol_code[i][2]);
1646 if (!strncmp(s, symbol_code[i][1], strlen(symbol_code[i][1]))) {
1647 //printf(" match\n");
1648 return (int) *symbol_code[i][2];
1649 }
1650 //printf(" no match\n");
1651 }
1652 //printf("index_for_math_symbol(%s) cannot find a match\n", s);
1653 return (int) 'M'; // a guess, since we have no clue
1654 }
1655 #endif
1656
1657 // Return thinspace (=1/6 of width of "M" in current font), in cm
1658 double
gr_thinspace_cm()1659 gr_thinspace_cm()
1660 {
1661 return (gr_charwidth_cm(int('M'), CurrentFont.id, CurrentFont.size_pt) / 6.0);
1662 }
1663
1664 // Return width of quad (= width of "M" in current font), in cm
1665 double
gr_quad_cm()1666 gr_quad_cm()
1667 {
1668 return (gr_charwidth_cm((int) 'M', CurrentFont.id, CurrentFont.size_pt));
1669 }
1670
1671 // Following page should substituted as output from
1672 // ~kelley/src/gri/src/get_font_metrics
1673
1674 struct font_metric {
1675 float XHeight;
1676 float CapHeight;
1677 float Ascender;
1678 float Descender;
1679 float width[128];
1680 };
1681 //
1682 // Following font metric generated by `get_font_metrics'
1683 // perlscript from Font Metric file `/usr/openwin/lib/X11/fonts/F3/afm/Courier.afm'.
1684 // All measurement in centimetres, given a pointsize of 1.0
1685 //
1686
1687 // Created by Perl script get_font_metrics.pl
1688 struct font_metric CenturyRoman = {
1689 0.016369, // XHeight
1690 0.025471, // CapHeight
1691 0.026000, // Ascender
1692 -0.007232, // Descender
1693 { // Widths of first 128 characters
1694 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1695 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1696 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1697 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1698 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1699 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1700 0.0000000, 0.0000000, 0.0098072, 0.0104422, 0.0137231,
1701 0.0196144, 0.0196144, 0.0293864, 0.0287514, 0.0071967,
1702 0.0117475, 0.0117475, 0.0176389, 0.0213783, 0.0098072,
1703 0.0117475, 0.0098072, 0.0098072, 0.0196144, 0.0196144,
1704 0.0196144, 0.0196144, 0.0196144, 0.0196144, 0.0196144,
1705 0.0196144, 0.0196144, 0.0196144, 0.0098072, 0.0098072,
1706 0.0213783, 0.0213783, 0.0213783, 0.0156633, 0.0259997,
1707 0.0254706, 0.0254706, 0.0254706, 0.0274461, 0.0254706,
1708 0.0235303, 0.0274461, 0.0293864, 0.0143581, 0.0196144,
1709 0.0274461, 0.0235303, 0.0333022, 0.0287514, 0.0274461,
1710 0.0235303, 0.0274461, 0.0254706, 0.0222250, 0.0235303,
1711 0.0287514, 0.0254706, 0.0346075, 0.0248356, 0.0248356,
1712 0.0215547, 0.0117475, 0.0213783, 0.0117475, 0.0213783,
1713 0.0176389, 0.0071967, 0.0196144, 0.0196144, 0.0156633,
1714 0.0202494, 0.0176389, 0.0117475, 0.0189442, 0.0215547,
1715 0.0111125, 0.0104422, 0.0209197, 0.0111125, 0.0313619,
1716 0.0215547, 0.0176389, 0.0202494, 0.0196144, 0.0156633,
1717 0.0163336, 0.0137231, 0.0215547, 0.0189442, 0.0274461,
1718 0.0189442, 0.0189442, 0.0169686, 0.0117475, 0.0213783,
1719 0.0117475, 0.0213783, 0.0000000
1720 }
1721 };
1722
1723 struct font_metric Courier = {
1724 0.015028, // XHeight
1725 0.019826, // CapHeight
1726 0.022190, // Ascender
1727 -0.005539, // Descender
1728 { // Widths of first 128 characters
1729 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1730 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1731 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1732 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1733 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1734 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1735 0.0000000, 0.0000000, 0.0211667, 0.0211667, 0.0211667,
1736 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1737 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1738 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1739 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1740 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1741 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1742 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1743 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1744 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1745 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1746 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1747 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1748 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1749 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1750 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1751 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1752 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1753 0.0211667, 0.0211667, 0.0211667, 0.0211667, 0.0211667,
1754 0.0211667, 0.0211667, 0.0000000
1755 }
1756 };
1757 //
1758 // Following font metric generated by `get_font_metrics'
1759 // perlscript from Font Metric file `/usr/openwin/lib/X11/fonts/F3/afm/Helvetica.afm'.
1760 // All measurement in centimetres, given a pointsize of 1.0
1761 //
1762 struct font_metric Helvetica = {
1763 0.018450, // XHeight
1764 0.025329, // CapHeight
1765 0.025329, // Ascender
1766 -0.007302, // Descender
1767 { // Widths of first 128 characters
1768 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1769 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1770 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1771 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1772 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1773 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1774 0.0000000, 0.0000000, 0.0098072, 0.0098072, 0.0125236,
1775 0.0196144, 0.0196144, 0.0313619, 0.0235303, 0.0078317,
1776 0.0117475, 0.0117475, 0.0137231, 0.0206022, 0.0098072,
1777 0.0117475, 0.0098072, 0.0098072, 0.0196144, 0.0196144,
1778 0.0196144, 0.0196144, 0.0196144, 0.0196144, 0.0196144,
1779 0.0196144, 0.0196144, 0.0196144, 0.0098072, 0.0098072,
1780 0.0206022, 0.0206022, 0.0206022, 0.0196144, 0.0358069,
1781 0.0235303, 0.0235303, 0.0254706, 0.0254706, 0.0235303,
1782 0.0215547, 0.0274461, 0.0254706, 0.0098072, 0.0176389,
1783 0.0235303, 0.0196144, 0.0293864, 0.0254706, 0.0274461,
1784 0.0235303, 0.0274461, 0.0254706, 0.0235303, 0.0215547,
1785 0.0254706, 0.0235303, 0.0333022, 0.0235303, 0.0235303,
1786 0.0215547, 0.0098072, 0.0098072, 0.0098072, 0.0165453,
1787 0.0196144, 0.0078317, 0.0196144, 0.0196144, 0.0176389,
1788 0.0196144, 0.0196144, 0.0098072, 0.0196144, 0.0196144,
1789 0.0078317, 0.0078317, 0.0176389, 0.0078317, 0.0293864,
1790 0.0196144, 0.0196144, 0.0196144, 0.0196144, 0.0117475,
1791 0.0176389, 0.0098072, 0.0196144, 0.0176389, 0.0254706,
1792 0.0176389, 0.0176389, 0.0176389, 0.0117828, 0.0091722,
1793 0.0117828, 0.0206022, 0.0000000
1794 }
1795 };
1796 //
1797 // Following font metric generated by `get_font_metrics'
1798 // perlscript from Font Metric file `/usr/openwin/lib/X11/fonts/F3/afm/Helvetica-Oblique.afm'.
1799 // All measurement in centimetres, given a pointsize of 1.0
1800 //
1801 struct font_metric Helvetica_Oblique = {
1802 0.018450, // XHeight
1803 0.025329, // CapHeight
1804 0.025329, // Ascender
1805 -0.007302, // Descender
1806 { // Widths of first 128 characters
1807 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1808 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1809 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1810 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1811 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1812 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1813 0.0000000, 0.0000000, 0.0098072, 0.0098072, 0.0125236,
1814 0.0196144, 0.0196144, 0.0313619, 0.0235303, 0.0078317,
1815 0.0117475, 0.0117475, 0.0137231, 0.0206022, 0.0098072,
1816 0.0117475, 0.0098072, 0.0098072, 0.0196144, 0.0196144,
1817 0.0196144, 0.0196144, 0.0196144, 0.0196144, 0.0196144,
1818 0.0196144, 0.0196144, 0.0196144, 0.0098072, 0.0098072,
1819 0.0206022, 0.0206022, 0.0206022, 0.0196144, 0.0358069,
1820 0.0235303, 0.0235303, 0.0254706, 0.0254706, 0.0235303,
1821 0.0215547, 0.0274461, 0.0254706, 0.0098072, 0.0176389,
1822 0.0235303, 0.0196144, 0.0293864, 0.0254706, 0.0274461,
1823 0.0235303, 0.0274461, 0.0254706, 0.0235303, 0.0215547,
1824 0.0254706, 0.0235303, 0.0333022, 0.0235303, 0.0235303,
1825 0.0215547, 0.0098072, 0.0098072, 0.0098072, 0.0165453,
1826 0.0196144, 0.0078317, 0.0196144, 0.0196144, 0.0176389,
1827 0.0196144, 0.0196144, 0.0098072, 0.0196144, 0.0196144,
1828 0.0078317, 0.0078317, 0.0176389, 0.0078317, 0.0293864,
1829 0.0196144, 0.0196144, 0.0196144, 0.0196144, 0.0117475,
1830 0.0176389, 0.0098072, 0.0196144, 0.0176389, 0.0254706,
1831 0.0176389, 0.0176389, 0.0176389, 0.0117828, 0.0091722,
1832 0.0117828, 0.0206022, 0.0000000
1833 }
1834 };
1835 //
1836 // Following font metric generated by `get_font_metrics'
1837 // perlscript from Font Metric file `/usr/openwin/lib/X11/fonts/F3/afm/Helvetica-Bold.afm'.
1838 // All measurement in centimetres, given a pointsize of 1.0
1839 //
1840 struct font_metric Helvetica_Bold = {
1841 0.018768, // XHeight
1842 0.025329, // CapHeight
1843 0.025329, // Ascender
1844 -0.007302, // Descender
1845 { // Widths of first 128 characters
1846 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1847 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1848 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1849 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1850 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1851 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1852 0.0000000, 0.0000000, 0.0098072, 0.0117475, 0.0167217,
1853 0.0196144, 0.0196144, 0.0313619, 0.0254706, 0.0098072,
1854 0.0117475, 0.0117475, 0.0137231, 0.0206022, 0.0098072,
1855 0.0117475, 0.0098072, 0.0098072, 0.0196144, 0.0196144,
1856 0.0196144, 0.0196144, 0.0196144, 0.0196144, 0.0196144,
1857 0.0196144, 0.0196144, 0.0196144, 0.0117475, 0.0117475,
1858 0.0206022, 0.0206022, 0.0206022, 0.0215547, 0.0343958,
1859 0.0254706, 0.0254706, 0.0254706, 0.0254706, 0.0235303,
1860 0.0215547, 0.0274461, 0.0254706, 0.0098072, 0.0196144,
1861 0.0254706, 0.0215547, 0.0293864, 0.0254706, 0.0274461,
1862 0.0235303, 0.0274461, 0.0254706, 0.0235303, 0.0215547,
1863 0.0254706, 0.0235303, 0.0333022, 0.0235303, 0.0235303,
1864 0.0215547, 0.0117475, 0.0098072, 0.0117475, 0.0206022,
1865 0.0196144, 0.0098072, 0.0196144, 0.0215547, 0.0196144,
1866 0.0215547, 0.0196144, 0.0117475, 0.0215547, 0.0215547,
1867 0.0098072, 0.0098072, 0.0196144, 0.0098072, 0.0313619,
1868 0.0215547, 0.0215547, 0.0215547, 0.0215547, 0.0137231,
1869 0.0196144, 0.0117475, 0.0215547, 0.0196144, 0.0274461,
1870 0.0196144, 0.0196144, 0.0176389, 0.0137231, 0.0098778,
1871 0.0137231, 0.0206022, 0.0000000
1872 }
1873 };
1874 //
1875 // Following font metric generated by `get_font_metrics'
1876 // perlscript from Font Metric file `/usr/openwin/lib/X11/fonts/F3/afm/Palatino-Roman.afm'.
1877 // All measurement in centimetres, given a pointsize of 1.0
1878 //
1879 struct font_metric PalatinoRoman = {
1880 0.016545, // XHeight
1881 0.024412, // CapHeight
1882 0.025612, // Ascender
1883 -0.009913, // Descender
1884 { // Widths of first 128 characters
1885 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1886 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1887 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1888 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1889 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1890 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1891 0.0000000, 0.0000000, 0.0088194, 0.0098072, 0.0130881,
1892 0.0176389, 0.0176389, 0.0296333, 0.0274461, 0.0098072,
1893 0.0117475, 0.0117475, 0.0137231, 0.0213783, 0.0088194,
1894 0.0117475, 0.0088194, 0.0213783, 0.0176389, 0.0176389,
1895 0.0176389, 0.0176389, 0.0176389, 0.0176389, 0.0176389,
1896 0.0176389, 0.0176389, 0.0176389, 0.0088194, 0.0088194,
1897 0.0213783, 0.0213783, 0.0213783, 0.0156633, 0.0263525,
1898 0.0274461, 0.0215547, 0.0250119, 0.0273050, 0.0215547,
1899 0.0196144, 0.0269169, 0.0293511, 0.0118886, 0.0117475,
1900 0.0256117, 0.0215547, 0.0333728, 0.0293158, 0.0277283,
1901 0.0213078, 0.0277283, 0.0235656, 0.0185208, 0.0216253,
1902 0.0274461, 0.0254706, 0.0352778, 0.0235303, 0.0235303,
1903 0.0235303, 0.0117475, 0.0213783, 0.0117475, 0.0213783,
1904 0.0176389, 0.0098072, 0.0176389, 0.0195086, 0.0156633,
1905 0.0215547, 0.0168981, 0.0117475, 0.0196144, 0.0205317,
1906 0.0102658, 0.0082550, 0.0196144, 0.0102658, 0.0311503,
1907 0.0205317, 0.0192617, 0.0212019, 0.0197556, 0.0139347,
1908 0.0149578, 0.0115006, 0.0212725, 0.0199319, 0.0294217,
1909 0.0182033, 0.0196144, 0.0176389, 0.0117475, 0.0213783,
1910 0.0117475, 0.0213783, 0.0000000
1911 }
1912 };
1913 // Created by Perl script get_font_metrics.pl
1914 struct font_metric PalatinoItalic = {
1915 0.017004, // XHeight
1916 0.024412, // CapHeight
1917 0.025859, // Ascender
1918 -0.009737, // Descender
1919 { // Widths of first 128 characters
1920 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1921 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1922 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1923 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1924 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1925 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1926 0.0000000, 0.0000000, 0.0088194, 0.0117475, 0.0176389,
1927 0.0176389, 0.0176389, 0.0313619, 0.0274461, 0.0098072,
1928 0.0117475, 0.0117475, 0.0137231, 0.0213783, 0.0088194,
1929 0.0117475, 0.0088194, 0.0104422, 0.0176389, 0.0176389,
1930 0.0176389, 0.0176389, 0.0176389, 0.0176389, 0.0176389,
1931 0.0176389, 0.0176389, 0.0176389, 0.0088194, 0.0088194,
1932 0.0213783, 0.0213783, 0.0213783, 0.0176389, 0.0263525,
1933 0.0254706, 0.0215547, 0.0235303, 0.0274461, 0.0215547,
1934 0.0196144, 0.0254706, 0.0274461, 0.0117475, 0.0117475,
1935 0.0235303, 0.0196144, 0.0333022, 0.0274461, 0.0274461,
1936 0.0215547, 0.0274461, 0.0235303, 0.0196144, 0.0215547,
1937 0.0274461, 0.0254706, 0.0333022, 0.0254706, 0.0235303,
1938 0.0235303, 0.0117475, 0.0213783, 0.0117475, 0.0213783,
1939 0.0176389, 0.0098072, 0.0156633, 0.0163336, 0.0143581,
1940 0.0176389, 0.0137231, 0.0098072, 0.0176389, 0.0176389,
1941 0.0098072, 0.0098072, 0.0156633, 0.0098072, 0.0274461,
1942 0.0196144, 0.0156633, 0.0176389, 0.0163336, 0.0137231,
1943 0.0137231, 0.0117475, 0.0196144, 0.0176389, 0.0254706,
1944 0.0176389, 0.0176389, 0.0156633, 0.0117475, 0.0213783,
1945 0.0117475, 0.0213783, 0.0000000
1946 }
1947 };
1948
1949
1950
1951 // Created by Perl script get_font_metrics.pl
1952 struct font_metric PalatinoBold = {
1953 0.016616, // XHeight
1954 0.024024, // CapHeight
1955 0.025400, // Ascender
1956 -0.009102, // Descender
1957 { // Widths of first 128 characters
1958 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1959 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1960 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1961 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1962 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1963 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
1964 0.0000000, 0.0000000, 0.0088194, 0.0098072, 0.0141817,
1965 0.0176389, 0.0176389, 0.0313619, 0.0293864, 0.0098072,
1966 0.0117475, 0.0117475, 0.0156633, 0.0213783, 0.0088194,
1967 0.0117475, 0.0088194, 0.0104422, 0.0176389, 0.0176389,
1968 0.0176389, 0.0176389, 0.0176389, 0.0176389, 0.0176389,
1969 0.0176389, 0.0176389, 0.0176389, 0.0088194, 0.0088194,
1970 0.0213783, 0.0213783, 0.0213783, 0.0156633, 0.0263525,
1971 0.0274461, 0.0235303, 0.0254706, 0.0293864, 0.0215547,
1972 0.0196144, 0.0293864, 0.0293864, 0.0137231, 0.0137231,
1973 0.0274461, 0.0215547, 0.0352778, 0.0293864, 0.0293864,
1974 0.0215547, 0.0293864, 0.0254706, 0.0215547, 0.0235303,
1975 0.0274461, 0.0274461, 0.0352778, 0.0235303, 0.0235303,
1976 0.0235303, 0.0117475, 0.0213783, 0.0117475, 0.0213783,
1977 0.0176389, 0.0098072, 0.0176389, 0.0215547, 0.0156633,
1978 0.0215547, 0.0176389, 0.0137231, 0.0196144, 0.0215547,
1979 0.0117475, 0.0117475, 0.0215547, 0.0117475, 0.0313619,
1980 0.0215547, 0.0196144, 0.0215547, 0.0215547, 0.0137231,
1981 0.0156633, 0.0117475, 0.0215547, 0.0196144, 0.0293864,
1982 0.0176389, 0.0196144, 0.0176389, 0.0109361, 0.0213783,
1983 0.0109361, 0.0213783, 0.0000000
1984 }
1985 };
1986
1987
1988 //
1989 // Following font metric generated by `get_font_metrics'
1990 // perlscript from Font Metric file `/usr/openwin/lib/X11/fonts/F3/afm/Symbol.afm'.
1991 // All measurement in centimetres, given a pointsize of 1.0
1992 //
1993 struct font_metric Symbol = {
1994 0.000000, // XHeight
1995 0.000000, // CapHeight
1996 0.000000, // Ascender
1997 0.000000, // Descender
1998 { // Widths of first 128 characters
1999 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2000 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2001 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2002 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2003 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2004 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2005 0.0000000, 0.0000000, 0.0088194, 0.0117475, 0.0251531,
2006 0.0176389, 0.0193675, 0.0293864, 0.0274461, 0.0154869,
2007 0.0117475, 0.0117475, 0.0176389, 0.0193675, 0.0088194,
2008 0.0193675, 0.0088194, 0.0098072, 0.0176389, 0.0176389,
2009 0.0176389, 0.0176389, 0.0176389, 0.0176389, 0.0176389,
2010 0.0176389, 0.0176389, 0.0176389, 0.0098072, 0.0098072,
2011 0.0193675, 0.0193675, 0.0193675, 0.0156633, 0.0193675,
2012 0.0254706, 0.0235303, 0.0254706, 0.0215900, 0.0215547,
2013 0.0269169, 0.0212725, 0.0254706, 0.0117475, 0.0222603,
2014 0.0254706, 0.0242006, 0.0313619, 0.0254706, 0.0254706,
2015 0.0270933, 0.0261408, 0.0196144, 0.0208844, 0.0215547,
2016 0.0243417, 0.0154869, 0.0270933, 0.0227542, 0.0280458,
2017 0.0215547, 0.0117475, 0.0304447, 0.0117475, 0.0232128,
2018 0.0176389, 0.0176389, 0.0222603, 0.0193675, 0.0193675,
2019 0.0174272, 0.0154869, 0.0183797, 0.0144992, 0.0212725,
2020 0.0116064, 0.0212725, 0.0193675, 0.0193675, 0.0203200,
2021 0.0183797, 0.0193675, 0.0193675, 0.0183797, 0.0193675,
2022 0.0212725, 0.0154869, 0.0203200, 0.0251531, 0.0242006,
2023 0.0173919, 0.0242006, 0.0174272, 0.0169333, 0.0070556,
2024 0.0169333, 0.0193675, 0.0000000
2025 }
2026 };
2027 //
2028 // Following font metric generated by `get_font_metrics'
2029 // perlscript from Font Metric file `/usr/openwin/lib/X11/fonts/F3/afm/Times-Roman.afm'.
2030 // All measurement in centimetres, given a pointsize of 1.0
2031 //
2032 struct font_metric TimesRoman = {
2033 0.015875, // XHeight
2034 0.023354, // CapHeight
2035 0.024095, // Ascender
2036 -0.007655, // Descender
2037 { // Widths of first 128 characters
2038 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2039 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2040 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2041 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2042 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2043 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
2044 0.0000000, 0.0000000, 0.0088194, 0.0117475, 0.0143933,
2045 0.0176389, 0.0176389, 0.0293864, 0.0274461, 0.0117475,
2046 0.0117475, 0.0117475, 0.0176389, 0.0198967, 0.0088194,
2047 0.0117475, 0.0088194, 0.0098072, 0.0176389, 0.0176389,
2048 0.0176389, 0.0176389, 0.0176389, 0.0176389, 0.0176389,
2049 0.0176389, 0.0176389, 0.0176389, 0.0098072, 0.0098072,
2050 0.0198967, 0.0198967, 0.0198967, 0.0156633, 0.0324908,
2051 0.0254706, 0.0235303, 0.0235303, 0.0254706, 0.0215547,
2052 0.0196144, 0.0254706, 0.0254706, 0.0117475, 0.0137231,
2053 0.0254706, 0.0215547, 0.0313619, 0.0254706, 0.0254706,
2054 0.0196144, 0.0254706, 0.0235303, 0.0196144, 0.0215547,
2055 0.0254706, 0.0254706, 0.0333022, 0.0254706, 0.0254706,
2056 0.0215547, 0.0117475, 0.0098072, 0.0117475, 0.0165453,
2057 0.0176389, 0.0117475, 0.0156633, 0.0176389, 0.0156633,
2058 0.0176389, 0.0156633, 0.0117475, 0.0176389, 0.0176389,
2059 0.0098072, 0.0098072, 0.0176389, 0.0098072, 0.0274461,
2060 0.0176389, 0.0176389, 0.0176389, 0.0176389, 0.0117475,
2061 0.0137231, 0.0098072, 0.0176389, 0.0176389, 0.0254706,
2062 0.0176389, 0.0176389, 0.0156633, 0.0169333, 0.0070556,
2063 0.0169333, 0.0190853, 0.0000000
2064 }
2065 };
2066
2067 /*
2068 * gr_charwidth_cm(char c, int font, double fontsize_pt)
2069 *
2070 * RETURN VALUE the width of the character, in centimetres
2071 *
2072 * Font info created by the `get_font_metrics' perlscript, in the Gri src
2073 * directory. This looks in the OpenWindows font metrics files to figure the
2074 * pertintent stuff out. (You might have to edit this for different
2075 * machines).
2076 */
2077 static double
gr_charwidth_cm(int c,int font,double fontsize_pt)2078 gr_charwidth_cm(int c, int font, double fontsize_pt)
2079 {
2080 unsigned char i = (int) c;
2081 if (i > 127)
2082 return fontsize_pt * 0.0211663; /* error, but guess Courier size
2083 * anyway */
2084 switch (font) {
2085 case gr_font_TimesRoman:
2086 return fontsize_pt * TimesRoman.width[i];
2087 case gr_font_Courier:
2088 return fontsize_pt * 0.0211663; /* Courier has fixed width */
2089 case gr_font_Symbol:
2090 return fontsize_pt * Symbol.width[i];
2091 case gr_font_Helvetica:
2092 return fontsize_pt * Helvetica.width[i];
2093 case gr_font_HelveticaBold:
2094 return fontsize_pt * Helvetica_Bold.width[i];
2095 case gr_font_PalatinoRoman:
2096 return fontsize_pt * PalatinoRoman.width[i];
2097 case gr_font_Century:
2098 return fontsize_pt * CenturyRoman.width[i];
2099 default:
2100 break;
2101 /* Guess similar size to Helvetica */
2102 }
2103 return (fontsize_pt * Helvetica.width[i]);
2104 }
2105
2106 double
gr_current_descender()2107 gr_current_descender() // descender, in positive cm
2108 {
2109 switch (CurrentFont.id) {
2110 case gr_font_Courier:
2111 return (-CurrentFont.size_pt * Courier.Descender);
2112 case gr_font_Helvetica:
2113 return(-CurrentFont.size_pt * Helvetica.Descender);
2114 case gr_font_Symbol:
2115 return(-CurrentFont.size_pt * Symbol.Descender);
2116 case gr_font_TimesRoman:
2117 return(-CurrentFont.size_pt * TimesRoman.Descender);
2118 case gr_font_Century:
2119 return(-CurrentFont.size_pt * CenturyRoman.Descender);
2120 case gr_font_PalatinoRoman:
2121 return(-CurrentFont.size_pt * PalatinoRoman.Descender);
2122 case gr_font_PalatinoItalic:
2123 return(-CurrentFont.size_pt * PalatinoItalic.Descender);
2124 case gr_font_PalatinoBold:
2125 return(-CurrentFont.size_pt * PalatinoBold.Descender);
2126 default:
2127 break;
2128 }
2129 return CurrentFont.size_pt * 0.025329; // Guess similar to Helvetica
2130 }
2131
2132
2133 // gr_currentCapHeight_cm() -- find height of capital characters
2134 double
gr_currentCapHeight_cm()2135 gr_currentCapHeight_cm()
2136 {
2137 double height_cm = 0.0;
2138 switch (CurrentFont.id) {
2139 case gr_font_Courier:
2140 height_cm = (CurrentFont.size_pt * Courier.CapHeight);
2141 break;
2142 case gr_font_Helvetica:
2143 height_cm = (CurrentFont.size_pt * Helvetica.CapHeight);
2144 break;
2145 case gr_font_Symbol:
2146 height_cm = (CurrentFont.size_pt * Symbol.CapHeight);
2147 break;
2148 case gr_font_TimesRoman:
2149 height_cm = (CurrentFont.size_pt * TimesRoman.CapHeight);
2150 break;
2151 case gr_font_Century:
2152 height_cm = (CurrentFont.size_pt * CenturyRoman.CapHeight);
2153 break;
2154 case gr_font_PalatinoRoman:
2155 height_cm = (CurrentFont.size_pt * PalatinoRoman.CapHeight);
2156 break;
2157 case gr_font_PalatinoItalic:
2158 height_cm = (CurrentFont.size_pt * PalatinoItalic.CapHeight);
2159 break;
2160 case gr_font_PalatinoBold:
2161 height_cm = (CurrentFont.size_pt * PalatinoBold.CapHeight);
2162 break;
2163 default:
2164 /*
2165 * Don't know this font.
2166 */
2167 break;
2168 }
2169 if (height_cm > 0.0)
2170 return height_cm;
2171 else
2172 return CurrentFont.size_pt * 0.025329; /* Guess Helvetica */
2173 }
2174