x_text.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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 XDrawablePlotter (and XPlotter) version of the
  16. low-level paint_text_string() method, which is called to plot a label in
  17. the current (non-Hershey) font, at the current fontsize and textangle.
  18. The label is just a string: no control codes (font switching or
  19. sub/superscripts). The width of the string in user units is returned.
  20. This version not does support center-justification and right
  21. justification; only the default left-justification. That is all
  22. right, since justification is handled at a higher level. */
  23. /* This file also contains the XDrawablePlotter (and XPlotter) version of
  24. the flabelwidth_other() method, which is called to compute the width, in
  25. user coordinates, of a label. */
  26. #include "sys-defines.h"
  27. #include "extern.h"
  28. /* When this is called in g_alabel.c, the X font has already been
  29. retrieved, in whole or in part (by calling "_set_font()", which in turn
  30. calls "_plotter->retrieve_font()", which is bound to the
  31. _pl_x_retrieve_font() routine in x_retrieve.c). I.e., whatever portion of
  32. the X font was required to be retrieved in order to return font metrics,
  33. has previously been retrieved.
  34. To retrieve a larger part, we call _pl_x_retrieve_font() again. But this
  35. time, we pass the label to be rendered to _pl_x_retrieve_font() as a
  36. "hint", i.e., as the x_label data member of (the driver-specific part
  37. of) the drawing state. That tells _pl_x_retrieve_font how much more of the
  38. font to retrieve. This scheme is a hack, but it works (and doesn't
  39. violate layering). */
  40. #include "x_afftext.h"
  41. double
  42. _pl_x_paint_text_string (R___(Plotter *_plotter) const unsigned char *s, int h_just, int v_just)
  43. {
  44. const char *saved_font_name;
  45. char *temp_font_name;
  46. bool ok;
  47. double x, y;
  48. double width = 0.0; /* width of string in user units */
  49. double rot[4]; /* user-frame rotation matrix */
  50. double a[4]; /* transformation matrix for XAffDrawString() */
  51. int i, ix, iy;
  52. /* sanity check; this routine supports only baseline positioning */
  53. if (v_just != PL_JUST_BASE)
  54. return 0.0;
  55. /* similarly for horizontal justification */
  56. if (h_just != PL_JUST_LEFT)
  57. return 0.0;
  58. if (*s == (unsigned char)'\0')
  59. return 0.0;
  60. /* Do retrieval, fill in the X-specific field x_font_struct of the
  61. drawing state. (We've previously retrieved a small subset of the
  62. font, to obtain metrics used for text positioning, as mentioned above;
  63. so retrieving a larger portion should go smoothly.)
  64. We retrieve not `font_name' but rather `true_font_name', because the
  65. latter may have been what was retrieved, if a default X font had to be
  66. substituted; see g_retrieve.c. */
  67. if (_plotter->drawstate->true_font_name == NULL) /* shouldn't happen */
  68. return 0.0;
  69. saved_font_name = _plotter->drawstate->font_name;
  70. temp_font_name =
  71. (char *)_pl_xmalloc (strlen (_plotter->drawstate->true_font_name) + 1);
  72. strcpy (temp_font_name, _plotter->drawstate->true_font_name);
  73. _plotter->drawstate->font_name = temp_font_name;
  74. _plotter->drawstate->x_label = s; /* pass label hint */
  75. ok = _pl_x_retrieve_font (S___(_plotter));
  76. _plotter->drawstate->x_label = NULL; /* restore label hint to default */
  77. _plotter->drawstate->font_name = saved_font_name;
  78. free (temp_font_name);
  79. if (!ok) /* shouldn't happen */
  80. return 0.0;
  81. /* set font in GC used for drawing (the other GC, used for filling, is
  82. left alone) */
  83. XSetFont (_plotter->x_dpy, _plotter->drawstate->x_gc_fg,
  84. _plotter->drawstate->x_font_struct->fid);
  85. /* select our pen color as foreground color in X GC used for drawing */
  86. _pl_x_set_pen_color (S___(_plotter));
  87. /* compute position in device coordinates */
  88. x = XD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y);
  89. y = YD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y);
  90. /* X11 protocol OOB check */
  91. ix = IROUND(x);
  92. iy = IROUND(y);
  93. if (X_OOB_INT(ix) || X_OOB_INT(iy))
  94. {
  95. _plotter->warning (R___(_plotter)
  96. "not drawing a text string that is positioned too far for X11");
  97. return 0.0;
  98. }
  99. /* Draw the text string by calling XAffDrawString() in x_afftext.c, which
  100. operates by affinely transform a bitmap generated by XDrawString() in
  101. the following way: it pulls it back from the server as an image,
  102. transforms the image, and then sends the image back to the server. */
  103. /* First, compute a 2x2 matrix a[] that would, in the jargon of the
  104. matrix extension to the XLFD (X Logical Font Description) scheme, be
  105. called a `pixel matrix'. It specifies how XAffDrawAffString should
  106. `anamorphically transform' the text bitmap produced by XDrawString(),
  107. to yield the bitmap we want. It's essentially the product of (i) the
  108. user-frame text rotation matrix, and (ii) the user_space->device_space
  109. transformation matrix. But see additional comments below. */
  110. /* user-frame rotation matrix */
  111. rot[0] = cos (M_PI * _plotter->drawstate->text_rotation / 180.0);
  112. rot[1] = sin (M_PI * _plotter->drawstate->text_rotation / 180.0);
  113. rot[2] = - sin (M_PI * _plotter->drawstate->text_rotation / 180.0);
  114. rot[3] = cos (M_PI * _plotter->drawstate->text_rotation / 180.0);
  115. /* Compute matrix product. But note flipped-y convention affecting a[1]
  116. and a[3]. Sign flipping is because the pixel matrix (as used in the
  117. XLFD matrix extension and hence, for consistency, by our code by
  118. XAffDrawAffString()) is expressed with respect to a right-handed
  119. coordinate system, in which y grows upward, rather than X11's default
  120. left-handed coordinate system, in which y grows downward. */
  121. a[0] = (rot[0] * _plotter->drawstate->transform.m[0]
  122. + rot[1] * _plotter->drawstate->transform.m[2]);
  123. a[1] = - (rot[0] * _plotter->drawstate->transform.m[1]
  124. + rot[1] * _plotter->drawstate->transform.m[3]);
  125. a[2] = (rot[2] * _plotter->drawstate->transform.m[0]
  126. + rot[3] * _plotter->drawstate->transform.m[2]);
  127. a[3] = - (rot[2] * _plotter->drawstate->transform.m[1]
  128. + rot[3] * _plotter->drawstate->transform.m[3]);
  129. /* Apply an overall scaling. We want the text string to appear at a
  130. certain font size in the user frame; and the font that XDrawString
  131. will use was retrieved at a certain pixel size in the device frame.
  132. So we compensate on both sides, so to speak. We multiply by
  133. true_font_size / x_font_pixel_size, where the numerator refers to the
  134. user frame, and the denominator to the device frame. */
  135. for (i = 0; i < 4; i++)
  136. a[i] = a[i]
  137. * (_plotter->drawstate->true_font_size / _plotter->drawstate->x_font_pixel_size);
  138. if (_plotter->x_double_buffering != X_DBL_BUF_NONE)
  139. /* double buffering, have a `x_drawable3' to draw into */
  140. XAffDrawAffString (_plotter->x_dpy, _plotter->x_drawable3,
  141. _plotter->drawstate->x_gc_fg,
  142. _plotter->drawstate->x_font_struct,
  143. ix, iy, a, (char *)s);
  144. else
  145. {
  146. /* not double buffering, have no `x_drawable3' */
  147. if (_plotter->x_drawable1)
  148. XAffDrawAffString (_plotter->x_dpy, _plotter->x_drawable1,
  149. _plotter->drawstate->x_gc_fg,
  150. _plotter->drawstate->x_font_struct,
  151. ix, iy, a, (char *)s);
  152. if (_plotter->x_drawable2)
  153. XAffDrawAffString (_plotter->x_dpy, _plotter->x_drawable2,
  154. _plotter->drawstate->x_gc_fg,
  155. _plotter->drawstate->x_font_struct,
  156. ix, iy, a, (char *)s);
  157. }
  158. /* compute width of just-drawn string in user units */
  159. width = (((XTextWidth (_plotter->drawstate->x_font_struct,
  160. (char *)s,
  161. (int)(strlen((char *)s)))
  162. *_plotter->drawstate->true_font_size))
  163. / _plotter->drawstate->x_font_pixel_size);
  164. /* maybe flush X output buffer and handle X events (a no-op for
  165. XDrawablePlotters, which is overridden for XPlotters) */
  166. _maybe_handle_x_events (S___(_plotter));
  167. return width;
  168. }
  169. /* Compute width, in user coordinates, of label in the currently selected
  170. font (no escape sequences!). Current font is assumed to be a
  171. non-Hershey font (so we have an X font structure for it). This is
  172. installed as an internal class method, invoked if the current font is
  173. non-Hershey (which means Postscript, PCL, or `other' [i.e. any non-PS,
  174. non-PCL, retrievable X font]. */
  175. /* When this is called in g_alabel.c, the X font has already been
  176. retrieved, in whole or in part (by calling "_set_font()", which in turn
  177. calls "_plotter->retrieve_font()", i.e., which calls the
  178. _pl_x_retrieve_font() routine in x_retrieve.c). I.e., whatever portion of
  179. the X font was required to be retrieved in order to return font metrics,
  180. has previously been retrieved.
  181. To retrieve a larger part, we call _pl_x_retrieve_font() again. But this
  182. time, we pass the label to be rendered to _pl_x_retrieve_font() as a
  183. "hint", i.e., as a data member of (the driver-specific part of) the
  184. drawing state. That tells _pl_x_retrieve_font how much more of the font to
  185. retrieve. This scheme is an ugly hack, but it works (and doesn't
  186. violate layering). */
  187. double
  188. _pl_x_get_text_width (R___(Plotter *_plotter) const unsigned char *s)
  189. {
  190. const char *saved_font_name;
  191. char *temp_font_name;
  192. bool ok;
  193. double width;
  194. /* Do retrieval, but use current `true_font_name' as our font name (see
  195. above; we've previously retrieved a subset of it). */
  196. if (_plotter->drawstate->true_font_name == NULL) /* shouldn't happen */
  197. return 0.0;
  198. saved_font_name = _plotter->drawstate->font_name;
  199. temp_font_name =
  200. (char *)_pl_xmalloc (strlen (_plotter->drawstate->true_font_name) + 1);
  201. strcpy (temp_font_name, _plotter->drawstate->true_font_name);
  202. _plotter->drawstate->font_name = temp_font_name;
  203. _plotter->drawstate->x_label = s; /* pass label hint */
  204. ok = _pl_x_retrieve_font (S___(_plotter));
  205. _plotter->drawstate->x_label = NULL; /* restore label hint to default */
  206. _plotter->drawstate->font_name = saved_font_name;
  207. free (temp_font_name);
  208. if (!ok) /* shouldn't happen */
  209. return 0.0;
  210. /* compute width of string in user units; see above comments on
  211. `compensating on both sides' */
  212. width = ((XTextWidth (_plotter->drawstate->x_font_struct,
  213. (char *)s,
  214. (int)(strlen((char *)s)))
  215. *_plotter->drawstate->true_font_size)
  216. / _plotter->drawstate->x_font_pixel_size);
  217. /* maybe flush X output buffer and handle X events (a no-op for
  218. XDrawablePlotters, which is overridden for XPlotters) */
  219. _maybe_handle_x_events (S___(_plotter));
  220. return width;
  221. }