~ubuntu-branches/ubuntu/jaunty/plotutils/jaunty

« back to all changes in this revision

Viewing changes to libplot/x_text.c

  • Committer: Bazaar Package Importer
  • Author(s): Floris Bruynooghe
  • Date: 2007-05-10 19:48:54 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070510194854-mrr3lgwzpxd8hovo
Tags: 2.5-2
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the GNU plotutils package.  Copyright (C) 1995,
 
2
   1996, 1997, 1998, 1999, 2000, 2005, Free Software Foundation, Inc.
 
3
 
 
4
   The GNU plotutils package is free software.  You may redistribute it
 
5
   and/or modify it under the terms of the GNU General Public License as
 
6
   published by the Free Software foundation; either version 2, or (at your
 
7
   option) any later version.
 
8
 
 
9
   The GNU plotutils package is distributed in the hope that it will be
 
10
   useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
   General Public License for more details.
 
13
 
 
14
   You should have received a copy of the GNU General Public License along
 
15
   with the GNU plotutils package; see the file COPYING.  If not, write to
 
16
   the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
 
17
   Boston, MA 02110-1301, USA. */
 
18
 
1
19
/* This file contains the XDrawablePlotter (and XPlotter) version of the
2
20
   low-level paint_text_string() method, which is called to plot a label in
3
21
   the current (non-Hershey) font, at the current fontsize and textangle.
18
36
/* When this is called in g_alabel.c, the X font has already been
19
37
   retrieved, in whole or in part (by calling "_set_font()", which in turn
20
38
   calls "_plotter->retrieve_font()", which is bound to the
21
 
   _x_retrieve_font() routine in x_retrieve.c).  I.e., whatever portion of
 
39
   _pl_x_retrieve_font() routine in x_retrieve.c).  I.e., whatever portion of
22
40
   the X font was required to be retrieved in order to return font metrics,
23
41
   has previously been retrieved.
24
42
 
25
 
   To retrieve a larger part, we call _x_retrieve_font() again.  But this
26
 
   time, we pass the label to be rendered to _x_retrieve_font() as a
27
 
   "hint", i.e., as a data member of (the driver-specific part of) the
28
 
   drawing state.  That tells _x_retrieve_font how much more of the font to
29
 
   retrieve.  This scheme is a hack, but it works (and doesn't violate
30
 
   layering).
 
43
   To retrieve a larger part, we call _pl_x_retrieve_font() again.  But this
 
44
   time, we pass the label to be rendered to _pl_x_retrieve_font() as a
 
45
   "hint", i.e., as the x_label data member of (the driver-specific part
 
46
   of) the drawing state.  That tells _pl_x_retrieve_font how much more of the
 
47
   font to retrieve.  This scheme is a hack, but it works (and doesn't
 
48
   violate layering).  */
31
49
 
32
 
   The original retrieval may well have mapped the font name to something
33
 
   else (in the case of an unavailable X font, a default X font may have
34
 
   been substituted).  So we're careful to use drawstate->true_font_name as
35
 
   drawstate->font_name, for the duration of the second retrieval.  Note:
36
 
   this requires a strcpy, since _x_retrieve_font() may free the
37
 
   true_font_name member. */
 
50
#include "x_afftext.h"
38
51
 
39
52
double
40
 
#ifdef _HAVE_PROTOS
41
 
_x_paint_text_string (R___(Plotter *_plotter) const unsigned char *s, int h_just, int v_just)
42
 
#else
43
 
_x_paint_text_string (R___(_plotter) s, h_just, v_just)
44
 
     S___(Plotter *_plotter;)
45
 
     const unsigned char *s;
46
 
     int h_just;
47
 
     int v_just;
48
 
#endif
 
