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 internal _pl_g_set_font method, which is called
20    when the font_name, font_size, and textangle fields of the current
21    drawing state have been filled in.  It retrieves the specified font, and
22    fills in the true_font_name, true_font_size, font_type, typeface_index,
23    font_index, font_is_iso8858_1, font_ascent, font_descent, and
24    font_cap_height fields of the drawing state.
25 
26    _pl_g_set_font is invoked by _API_alabel() and _API_flabelwidth(), and
27    also by _API_fontname(), _API_fontsize(), and _API_textangle() (only
28    because those three functions in the API must return a font size).
29 
30    _pl_g_set_font does the following, in order:
31 
32    1. If font_name is the name of a supported Hershey font, i.e., one in
33    libplot's database, it fills in the fields itself.
34 
35    2. If the font name is the name of a supported font of a non-Hershey
36    type (i.e. PS/PCL/Stick), it _tentatively_ fills in the fields.  If the
37    font name doesn't appear in libplot's internal database, it simply sets
38    the font_type to `PL_F_OTHER'.
39 
40    3a. If the font name isn't the name of a supported Hershey font, it
41    invokes the Plotter-specific `retrieve_font' method.  In most Plotters
42    this simply returns true.  (See the stub _pl_g_retrieve_font() below.)
43    But in principle it may modify the fields arbitrarily, perhaps consult
44    an external database, etc.
45 
46    3b. If retrieve_font returns false, a default Hershey font is
47    substituted, and the fields are filled in.  This feature is used e.g. by
48    Fig Plotters, which support any of the 35 PS fonts in libplot's
49    database, except when the user frame -> device frame map is anisotropic
50    (i.e. non-uniform).  It is also used by X Drawable Plotters, which may
51    or may not have a PS font available, and in fact may or may not have any
52    given font of type `PL_F_OTHER' (see above) available. */
53 
54 #include "sys-defines.h"
55 #include "extern.h"
56 #include "g_her_metr.h"
57 
58 #define MAP_HERSHEY_UNITS_TO_USER_UNITS(size, drawstate) \
59 	((size)*(drawstate->true_font_size)/(HERSHEY_EM))
60 
61 /* forward references */
62 static bool _match_hershey_font (plDrawState *drawstate);
63 static bool _match_ps_font (plDrawState *drawstate);
64 static bool _match_pcl_font (plDrawState *drawstate);
65 static bool _match_stick_font (plDrawState *drawstate, bool have_extra_stick_fonts);
66 
67 void
_pl_g_set_font(S___ (Plotter * _plotter))68 _pl_g_set_font (S___(Plotter *_plotter))
69 {
70   plDrawState *drawstate = _plotter->drawstate;
71   plPlotterData *data = _plotter->data;
72   const char *default_font_name;
73   bool matched;
74 
75   /* try to match font name in our database */
76 
77   if (_match_hershey_font (drawstate))
78     /* Matched a Hershey font name in our database, and all fields filled
79        in definitively, so return without invoking Plotter-specific
80        `retrieve_font', which knows nothing about Hershey fonts anyway */
81     return;
82 
83   matched = false;
84 
85   /* Try to match the font name with the name of a PCL font or a PS font in
86      the database, and tentatively fill in fields.  But there is a
87      namespace collision: "Courier" etc. and "Symbol" occur on both lists.
88      Which list we search first depends on what type of Plotter this is. */
89 
90   if (data->pcl_before_ps)
91     {
92       /* search PCL font list first */
93       if ((data->have_pcl_fonts
94 	   && _match_pcl_font (drawstate))
95 	  ||
96           (data->have_ps_fonts
97 	   && _match_ps_font (drawstate)))
98 	matched = true;
99     }
100   else
101     {
102       /* search PS font list first */
103       if ((data->have_ps_fonts
104 	   && _match_ps_font (drawstate))
105 	  ||
106 	  (data->have_pcl_fonts
107 	   && _match_pcl_font (drawstate)))
108 	matched = true;
109     }
110 
111   /* if unmatched, search through Stick font list too */
112   if (matched == false && data->have_stick_fonts
113       && _match_stick_font (drawstate,
114 			    data->have_extra_stick_fonts ? true : false))
115     matched = true;
116 
117   if (matched == false)
118     /* fill in the only fields we can */
119     {
120       free ((char *)drawstate->true_font_name);
121       drawstate->true_font_name =
122 	(const char *)_pl_xmalloc (strlen (drawstate->font_name) + 1);
123       strcpy ((char *)drawstate->true_font_name, drawstate->font_name);
124       drawstate->true_font_size = drawstate->font_size;
125 
126       drawstate->font_type = PL_F_OTHER;
127       drawstate->typeface_index = 0;
128       drawstate->font_index = 1;
129 
130       /* NOT filled in yet: font_is_iso8859_1, font_ascent, font_descent,
131 	 and font_cap_height; they're left to Plotter-specific retrieval
132 	 routine, if it can supply them (in the case of a Metafile Plotter,
133 	 it surely can't). */
134     }
135 
136   /* If we got here, font name isn't that of a Hershey font, and `matched'
137      indicates whether or not it's listed in our font name database, as one
138      of the types of font this Plotter can handle.  So invoke low-level
139      Plotter-specific retrieval routine.  Do it even if we haven't matched
140      the font, if this Plotter claims to be able to handle `other' fonts,
141      i.e., ones not listed in our database. */
142 
143   if (matched || (!matched && data->have_other_fonts))
144     /* try to invoke low-level Plotter-specific routine to finish the job
145        of filling in fields, including Plotter-specific ones */
146     {
147       if (_plotter->retrieve_font (S___(_plotter)))
148 	/* all finished... */
149 	return;
150     }
151 
152   /* Plotter-specific retrieval failed: it doesn't like the font name or
153      other drawstate parameters (size, textangle, transformation matrix?)  */
154 
155   /* Via a recursive call, try to retrieve default font for this Plotter
156      type (if it's different from the one we just failed to retrieve;
157      otherwise retrieve the default Hershey font).  */
158 
159   switch (data->default_font_type)
160     {
161     case PL_F_POSTSCRIPT:
162       default_font_name = PL_DEFAULT_POSTSCRIPT_FONT;
163       break;
164     case PL_F_PCL:
165       default_font_name = PL_DEFAULT_PCL_FONT;
166       break;
167     case PL_F_STICK:
168       default_font_name = PL_DEFAULT_STICK_FONT;
169       break;
170     case PL_F_HERSHEY:		/* Hershey shouldn't happen */
171     default:
172       default_font_name = PL_DEFAULT_HERSHEY_FONT;
173       break;
174 
175       /* N.B. No support yet for a Plotter-specific default font that is of
176 	 PL_F_OTHER type, i.e., isn't listed in the libplot font database. */
177     }
178 
179   if (strcmp (drawstate->font_name, default_font_name) == 0
180       || strcmp (drawstate->true_font_name, default_font_name) == 0)
181     /* default font is the one we just failed to retrieve: so use Hershey:
182        internal and guaranteed to be available */
183     default_font_name = PL_DEFAULT_HERSHEY_FONT;
184 
185   /* stash fontname we failed to retrieve; then do recursive call, turning
186      off font warnings for the duration; restore fontname field */
187   {
188     const char *saved_font_name;
189     bool saved_font_warning_issued;
190 
191     saved_font_name = drawstate->font_name;
192     drawstate->font_name = default_font_name;
193     saved_font_warning_issued = _plotter->data->font_warning_issued;
194     _plotter->data->font_warning_issued = true;	/* turn off warnings */
195     _pl_g_set_font (S___(_plotter));
196     _plotter->data->font_warning_issued = saved_font_warning_issued;
197     drawstate->font_name = saved_font_name;
198   }
199 
200   if (data->issue_font_warning && !_plotter->data->font_warning_issued)
201     /* squawk */
202     {
203       char *buf;
204 
205       buf = (char *)_pl_xmalloc (strlen (drawstate->font_name) + strlen (drawstate->true_font_name) + 100);
206       sprintf (buf, "cannot retrieve font \"%s\", using default \"%s\"",
207 	       drawstate->font_name, drawstate->true_font_name);
208       _plotter->warning (R___(_plotter) buf);
209       free (buf);
210       _plotter->data->font_warning_issued = true;
211     }
212 }
213 
214 static bool
_match_hershey_font(plDrawState * drawstate)215 _match_hershey_font (plDrawState *drawstate)
216 {
217   int i;
218 
219   /* is font a Hershey font? */
220   i = -1;
221   while (_pl_g_hershey_font_info[++i].name)
222     {
223       if (_pl_g_hershey_font_info[i].visible) /* i.e. font not internal-only */
224 	if (strcasecmp (_pl_g_hershey_font_info[i].name,
225 			drawstate->font_name) == 0
226 	    || (_pl_g_hershey_font_info[i].othername
227 		&& strcasecmp (_pl_g_hershey_font_info[i].othername,
228 			       drawstate->font_name) == 0))
229 	  /* fill in fields */
230 	  {
231 	    free ((char *)drawstate->true_font_name);
232 	    drawstate->true_font_name =
233 	      (const char *)_pl_xmalloc (strlen (_pl_g_hershey_font_info[i].name) + 1);
234 	    strcpy ((char *)drawstate->true_font_name, _pl_g_hershey_font_info[i].name);
235 	    drawstate->true_font_size = drawstate->font_size;
236 
237 	    drawstate->font_type = PL_F_HERSHEY;
238 	    drawstate->typeface_index = _pl_g_hershey_font_info[i].typeface_index;
239 	    drawstate->font_index = _pl_g_hershey_font_info[i].font_index;
240 	    drawstate->font_is_iso8859_1 = _pl_g_hershey_font_info[i].iso8859_1;
241 
242 	    /* N.B. this macro uses true_font_size */
243 	    drawstate->font_cap_height =
244 	      MAP_HERSHEY_UNITS_TO_USER_UNITS(HERSHEY_CAPHEIGHT, drawstate);
245 	    drawstate->font_ascent =
246 	      MAP_HERSHEY_UNITS_TO_USER_UNITS(HERSHEY_ASCENT, drawstate);
247 	    drawstate->font_descent =
248 	      MAP_HERSHEY_UNITS_TO_USER_UNITS(HERSHEY_DESCENT, drawstate);
249 
250 	    return true;
251 	  }
252     }
253   return false;
254 }
255 
256 static bool
_match_pcl_font(plDrawState * drawstate)257 _match_pcl_font (plDrawState *drawstate)
258 {
259   int i = -1;
260 
261   /* is font a PCL font in libplot's database? */
262   while (_pl_g_pcl_font_info[++i].ps_name)
263     {
264       if (strcasecmp (_pl_g_pcl_font_info[i].ps_name,
265 		      drawstate->font_name) == 0
266 	  /* try alternative PS font name if any */
267 	  || (_pl_g_pcl_font_info[i].ps_name_alt != NULL
268 	      && strcasecmp (_pl_g_pcl_font_info[i].ps_name_alt,
269 			     drawstate->font_name) == 0)
270 	  /* try X font name too */
271 	  || strcasecmp (_pl_g_pcl_font_info[i].x_name,
272 			 drawstate->font_name) == 0)
273 	{
274 	  free ((char *)drawstate->true_font_name);
275 	  drawstate->true_font_name =
276 	    (const char *)_pl_xmalloc (strlen (_pl_g_pcl_font_info[i].ps_name) + 1);
277 	  strcpy ((char *)drawstate->true_font_name, _pl_g_pcl_font_info[i].ps_name);
278 	  drawstate->true_font_size = drawstate->font_size;
279 
280 	  drawstate->font_type = PL_F_PCL;
281 	  drawstate->typeface_index = _pl_g_pcl_font_info[i].typeface_index;
282 	  drawstate->font_index = _pl_g_pcl_font_info[i].font_index;
283 	  drawstate->font_is_iso8859_1 = _pl_g_pcl_font_info[i].iso8859_1;
284 
285 	  drawstate->font_ascent
286 	    = drawstate->true_font_size
287 	      * (double)(_pl_g_pcl_font_info[i].font_ascent)/1000.0;
288 	  drawstate->font_descent
289 	    = drawstate->true_font_size
290 	      * (double)(_pl_g_pcl_font_info[i].font_descent)/1000.0;
291 	  drawstate->font_cap_height
292 	    = drawstate->true_font_size
293 	      * (double)(_pl_g_pcl_font_info[i].font_cap_height)/1000.0;
294 	  return true;
295 	}
296     }
297   return false;
298 }
299 
300 static bool
_match_ps_font(plDrawState * drawstate)301 _match_ps_font (plDrawState *drawstate)
302 {
303   int i = -1;
304 
305   /* is font a PS font in libplot's database ? */
306   while (_pl_g_ps_font_info[++i].ps_name)
307     {
308       if (strcasecmp (_pl_g_ps_font_info[i].ps_name,
309 		      drawstate->font_name) == 0
310 	  /* try alternative PS font name if any */
311 	  || (_pl_g_ps_font_info[i].ps_name_alt != NULL
312 	      && strcasecmp (_pl_g_ps_font_info[i].ps_name_alt,
313 			     drawstate->font_name) == 0)
314 	  /* try 2nd alternative PS font name if any */
315 	  || (_pl_g_ps_font_info[i].ps_name_alt2 != NULL
316 	      && strcasecmp (_pl_g_ps_font_info[i].ps_name_alt2,
317 			     drawstate->font_name) == 0)
318 	  /* try X font name too */
319 	  || strcasecmp (_pl_g_ps_font_info[i].x_name,
320 			 drawstate->font_name) == 0
321 	  /* try alternative X font name if any */
322 	  || (_pl_g_ps_font_info[i].x_name_alt != NULL
323 	      && strcasecmp (_pl_g_ps_font_info[i].x_name_alt,
324 			     drawstate->font_name) == 0))
325 	{
326 	  free ((char *)drawstate->true_font_name);
327 	  drawstate->true_font_name =
328 	    (const char *)_pl_xmalloc (strlen (_pl_g_ps_font_info[i].ps_name) + 1);
329 	  strcpy ((char *)drawstate->true_font_name, _pl_g_ps_font_info[i].ps_name);
330 
331 	  drawstate->true_font_size = drawstate->font_size;
332 
333 	  drawstate->font_type = PL_F_POSTSCRIPT;
334 	  drawstate->typeface_index = _pl_g_ps_font_info[i].typeface_index;
335 	  drawstate->font_index = _pl_g_ps_font_info[i].font_index;
336 	  drawstate->font_is_iso8859_1 = _pl_g_ps_font_info[i].iso8859_1;
337 
338 	  drawstate->font_ascent
339 	    = drawstate->true_font_size
340 	      * (double)(_pl_g_ps_font_info[i].font_ascent)/1000.0;
341 	  drawstate->font_descent
342 	    = drawstate->true_font_size
343 	      * (double)(_pl_g_ps_font_info[i].font_descent)/1000.0;
344 	  drawstate->font_cap_height
345 	    = drawstate->true_font_size
346 	      * (double)(_pl_g_ps_font_info[i].font_cap_height)/1000.0;
347 	  return true;
348 	}
349     }
350   return false;
351 }
352 
353 static bool
_match_stick_font(plDrawState * drawstate,bool have_extra_stick_fonts)354 _match_stick_font (plDrawState *drawstate, bool have_extra_stick_fonts)
355 {
356   int i = -1;
357 
358   /* is font a PCL font in libplot's database? */
359   while (_pl_g_stick_font_info[++i].ps_name)
360     {
361       if (_pl_g_stick_font_info[i].basic == false
362 	  && !have_extra_stick_fonts)
363 	/* not a basic Stick font, and this Plotter supports only the basic
364 	   ones */
365 	continue;
366 
367       if (strcasecmp (_pl_g_stick_font_info[i].ps_name,
368 		      drawstate->font_name) == 0)
369 	/* fill in fields */
370 	{
371 	  free ((char *)drawstate->true_font_name);
372 	  drawstate->true_font_name =
373 	    (const char *)_pl_xmalloc (strlen (_pl_g_stick_font_info[i].ps_name) + 1);
374 	  strcpy ((char *)drawstate->true_font_name, _pl_g_stick_font_info[i].ps_name);
375 	  drawstate->true_font_size = drawstate->font_size;
376 	  drawstate->true_font_size = drawstate->font_size;
377 	  drawstate->true_font_size = drawstate->font_size;
378 
379 	  drawstate->font_type = PL_F_STICK;
380 	  drawstate->typeface_index = _pl_g_stick_font_info[i].typeface_index;
381 	  drawstate->font_index = _pl_g_stick_font_info[i].font_index;
382 	  drawstate->font_is_iso8859_1 = _pl_g_stick_font_info[i].iso8859_1;
383 
384 	  drawstate->font_ascent
385 	    = drawstate->true_font_size
386 	    * (double)(_pl_g_stick_font_info[i].font_ascent)/1000.0;
387 	  drawstate->font_descent
388 	    = drawstate->true_font_size
389 	    * (double)(_pl_g_stick_font_info[i].font_descent)/1000.0;
390 	  drawstate->font_cap_height
391 	    /* The `0.7' is undocumented HP magic; see comments in
392 	       h_font.c and g_fontd2.c */
393 	    = 0.7 * drawstate->true_font_size;
394 
395 	  return true;
396 	}
397     }
398   return false;
399 }
400 
401 /* This is the generic version of the _retrieve_font method, which does
402    nothing.  Many types of Plotter use this, but some, e.g., FigPlotters
403    and XDrawablePlotters (and X Plotters) override it.  See
404    _pl_f_retrieve_font() and _pl_x_retrieve_font(). */
405 
406 bool
_pl_g_retrieve_font(S___ (Plotter * _plotter))407 _pl_g_retrieve_font (S___(Plotter *_plotter))
408 {
409   return true;
410 }
411