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