53
_pl_x_paint_text_string (R___(Plotter *_plotter) const unsigned char *s, int h_just, int v_just)
49
54
{
50
55
  const char *saved_font_name;
51
56
  char *temp_font_name;
52
57
  bool ok;
53
 
  double x, y, width;
54
 
  int offset = 0;
 
58
  double x, y;
 
59
  double width = 0.0;           /* width of string in user units */
 
60
  double rot[4];                /* user-frame rotation matrix */
 
61
  double a[4];             /* transformation matrix for XAffDrawString() */
 
62
  int i, ix, iy;
55
63
  
56
64
  /* sanity check; this routine supports only baseline positioning */
57
 
  if (v_just != JUST_BASE)
 
65
  if (v_just != PL_JUST_BASE)
58
66
    return 0.0;
59
67
 
60
68
  /* similarly for horizontal justification */
61
 
  if (h_just != JUST_LEFT)
 
69
  if (h_just != PL_JUST_LEFT)
62
70
    return 0.0;
63
71
 
64
72
  if (*s == (unsigned char)'\0')
65
73
    return 0.0;
66
74
 
67
 
  /* Do retrieval, but use current `true_font_name' as our font name (see
68
 
     above; we've previously retrieved a subset of it). */
 
75
  /* Do retrieval, fill in the X-specific field x_font_struct of the
 
76
     drawing state.  (We've previously retrieved a small subset of the
 
77
     font, to obtain metrics used for text positioning, as mentioned above;
 
78
     so retrieving a larger portion should go smoothly.)   
 
79
 
 
80
     We retrieve not `font_name' but rather `true_font_name', because the
 
81
     latter may have been what was retrieved, if a default X font had to be
 
82
     substituted; see g_retrieve.c. */
69
83
 
70
84
  if (_plotter->drawstate->true_font_name == NULL) /* shouldn't happen */
71
85
    return 0.0;
72
86
 
73
87
  saved_font_name = _plotter->drawstate->font_name;
74
88
  temp_font_name = 
75
 
    (char *)_plot_xmalloc (strlen (_plotter->drawstate->true_font_name) + 1);
 
89
    (char *)_pl_xmalloc (strlen (_plotter->drawstate->true_font_name) + 1);
76
90
  strcpy (temp_font_name, _plotter->drawstate->true_font_name);
77
91
  _plotter->drawstate->font_name = temp_font_name;
78
92
 
79
93
  _plotter->drawstate->x_label = s; /* pass label hint */
80
 
  ok = _x_retrieve_font (S___(_plotter));
 
94
  ok = _pl_x_retrieve_font (S___(_plotter));
81
95
  _plotter->drawstate->x_label = NULL; /* restore label hint to default */
82
96
 
83
97
  _plotter->drawstate->font_name = saved_font_name;
86
100
  if (!ok)                      /* shouldn't happen */
87
101
    return 0.0;
88
102
 
89
 
  /* Set font in GC used for drawing (the other GC, used for filling, is
90
 
     left alone).  _x_retrieve_font() does not do this. */
 
103
  /* set font in GC used for drawing (the other GC, used for filling, is
 
104
     left alone) */
91
105
  XSetFont (_plotter->x_dpy, _plotter->drawstate->x_gc_fg,
92
106
            _plotter->drawstate->x_font_struct->fid);
93
107
 
94
108
  /* select our pen color as foreground color in X GC used for drawing */
95
 
  _x_set_pen_color (S___(_plotter));
 
109
  _pl_x_set_pen_color (S___(_plotter));
96
110
  
97
111
  /* compute position in device coordinates */
98
112
  x = XD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y);
99
113
  y = YD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y);
100
114
  
101
 
  if (_plotter->drawstate->x_native_positioning)
102
 
    /* a special case: the font name did not include a pixel matrix, or it
103
 
       did but the text rotation angle is zero; so move the easy way, i.e.,
104
 
       use native repositioning */
