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 
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 
19 /* This file contains the Fig-driver-specific version of the low-level
20    paint_text_string() method, which is called to plot a label in the
21    current PS font, at the current fontsize and textangle.  The label is
22    just a string: no control codes (font switching or sub/superscripts).
23 
24    The width of the string in user units is returned.
25 
26    This version does not support `sheared' fonts, since xfig does not
27    support them.  But it does support center-justification and right
28    justification as well as the default left-justification, since the xfig
29    format supports them. */
30 
31 #include "sys-defines.h"
32 #include "extern.h"
33 
34 #define FONT_TYPE_LATEX 0	/* don't support LaTeX fonts currently */
35 #define FONT_TYPE_PS 4
36 
37 #define GOOD_PRINTABLE_ASCII(c) ((c >= 0x20) && (c <= 0x7E))
38 
39 /* Fig horizontal alignment styles, indexed by internal number
40    (left/center/right) */
41 #define FIG_ALIGN_LEFT 0
42 #define FIG_ALIGN_CENTER 1
43 #define FIG_ALIGN_RIGHT 2
44 static const int fig_horizontal_alignment_style[PL_NUM_HORIZ_JUST_TYPES] =
45 { FIG_ALIGN_LEFT, FIG_ALIGN_CENTER, FIG_ALIGN_RIGHT };
46 
47 /* This prints a single-font, single-font-size label.  When this is called,
48    the current point is on the intended baseline of the label.  */
49 
50 /* ARGS: h_just,v_just are PL_JUST_{LEFT|CENTER|RIGHT}, PL_JUST_{TOP etc.} */
51 double
_pl_f_paint_text_string(R___ (Plotter * _plotter)const unsigned char * s,int h_just,int v_just)52 _pl_f_paint_text_string (R___(Plotter *_plotter) const unsigned char *s, int h_just, int v_just)
53 {
54   int len, master_font_index;
55   unsigned char *ptr, *t;
56   double theta, costheta, sintheta;
57   double label_width, label_ascent;
58   double initial_x, initial_y;
59   double horizontal_x, horizontal_y, vertical_x, vertical_y;
60   double horizontal_fig_length, vertical_fig_length;
61   double horizontal_fig_x, vertical_fig_x;
62   double horizontal_fig_y, vertical_fig_y;
63   double angle_device;
64 
65   /* sanity check */
66   if (_plotter->drawstate->font_type != PL_F_POSTSCRIPT)
67     return 0.0;
68 
69   /* sanity check; this routine supports only baseline positioning */
70   if (v_just != PL_JUST_BASE)
71     return 0.0;
72 
73   /* if empty string, nothing to do */
74   if (*s == (unsigned char)'\0')
75     return 0.0;
76 
77   /* if font (previously retrieved) has a font size of zero in terms of
78      integer `Fig points', bail out right now, since xfig can't handle text
79      strings with zero point size */
80   if (_plotter->drawstate->fig_font_point_size == 0)
81     return 0.0;
82 
83   /* label rotation angle in radians */
84   theta = M_PI * _plotter->drawstate->text_rotation / 180.0;
85   sintheta = sin (theta);
86   costheta = cos (theta);
87 
88   /* compute index of font in master table of PS fonts, in g_fontdb.h */
89   master_font_index =
90     (_pl_g_ps_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
91 
92   /* compute label height and width, in user units */
93   label_width = _plotter->get_text_width (R___(_plotter) s);
94   label_ascent  = _plotter->drawstate->true_font_size * (_pl_g_ps_font_info[master_font_index]).font_ascent / 1000.0;
95 
96   /* vector along baseline of label, and an orthogonal vector which is the
97      other side of a rectangle containing the portion of the string above
98      the baseline (both in the user frame) */
99 
100   horizontal_x = costheta * label_width;
101   horizontal_y = sintheta * label_width;
102 
103   vertical_x =  - sintheta * label_ascent;
104   vertical_y =    costheta * label_ascent;
105 
106   /* Convert two above orthogonal vectors to the device frame, and compute
107      their lengths.  In the device frame they may no longer be orthogonal.
108      But xfig supports setting up only rectangular `hot regions', so we'll
109      use their lengths as the sides of a rectangle.  If user coor->device
110      coor map is highly sheared, this would be inappropriate.
111 
112      Incidentally, the height of the rectangular hot region should really
113      be the string ascent (from its bounding box), not the font ascent.
114      But since we don't include the bounding boxes of individual characters
115      in our g_fontdb.c, we have no way of computing the former. */
116 
117   horizontal_fig_x = XDV(horizontal_x, horizontal_y);
118   horizontal_fig_y = YDV(horizontal_x, horizontal_y);
119   horizontal_fig_length = sqrt(horizontal_fig_x * horizontal_fig_x
120 				+ horizontal_fig_y * horizontal_fig_y);
121 
122   /* text angle in device frame (note flipped-y convention) */
123   angle_device = - _xatan2 (horizontal_fig_y, horizontal_fig_x);
124   if (angle_device == 0.0)
125     angle_device = 0.0;		/* remove sign bit if any */
126 
127   /* avoid triggering a bug in xfig, which as of release 3.2.2 can't handle
128      rotated text strings consisting of a single space character (they
129      cause it to crash) */
130   if (angle_device != 0.0 && strcmp ((const char *)s, " ") == 0)
131     return _plotter->get_text_width (R___(_plotter) s);
132 
133   vertical_fig_x = XDV(vertical_x, vertical_y);
134   vertical_fig_y = YDV(vertical_x, vertical_y);
135   vertical_fig_length = sqrt(vertical_fig_x * vertical_fig_x
136 				+ vertical_fig_y * vertical_fig_y);
137 
138   /* where we should start from, in device frame (i.e. in Fig units) */
139   initial_x = XD((_plotter->drawstate->pos).x, (_plotter->drawstate->pos).y);
140   initial_y = YD((_plotter->drawstate->pos).x, (_plotter->drawstate->pos).y);
141 
142   /* evaluate fig colors lazily, i.e. only when needed */
143   _pl_f_set_pen_color (S___(_plotter));
144 
145   /* escape all backslashes in the text string, before output */
146   len = strlen ((char *)s);
147   ptr = (unsigned char *)_pl_xmalloc ((4 * len + 1) * sizeof(char));
148   t = ptr;
149   while (*s)
150     {
151       switch (*s)
152 	{
153 	case '\\':
154 	  *ptr++ = (unsigned char)'\\';
155 	  *ptr++ = *s++;
156           break;
157 	default:
158           if GOOD_PRINTABLE_ASCII (*s)
159 	    *ptr++ = *s++;
160           else
161             {
162                sprintf ((char *)ptr, "\\%03o", (unsigned int)*s);
163                ptr += 4;
164                s++;
165             }
166           break;
167 	}
168     }
169   *ptr = (unsigned char)'\0';
170 
171   /* update xfig's `depth' attribute */
172     if (_plotter->fig_drawing_depth > 0)
173       (_plotter->fig_drawing_depth)--;
174 
175   sprintf(_plotter->data->page->point,
176 	  "#TEXT\n%d %d %d %d %d %d %.3f %.3f %d %.3f %.3f %d %d %s\\001\n",
177 	  4,			/* text object */
178 	  /* xfig supports 3 justification types: left, center, or right. */
179 	  fig_horizontal_alignment_style[h_just],/* horizontal just. type */
180 	  _plotter->drawstate->fig_fgcolor, /* pen color */
181 	  _plotter->fig_drawing_depth, /* depth */
182 	  0,			/* pen style, ignored */
183 	  _pl_g_ps_font_info[master_font_index].fig_id, /* Fig font id */
184 	  (double)_plotter->drawstate->fig_font_point_size, /* point size (float) */
185 	  angle_device,		/* text rotation in radians (float) */
186 	  FONT_TYPE_PS,		/* Fig font type */
187 	  /* these next two are used only for setting up `hot spots' */
188 	  vertical_fig_length, /* string height, Fig units (float) */
189 	  horizontal_fig_length, /* string width, Fig units (float) */
190 	  /* coors of origin of label, in Fig units */
191 	  IROUND(initial_x),
192 	  IROUND(initial_y),
193 	  t);			/* munged string */
194   free (t);
195   _update_buffer (_plotter->data->page);
196 
197   return label_width;
198 }
199