g_alabel.c 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386
  1. /* This file is part of the GNU plotutils package. Copyright (C) 1995,
  2. 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
  3. The GNU plotutils package is free software. You may redistribute it
  4. and/or modify it under the terms of the GNU General Public License as
  5. published by the Free Software foundation; either version 2, or (at your
  6. option) any later version.
  7. The GNU plotutils package is distributed in the hope that it will be
  8. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with the GNU plotutils package; see the file COPYING. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  14. Boston, MA 02110-1301, USA. */
  15. /* This file contains the alabel method, which is a GNU extension to
  16. libplot. It draws a label, i.e. a text string, at the current location.
  17. Horizontal and vertical justification must be specified.
  18. ALABEL takes three arguments X_JUSTIFY, Y_JUSTIFY, and S, and places the
  19. label S according to the x and y axis adjustments specified in X_JUSTIFY
  20. and Y_JUSTIFY. X_JUSTIFY is equal to 'l', 'c', or 'r', signifying
  21. left-justified, centered, or right-justified, relative to the current
  22. position. Y_JUSTIFY is equal to 'b', 'x', 'c', or 't', signifying that
  23. the bottom, baseline, center, or top of the label should pass through
  24. the current position. */
  25. /* This file contains the label method, which is a standard part of libplot
  26. (supplied for backward compatibility). It draws a label, i.e. a text
  27. string, at the current location of the graphics device cursor. It is
  28. obsoleted by the alabel method, which allows justification. */
  29. /* This file also contains the labelwidth method, which is a GNU extension
  30. to libplot. It returns the width in user units of a label, i.e., a text
  31. string. */
  32. #include "sys-defines.h"
  33. #include "extern.h"
  34. #include "g_control.h"
  35. #define SCRIPTSIZE 0.6 /* rel. size of subscripts/superscripts */
  36. #define SUBSCRIPT_DX 0.0
  37. #define SUBSCRIPT_DY (-0.2)
  38. #define SUPERSCRIPT_DX 0.0
  39. #define SUPERSCRIPT_DY 0.375
  40. /* font we use for symbol escapes if the current font is a user-specified
  41. one [for X Windows] that doesn't belong to any of our builtin typefaces */
  42. #define SYMBOL_FONT "Symbol"
  43. /* Obsolete kludges to handle the zero-width marker symbols in our ArcMath
  44. and StickMath fonts; also zero-width overbar. N.B. `8' AND `17' ARE
  45. HARDCODED IN THE TABLE IN g_fontd2.c. */
  46. #define ARCMATH 8
  47. #define STICKMATH 17
  48. #define IS_MATH_FONT(fontnum) ((fontnum) == ARCMATH || (fontnum) == STICKMATH)
  49. #define IS_CENTERED_SYMBOL(c) (((c) >= 'A' && (c) <= 'O') || (c) == 'e')
  50. /* forward references */
  51. static unsigned char *esc_esc_string (const unsigned char *s);
  52. static bool simple_string (const unsigned short *codestring);
  53. static bool clean_iso_string (unsigned char *s);
  54. /* The flabelwidth() and falabel() methods. After checking for control
  55. characters in the input string (not allowed), we invoke either a
  56. Hershey-specific or a non-Hershey-specific method. */
  57. int
  58. _API_alabel (R___(Plotter *_plotter) int x_justify, int y_justify, const char *s)
  59. {
  60. char *t;
  61. if (!_plotter->data->open)
  62. {
  63. _plotter->error (R___(_plotter)
  64. "alabel: invalid operation");
  65. return -1;
  66. }
  67. _API_endpath (S___(_plotter)); /* flush path if any */
  68. if (s == NULL)
  69. return 0; /* avoid core dumps */
  70. /* copy because we may alter the string */
  71. t = (char *)_pl_xmalloc (strlen (s) + 1);
  72. strcpy (t, s);
  73. /* allow only character set in ISO encoding */
  74. {
  75. bool was_clean;
  76. was_clean = clean_iso_string ((unsigned char *)t);
  77. if (!was_clean)
  78. _plotter->warning (R___(_plotter)
  79. "ignoring control character (e.g. CR or LF) in label");
  80. }
  81. /* Be sure user-specified font has been retrieved. Font is changed by
  82. fontname/fontsize/textangle, all of which invoke _pl_g_set_font(), and
  83. by space/space2/concat, which may not. */
  84. _pl_g_set_font (S___(_plotter));
  85. if (_plotter->data->have_escaped_string_support)
  86. /* Plotter supports the display of labels natively, including the
  87. escape sequences that we use in labels for subscripts, superscripts,
  88. shifts among fonts, etc. Metafile Plotters are the only ones that
  89. are so powerful. Actually they just write the label, escape
  90. sequences and all, to the output stream. :-) */
  91. _plotter->paint_text_string_with_escapes (R___(_plotter)
  92. (unsigned char *)t,
  93. x_justify, y_justify);
  94. else
  95. /* must parse escape sequences (if any) in label */
  96. {
  97. if (_plotter->drawstate->font_type == PL_F_HERSHEY)
  98. /* call internal Hershey-specific routine to do the drawing, since
  99. any label in a Hershey font supports additional escape sequences */
  100. _pl_g_alabel_hershey (R___(_plotter)
  101. (unsigned char *)t, x_justify, y_justify);
  102. else
  103. /* non-Hershey: use parsing routine below, which ultimately calls
  104. _plotter->paint_text_string to invoke Plotter-specific code */
  105. _pl_g_render_non_hershey_string (R___(_plotter)
  106. t, true, x_justify, y_justify);
  107. }
  108. free (t);
  109. return 0;
  110. }
  111. int
  112. _API_label (R___(Plotter *_plotter) const char *s)
  113. {
  114. /* label should have baseline passing through current location, and
  115. should be left-justified */
  116. return _API_alabel (R___(_plotter) 'l', 'x', s);
  117. }
  118. double
  119. _API_flabelwidth (R___(Plotter *_plotter) const char *s)
  120. {
  121. double width = 0.0;
  122. char *t;
  123. if (!_plotter->data->open)
  124. {
  125. _plotter->error (R___(_plotter)
  126. "flabelwidth: invalid operation");
  127. return -1;
  128. }
  129. if (s == NULL)
  130. return 0.0; /* avoid core dumps */
  131. /* copy because we may alter the string */
  132. t = (char *)_pl_xmalloc (strlen (s) + 1);
  133. strcpy (t, s);
  134. /* allow only character set in ISO encoding */
  135. {
  136. bool was_clean;
  137. was_clean = clean_iso_string ((unsigned char *)t);
  138. if (!was_clean)
  139. _plotter->warning (R___(_plotter)
  140. "ignoring control character (e.g. CR or LF) in label");
  141. }
  142. /* Be sure user-specified font has been retrieved. Font is changed by
  143. fontname/fontsize/textangle, all of which invoke _pl_g_set_font(), and
  144. by space/space2/concat, which may not. */
  145. _pl_g_set_font (S___(_plotter));
  146. if (_plotter->drawstate->font_type == PL_F_HERSHEY)
  147. /* call Hershey-specific routine, since controlification acts slightly
  148. differently (a label in any Hershey font may contain more escape
  149. sequences than a label in a non-Hershey font) */
  150. width = _pl_g_flabelwidth_hershey (R___(_plotter)
  151. (unsigned char *)t);
  152. else
  153. /* invoke routine below to compute width; final two args are ignored */
  154. width = _pl_g_render_non_hershey_string (R___(_plotter)
  155. t, false, 'c', 'c');
  156. free (t);
  157. return width;
  158. }
  159. /* The non-Hershey version of the falabel() and flabelwidth() methods
  160. (merged). They are distinguished by the do_render flag being
  161. true/false; the return values (the width of the string) are the same.
  162. The final two arguments, specifying justification, are relevant only if
  163. the do_render flag is `true'. If do_render is true, the string is
  164. rendered in accordance with the justification instructions, and the
  165. graphics cursor position is updated accordingly. */
  166. /* We `controlify' the string, translating escape sequences to annotations,
  167. before passing it to a lower-level rendering routine. Note: for fonts
  168. of `OTHER' type [user-specified X Windows fonts], shifts between fonts
  169. within a single typeface are ignored, since we have no information on
  170. what the other fonts within the font's typeface are. The annotations
  171. simply indicate whether or not a symbol font should be switched to, for
  172. the purpose of symbol escapes. For fonts of `OTHER' type, font #1 means
  173. the user-specified font and font #0 means the symbol font. */
  174. /* As noted, this version is invoked only if the current font is
  175. non-Hershey. But due to failure to retrieve an X font, it is possible
  176. that the font could switch to a Hershey font during rendering. So our
  177. lower-level rendering routine _pl_g_render_simple_string(), which this
  178. calls, may find itself invoked on a string to be rendered in a Hershey
  179. font. That's OK; it can handle it. */
  180. /* This routine checks whether a Plotter can handle horizontal and vertical
  181. justification requests. If it can't, it does its own repositioning
  182. before invoking _pl_g_render_simple_string. */
  183. /* ARGS: do_render = draw the string? */
  184. double
  185. _pl_g_render_non_hershey_string (R___(Plotter *_plotter) const char *s, bool do_render, int x_justify, int y_justify)
  186. {
  187. int h_just = PL_JUST_LEFT; /* all devices can handle left justification */
  188. int v_just = PL_JUST_BASE;
  189. unsigned short *codestring;
  190. unsigned short *cptr;
  191. double width = 0.0, added_width;
  192. double pushed_width = 0.0; /* pushed by user */
  193. int current_font_index;
  194. /* initial values of these attributes (will be restored at end) */
  195. double initial_font_size;
  196. const char *initial_font_name;
  197. int initial_font_type;
  198. /* initial and saved locations */
  199. double initial_position_x = _plotter->drawstate->pos.x;
  200. double initial_position_y = _plotter->drawstate->pos.y;
  201. double pushed_position_x = _plotter->drawstate->pos.x;
  202. double pushed_position_y = _plotter->drawstate->pos.y;
  203. /* misc. */
  204. char x_justify_c, y_justify_c;
  205. double x_offset, y_offset;
  206. double x_displacement = 1.0, x_displacement_internal = 1.0;
  207. double overall_width = 0.0;
  208. double cap_height, ascent, descent;
  209. double userdx, userdy, theta, sintheta = 0.0, costheta = 1.0;
  210. /* convert string to a codestring, including annotations */
  211. codestring = _pl_g_controlify (R___(_plotter) (const unsigned char *)s);
  212. if (do_render) /* perform needed computations; reposition */
  213. {
  214. /* compute label width in user units via a recursive call; final two
  215. args are ignored */
  216. overall_width = _pl_g_render_non_hershey_string (R___(_plotter)
  217. s, false, 'c', 'c');
  218. /* compute initial offsets that must be performed due to
  219. justification; also displacements that must be performed after
  220. rendering (see above)*/
  221. x_justify_c = (char)x_justify;
  222. y_justify_c = (char)y_justify;
  223. switch (x_justify_c)
  224. {
  225. case 'l': /* left justified */
  226. default:
  227. h_just = PL_JUST_LEFT;
  228. x_offset = 0.0;
  229. x_displacement = 1.0;
  230. x_displacement_internal = 1.0;
  231. /* range [0,1] */
  232. break;
  233. case 'c': /* centered */
  234. h_just = PL_JUST_CENTER;
  235. x_offset = -0.5;
  236. x_displacement = 0.0;
  237. x_displacement_internal = 0.0;
  238. /* range [-0.5,0.5] */
  239. break;
  240. case 'r': /* right justified */
  241. h_just = PL_JUST_RIGHT;
  242. x_offset = -1.0;
  243. x_displacement = -1.0;
  244. x_displacement_internal = -1.0;
  245. /* range [-1,0] */
  246. break;
  247. }
  248. /* need these to compute offset for vertical justification */
  249. cap_height = _plotter->drawstate->font_cap_height;
  250. ascent = _plotter->drawstate->font_ascent;
  251. descent = _plotter->drawstate->font_descent;
  252. switch (y_justify_c) /* placement of label with respect
  253. to y coordinate */
  254. {
  255. case 'b': /* current point is at bottom */
  256. v_just = PL_JUST_BOTTOM;
  257. y_offset = descent;
  258. break;
  259. case 'x': /* current point is on baseline */
  260. default:
  261. v_just = PL_JUST_BASE;
  262. y_offset = 0.0;
  263. break;
  264. case 'c': /* current point midway between bottom, top */
  265. v_just = PL_JUST_HALF;
  266. y_offset = 0.5 * (descent - ascent);
  267. break;
  268. case 'C': /* current point is on cap line */
  269. v_just = PL_JUST_CAP;
  270. y_offset = - cap_height;
  271. break;
  272. case 't': /* current point is at top */
  273. v_just = PL_JUST_TOP;
  274. y_offset = - ascent;
  275. break;
  276. }
  277. /* If codestring is a string in a single font, with no control codes,
  278. we'll render it using native device justification, rather than
  279. positioning a left-justified string by hand. So e.g., if right or
  280. centered justification was specified when alabel() was called by
  281. the user, the string as drawn on the device will have the same
  282. justification. This is particularly important for the Fig and AI
  283. drivers. Anything else would exasperate the user, even if the
  284. positioning is correct. */
  285. if ((_plotter->drawstate->font_type == PL_F_HERSHEY
  286. || _plotter->data->have_horizontal_justification)
  287. && simple_string (codestring))
  288. /* will use native justification, so don't perform initial offset */
  289. x_offset = 0.0;
  290. else
  291. /* will use x_offset to position by hand */
  292. {
  293. h_just = PL_JUST_LEFT;
  294. x_displacement_internal = 1.0;
  295. }
  296. /* Similarly, in simple cases use native vertical justification if
  297. it's available (very few types of Plotter support it). */
  298. if ((_plotter->drawstate->font_type == PL_F_HERSHEY
  299. || _plotter->data->have_vertical_justification)
  300. && simple_string (codestring))
  301. /* will use native justification, so don't perform initial offset */
  302. y_offset = 0.0;
  303. else
  304. /* will use y_offset to position by hand */
  305. v_just = PL_JUST_BASE;
  306. /* justification-related offsets we'll carry out */
  307. userdx = x_offset * overall_width;
  308. userdy = y_offset;
  309. /* label rotation angle in radians */
  310. theta = M_PI * _plotter->drawstate->text_rotation / 180.0;
  311. sintheta = sin (theta);
  312. costheta = cos (theta);
  313. /* perform both horizontal and vertical offsets; after this, current
  314. point will be on intended baseline of label */
  315. _plotter->drawstate->pos.x += costheta * userdx - sintheta * userdy;
  316. _plotter->drawstate->pos.y += sintheta * userdx + costheta * userdy;
  317. }
  318. /* save font name (will be restored at end) */
  319. {
  320. char *font_name;
  321. initial_font_name = _plotter->drawstate->font_name;
  322. font_name = (char *)_pl_xmalloc (1 + strlen (initial_font_name));
  323. strcpy (font_name, initial_font_name);
  324. _plotter->drawstate->font_name = font_name;
  325. }
  326. /* save font size too */
  327. initial_font_size = _plotter->drawstate->font_size;
  328. /* also save the font type, since for fonts of type PL_F_OTHER (e.g.,
  329. user-specified X Windows fonts not in our tables), switching fonts
  330. between substrings, e.g. to use the X Windows symbol font, may
  331. inconveniently switch _plotter->drawstate->font_type on us */
  332. initial_font_type = _plotter->drawstate->font_type;
  333. /* initialize current font index (font type presumably is not Hershey) */
  334. switch (_plotter->drawstate->font_type)
  335. {
  336. case PL_F_HERSHEY:
  337. current_font_index =
  338. (_pl_g_hershey_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
  339. break;
  340. case PL_F_POSTSCRIPT:
  341. current_font_index =
  342. (_pl_g_ps_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
  343. break;
  344. case PL_F_PCL:
  345. current_font_index =
  346. (_pl_g_pcl_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
  347. break;
  348. case PL_F_STICK:
  349. current_font_index =
  350. (_pl_g_stick_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
  351. break;
  352. case PL_F_OTHER:
  353. current_font_index = 1; /* `1' just means the font we start out with */
  354. break;
  355. default: /* shouldn't happen */
  356. return 0.0;
  357. }
  358. /* now loop through codestring, parsing each code in succession; when
  359. shifting to subscripts/superscripts we change the nominal font size,
  360. and retrieve a new font */
  361. cptr = codestring;
  362. while (*cptr) /* end when (unsigned short)0 is seen */
  363. {
  364. unsigned short c;
  365. c = *cptr;
  366. if (c & CONTROL_CODE)
  367. /* parse control code; many possibilities */
  368. {
  369. switch (c & ~CONTROL_CODE)
  370. {
  371. case C_BEGIN_SUBSCRIPT:
  372. width += SUBSCRIPT_DX * _plotter->drawstate->true_font_size;
  373. if (do_render)
  374. {
  375. _plotter->drawstate->pos.x +=
  376. (costheta * SUBSCRIPT_DX - sintheta * SUBSCRIPT_DY)
  377. * _plotter->drawstate->true_font_size;
  378. _plotter->drawstate->pos.y +=
  379. (sintheta * SUBSCRIPT_DX + costheta * SUBSCRIPT_DY)
  380. * _plotter->drawstate->true_font_size;
  381. }
  382. _plotter->drawstate->font_size *= SCRIPTSIZE;
  383. _pl_g_set_font (S___(_plotter));
  384. break;
  385. case C_BEGIN_SUPERSCRIPT :
  386. width += SUPERSCRIPT_DX * _plotter->drawstate->true_font_size;
  387. if (do_render)
  388. {
  389. _plotter->drawstate->pos.x +=
  390. (costheta * SUPERSCRIPT_DX - sintheta * SUPERSCRIPT_DY)
  391. * _plotter->drawstate->true_font_size;
  392. _plotter->drawstate->pos.y +=
  393. (sintheta * SUPERSCRIPT_DX + costheta * SUPERSCRIPT_DY)
  394. * _plotter->drawstate->true_font_size;
  395. }
  396. _plotter->drawstate->font_size *= SCRIPTSIZE;
  397. _pl_g_set_font (S___(_plotter));
  398. break;
  399. case C_END_SUBSCRIPT:
  400. width -= SUBSCRIPT_DX * _plotter->drawstate->true_font_size;
  401. _plotter->drawstate->font_size /= SCRIPTSIZE;
  402. _pl_g_set_font (S___(_plotter));
  403. if (do_render)
  404. {
  405. (_plotter->drawstate->pos).x -= (costheta * SUBSCRIPT_DX
  406. - sintheta * SUBSCRIPT_DY) * _plotter->drawstate->true_font_size;
  407. (_plotter->drawstate->pos).y -= (sintheta * SUBSCRIPT_DX
  408. + costheta * SUBSCRIPT_DY) * _plotter->drawstate->true_font_size;
  409. }
  410. break;
  411. case C_END_SUPERSCRIPT:
  412. width -= SUPERSCRIPT_DX * _plotter->drawstate->true_font_size;
  413. _plotter->drawstate->font_size /= SCRIPTSIZE;
  414. _pl_g_set_font (S___(_plotter));
  415. if (do_render)
  416. {
  417. (_plotter->drawstate->pos).x -= (costheta * SUPERSCRIPT_DX
  418. - sintheta * SUPERSCRIPT_DY) * _plotter->drawstate->true_font_size;
  419. (_plotter->drawstate->pos).y -= (sintheta * SUPERSCRIPT_DX
  420. + costheta * SUPERSCRIPT_DY) * _plotter->drawstate->true_font_size;
  421. }
  422. break;
  423. case C_PUSH_LOCATION:
  424. pushed_position_x = _plotter->drawstate->pos.x;
  425. pushed_position_y = _plotter->drawstate->pos.y;
  426. pushed_width = width;
  427. break;
  428. case C_POP_LOCATION:
  429. if (do_render)
  430. {
  431. _plotter->drawstate->pos.x = pushed_position_x;
  432. _plotter->drawstate->pos.y = pushed_position_y;
  433. }
  434. width = pushed_width;
  435. break;
  436. case C_RIGHT_ONE_EM:
  437. if (do_render)
  438. {
  439. _plotter->drawstate->pos.x += costheta * _plotter->drawstate->true_font_size;
  440. _plotter->drawstate->pos.y += sintheta * _plotter->drawstate->true_font_size;
  441. }
  442. width += _plotter->drawstate->true_font_size;
  443. break;
  444. case C_RIGHT_HALF_EM:
  445. if (do_render)
  446. {
  447. (_plotter->drawstate->pos).x += costheta * _plotter->drawstate->true_font_size / 2.0;
  448. (_plotter->drawstate->pos).y += sintheta * _plotter->drawstate->true_font_size / 2.0;
  449. }
  450. width += _plotter->drawstate->true_font_size / 2.0;
  451. break;
  452. case C_RIGHT_QUARTER_EM:
  453. if (do_render)
  454. {
  455. (_plotter->drawstate->pos).x += costheta * _plotter->drawstate->true_font_size / 4.0;
  456. (_plotter->drawstate->pos).y += sintheta * _plotter->drawstate->true_font_size / 4.0;
  457. }
  458. width += _plotter->drawstate->true_font_size / 4.0;
  459. break;
  460. case C_RIGHT_SIXTH_EM:
  461. if (do_render)
  462. {
  463. (_plotter->drawstate->pos).x += costheta * _plotter->drawstate->true_font_size / 6.0;
  464. (_plotter->drawstate->pos).y += sintheta * _plotter->drawstate->true_font_size / 6.0;
  465. }
  466. width += _plotter->drawstate->true_font_size / 6.0;
  467. break;
  468. case C_RIGHT_EIGHTH_EM:
  469. if (do_render)
  470. {
  471. (_plotter->drawstate->pos).x += costheta * _plotter->drawstate->true_font_size / 8.0;
  472. (_plotter->drawstate->pos).y += sintheta * _plotter->drawstate->true_font_size / 8.0;
  473. }
  474. width += _plotter->drawstate->true_font_size / 8.0;
  475. break;
  476. case C_RIGHT_TWELFTH_EM:
  477. if (do_render)
  478. {
  479. (_plotter->drawstate->pos).x += costheta * _plotter->drawstate->true_font_size / 12.0;
  480. (_plotter->drawstate->pos).y += sintheta * _plotter->drawstate->true_font_size / 12.0;
  481. }
  482. width += _plotter->drawstate->true_font_size / 8.0;
  483. break;
  484. /* Kludge: used only for \rn macro, i.e. in square roots, if
  485. the current font is a PS or PCL font. See g_cntrlify.c.
  486. If the font is a Hershey font, \rn is implemented
  487. differently, and for Stick fonts it isn't implemented at all.
  488. Painfully, the amount of shift differs depending whether
  489. this is a PS or a PCL typeface, since the `radicalex'
  490. characters are quite different. See comment in
  491. g_cntrlify.c. */
  492. case C_RIGHT_RADICAL_SHIFT:
  493. if (do_render)
  494. {
  495. if (_plotter->drawstate->font_type == PL_F_PCL)
  496. {
  497. (_plotter->drawstate->pos).x += costheta * _plotter->drawstate->true_font_size * PCL_RADICAL_WIDTH;
  498. (_plotter->drawstate->pos).y += sintheta * _plotter->drawstate->true_font_size * PCL_RADICAL_WIDTH;
  499. }
  500. else
  501. {
  502. (_plotter->drawstate->pos).x += costheta * _plotter->drawstate->true_font_size * PS_RADICAL_WIDTH;
  503. (_plotter->drawstate->pos).y += sintheta * _plotter->drawstate->true_font_size * PS_RADICAL_WIDTH;
  504. }
  505. /* I'm going to let this serve for the PCL case; it seems
  506. to work (i.e. yield more or less the correct width).
  507. We definitely don't want PCL_RADICAL_WIDTH here. */
  508. }
  509. width += _plotter->drawstate->true_font_size * PS_RADICAL_WIDTH;
  510. break;
  511. case C_LEFT_ONE_EM:
  512. if (do_render)
  513. {
  514. (_plotter->drawstate->pos).x -= costheta * _plotter->drawstate->true_font_size;
  515. (_plotter->drawstate->pos).y -= sintheta * _plotter->drawstate->true_font_size;
  516. }
  517. width -= _plotter->drawstate->true_font_size;
  518. break;
  519. case C_LEFT_HALF_EM:
  520. if (do_render)
  521. {
  522. (_plotter->drawstate->pos).x -= costheta * _plotter->drawstate->true_font_size / 2.0;
  523. (_plotter->drawstate->pos).y -= sintheta * _plotter->drawstate->true_font_size / 2.0;
  524. }
  525. width -= _plotter->drawstate->true_font_size / 2.0;
  526. break;
  527. case C_LEFT_QUARTER_EM:
  528. if (do_render)
  529. {
  530. (_plotter->drawstate->pos).x -= costheta * _plotter->drawstate->true_font_size / 4.0;
  531. (_plotter->drawstate->pos).y -= sintheta * _plotter->drawstate->true_font_size / 4.0;
  532. }
  533. width -= _plotter->drawstate->true_font_size / 4.0;
  534. break;
  535. case C_LEFT_SIXTH_EM:
  536. if (do_render)
  537. {
  538. (_plotter->drawstate->pos).x -= costheta * _plotter->drawstate->true_font_size / 6.0;
  539. (_plotter->drawstate->pos).y -= sintheta * _plotter->drawstate->true_font_size / 6.0;
  540. }
  541. width -= _plotter->drawstate->true_font_size / 6.0;
  542. break;
  543. case C_LEFT_EIGHTH_EM:
  544. if (do_render)
  545. {
  546. (_plotter->drawstate->pos).x -= costheta * _plotter->drawstate->true_font_size / 8.0;
  547. (_plotter->drawstate->pos).y -= sintheta * _plotter->drawstate->true_font_size / 8.0;
  548. }
  549. width -= _plotter->drawstate->true_font_size / 8.0;
  550. break;
  551. case C_LEFT_TWELFTH_EM:
  552. if (do_render)
  553. {
  554. (_plotter->drawstate->pos).x -= costheta * _plotter->drawstate->true_font_size / 12.0;
  555. (_plotter->drawstate->pos).y -= sintheta * _plotter->drawstate->true_font_size / 12.0;
  556. }
  557. width -= _plotter->drawstate->true_font_size / 8.0;
  558. break;
  559. /* Kludge: used only for \rn macro, i.e. in square roots.
  560. Painfully, the amount of shift differs depending whether
  561. this is a PS or a PCL typeface, since the `radicalex'
  562. characters are quite different. See comment above, and
  563. comment in g_cntrlify.c. */
  564. case C_LEFT_RADICAL_SHIFT:
  565. if (do_render)
  566. {
  567. if (_plotter->drawstate->font_type == PL_F_PCL)
  568. {
  569. (_plotter->drawstate->pos).x -= costheta * _plotter->drawstate->true_font_size * PCL_RADICAL_WIDTH;
  570. (_plotter->drawstate->pos).y -= sintheta * _plotter->drawstate->true_font_size * PCL_RADICAL_WIDTH;
  571. }
  572. else
  573. {
  574. (_plotter->drawstate->pos).x -= costheta * _plotter->drawstate->true_font_size * PS_RADICAL_WIDTH;
  575. (_plotter->drawstate->pos).y -= sintheta * _plotter->drawstate->true_font_size * PS_RADICAL_WIDTH;
  576. }
  577. }
  578. /* see comment in C_RIGHT_RADICAL_SHIFT case, above */
  579. width -= _plotter->drawstate->true_font_size * PS_RADICAL_WIDTH;
  580. break;
  581. /* unrecognized control code */
  582. default:
  583. break;
  584. }
  585. cptr++; /* on to next element of codestring */
  586. }
  587. else /* an ordinary character, with font annotation */
  588. {
  589. unsigned char *s, *sptr;
  590. int new_font_index = (c >> FONT_SHIFT) & ONE_BYTE;
  591. /* perform font switching if necessary */
  592. if (new_font_index != current_font_index)
  593. {
  594. /* We check initial_font_type, not _drawstate->font_type,
  595. because the latter gets trashed if e.g. (1) we start out
  596. with a font of type PL_F_OTHER, e.g. a user-specified X
  597. Windows font not in our tables, and (2) we switch to the X
  598. Windows Symbol font in mid-string, since that font is of
  599. type PL_F_POSTSCRIPT. */
  600. switch (initial_font_type)
  601. {
  602. case PL_F_HERSHEY:
  603. free ((char *)_plotter->drawstate->font_name);
  604. {
  605. char *font_name;
  606. font_name =
  607. (char *)_pl_xmalloc(1 + strlen (_pl_g_hershey_font_info[new_font_index].name));
  608. strcpy (font_name, _pl_g_hershey_font_info[new_font_index].name);
  609. _plotter->drawstate->font_name = font_name;
  610. }
  611. break;
  612. case PL_F_POSTSCRIPT:
  613. free ((char *)_plotter->drawstate->font_name);
  614. {
  615. char *font_name;
  616. font_name =
  617. (char *)_pl_xmalloc(1 + strlen (_pl_g_ps_font_info[new_font_index].ps_name));
  618. strcpy (font_name, _pl_g_ps_font_info[new_font_index].ps_name);
  619. _plotter->drawstate->font_name = font_name;
  620. }
  621. break;
  622. case PL_F_PCL:
  623. free ((char *)_plotter->drawstate->font_name);
  624. {
  625. char *font_name;
  626. font_name =
  627. (char *)_pl_xmalloc(1 + strlen (_pl_g_pcl_font_info[new_font_index].ps_name));
  628. strcpy (font_name, _pl_g_pcl_font_info[new_font_index].ps_name);
  629. _plotter->drawstate->font_name = font_name;
  630. }
  631. break;
  632. case PL_F_STICK:
  633. free ((char *)_plotter->drawstate->font_name);
  634. {
  635. char *font_name;
  636. font_name =
  637. (char *)_pl_xmalloc(1 + strlen (_pl_g_stick_font_info[new_font_index].ps_name));
  638. strcpy (font_name, _pl_g_stick_font_info[new_font_index].ps_name);
  639. _plotter->drawstate->font_name = font_name;
  640. }
  641. break;
  642. case PL_F_OTHER:
  643. free ((char *)_plotter->drawstate->font_name);
  644. {
  645. char *font_name;
  646. if (new_font_index == 0) /* symbol font */
  647. {
  648. font_name =
  649. (char *)_pl_xmalloc(1 + strlen (SYMBOL_FONT));
  650. strcpy (font_name, SYMBOL_FONT);
  651. }
  652. else
  653. /* Currently, only alternative to zero (symbol font) is
  654. 1, i.e. restore font we started out with. */
  655. {
  656. font_name =
  657. (char *)_pl_xmalloc(1 + strlen (initial_font_name));
  658. strcpy (font_name, initial_font_name);
  659. }
  660. _plotter->drawstate->font_name = font_name;
  661. }
  662. break;
  663. default: /* shouldn't happen */
  664. break;
  665. }
  666. _pl_g_set_font (S___(_plotter));
  667. current_font_index = new_font_index;
  668. }
  669. /* extract substring consisting of characters in the same font */
  670. sptr = s
  671. = (unsigned char *)_pl_xmalloc ((4 * _codestring_len (cptr) + 1) * sizeof(char));
  672. while (*cptr
  673. && (*cptr & CONTROL_CODE) == 0
  674. && ((*cptr >> FONT_SHIFT) & ONE_BYTE) == current_font_index)
  675. *sptr++ = (*cptr++) & ONE_BYTE;
  676. *sptr = (unsigned char)'\0';
  677. /* Compute width of single-font substring in user units, add it.
  678. Either render or not, as requested. */
  679. added_width = _pl_g_render_simple_string (R___(_plotter)
  680. s, do_render, h_just, v_just);
  681. width += added_width;
  682. if (do_render)
  683. {
  684. /* resposition due to rendering of label */
  685. _plotter->drawstate->pos.x +=
  686. costheta * x_displacement_internal * added_width;
  687. _plotter->drawstate->pos.y +=
  688. sintheta * x_displacement_internal * added_width;
  689. }
  690. free (s);
  691. }
  692. }
  693. /* free the codestring (no memory leaks please) */
  694. free (codestring);
  695. /* restore initial font */
  696. free ((char *)_plotter->drawstate->font_name);
  697. _plotter->drawstate->font_name = initial_font_name;
  698. _plotter->drawstate->font_size = initial_font_size;
  699. _pl_g_set_font (S___(_plotter));
  700. if (do_render)
  701. {
  702. /* restore position to what it was before printing label */
  703. _plotter->drawstate->pos.x = initial_position_x;
  704. _plotter->drawstate->pos.y = initial_position_y;
  705. /* shift due to printing of label */
  706. _plotter->drawstate->pos.x += costheta * x_displacement * overall_width;
  707. _plotter->drawstate->pos.y += sintheta * x_displacement * overall_width;
  708. }
  709. return width;
  710. }
  711. /* Compute the width of an ordinary single-font string (no escape sequences
  712. to switch fonts or position subscripts and superscripts, etc.), and also
  713. render it, if requested.
  714. The rendering only takes place if the do_render flag is set. If it is
  715. not, the width is returned only (the h_just and v_just arguments being
  716. ignored).
  717. The font type here is arbitrary (either non-Hershey or non-Hershey).
  718. That makes this callable by _pl_g_render_non_hershey_string(), inside
  719. which the font can switch from non-Hershey to Hershey. See comments
  720. above.
  721. This is never called to do rendering unless the Plotter can handle the
  722. specified types of justification. */
  723. /* ARGS: h_just,v_just are PL_JUST_{LEFT|CENTER|RIGHT}, PL_JUST_{TOP etc.} */
  724. double
  725. _pl_g_render_simple_string (R___(Plotter *_plotter) const unsigned char *s, bool do_render, int h_just, int v_just)
  726. {
  727. double width;
  728. if (_plotter->drawstate->font_type == PL_F_HERSHEY)
  729. /* Use our internal Hershey width-computation or rendering routine.
  730. But they do more than is needed: they handle escape sequences too,
  731. via their own controlification. So we escape all backslashes.
  732. More importantly, we work around the fact that unlike the
  733. Plotter-specific `paint_text_string' rendering routines,
  734. _pl_g_alabel_hershey() shifts the current graphics cursor
  735. position, since it draws Hershey characters as polygonal paths. */
  736. {
  737. unsigned char *t;
  738. t = esc_esc_string (s);
  739. width = _pl_g_flabelwidth_hershey (R___(_plotter) t);
  740. if (do_render)
  741. {
  742. plPoint initial_pos;
  743. initial_pos = _plotter->drawstate->pos; /* save */
  744. _pl_g_alabel_hershey (R___(_plotter) t, h_just, v_just);
  745. _plotter->drawstate->pos = initial_pos; /* restore */
  746. }
  747. free (t);
  748. }
  749. else
  750. /* not a Hershey font */
  751. {
  752. if (do_render)
  753. width = _plotter->paint_text_string (R___(_plotter) s, h_just, v_just);
  754. else
  755. width = _plotter->get_text_width (R___(_plotter) s);
  756. }
  757. return width;
  758. }
  759. /* A generic internal method that computes the width (total delta x) of a
  760. character string to be rendered in the currently selected font, so long
  761. as it is non-Hershey. It accesses the font database in g_fontdb.c.
  762. The string is just a string (no control codes, font switchings, font
  763. annotations, etc.).
  764. This supports the 35 standard PS fonts, the 45 standard PCL fonts, and
  765. our Stick fonts (i.e. device-resident HP fonts). It does not support
  766. `other' fonts, which some Plotters support; for such fonts, it returns
  767. 0.0. So Plotters that support `other' fonts, such as XDrawable and X
  768. Plotters, will need to override this, in toto. */
  769. double
  770. _pl_g_get_text_width (R___(Plotter *_plotter) const unsigned char *s)
  771. {
  772. int index;
  773. int width = 0;
  774. double swidth = 0.0;
  775. unsigned char current_char;
  776. int master_font_index; /* index into master table */
  777. double retval;
  778. switch (_plotter->drawstate->font_type)
  779. {
  780. case PL_F_POSTSCRIPT:
  781. /* compute font index in master PS font table */
  782. master_font_index =
  783. (_pl_g_ps_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
  784. for (index=0; s[index]!='\0'; index++)
  785. {
  786. current_char = (unsigned int)s[index];
  787. width
  788. += ((_pl_g_ps_font_info[master_font_index]).width)[current_char];
  789. }
  790. retval = _plotter->drawstate->true_font_size * (double)width / 1000.0;
  791. break;
  792. case PL_F_PCL:
  793. /* compute font index in master PCL font table */
  794. master_font_index =
  795. (_pl_g_pcl_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
  796. for (index=0; s[index]!='\0'; index++)
  797. {
  798. current_char = (unsigned int)s[index];
  799. width
  800. += ((_pl_g_pcl_font_info[master_font_index]).width)[current_char];
  801. }
  802. retval = _plotter->drawstate->true_font_size * (double)width / 1000.0;
  803. break;
  804. case PL_F_STICK:
  805. /* compute font index in master table of device-resident HP fonts */
  806. master_font_index =
  807. (_pl_g_stick_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
  808. /* The width tables for Stick fonts (in g_fontdb.c) give character
  809. widths in terms of abstract raster units (the grid on which the
  810. character was defined). Font size is twice the width of the
  811. abstract raster (by definition). So in principle, to compute the
  812. width of a character string, we just need to add the character
  813. widths together, and normalize using the font size.
  814. It's more complicated than that, in part because our width tables
  815. for Stick fonts, unlike those for PCL fonts, contain the bounding
  816. box widths rather than the character cell widths. Also, for
  817. agreement with the PS rendering convention, we need to add a bit
  818. of leading whitespace, and a bit of trailing whitespace. There is
  819. also the key issue of kerning: full-featured HP-GL and HP-GL/2
  820. plotters normally kern text strings in any Stick font via
  821. in-device kerning tables, although PCL devices such as LaserJets,
  822. when doing HP-GL/2 emulation, apparently don't.
  823. So there are two cases.
  824. 1. The case of no device-resident kerning, which is the case for
  825. PCL devices such as LaserJets that do (lamebrained) HP-GL/2
  826. emulation. Much as for a string rendered in a PCL font, the true
  827. width (character cell width) of a character equals
  828. offset + bounding box width + offset
  829. In fact, offset is independent of character; it depends only on
  830. the font. So the string width we compute for a string consisting
  831. of n characters is:
  832. offset + bb width #1 + offset
  833. + offset + bb width #2 + offset
  834. + ...
  835. + offset + bb width #n + offset
  836. The first and last offsets in this formula provide the leading and
  837. trailing bits of whitespace.
  838. 2. The case of device-resident kerning, according to HP's spacing
  839. tables (our copies of the device spacing tables are in
  840. g_fontd2.c). The string width we return is:
  841. offset + bb width #1 + spacing(1,2) + bb width #2 + spacing(2,3)
  842. + ... + spacing(n-1,n) + bb width #n + offset
  843. where spacing(1,2) is the spacing between characters 1 and 2, etc.
  844. The basic reference for HP's kerning scheme for Stick fonts is
  845. "Firmware Determines Plotter Personality", by L. W. Hennessee,
  846. A. K. Frankel, M. A. Overton, and R. B. Smith, Hewlett-Packard
  847. Journal, Nov. 1981, pp. 16-25. Every character belongs to a `row
  848. class' and a `column class', i.e., `right edge class' and `left
  849. edge class'. Any spacing table is indexed by row class and column
  850. class.
  851. [What HP later did in their LaserJets, which don't do kerning of
  852. Stick fonts, is apparently a degenerate case of this setup, with
  853. all the inter-character spacings changed to 2*offset.]
  854. A couple of additional comments on kerning:
  855. Comment A. The width of the space character (ASCII SP) is 3/2
  856. times as large if kerning is used, as it is in in the absence of
  857. kerning (e.g., in a LaserJet). Without kerning, it's 0.5 times
  858. the font size, like any other character, but in devices with
  859. kerning, it's 0.75 times the font size. That sounds like a major
  860. difference, but the use of kerning more or less compensates for
  861. it. See comment in code below.
  862. Comment B. Our homebrewed ANK fonts consist of a lower half
  863. encoded according to JIS ASCII, and an upper half encoded
  864. according to the half-width Katakana encoding. These two halves
  865. are different HP 7-bit character sets and use different spacing
  866. tables, since their abstract raster widths differ (42 and 45,
  867. respectively). HP's convention is apparently that if, between
  868. character k and character k+1, there's a switch between spacing
  869. tables and spacing(k,k+1) can't be computed via lookup, then
  870. bb width #k + spacing(k,k+1) + bb width #(k+1)
  871. should be replaced by
  872. width_of_space_character + bb width #(k+1)
  873. That's the way we do it. */
  874. if (_plotter->data->kern_stick_fonts)
  875. /* have device-resident kerning, so we compute inter-character
  876. spacing from spacing tables in g_fontd2.c, which we hope match
  877. the device-resident tables */
  878. {
  879. const struct plStickFontSpacingTableStruct *ktable_lower, *ktable_upper;
  880. const struct plStickCharSpacingTableStruct *stable_lower, *stable_upper;
  881. const short *lower_spacing, *upper_spacing; /* spacing tables */
  882. int lower_cols, upper_cols; /* table sizes */
  883. const char *lower_char_to_row, *lower_char_to_col; /* char to pos */
  884. const char *upper_char_to_row, *upper_char_to_col; /* char to pos */
  885. bool halves_use_different_tables; /* upper/lower spacing tables differ?*/
  886. /* kerning table and spacing table structs, for each font half */
  887. ktable_lower = &(_pl_g_stick_kerning_tables[_pl_g_stick_font_info[master_font_index].kerning_table_lower]);
  888. ktable_upper = &(_pl_g_stick_kerning_tables[_pl_g_stick_font_info[master_font_index].kerning_table_upper]);
  889. stable_lower = &(_pl_g_stick_spacing_tables[ktable_lower->spacing_table]);
  890. stable_upper = &(_pl_g_stick_spacing_tables[ktable_upper->spacing_table]);
  891. /* do font halves use different spacing tables (e.g. ANK fonts)? */
  892. halves_use_different_tables
  893. = (stable_lower != stable_upper ? true : false);
  894. /* numbers of columns in each of the two spacing tables (number of
  895. rows isn't used) */
  896. lower_cols = stable_lower->cols;
  897. upper_cols = stable_upper->cols;
  898. /* arrays (size 128), mapping character to row/column of spacing
  899. table */
  900. lower_char_to_row = ktable_lower->row;
  901. lower_char_to_col = ktable_lower->col;
  902. upper_char_to_row = ktable_upper->row;
  903. upper_char_to_col = ktable_upper->col;
  904. /* spacing tables for each half of the font */
  905. lower_spacing = stable_lower->kerns;
  906. upper_spacing = stable_upper->kerns;
  907. /* add an initial bit of whitespace (an `offset'), to make the
  908. Stick font rendering agree with the PS font rendering
  909. convention */
  910. swidth
  911. += (((double)(_pl_g_stick_font_info[master_font_index].offset))
  912. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_lower));
  913. /* loop through chars in label */
  914. for (index=0; s[index]!='\0'; index++)
  915. {
  916. unsigned char c, d;
  917. c = (unsigned int)s[index];
  918. if (c < 0x80)
  919. /* lower half */
  920. {
  921. double spacefactor, char_width;
  922. /* Our width tables in g_fontd2.c are most appropriate
  923. for LaserJets doing HP-GL/2 emulation, rather than for
  924. true HP-GL/2. Major difference is that in true
  925. HP-GL/2, width of space character is 3/2 times larger,
  926. e.g. in the Arc font it is 42 abstract raster units
  927. rather than 28. (This difference is partly
  928. compensated for by true HP-GL/2 having kerning, unlike
  929. LaserJets' HP-GL/2 emulation.) */
  930. if (c == ' ')
  931. spacefactor = 1.5;
  932. else
  933. spacefactor = 1.0;
  934. /* add width of char */
  935. char_width
  936. = (((double)(_pl_g_stick_font_info[master_font_index].width[c]))
  937. * spacefactor
  938. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_lower));
  939. swidth += char_width;
  940. if ((d = (unsigned int)s[index+1]) != '\0')
  941. /* current char is not final char in string, so add spacing
  942. between it and the next char */
  943. {
  944. int row, col;
  945. int spacing;
  946. /* compute row class for current character, i.e., its
  947. `right edge class' */
  948. row = lower_char_to_row[c];
  949. /* compute and add spacing; if we switch from lower
  950. to upper half here, and upper half uses a
  951. different spacing table, just replace width of c
  952. by width of ` ' (see explanation above) */
  953. if (d < 0x80)
  954. {
  955. col = lower_char_to_col[d];
  956. spacing = lower_spacing[row * lower_cols + col];
  957. }
  958. else if (!halves_use_different_tables)
  959. {
  960. col = upper_char_to_col[d - 0x80];
  961. spacing = lower_spacing[row * lower_cols + col];
  962. }
  963. else if (c == ' ' || (d == ' ' + 0x80))
  964. /* space characters have no kerning */
  965. spacing = 0;
  966. else
  967. /* c -> ` ', see above. */
  968. spacing =
  969. - IROUND(spacefactor * _pl_g_stick_font_info[master_font_index].width[c])
  970. + IROUND(1.5 * _pl_g_stick_font_info[master_font_index].width[' ']);
  971. swidth
  972. += ((double)spacing)
  973. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_lower);
  974. }
  975. }
  976. else
  977. /* upper half */
  978. {
  979. double spacefactor, char_width;
  980. if (c == ' ' + 0x80) /* i.e. `unbreakable SP' */
  981. spacefactor = 1.5;
  982. else
  983. spacefactor = 1.0;
  984. /* add width of char */
  985. char_width
  986. = (((double)(_pl_g_stick_font_info[master_font_index].width[c]))
  987. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_upper));
  988. swidth += char_width;
  989. if ((d = (unsigned int)s[index+1]) != '\0')
  990. /* current char is not final char in string, so add spacing
  991. between it and the next char */
  992. {
  993. int row, col;
  994. int spacing;
  995. /* compute row class for current character, i.e., its
  996. `right edge class' */
  997. row = upper_char_to_row[c - 0x80];
  998. /* compute and add spacing; if we switch from upper
  999. to lower half here, and lower half uses a
  1000. different spacing table, just replace width of c
  1001. by width of ` ' (see explanation above) */
  1002. if (d >= 0x80)
  1003. {
  1004. col = upper_char_to_col[d - 0x80];
  1005. spacing = upper_spacing[row * upper_cols + col];
  1006. }
  1007. else if (!halves_use_different_tables)
  1008. {
  1009. col = lower_char_to_col[d];
  1010. spacing = upper_spacing[row * upper_cols + col];
  1011. }
  1012. else if ((c == ' ' + 0x80) || d == ' ')
  1013. /* space characters have no kerning */
  1014. spacing = 0;
  1015. else
  1016. /* c -> ` ', see above. */
  1017. spacing =
  1018. - IROUND(spacefactor * _pl_g_stick_font_info[master_font_index].width[c])
  1019. + IROUND(1.5 * _pl_g_stick_font_info[master_font_index].width[' ']);
  1020. swidth
  1021. += ((double)spacing)
  1022. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_upper);
  1023. }
  1024. }
  1025. }
  1026. /* add a trailing bit of whitespace (an `offset'), to make the
  1027. Stick font rendering agree with the PS rendering convention */
  1028. swidth
  1029. += (((double)(_pl_g_stick_font_info[master_font_index].offset))
  1030. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_lower));
  1031. }
  1032. else
  1033. /* No device-resident kerning; this is the case, e.g., for PCL5
  1034. devices doing their (lamebrained) HP-GL/2 emulation. We use a
  1035. fixed offset between each pair of characters, which is the way
  1036. HP LaserJets. We also use this offset as the width of the `bit
  1037. of whitespace' that we add at beginning and end of label. */
  1038. {
  1039. /* loop through chars in label */
  1040. for (index=0; s[index]!='\0'; index++)
  1041. {
  1042. unsigned char c;
  1043. c = (unsigned int)s[index];
  1044. #if 0
  1045. /* COMMENTED OUT BECAUSE IT WAS IDIOTIC */
  1046. /* kludge around HP's convention for centered marker symbols
  1047. (poor fellows ain't got no width a-tall) */
  1048. if (IS_MATH_FONT(master_font_index) && IS_CENTERED_SYMBOL(c))
  1049. continue;
  1050. #endif
  1051. if (c < 0x80)
  1052. /* lower half */
  1053. {
  1054. swidth
  1055. += (((double)(_pl_g_stick_font_info[master_font_index].offset))
  1056. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_lower));
  1057. swidth
  1058. += (((double)(_pl_g_stick_font_info[master_font_index].width[c]))
  1059. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_lower));
  1060. swidth
  1061. += (((double)(_pl_g_stick_font_info[master_font_index].offset))
  1062. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_lower));
  1063. }
  1064. else
  1065. /* upper half */
  1066. {
  1067. swidth
  1068. += (((double)(_pl_g_stick_font_info[master_font_index].offset))
  1069. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_upper));
  1070. swidth
  1071. += (((double)(_pl_g_stick_font_info[master_font_index].width[c]))
  1072. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_upper));
  1073. swidth
  1074. += (((double)(_pl_g_stick_font_info[master_font_index].offset))
  1075. /(2 * _pl_g_stick_font_info[master_font_index].raster_width_upper));
  1076. }
  1077. }
  1078. }
  1079. /* normalize: use font size to convert width to user units */
  1080. retval = _plotter->drawstate->true_font_size * (double)swidth;
  1081. break;
  1082. case PL_F_OTHER:
  1083. retval = 0.0;
  1084. break;
  1085. default: /* shouldn't happen */
  1086. retval = 0.0;
  1087. break;
  1088. }
  1089. return retval;
  1090. }
  1091. /* test whether a controlified string is simple in the sense that it
  1092. consists of characters in a single font, and no control codes */
  1093. static bool
  1094. simple_string (const unsigned short *codestring)
  1095. {
  1096. const unsigned short *cptr = codestring;
  1097. unsigned short c, d;
  1098. int font_index;
  1099. if (*codestring == 0)
  1100. return true;
  1101. c = *codestring;
  1102. if (c & CONTROL_CODE)
  1103. return false;
  1104. font_index = (c >> FONT_SHIFT) & ONE_BYTE;
  1105. while ((d = *cptr++) != 0)
  1106. {
  1107. int local_font_index;
  1108. if (d & CONTROL_CODE)
  1109. return false;
  1110. local_font_index = (d >> FONT_SHIFT) & ONE_BYTE;
  1111. if (local_font_index != font_index)
  1112. return false;
  1113. }
  1114. return true;
  1115. }
  1116. /* Removes all characters not in the ISO-8859-? character sets from a
  1117. string. I.e. remove control characters (characters in the range 0x01
  1118. to 0x1F, including LF and CR, and also 0x7f, i.e. DEL). We take
  1119. characters in the range 0x80 to 0x9F to be control characters too, since
  1120. they are undefined in the ISO character sets.
  1121. Actually, in PS fonts (with ISO encoding vector) they encode accents;
  1122. and in the encoding used in Fig files, they encode a few special
  1123. characters not found elsewhere. But the interpretation of the
  1124. 0x80--0x9F range is device dependent, and our goal is device
  1125. independence, so away the range goes. */
  1126. #define GOOD_ISO(c) (((c >= 0x20) && (c <= 0x7E)) || ((c >= 0xA0) && (c <= 0xFF)))
  1127. static bool
  1128. clean_iso_string (unsigned char *s)
  1129. {
  1130. bool was_clean = true;
  1131. unsigned char *t;
  1132. for (t = s; *s; s++)
  1133. {
  1134. if (GOOD_ISO(*s))
  1135. {
  1136. *t = *s;
  1137. t++;
  1138. }
  1139. else
  1140. was_clean = false;
  1141. }
  1142. *t = (unsigned char)'\0';
  1143. return was_clean;
  1144. }
  1145. /* escape all backslashes in a string; the returned string is allocated on
  1146. the heap and can be freed. */
  1147. static unsigned char *
  1148. esc_esc_string (const unsigned char *s)
  1149. {
  1150. const unsigned char *sptr;
  1151. unsigned char *t, *tptr;
  1152. t = (unsigned char *)_pl_xmalloc (2 * strlen ((char *)s) + 1);
  1153. sptr = s;
  1154. tptr = t;
  1155. while (*sptr)
  1156. {
  1157. *tptr++ = *sptr;
  1158. if (*sptr == '\\')
  1159. *tptr++ = *sptr;
  1160. sptr++;
  1161. }
  1162. *tptr = '\0';
  1163. return t;
  1164. }
  1165. /* Versions of the falabel() method that do nothing; derived (non-generic)
  1166. Plotters must override them if they wish to use them. */
  1167. void
  1168. _pl_g_paint_text_string_with_escapes (R___(Plotter *_plotter) const unsigned char *s, int h_just, int v_just)
  1169. {
  1170. return;
  1171. }
  1172. double
  1173. _pl_g_paint_text_string (R___(Plotter *_plotter) const unsigned char *s, int h_just, int v_just)
  1174. {
  1175. return 0.0;
  1176. }