105
 
    {
106
 
      int label_len = strlen ((char *)s);
107
 
      int ix = IROUND(x);
108
 
      int iy = IROUND(y);
109
 
 
110
 
      /* X11 protocol OOB check */
111
 
      if (XOOB_INT(ix) || XOOB_INT(iy))
112
 
        {
113
 
          _plotter->warning (R___(_plotter) 
114
 
            "not drawing a text string that is positioned too far for X11");
115
 
          return 0.0;
116
 
        }
117
 
 
118
 
      if (_plotter->x_double_buffering != DBL_NONE)
119
 
        /* double buffering, have a `x_drawable3' to draw into */
120
 
        XDrawString (_plotter->x_dpy, _plotter->x_drawable3, 
121
 
                     _plotter->drawstate->x_gc_fg, 
122
 
                     ix, iy, (char *)s, label_len);
123
 
      else
124
 
        {
125
 
          /* not double buffering, have no `x_drawable3' */
126
 
          if (_plotter->x_drawable1)
127
 
            XDrawString (_plotter->x_dpy, _plotter->x_drawable1, 
128
 
                         _plotter->drawstate->x_gc_fg, 
129
 
                         ix, iy, (char *)s, label_len);
130
 
          if (_plotter->x_drawable2)
131
 
            XDrawString (_plotter->x_dpy, _plotter->x_drawable2, 
132
 
                         _plotter->drawstate->x_gc_fg, 
133
 
                         ix, iy, (char *)s, label_len);
134
 
        }
135
 
 
136
 
      /* compute width of string in normalized units (font size = 1000) */
137
 
      offset = IROUND(1000.0 * XTextWidth (_plotter->drawstate->x_font_struct, 
138
 
                                           (char *)s, 
139
 
                                           (int)(strlen((char *)s))) / 
140
 
                      _plotter->drawstate->x_font_pixmatrix[0]);
141
 
    }  
142
 
  else 
143
 
    /* general case: due to nonzero text rotation and/or a non-uniform
144
 
       transformation from user to device coordinates, a pixel matrix
145
 
       appeared explicitly in the font name (and hence the font name was an
146
 
       XLFD font name); must move the cursor and plot each character
147
 
       individually.  */
148
 
    {
149
 
      const unsigned char *stringptr = s;
150
 
      
151
 
      /* loop over characters */
152
 
      while (*stringptr)
153
 
        {
154
 
          int charno = *stringptr;
155
 
          int char_offset = 
156
 
            charno - _plotter->drawstate->x_font_struct->min_char_or_byte2;
157
 
          int ix, iy;
158
 
          
159
 
          ix = IROUND(x + 
160
 
                      offset * _plotter->drawstate->x_font_pixmatrix[0]/1000.0);
161
 
          iy = IROUND(y 
162
 
                      -offset * _plotter->drawstate->x_font_pixmatrix[1]/1000.0);
163
 
 
164
 
          /* X11 protocol OOB check */
165
 
          if (XOOB_INT(ix) || XOOB_INT(iy))
166
 
            {
167
 
              _plotter->warning (R___(_plotter) 
168
 
                "truncating a text string that extends too far for X11");
169
 
              return 0.0;
170
 
            }
171
 
 
172
 
          if (_plotter->x_double_buffering != DBL_NONE)
173
 
            /* double buffering, have a `x_drawable3' to draw into */
174
 
            XDrawString (_plotter->x_dpy, _plotter->x_drawable3,
175
 
                         _plotter->drawstate->x_gc_fg, 
176
 
                         ix, iy, (char *)stringptr, 1);
177
 
          else
178
 
            /* not double buffering, have no `x_drawable3' */
179
 
            {
180
 
              if (_plotter->x_drawable1)
181
 
                XDrawString (_plotter->x_dpy, _plotter->x_drawable1,
182
 
                             _plotter->drawstate->x_gc_fg, 
183
 
                             ix, iy, (char *)stringptr, 1);
184
 
              if (_plotter->x_drawable2)
185
 
                XDrawString (_plotter->x_dpy, _plotter->x_drawable2,
186
 
                             _plotter->drawstate->x_gc_fg, 
187
 
                             ix, iy, (char *)stringptr, 1);
188
 
            }
189
 
          
190
 
          /* add this glyph's contribution to the width of the string, in
191
 
             normalized units (font size = 1000) */
192
 
          offset += (_plotter->drawstate->x_font_struct->per_char ?
193
 
                     _plotter->drawstate->x_font_struct->per_char[char_offset].attributes :
194
 
                     _plotter->drawstate->x_font_struct->min_bounds.attributes);
195
 
 
196
 
          stringptr++;
197
 
        }
198
 
    }
199
 
  
200
 
  /* convert normalized string width to width in user coors */
201
 
  width = _plotter->drawstate->true_font_size * (double)offset / 1000.0;
202
 
 
 
115
  /* X11 protocol OOB check */
 
116
  ix = IROUND(x);
 
117
  iy = IROUND(y);
 
118
  if (X_OOB_INT(ix) || X_OOB_INT(iy))
 
119
    {
 
120
      _plotter->warning (R___(_plotter) 
 
121
                         "not drawing a text string that is positioned too far for X11");
 
122
      return 0.0;
 
123
    }
 
124
    
 
125
  /* Draw the text string by calling XAffDrawString() in x_afftext.c, which
 
126
     operates by affinely transform a bitmap generated by XDrawString() in
 
127
     the following way: it pulls it back from the server as an image,
 
128
     transforms the image, and then sends the image back to the server. */
 
129
  
 
130
  /* First, compute a 2x2 matrix a[] that would, in the jargon of the
 
131
     matrix extension to the XLFD (X Logical Font Description) scheme, be
 
132
     called a `pixel matrix'.  It specifies how XAffDrawAffString should
 
133
     `anamorphically transform' the text bitmap produced by XDrawString(),
 
134
     to yield the bitmap we want.  It's essentially the product of (i) the
 
135
     user-frame text rotation matrix, and (ii) the user_space->device_space
 
136
     transformation matrix.  But see additional comments below. */
 
137
 
 
138
  /* user-frame rotation matrix */
 
139
  rot[0] = cos (M_PI * _plotter->drawstate->text_rotation / 180.0);
 
140
  rot[1] = sin (M_PI * _plotter->drawstate->text_rotation / 180.0);
 
141
  rot[2] = - sin (M_PI * _plotter->drawstate->text_rotation / 180.0);
 
142
  rot[3] = cos (M_PI * _plotter->drawstate->text_rotation / 180.0);
 
143
  
 
144
  /* Compute matrix product.  But note flipped-y convention affecting a[1]
 
145
     and a[3].  Sign flipping is because the pixel matrix (as used in the
 
146
     XLFD matrix extension and hence, for consistency, by our code by
 
147
     XAffDrawAffString()) is expressed with respect to a right-handed
 
148
     coordinate system, in which y grows upward, rather than X11's default
 
149
     left-handed coordinate system, in which y grows downward. */
 
150
 
 
151
  a[0] =  (rot[0] * _plotter->drawstate->transform.m[0] 
 
152
           + rot[1] * _plotter->drawstate->transform.m[2]);
 
153
  a[1] =  - (rot[0] * _plotter->drawstate->transform.m[1] 
 
154
             + rot[1] * _plotter->drawstate->transform.m[3]);
 
155
  a[2] =  (rot[2] * _plotter->drawstate->transform.m[0] 
 
156
           + rot[3] * _plotter->drawstate->transform.m[2]);
 
157
  a[3] =  - (rot[2] * _plotter->drawstate->transform.m[1] 
 
158
             + rot[3] * _plotter->drawstate->transform.m[3]);
 
159
  
 
160
  /* Apply an overall scaling.  We want the text string to appear at a
 
161
     certain font size in the user frame; and the font that XDrawString
 
162
     will use was retrieved at a certain pixel size in the device frame.
 
163
     So we compensate on both sides, so to speak.  We multiply by
 
164
     true_font_size / x_font_pixel_size, where the numerator refers to the
 
165
     user frame, and the denominator to the device frame. */
 
166
 
 
167
  for (i = 0; i < 4; i++)
 
168
    a[i] = a[i] 
 
169
      * (_plotter->drawstate->true_font_size / _plotter->drawstate->x_font_pixel_size);
 
170
    
 
171
  if (_plotter->x_double_buffering != X_DBL_BUF_NONE)
 
172
    /* double buffering, have a `x_drawable3' to draw into */
 
173
    XAffDrawAffString (_plotter->x_dpy, _plotter->x_drawable3, 
 
174
                       _plotter->drawstate->x_gc_fg, 
 
175
                       _plotter->drawstate->x_font_struct,
 
176
                       ix, iy, a, (char *)s);
 
177
  else
 
178
    {
 
179
      /* not double buffering, have no `x_drawable3' */
 
180
      if (_plotter->x_drawable1)
 
181
        XAffDrawAffString (_plotter->x_dpy, _plotter->x_drawable1, 
 
182
                           _plotter->drawstate->x_gc_fg, 
 
183
                           _plotter->drawstate->x_font_struct,
 
184
                           ix, iy, a, (char *)s);
 
185
      if (_plotter->x_drawable2)
 
186
        XAffDrawAffString (_plotter->x_dpy, _plotter->x_drawable2, 
 
187
                           _plotter->drawstate->x_gc_fg, 
 
188
                           _plotter->drawstate->x_font_struct,
 
189
                           ix, iy, a, (char *)s);
 
190
    }
 
191
    
 
192
  /* compute width of just-drawn string in user units */
 
193
  width = (((XTextWidth (_plotter->drawstate->x_font_struct, 
 
194
                         (char *)s, 
 
195
                         (int)(strlen((char *)s)))
 
196
             *_plotter->drawstate->true_font_size))
 
197
           / _plotter->drawstate->x_font_pixel_size);
 
198
  
203
199
  /* maybe flush X output buffer and handle X events (a no-op for
204
200
     XDrawablePlotters, which is overridden for XPlotters) */
205
201
  _maybe_handle_x_events (S___(_plotter));
217
213
/* When this is called in g_alabel.c, the X font has already been
218
214
   retrieved, in whole or in part (by calling "_set_font()", which in turn
219
215
   calls "_plotter->retrieve_font()", i.e., which calls the
220
 
   _x_retrieve_font() routine in x_retrieve.c).  I.e., whatever portion of
 
216
   _pl_x_retrieve_font() routine in x_retrieve.c).  I.e., whatever portion of
221
217
   the X font was required to be retrieved in order to return font metrics,
222
218
   has previously been retrieved.
223
219
 
224
 
   To retrieve a larger part, we call _x_retrieve_font() again.  But this
225
 
   time, we pass the label to be rendered to _x_retrieve_font() as a
 
220
   To retrieve a larger part, we call _pl_x_retrieve_font() again.  But this
 
221
   time, we pass the label to be rendered to _pl_x_retrieve_font() as a
226
222
   "hint", i.e., as a data member of (the driver-specific part of) the
227
 
   drawing state.  That tells _x_retrieve_font how much more of the font to
 
223
   drawing state.  That tells _pl_x_retrieve_font how much more of the font to
228
224
   retrieve.  This scheme is an ugly hack, but it works (and doesn't
229
 
   violate layering).
230
 
 
231
 
   The original retrieval may well have mapped the font name to something
232
 
   else (in the case of an unavailable X font, a default X font may have
233
 
   been substituted).  So we're careful to use drawstate->true_font_name as
234
 
   drawstate->font_name, for the duration of the second retrieval.  Note:
235
 
   this requires a strcpy, since _x_retrieve_font() may free the
236
 
   true_font_name member. */
 
225
   violate layering). */
237
226
 
238
227
double
239
 
#ifdef _HAVE_PROTOS
240
 
_x_get_text_width (R___(Plotter *_plotter) const unsigned char *s)
241
 
#else
242
 
_x_get_text_width (R___(_plotter) s)
243
 
     S___(Plotter *_plotter;)
244
 
     const unsigned char *s;
245
 
#endif
 
228
_pl_x_get_text_width (R___(Plotter *_plotter) const unsigned char *s)
246
229
{
247
230
  const char *saved_font_name;
248
231
  char *temp_font_name;
249
232
  bool ok;
250
 
  int offset = 0;
251
 
  double label_width;
252
 
  
 
233
  double width;
 
234
 
253
235
  /* Do retrieval, but use current `true_font_name' as our font name (see
254
236
     above; we've previously retrieved a subset of it). */
255
237
 
258
240
 
259
241
  saved_font_name = _plotter->drawstate->font_name;
260
242
  temp_font_name = 
261
 
    (char *)_plot_xmalloc (strlen (_plotter->drawstate->true_font_name) + 1);
 
243
    (char *)_pl_xmalloc (strlen (_plotter->drawstate->true_font_name) + 1);
262
244
  strcpy (temp_font_name, _plotter->drawstate->true_font_name);
263
245
  _plotter->drawstate->font_name = temp_font_name;
264
246
 
265
247
  _plotter->drawstate->x_label = s; /* pass label hint */
266
 
  ok = _x_retrieve_font (S___(_plotter));
 
248
  ok = _pl_x_retrieve_font (S___(_plotter));
267
249
  _plotter->drawstate->x_label = NULL; /* restore label hint to default */
268
250
 
269
251
  _plotter->drawstate->font_name = saved_font_name;
272
254
  if (!ok)                      /* shouldn't happen */
273
255
    return 0.0;
274
256
 
275
 
  if (_plotter->drawstate->x_native_positioning)
276
 
    /* have a non-XLFD font, or an XLFD with zero textrotation, no shearing */
277
 
 
278
 
    /* compute width of string in normalized units (font size = 1000) */
279
 
    offset = IROUND(1000.0 * XTextWidth (_plotter->drawstate->x_font_struct, 
280
 
                                         (char *)s, 
281
 
                                         (int)(strlen((char *)s))) / 
282
 
                    _plotter->drawstate->x_font_pixmatrix[0]);
283
 
  else                          
284
 
    /* necessarily have an XLFD font, may need to take shearing into account */
285
 
    {
286
 
      /* loop over characters */
287
 
      while (*s)
288
 
        {
289
 
          int charno = *s;
290
 
          int char_offset = 
291
 
            charno - _plotter->drawstate->x_font_struct->min_char_or_byte2;
292
 
          
293
 
          /* add this glyph's contribution to the width of the string, in
294
 
             normalized units (font size = 1000) */
295
 
          offset += (_plotter->drawstate->x_font_struct->per_char ?
296
 
                     _plotter->drawstate->x_font_struct->per_char[char_offset].attributes :
297
 
                     _plotter->drawstate->x_font_struct->min_bounds.attributes);
298
 
          s++;
299
 
        }
300
 
    }
301
 
 
302
 
  /* convert normalized string width to width in user coors */
303
 
  label_width = _plotter->drawstate->true_font_size * (double)offset / 1000.0;
304
 
 
 
257
  /* compute width of string in user units; see above comments on
 
258
     `compensating on both sides' */
 
259
  width = ((XTextWidth (_plotter->drawstate->x_font_struct, 
 
260
                        (char *)s, 
 
261
                        (int)(strlen((char *)s)))
 
262
            *_plotter->drawstate->true_font_size)
 
263
           / _plotter->drawstate->x_font_pixel_size);
 
264
  
305
265
  /* maybe flush X output buffer and handle X events (a no-op for
306
266
     XDrawablePlotters, which is overridden for XPlotters) */
307
267
  _maybe_handle_x_events (S___(_plotter));
308
268
 
309
 
  return label_width;
 
269
  return width;
310
270
}