1 /* libwmf (font.c): library for wmf conversion
2    Copyright (C) 2000,2001 Francis James Franklin
3 
4    The libwmf Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8 
9    The libwmf Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public
15    License along with the libwmf Library; see the file COPYING.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18 
19 
20 #ifdef HAVE_CONFIG_H
21 #include "wmfconfig.h"
22 #endif /* HAVE_CONFIG_H */
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27 #include <ctype.h>
28 #include <sys/stat.h>
29 
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 
34 #include "wmfdefs.h"
35 
36 #include "font.h"
37 
38 #ifdef _WIN32
39 
40 extern char* _libwmf_get_fontdir();
41 
_libwmf_get_xtra_fontmap(void)42 static char* _libwmf_get_xtra_fontmap (void)
43 {
44 	static char retval[1000] = "";
45 
46 	if (retval[0] == '\0')
47 	{	strcpy (retval, _libwmf_get_fontdir ());
48 		strcat (retval, "\\share\\libwmf\\fonts\\fontmap");
49 	}
50 
51 	return retval;
52 }
53 
54 #undef WMF_XTRA_FONTMAP
55 #define WMF_XTRA_FONTMAP _libwmf_get_xtra_fontmap ()
56 
remap_font_file_name(wmfAPI * API,char * filename)57 static char* remap_font_file_name(wmfAPI* API,char* filename)
58 {
59 	/* If filename is prefixed with the compile-time WMF_FONTDIR,
60 	 * substitute the run-time font directory.
61 	 */
62 	char* retval;
63 	if (strncmp (filename, WMF_FONTDIR "/", strlen (WMF_FONTDIR "/")) == 0)
64 	{	retval = wmf_malloc (API,strlen (filename) - strlen (WMF_FONTDIR) + strlen (_libwmf_get_fontdir ()) + 1);
65 		strcpy (retval,_libwmf_get_fontdir ());
66 		strcat (retval,filename + strlen (WMF_FONTDIR));
67 	}
68 	else
69 	{	retval = wmf_strdup (API,filename);
70 	}
71 
72 	return retval;
73 }
74 
75 #endif
76 
ipa_font_add_wmf(wmfAPI * API,wmfFontMap * mapping)77 static void ipa_font_add_wmf (wmfAPI* API,wmfFontMap* mapping)
78 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
79 
80 	wmfFontMap* more;
81 
82 	unsigned int i = 0;
83 
84 	while (font_data->wmf[i].name)
85 	{	if (strcmp (font_data->wmf[i].name,mapping->name) == 0) break;
86 		i++;
87 	}
88 
89 	if (font_data->wmf[i].name) return; /* Entry exists already */
90 
91 	if ((i & 0x0f) == (unsigned int) 0x0f)
92 	{	more = (wmfFontMap*) wmf_realloc (API,font_data->wmf,(i + 0x11) * sizeof (wmfFontMap));
93 
94 		if (ERR (API))
95 		{	WMF_DEBUG (API,"bailing...");
96 			return;
97 		}
98 
99 		font_data->wmf = more;
100 	}
101 
102 	font_data->wmf[i].name       = wmf_strdup (API,mapping->name      );
103 	font_data->wmf[i].normal     = wmf_strdup (API,mapping->normal    );
104 	font_data->wmf[i].italic     = wmf_strdup (API,mapping->italic    );
105 	font_data->wmf[i].bold       = wmf_strdup (API,mapping->bold      );
106 	font_data->wmf[i].bolditalic = wmf_strdup (API,mapping->bolditalic);
107 
108 	if (ERR (API))
109 	{	WMF_DEBUG (API,"bailing...");
110 		return;
111 	}
112 
113 	i++;
114 	font_data->wmf[i].name = 0;
115 }
116 
ipa_font_add_sub(wmfAPI * API,wmfMapping * mapping)117 static void ipa_font_add_sub (wmfAPI* API,wmfMapping* mapping)
118 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
119 
120 	wmfMapping* more;
121 
122 	unsigned int i = 0;
123 
124 	while (font_data->sub[i].name)
125 	{	if (strcmp (font_data->sub[i].name,mapping->name) == 0) break;
126 		i++;
127 	}
128 
129 	if (font_data->sub[i].name) return; /* Entry exists already */
130 
131 	if ((i & 0x0f) == (unsigned int) 0x0f)
132 	{	more = (wmfMapping*) wmf_realloc (API,font_data->sub,(i + 0x11) * sizeof (wmfMapping));
133 
134 		if (ERR (API))
135 		{	WMF_DEBUG (API,"bailing...");
136 			return;
137 		}
138 
139 		font_data->sub = more;
140 	}
141 
142 	font_data->sub[i].name    = wmf_strdup (API,mapping->name   );
143 	font_data->sub[i].mapping = wmf_strdup (API,mapping->mapping);
144 
145 	if (ERR (API))
146 	{	WMF_DEBUG (API,"bailing...");
147 		return;
148 	}
149 
150 	i++;
151 	font_data->sub[i].name = 0;
152 }
153 
ipa_font_add_ps(wmfAPI * API,wmfMapping * mapping)154 static void ipa_font_add_ps (wmfAPI* API,wmfMapping* mapping)
155 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
156 
157 	wmfFT_Mapping* more;
158 
159 	unsigned int i = 0;
160 
161 	while (font_data->ps[i].name)
162 	{	if (strcmp (font_data->ps[i].name,mapping->name) == 0) break;
163 		i++;
164 	}
165 
166 	if (font_data->ps[i].name) return; /* Entry exists already */
167 
168 	if ((i & 0x0f) == (unsigned int) 0x0f)
169 	{	more = (wmfFT_Mapping*) wmf_realloc (API,font_data->ps,(i + 0x11) * sizeof (wmfFT_Mapping));
170 
171 		if (ERR (API))
172 		{	WMF_DEBUG (API,"bailing...");
173 			return;
174 		}
175 
176 		font_data->ps = more;
177 	}
178 
179 	font_data->ps[i].name     = wmf_strdup (API,mapping->name   );
180 	font_data->ps[i].mapping  = wmf_strdup (API,mapping->mapping);
181 	font_data->ps[i].encoding = mapping->encoding;
182 
183 	if (ERR (API))
184 	{	WMF_DEBUG (API,"bailing...");
185 		return;
186 	}
187 
188 	font_data->ps[i].face = 0;
189 
190 	i++;
191 	font_data->ps[i].name = 0;
192 }
193 
ipa_font_add_cache(wmfAPI * API,wmfFT_CacheEntry * entry)194 static void ipa_font_add_cache (wmfAPI* API,wmfFT_CacheEntry* entry)
195 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
196 
197 	wmfFT_CacheEntry* more;
198 
199 	unsigned int i = 0;
200 
201 	while (font_data->cache[i].name)
202 	{	if (strcmp (font_data->cache[i].path,entry->path) == 0) break;
203 		i++;
204 	}
205 
206 	if (font_data->cache[i].name) return; /* Entry exists already */
207 
208 	if ((i & 0x0f) == (unsigned int) 0x0f)
209 	{	more = (wmfFT_CacheEntry*) wmf_realloc (API,font_data->cache,(i + 0x11) * sizeof (wmfFT_CacheEntry));
210 
211 		if (ERR (API))
212 		{	WMF_DEBUG (API,"bailing...");
213 			return;
214 		}
215 
216 		font_data->cache = more;
217 	}
218 
219 	font_data->cache[i].name = wmf_strdup (API,entry->name);
220 	font_data->cache[i].path = wmf_strdup (API,entry->path);
221 	font_data->cache[i].face = entry->face;
222 
223 	if (ERR (API))
224 	{	WMF_DEBUG (API,"bailing...");
225 		return;
226 	}
227 
228 	i++;
229 	font_data->cache[i].name = 0;
230 }
231 
wmf_ipa_font_lookup(wmfAPI * API,char * ps_name)232 char* wmf_ipa_font_lookup (wmfAPI* API,char* ps_name)
233 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
234 
235 	unsigned int i = 0;
236 
237 	while (font_data->cache[i].name)
238 	{	if (strcmp (font_data->cache[i].name,ps_name) == 0) break;
239 		i++;
240 	}
241 
242 	if (font_data->cache[i].name == 0) return (0);
243 
244 	return (font_data->cache[i].path);
245 }
246 
wmf_ipa_font_init(wmfAPI * API,wmfAPI_Options * options)247 void wmf_ipa_font_init (wmfAPI* API,wmfAPI_Options* options)
248 {	wmfFontData* font_data = 0;
249 
250 	wmfFontmapData* fontmap_data = 0;
251 
252 	unsigned int i;
253 	unsigned int count;
254 
255 	API->font_data = wmf_malloc (API,sizeof (wmfFontData));
256 
257 	if (ERR (API))
258 	{	WMF_DEBUG (API,"bailing...");
259 		return;
260 	}
261 
262 	font_data = (wmfFontData*) API->font_data;
263 
264 	font_data->map = wmf_ipa_font_map;
265 
266 	font_data->stringwidth = wmf_ipa_font_stringwidth;
267 
268 	font_data->user_data = wmf_malloc (API,sizeof (wmfFontmapData));
269 
270 	if (ERR (API))
271 	{	WMF_DEBUG (API,"bailing...");
272 		return;
273 	}
274 
275 	fontmap_data = (wmfFontmapData*) font_data->user_data;
276 
277 	API->fonts = (char**) wmf_malloc (API,16 * sizeof (char*));
278 
279 	if (ERR (API))
280 	{	WMF_DEBUG (API,"bailing...");
281 		return;
282 	}
283 
284 	API->fonts[0] = 0;
285 
286 	fontmap_data->fontdirs = (char**) wmf_malloc (API,16 * sizeof (char*));
287 
288 	if (ERR (API))
289 	{	WMF_DEBUG (API,"bailing...");
290 		return;
291 	}
292 
293 	fontmap_data->fontdirs[0] = 0;
294 
295 	fontmap_data->wmf = (wmfFontMap*) wmf_malloc (API,16 * sizeof (wmfFontMap));
296 
297 	if (ERR (API))
298 	{	WMF_DEBUG (API,"bailing...");
299 		return;
300 	}
301 
302 	fontmap_data->wmf[0].name = 0;
303 
304 	if ((API->flags & WMF_OPT_FONTMAP) && options->font.wmf)
305 	{	i = 0;
306 		while (options->font.wmf[i].name)
307 		{	ipa_font_add_wmf (API,&(options->font.wmf[i]));
308 
309 			if (ERR (API)) break;
310 
311 			i++;
312 		}
313 		if (ERR (API))
314 		{	WMF_DEBUG (API,"bailing...");
315 			return;
316 		}
317 	}
318 
319 	count = sizeof WMFFontMap / sizeof (wmfFontMap);
320 
321 	for (i = 0; i < count; i++)
322 	{	ipa_font_add_wmf (API,&(WMFFontMap[i]));
323 
324 		if (ERR (API)) break;
325 	}
326 	if (ERR (API))
327 	{	WMF_DEBUG (API,"bailing...");
328 		return;
329 	}
330 
331 	fontmap_data->sub = (wmfMapping*) wmf_malloc (API,16 * sizeof (wmfMapping));
332 
333 	if (ERR (API))
334 	{	WMF_DEBUG (API,"bailing...");
335 		return;
336 	}
337 
338 	fontmap_data->sub[0].name = 0;
339 
340 	if ((API->flags & WMF_OPT_FONTMAP) && options->font.sub)
341 	{	i = 0;
342 		while (options->font.sub[i].name)
343 		{	ipa_font_add_sub (API,&(options->font.sub[i]));
344 
345 			if (ERR (API)) break;
346 
347 			i++;
348 		}
349 		if (ERR (API))
350 		{	WMF_DEBUG (API,"bailing...");
351 			return;
352 		}
353 	}
354 
355 	count = sizeof SubFontMap / sizeof (wmfMapping);
356 
357 	for (i = 0; i < count; i++)
358 	{	ipa_font_add_sub (API,&(SubFontMap[i]));
359 
360 		if (ERR (API)) break;
361 	}
362 	if (ERR (API))
363 	{	WMF_DEBUG (API,"bailing...");
364 		return;
365 	}
366 
367 	fontmap_data->ps = (wmfFT_Mapping*) wmf_malloc (API,16 * sizeof (wmfFT_Mapping));
368 
369 	if (ERR (API))
370 	{	WMF_DEBUG (API,"bailing...");
371 		return;
372 	}
373 
374 	fontmap_data->ps[0].name = 0;
375 
376 	fontmap_data->cache = (wmfFT_CacheEntry*) wmf_malloc (API,16 * sizeof (wmfFT_CacheEntry));
377 
378 	if (ERR (API))
379 	{	WMF_DEBUG (API,"bailing...");
380 		return;
381 	}
382 
383 	fontmap_data->cache[0].name = 0;
384 
385 	if ((API->flags & WMF_OPT_FONTMAP) && options->font.ps)
386 	{	i = 0;
387 		while (options->font.ps[i].name)
388 		{	ipa_font_add_ps (API,&(options->font.ps[i]));
389 
390 			if (ERR (API)) break;
391 
392 			i++;
393 		}
394 		if (ERR (API))
395 		{	WMF_DEBUG (API,"bailing...");
396 			return;
397 		}
398 	}
399 
400 	count = 13;
401 
402 	for (i = 0; i < count; i++)
403 	{	ipa_font_add_ps (API,&(PSFontMap[i]));
404 
405 		if (ERR (API)) break;
406 	}
407 	if (ERR (API))
408 	{	WMF_DEBUG (API,"bailing...");
409 		return;
410 	}
411 
412 	if (FT_Init_FreeType (&(fontmap_data->Library)) != 0)
413 	{	WMF_ERROR (API,"Failed to initialize freetype...");
414 		API->err = wmf_E_DeviceError;
415 		fontmap_data->Library = 0;
416 	}
417 
418 	API->flags |= API_FTLIBRARY_OPEN;
419 
420 	fontmap_data->FD.max = 0;
421 	fontmap_data->FD.len = 0;
422 
423 	fontmap_data->FD.FI = 0;
424 
425 	if (API->flags & WMF_OPT_SYS_FONTS)
426 	{	if (API->flags & WMF_OPT_SYS_FONTMAP)
427 		{	wmf_ipa_font_map_xml (API,&(fontmap_data->FD),options->sys_fontmap_file);
428 		}
429 		else
430 		{	wmf_ipa_font_map_xml (API,&(fontmap_data->FD),WMF_SYS_FONTMAP);
431 		}
432 	}
433 
434 	if (API->flags & WMF_OPT_XTRA_FONTS)
435 	{	if (API->flags & WMF_OPT_XTRA_FONTMAP)
436 		{	wmf_ipa_font_map_xml (API,&(fontmap_data->FD),options->xtra_fontmap_file);
437 		}
438 		else
439 		{	wmf_ipa_font_map_xml (API,&(fontmap_data->FD),WMF_XTRA_FONTMAP);
440 		}
441 	}
442 
443 	fontmap_data->GS.max = 0;
444 	fontmap_data->GS.len = 0;
445 
446 	fontmap_data->GS.FI = 0;
447 
448 	if (API->flags & WMF_OPT_GS_FONTMAP)
449 	{	wmf_ipa_font_map_gs (API,&(fontmap_data->GS),options->gs_fontmap_file);
450 	}
451 	else
452 	{	wmf_ipa_font_map_gs (API,&(fontmap_data->GS),WMF_GS_FONTMAP);
453 	}
454 }
455 
wmf_ipa_font_map_set(wmfAPI * API,wmfMap map)456 void wmf_ipa_font_map_set (wmfAPI* API,wmfMap map)
457 {	wmfFontData* font_data = (wmfFontData*) API->font_data;
458 
459 	font_data->map = map;
460 }
461 
wmf_ipa_font_dir(wmfAPI * API,char * fontdir)462 void wmf_ipa_font_dir (wmfAPI* API,char* fontdir)
463 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
464 
465 	char** more;
466 
467 	unsigned int i = 0;
468 
469 	while (font_data->fontdirs[i])
470 	{	if (strcmp (font_data->fontdirs[i],fontdir) == 0) break;
471 		i++;
472 	}
473 
474 	if (font_data->fontdirs[i]) return; /* Entry exists already */
475 
476 	if ((i & 0x0f) == (unsigned int) 0x0f)
477 	{	more = (char**) wmf_realloc (API,font_data->fontdirs,(i + 0x11) * sizeof (char*));
478 
479 		if (ERR (API))
480 		{	WMF_DEBUG (API,"bailing...");
481 			return;
482 		}
483 
484 		font_data->fontdirs = more;
485 	}
486 
487 	font_data->fontdirs[i] = wmf_strdup (API,fontdir);
488 
489 	if (ERR (API))
490 	{	WMF_DEBUG (API,"bailing...");
491 		return;
492 	}
493 
494 	i++;
495 	font_data->fontdirs[i] = 0;
496 }
497 
ipa_font_add_api(wmfAPI * API,char * name)498 static void ipa_font_add_api (wmfAPI* API,char* name)
499 {	char** more;
500 
501 	unsigned int i = 0;
502 
503 	while (API->fonts[i])
504 	{	if (strcmp (API->fonts[i],name) == 0) break;
505 		i++;
506 	}
507 
508 	if (API->fonts[i]) return; /* Entry exists already */
509 
510 	if ((i & 0x0f) == (unsigned int) 0x0f)
511 	{	more = (char**) wmf_realloc (API,API->fonts,(i + 0x11) * sizeof (char*));
512 
513 		if (ERR (API))
514 		{	WMF_DEBUG (API,"bailing...");
515 			return;
516 		}
517 
518 		API->fonts = more;
519 	}
520 
521 	API->fonts[i] = wmf_strdup (API,name);
522 
523 	if (ERR (API))
524 	{	WMF_DEBUG (API,"bailing...");
525 		return;
526 	}
527 
528 	i++;
529 	API->fonts[i] = 0;
530 }
531 
532 /* Returns width of string in points, assuming (unstretched) font size of 1pt
533  * WARNING: This is not very accurate. If anyone has a better idea, then...
534  */
wmf_ipa_font_stringwidth(wmfAPI * API,wmfFont * font,char * str)535 float wmf_ipa_font_stringwidth (wmfAPI* API,wmfFont* font,char* str)
536 {	FT_Face face = WMF_FONT_FTFACE (font);
537 
538 	if (!face) return 0.0;
539 
540 	FT_Vector delta;
541 
542 	FT_Bool use_kerning;
543 
544 	FT_UInt glyph_index;
545 	FT_UInt previous;
546 
547 	float width;
548 
549 	int i;
550 	int length;
551 
552 	if ((face == 0) || (str == 0))
553 	{	WMF_DEBUG (API,"wmf_ipa_font_stringwidth: NULL face or str - ??");
554 		return 0;
555 	}
556 
557 	FT_Set_Char_Size (face,0,12 * 64,300,100);
558 
559 	FT_Set_Transform (face,0,0);
560 
561 	use_kerning = FT_HAS_KERNING (face);
562 
563 	previous = 0;
564 
565 	width = 0;
566 
567 	length = strlen (str);
568 
569 	for (i = 0; i < length; i++)
570 	{	/* convert character code to glyph index */
571 		/* ==== Should this be unsigned ??  ==== */
572 
573 		glyph_index = FT_Get_Char_Index (face,str[i]);
574 
575 		if (use_kerning && previous && glyph_index)
576 		{	FT_Get_Kerning (face,previous,glyph_index,0,&delta);
577 
578 			width += (float) (delta.x >> 6);
579 		}
580 
581 		if (glyph_index)
582 		{	/* load glyph image into the slot.  DO NOT RENDER IT! */
583 			FT_Load_Glyph (face,glyph_index,FT_LOAD_DEFAULT);
584 
585 			if (face->glyph) width += (float) (face->glyph->advance.x >> 6);
586 		}
587 
588 		previous = glyph_index;
589 	}
590 
591 	return (width*72/(300*12));
592 }
593 
ipa_char_position(wmfFont * font,char * str,char * last)594 static float ipa_char_position (wmfFont* font,char* str,char* last)
595 {	FT_Face face = WMF_FONT_FTFACE (font);
596 
597 	if (!face) return 0.0;
598 
599 	FT_Vector delta;
600 
601 	FT_Bool use_kerning;
602 
603 	FT_UInt glyph_index;
604 	FT_UInt previous;
605 
606 	float width;
607 
608 	char* ptr;
609 
610 	FT_Set_Char_Size (face,0,12 * 64,300,100);
611 
612 	FT_Set_Transform (face,0,0);
613 
614 	use_kerning = FT_HAS_KERNING (face);
615 
616 	previous = 0;
617 
618 	width = 0;
619 
620 	for (ptr = str; ptr <= last; ptr++)
621 	{	/* convert character code to glyph index */ /* === Should this be unsigned ?? ==== */
622 		glyph_index = FT_Get_Char_Index (face,(*ptr));
623 
624 		if (use_kerning && previous && glyph_index)
625 		{	FT_Get_Kerning (face,previous,glyph_index,0,&delta);
626 
627 			width += (float) (delta.x >> 6);
628 		}
629 
630 		if (ptr == last) break;
631 
632 		/* load glyph image into the slot.  DO NOT RENDER IT! */
633 		FT_Load_Glyph (face,glyph_index,FT_LOAD_DEFAULT);
634 
635 		width += (float) (face->glyph->advance.x >> 6);
636 
637 		previous = glyph_index;
638 	}
639 
640 	return (width*72/(300*12));
641 }
642 
wmf_ipa_draw_text(wmfAPI * API,wmfDrawText_t * draw_text,wmfCharDrawer ipa_draw_text)643 void wmf_ipa_draw_text (wmfAPI* API,wmfDrawText_t* draw_text,wmfCharDrawer ipa_draw_text)
644 {	wmfDrawText_t draw_char;
645 
646 	size_t i;
647 	size_t length;
648 
649 	char buffer[2];
650 
651 	float text_width;
652 
653 	float cos_theta;
654 	float sin_theta;
655 
656 	double theta;
657 
658 	length = strlen (draw_text->str);
659 
660 	theta = - WMF_TEXT_ANGLE (draw_text->dc->font);
661 
662 	cos_theta = (float) cos (theta);
663 	sin_theta = (float) sin (theta);
664 
665 	for (i = 0; i < length; i++)
666 	{	draw_char.dc = draw_text->dc;
667 
668 		buffer[0] = draw_text->str[i];
669 		buffer[1] = 0;
670 
671 		text_width = ipa_char_position (draw_text->dc->font,draw_text->str,draw_text->str+i);
672 
673 		text_width = (float) ((double) text_width * draw_text->font_height * draw_text->font_ratio);
674 
675 		draw_char.pt.x = draw_text->pt.x + text_width * cos_theta;
676 		draw_char.pt.y = draw_text->pt.y + text_width * sin_theta;
677 
678 		draw_char.TL.x = 0;
679 		draw_char.TL.y = 0;
680 		draw_char.BR.x = 0;
681 		draw_char.BR.y = 0;
682 
683 		draw_char.bbox.TL.x = 0;
684 		draw_char.bbox.TL.y = 0;
685 		draw_char.bbox.TR.x = 0;
686 		draw_char.bbox.TR.y = 0;
687 		draw_char.bbox.BR.x = 0;
688 		draw_char.bbox.BR.y = 0;
689 		draw_char.bbox.BL.x = 0;
690 		draw_char.bbox.BL.y = 0;
691 
692 		draw_char.str = buffer;
693 
694 		draw_char.flags = draw_text->flags;
695 
696 		draw_char.font_height = draw_text->font_height;
697 		draw_char.font_ratio  = draw_text->font_ratio;
698 
699 		ipa_draw_text (API,&draw_char);
700 	}
701 }
702 
wmf_ipa_font_map_xml(wmfAPI * API,wmfXML_FontData * FD,char * xmlfontmap)703 void wmf_ipa_font_map_xml (wmfAPI* API,wmfXML_FontData* FD,char* xmlfontmap)
704 {	FD->max = 0;
705 	FD->len = 0;
706 
707 	FD->FI = 0;
708 
709 #ifdef HAVE_EXPAT
710 	exmlfontmap_read (API,FD,xmlfontmap);
711 	return;
712 #endif /* HAVE_EXPAT */
713 #ifdef HAVE_LIBXML2
714 	xml2fontmap_read (API,FD,xmlfontmap);
715 	return;
716 #endif /* HAVE_LIBXML2 */
717 	WMF_DEBUG (API,"warning: no XML support!");
718 }
719 
720 #ifdef HAVE_EXPAT
721 
722 #include <expat.h>
723 
724 #define EXML_BUFSIZE 1024
725 
exml_start(void * user_data,const char * tag,const char ** attributes)726 static void exml_start (void* user_data,const char* tag,const char** attributes)
727 {	const char** attr;
728 
729 	EXML_FontData* exml_data = (EXML_FontData*) user_data;
730 
731 	wmfAPI* API = exml_data->API;
732 
733 	wmfXML_FontData* FD = exml_data->FD;
734 
735 	wmfXML_FontInfo* more = 0;
736 
737 	wmfXML_FontInfo FI;
738 
739 	if ((tag == 0) || (attributes == 0)) return;
740 
741 	if (strcmp (tag,"font")) return;
742 
743 	FI.format = 0;
744 	FI.metrics = 0;
745 	FI.glyphs = 0;
746 	FI.name = 0;
747 	FI.fullname = 0;
748 	FI.familyname = 0;
749 	FI.weight = 0;
750 	FI.version = 0;
751 	FI.alias = 0;
752 
753 	attr = attributes;
754 	while (*attr)
755 	{	if (strcmp ((*attr),"format") == 0)
756 		{	attr++;
757 			FI.format = wmf_strdup (API,(char*) (*attr));
758 		}
759 		else if (strcmp ((*attr),"metrics") == 0)
760 		{	attr++;
761 			FI.metrics = wmf_strdup (API,(char*) (*attr));
762 		}
763 		else if (strcmp ((*attr),"glyphs") == 0)
764 		{	attr++;
765 			FI.glyphs = wmf_strdup (API,(char*) (*attr));
766 		}
767 		else if (strcmp ((*attr),"name") == 0)
768 		{	attr++;
769 			FI.name = wmf_strdup (API,(char*) (*attr));
770 		}
771 		else if (strcmp ((*attr),"fullname") == 0)
772 		{	attr++;
773 			FI.fullname = wmf_strdup (API,(char*) (*attr));
774 		}
775 		else if (strcmp ((*attr),"familyname") == 0)
776 		{	attr++;
777 			FI.familyname = wmf_strdup (API,(char*) (*attr));
778 		}
779 		else if (strcmp ((*attr),"weight") == 0)
780 		{	attr++;
781 			FI.weight = wmf_strdup (API,(char*) (*attr));
782 		}
783 		else if (strcmp ((*attr),"version") == 0)
784 		{	attr++;
785 			FI.version = wmf_strdup (API,(char*) (*attr));
786 		}
787 		else if (strcmp ((*attr),"alias") == 0)
788 		{	attr++;
789 			FI.alias = wmf_strdup (API,(char*) (*attr));
790 		}
791 		else attr++;
792 		attr++;
793 	}
794 
795 	if (FD->len == FD->max)
796 	{	more = wmf_realloc (API,FD->FI,(FD->max + 32) * sizeof (wmfXML_FontInfo));
797 		if (more)
798 		{	FD->FI = more;
799 			FD->max += 32;
800 		}
801 	}
802 	if (FD->len < FD->max)
803 	{	FD->FI[FD->len] = FI;
804 		FD->len++;
805 	}
806 }
807 
exmlfontmap_read(wmfAPI * API,wmfXML_FontData * FD,char * xmlfontmap)808 static void exmlfontmap_read (wmfAPI* API,wmfXML_FontData* FD,char* xmlfontmap)
809 {	int status = 0;
810 	int length;
811 
812 	char buffer[EXML_BUFSIZE];
813 
814 	void* user_data;
815 
816 	FILE* in;
817 
818 	EXML_FontData exml_data;
819 
820 	XML_Parser exml;
821 
822 	FD->max = 32;
823 	FD->len = 0;
824 
825 	FD->FI = wmf_malloc (API,FD->max * sizeof (wmfXML_FontInfo));
826 
827 	if (ERR (API))
828 	{	WMF_DEBUG (API,"bailing...");
829 		FD->max = 0;
830 		return;
831 	}
832 
833 	in = fopen (xmlfontmap,"r");
834 
835 	if (in == 0)
836 	{	WMF_DEBUG (API,"unable to open xml-fontmap");
837 		FD->max = 0;
838 		wmf_free (API,FD->FI);
839 		FD->FI = 0;
840 		return;
841 	}
842 
843 	exml = XML_ParserCreate (0);
844 
845 	if (exml == 0)
846 	{	WMF_DEBUG (API,"error creating expat-xml parser");
847 		FD->max = 0;
848 		wmf_free (API,FD->FI);
849 		FD->FI = 0;
850 		fclose (in);
851 		return;
852 	}
853 
854 	exml_data.API = API;
855 	exml_data.FD = FD;
856 
857 	user_data = (void*) (&exml_data);
858 
859 	XML_SetUserData (exml,user_data);
860 
861 	XML_SetStartElementHandler (exml,exml_start);
862 
863 	while (fgets (buffer,EXML_BUFSIZE,in))
864 	{	length = (int) strlen (buffer);
865 
866 		if (XML_Parse (exml,buffer,length,0) == 0)
867 		{	WMF_DEBUG (API,"expat-xml: error parsing xml fontmap");
868 			status = 1;
869 			break;
870 		}
871 	}
872 	if (status == 0) XML_Parse (exml,buffer,0,1);
873 
874 	XML_ParserFree (exml);
875 
876 	fclose (in);
877 
878 	if (FD->len == 0)
879 	{	FD->max = 0;
880 		wmf_free (API,FD->FI);
881 		FD->FI = 0;
882 	}
883 }
884 #endif /* HAVE_EXPAT */
885 
886 #ifdef HAVE_LIBXML2
887 
888 #include <libxml/parser.h>
889 #include <libxml/parserInternals.h>
890 
xml2_start(void * user_data,const char * tag,const char ** attributes)891 static void xml2_start (void* user_data,const char* tag,const char** attributes)
892 {	const char** attr;
893 
894 	XML2_FontData* xml2_data = (XML2_FontData*) user_data;
895 
896 	wmfAPI* API = xml2_data->API;
897 
898 	wmfXML_FontData* FD = xml2_data->FD;
899 
900 	wmfXML_FontInfo* more = 0;
901 
902 	wmfXML_FontInfo FI;
903 
904 	if ((tag == 0) || (attributes == 0)) return;
905 
906 	if (strcmp (tag,"font")) return;
907 
908 	FI.format = 0;
909 	FI.metrics = 0;
910 	FI.glyphs = 0;
911 	FI.name = 0;
912 	FI.fullname = 0;
913 	FI.familyname = 0;
914 	FI.weight = 0;
915 	FI.version = 0;
916 	FI.alias = 0;
917 
918 	attr = attributes;
919 	while (*attr)
920 	{	if (strcmp ((*attr),"format") == 0)
921 		{	attr++;
922 			FI.format = wmf_strdup (API,(char*) (*attr));
923 		}
924 		else if (strcmp ((*attr),"metrics") == 0)
925 		{	attr++;
926 			FI.metrics = wmf_strdup (API,(char*) (*attr));
927 		}
928 		else if (strcmp ((*attr),"glyphs") == 0)
929 		{	attr++;
930 			FI.glyphs = wmf_strdup (API,(char*) (*attr));
931 		}
932 		else if (strcmp ((*attr),"name") == 0)
933 		{	attr++;
934 			FI.name = wmf_strdup (API,(char*) (*attr));
935 		}
936 		else if (strcmp ((*attr),"fullname") == 0)
937 		{	attr++;
938 			FI.fullname = wmf_strdup (API,(char*) (*attr));
939 		}
940 		else if (strcmp ((*attr),"familyname") == 0)
941 		{	attr++;
942 			FI.familyname = wmf_strdup (API,(char*) (*attr));
943 		}
944 		else if (strcmp ((*attr),"weight") == 0)
945 		{	attr++;
946 			FI.weight = wmf_strdup (API,(char*) (*attr));
947 		}
948 		else if (strcmp ((*attr),"version") == 0)
949 		{	attr++;
950 			FI.version = wmf_strdup (API,(char*) (*attr));
951 		}
952 		else if (strcmp ((*attr),"alias") == 0)
953 		{	attr++;
954 			FI.alias = wmf_strdup (API,(char*) (*attr));
955 		}
956 		else attr++;
957 		attr++;
958 	}
959 
960 	if (FD->len == FD->max)
961 	{	more = wmf_realloc (API,FD->FI,(FD->max + 32) * sizeof (wmfXML_FontInfo));
962 		if (more)
963 		{	FD->FI = more;
964 			FD->max += 32;
965 		}
966 	}
967 	if (FD->len < FD->max)
968 	{	FD->FI[FD->len] = FI;
969 		FD->len++;
970 	}
971 }
972 
xml2fontmap_read(wmfAPI * API,wmfXML_FontData * FD,char * xmlfontmap)973 static void xml2fontmap_read (wmfAPI* API,wmfXML_FontData* FD,char* xmlfontmap)
974 {	XML2_FontData xml2_data;
975 
976 	xmlParserCtxtPtr ctxt;
977 
978 	xmlSAXHandler sax;
979 
980 	memset ((void*) (&sax), 0, sizeof (xmlSAXHandler));
981 
982 	sax.startElement = (startElementSAXFunc) xml2_start;
983 
984 	xml2_data.API = API;
985 	xml2_data.FD = FD;
986 
987 	ctxt = xmlCreateFileParserCtxt (xmlfontmap);
988 
989 	if (ctxt == 0) return;
990 
991 	ctxt->sax = &sax;
992 	ctxt->userData = (void*) (&xml2_data);
993 
994 	xmlParseDocument (ctxt);
995 
996 	ctxt->sax = 0;
997 
998 	xmlFreeParserCtxt (ctxt);
999 }
1000 
1001 #endif /* HAVE_LIBXML2 */
1002 
wmf_ipa_font_map_gs(wmfAPI * API,wmfGS_FontData * FD,char * gsfontmap)1003 void wmf_ipa_font_map_gs (wmfAPI* API,wmfGS_FontData* FD,char* gsfontmap)
1004 {	ipa_font_gs_file (API,FD,gsfontmap);
1005 
1006 	if (ERR (API))
1007 	{	WMF_DEBUG (API,"bailing...");
1008 		return;
1009 	}
1010 
1011 	/* TODO ?? */
1012 }
1013 
ipa_font_gs_file(wmfAPI * API,wmfGS_FontData * FD,char * file)1014 static void ipa_font_gs_file (wmfAPI* API,wmfGS_FontData* FD,char* file)
1015 {	char* line = 0;
1016 
1017 	char* name = 0;
1018 	char* alias = 0;
1019 
1020 	FILE* in = 0;
1021 
1022 	in = fopen (file,"r");
1023 
1024 	if (in == 0)
1025 	{	WMF_DEBUG (API,"ipa_font_gs_file: unable to read ghostscript fontmap!\n");
1026 		return;
1027 	}
1028 
1029 	while (wmf_true)
1030 	{	line = ipa_font_gs_readline (API,in);
1031 
1032 		if (line == 0) break;
1033 
1034 		if (*line)
1035 		{	name = line;
1036 			alias = line;
1037 
1038 			while (!isspace ((int) (*alias)))
1039 			{	if ((*alias) == 0) break;
1040 				alias++;
1041 			}
1042 			if (*alias)
1043 			{	(*alias) = 0;
1044 				alias++;
1045 			}
1046 
1047 			ipa_font_gs_add (API,FD,name,alias);
1048 		}
1049 
1050 		wmf_free (API,line);
1051 	}
1052 
1053 	fclose (in);
1054 }
1055 
ipa_font_gs_add(wmfAPI * API,wmfGS_FontData * FD,char * name,char * alias)1056 static void ipa_font_gs_add (wmfAPI* API,wmfGS_FontData* FD,char* name,char* alias)
1057 {	wmfGS_FontInfo* more = 0;
1058 
1059 	wmf_bool_t fMatched;
1060 
1061 	unsigned int i;
1062 
1063 	if ((name == 0) || (alias == 0)) return;
1064 
1065 	if (name[0] != '/') return;
1066 
1067 	if ((alias[0] != '/') && (alias[0] != '(')) return;
1068 
1069 	if ((alias[0] == '(') && (alias[strlen (alias) - 1] != ')')) return;
1070 
1071 	if (FD->FI == 0)
1072 	{	FD->FI = (wmfGS_FontInfo*) wmf_calloc (API,0x20,sizeof (wmfGS_FontInfo));
1073 
1074 		if (ERR (API))
1075 		{	WMF_DEBUG (API,"bailing...");
1076 			return;
1077 		}
1078 
1079 		FD->max = 0x20;
1080 		FD->len = 0;
1081 	}
1082 
1083 	fMatched = wmf_false;
1084 	for (i = 0; i < FD->len; i++)
1085 	{	if (strcmp (FD->FI[i].name,name+1) == 0)
1086 		{	wmf_free (API,FD->FI[i].alias);
1087 			FD->FI[i].alias = wmf_strdup (API,alias);
1088 			fMatched = wmf_true;
1089 			break;
1090 		}
1091 	}
1092 	if (fMatched) return;
1093 
1094 	if (FD->len == FD->max)
1095 	{	more = (wmfGS_FontInfo*) wmf_realloc (API,FD->FI,(FD->max+0x20) * sizeof (wmfGS_FontInfo));
1096 
1097 		if (ERR (API))
1098 		{	WMF_DEBUG (API,"bailing...");
1099 			return;
1100 		}
1101 
1102 		FD->FI = more;
1103 
1104 		FD->max += 0x20;
1105 	}
1106 
1107 	FD->FI[FD->len].name  = wmf_strdup (API,name+1);
1108 	FD->FI[FD->len].alias = wmf_strdup (API,alias);
1109 
1110 	FD->len++;
1111 }
1112 
ipa_font_gs_alias(wmfGS_FontData * FD,char * name)1113 static char* ipa_font_gs_alias (wmfGS_FontData* FD,char* name)
1114 {	char* alias = 0;
1115 
1116 	unsigned int i;
1117 
1118 	for (i = 0; i < FD->len; i++)
1119 	{	if (strcmp (FD->FI[i].name,name) == 0)
1120 		{	alias = FD->FI[i].alias;
1121 			break;
1122 		}
1123 	}
1124 
1125 	return (alias);
1126 }
1127 
ipa_font_gs_readline(wmfAPI * API,FILE * in)1128 static char* ipa_font_gs_readline (wmfAPI* API,FILE* in)
1129 {	char buf[128];
1130 
1131 	char* line = 0;
1132 	char* more = 0;
1133 	char* ptr = 0;
1134 	char* ptr1 = 0;
1135 	char* ptr2 = 0;
1136 
1137 	wmf_bool_t fBackSlash;
1138 	wmf_bool_t fContinue;
1139 	wmf_bool_t fReadExtra = wmf_false;
1140 
1141 	if (fgets (buf,128,in) == 0) return (0);
1142 
1143 	fBackSlash = wmf_false;
1144 	fContinue  = wmf_true;
1145 	ptr = buf;
1146 	while (*ptr)
1147 	{	if (((*ptr) == '%') && (!fBackSlash))
1148 		{	fContinue = wmf_false;
1149 			if (buf[strlen(buf)-1] != '\n')
1150 			{	fReadExtra = wmf_true;
1151 			}
1152 			else
1153 			{	fReadExtra = wmf_false;
1154 			}
1155 			(*ptr) = 0;
1156 			break;
1157 		}
1158 		if ((*ptr) == '\n')
1159 		{	if (fBackSlash)
1160 			{	fContinue = wmf_true;
1161 				ptr--;
1162 			}
1163 			else
1164 			{	fContinue = wmf_false;
1165 			}
1166 			(*ptr) = 0;
1167 			break;
1168 		}
1169 		if ((*ptr) == '\\')
1170 		{	fBackSlash = wmf_true;
1171 		}
1172 		else
1173 		{	fBackSlash = wmf_false;
1174 		}
1175 		ptr++;
1176 	}
1177 
1178 	line = wmf_strdup (API,buf);
1179 
1180 	if (line == 0) return (line);
1181 
1182 	while (fContinue)
1183 	{	if (fgets (buf,10,in) == 0)
1184 		{	wmf_free (API,line);
1185 			return (0);
1186 		}
1187 
1188 		fBackSlash = wmf_false;
1189 		fContinue  = wmf_true;
1190 		ptr = buf;
1191 		while (*ptr)
1192 		{	if (((*ptr) == '%') && (!fBackSlash))
1193 			{	fContinue = wmf_false;
1194 				fReadExtra = wmf_true;
1195 				(*ptr) = 0;
1196 				break;
1197 			}
1198 			if ((*ptr) == '\n')
1199 			{	if (fBackSlash)
1200 				{	fContinue = wmf_true;
1201 					ptr--;
1202 				}
1203 				else
1204 				{	fContinue = wmf_false;
1205 				}
1206 				(*ptr) = 0;
1207 				break;
1208 			}
1209 			if ((*ptr) == '\\')
1210 			{	fBackSlash = wmf_true;
1211 			}
1212 			else
1213 			{	fBackSlash = wmf_false;
1214 			}
1215 			ptr++;
1216 		}
1217 
1218 		more = wmf_str_append (API,line,buf);
1219 
1220 		wmf_free (API,line);
1221 
1222 		line = more;
1223 
1224 		if (line == 0)
1225 		{
1226 			break;
1227 		}
1228 	}
1229 
1230 	if (line == 0) return (0);
1231 
1232 	if (fReadExtra)
1233 	{
1234 		while (buf[strlen(buf)-1] != '\n')
1235 			if (fgets (buf,128,in) == 0)
1236 				break;
1237 	}
1238 
1239 	/* Strip the string */
1240 
1241 	ptr1 = line;
1242 	ptr2 = line;
1243 	while (*ptr2)
1244 	{	if (!isspace ((int) (*ptr2))) break;
1245 		ptr2++;
1246 	}
1247 	while (*ptr2)
1248 	{	if (isspace ((int) (*ptr2))) break;
1249 		(*ptr1) = (*ptr2);
1250 		ptr1++;
1251 		ptr2++;
1252 	}
1253 	if (*ptr2)
1254 	{	(*ptr1) = (*ptr2);
1255 		ptr1++;
1256 		ptr2++;
1257 	}
1258 	while (*ptr2)
1259 	{	if (!isspace ((int) (*ptr2))) break;
1260 		ptr2++;
1261 	}
1262 	while (*ptr2)
1263 	{	if (isspace ((int) (*ptr2))) break;
1264 		(*ptr1) = (*ptr2);
1265 		ptr1++;
1266 		ptr2++;
1267 	}
1268 	(*ptr1) = 0;
1269 
1270 	while ((--ptr1) >= line)
1271 	{	if (!isspace ((int) (*ptr1))) break;
1272 		(*ptr1) = 0;
1273 	}
1274 
1275 	ptr1 = line;
1276 	ptr2 = line;
1277 	while (*ptr2)
1278 	{	if ((*ptr2) == '%') ptr1--;
1279 		(*ptr1) = (*ptr2);
1280 		ptr1++;
1281 		ptr2++;
1282 	}
1283 	(*ptr1) = 0;
1284 
1285 	return (line);
1286 }
1287 
1288 /**
1289  * This is the fun bit.
1290  *
1291  * @param API  the API handle
1292  * @param font WMF font object: font's \b family \b name, \b italics flag, and the \b weight
1293  *
1294  * Other inputs include: a ghostscript-style Fontmap, and up to two XML RedHat-style fontmaps. (These are
1295  * all parsed earlier.) There are also the fallback 13 standard postscript fonts. And then there is a list
1296  * of font directories to search for fonts.
1297  *
1298  * \b libwmf requires fonts to have a postscript name, and maintains an internal cache of glyphs path and
1299  * \b freetype font face, keyed to postscript font name. Unfortunately, although the XML fontmaps do have
1300  * font \b family \b name, the GS fontmap does not. In the latter, therefore, matching WMF font info to
1301  * postscript font name is hit-and-miss.
1302  */
wmf_ipa_font_map(wmfAPI * API,wmfFont * font)1303 void wmf_ipa_font_map (wmfAPI* API,wmfFont* font)
1304 {	wmfIPAFont* ipa_font = 0;
1305 
1306 	char* mapping = 0;
1307 
1308 	if (font == 0) return;
1309 	if (font->user_data == 0)
1310 	{	font->user_data = wmf_malloc (API,sizeof (wmfIPAFont));
1311 
1312 		if (ERR (API))
1313 		{	WMF_DEBUG (API,"bailing...");
1314 			return;
1315 		}
1316 	}
1317 
1318 	ipa_font = (wmfIPAFont*) font->user_data;
1319 
1320 	ipa_font->ps_name = 0;
1321 	ipa_font->ft_face = 0;
1322 
1323 /* Check system fonts for match and load font face if found...
1324  */
1325 	if (ipa_font_sys_face (API,font,ipa_font_sys_map (API,font))) return;
1326 
1327 /* Check GS fontmap for match and load font face if found...
1328  */
1329 	if (ipa_font_gs_face (API,font,ipa_font_gs_map (API,font))) return;
1330 
1331 /* otherwise, load one of standard 13...
1332  */
1333 	mapping = ipa_font_std (API,font);
1334 
1335 	if (mapping)
1336 	{	if (ipa_font_face (API,font,mapping)) return;
1337 	}
1338 
1339 	WMF_ERROR (API,"wmf_ipa_font_map: failed to load *any* font!");
1340 	API->err = wmf_E_BadFile;
1341 }
1342 
1343 /**
1344  * Searches XML Fontmap for font-name matching WMF's font name.
1345  *
1346  * Basically, this is matching a font's family name + italic + weight parameters to a postscript name.
1347  * Font weight is problematic.
1348  */
ipa_font_sys_map(wmfAPI * API,wmfFont * font)1349 static wmfXML_FontInfo* ipa_font_sys_map (wmfAPI* API,wmfFont* font)
1350 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
1351 
1352 	wmfXML_FontInfo* FI = 0;
1353 
1354 	unsigned int i;
1355 
1356 	for (i = 0; i < font_data->FD.len; i++)
1357 	{	if (strcmp (font->lfFaceName,font_data->FD.FI[i].familyname) == 0)
1358 		{	if ( wmf_strstr (font_data->FD.FI[i].fullname,"Italic")
1359 			  || wmf_strstr (font_data->FD.FI[i].fullname,"Oblique"))
1360 			{	if (font->lfItalic != 1) continue;
1361 			}
1362 			else
1363 			{	if (font->lfItalic == 1) continue;
1364 			}
1365 			if ( wmf_strstr (font_data->FD.FI[i].weight,"Bold")
1366 			  || wmf_strstr (font_data->FD.FI[i].weight,"Demi")) /* or "Medium" ?? */
1367 			{	if (font->lfWeight <= 550) continue;
1368 			}
1369 			else
1370 			{	if (font->lfWeight >  550) continue;
1371 			}
1372 			FI = &(font_data->FD.FI[i]);
1373 			break;
1374 		}
1375 	}
1376 
1377 	return (FI);
1378 }
1379 
1380 /**
1381  * Checks XML Fontmap entry is valid before loading face.
1382  */
ipa_font_sys_face(wmfAPI * API,wmfFont * font,wmfXML_FontInfo * FI)1383 static FT_Face ipa_font_sys_face (wmfAPI* API,wmfFont* font,wmfXML_FontInfo* FI)
1384 {
1385 #if 0
1386 	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
1387 	struct stat stat_buf;
1388 #endif
1389 
1390 	FT_Face face = 0;
1391 
1392 	if (FI == 0) return (0);
1393 
1394 	if (FI->name == 0)
1395 	{	WMF_DEBUG (API,"no postscript name in system-font record?");
1396 		return (0);
1397 	}
1398 
1399 	if (FI->glyphs == 0)
1400 	{	WMF_DEBUG (API,"no glyphs in system-font record?");
1401 		return (0);
1402 	}
1403 
1404 	face = ipa_font_face (API,font,FI->name);
1405 
1406 	return (face);
1407 }
1408 
1409 /**
1410  * Searches GS Fontmap for font-name matching WMF's font name.
1411  *
1412  * Basically, this is matching a font's family name + italic + weight parameters to a postscript name.
1413  * I have decided to test only the first word of the family name, so incorrect matches are probably.
1414  * Font weight is problematic as well.
1415  */
ipa_font_gs_map(wmfAPI * API,wmfFont * font)1416 static wmfGS_FontInfo* ipa_font_gs_map (wmfAPI* API,wmfFont* font)
1417 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
1418 
1419 	wmfGS_FontData* GS = &(font_data->GS);
1420 	wmfGS_FontInfo* FI = 0;
1421 
1422 	wmf_bool_t require_italic;
1423 	wmf_bool_t require_bold;
1424 	wmf_bool_t found_italic;
1425 	wmf_bool_t found_bold;
1426 
1427 	unsigned int name_length = 0;
1428 	unsigned int i;
1429 
1430 	char* name = 0;
1431 	char* ptr = 0;
1432 
1433 	if (GS->len == 0) return (0);
1434 
1435 	name = font->lfFaceName;
1436 
1437 	if (name == 0 || name[0] == 0)
1438 		name = "Times";
1439 
1440 	/* Find first white-space character or eol
1441 	 */
1442 	ptr = name;
1443 	while (!isspace (*ptr))
1444 	{	if ((*ptr) == 0) break;
1445 		ptr++;
1446 		name_length++;
1447 	}
1448 
1449 	if (name_length == 0)
1450 	{	WMF_DEBUG (API,"Unexpectedly short font name?");
1451 		API->err = wmf_E_Glitch;
1452 		return (0);
1453 	}
1454 
1455 	require_italic = ((font->lfItalic == 1) ? wmf_true : wmf_false);
1456 
1457 	require_bold = ((font->lfWeight > 550) ? wmf_true : wmf_false);
1458 
1459 	/* Search for match in GS Fontmap list
1460 	 */
1461 	for (i = 0; i < GS->len; i++)
1462 	{	if (strncmp (name,GS->FI[i].name,name_length) == 0)
1463 		{	found_italic = wmf_false;
1464 			found_bold   = wmf_false;
1465 			if ( wmf_strstr (GS->FI[i].name,"Ital")
1466 			  || wmf_strstr (GS->FI[i].name,"Obli"))
1467 			{	found_italic = wmf_true;
1468 			}
1469 			if ( wmf_strstr (GS->FI[i].name,"Bold")
1470 			  || wmf_strstr (GS->FI[i].name,"Demi")) /* or "Medi" ?? */
1471 			{	found_bold   = wmf_true;
1472 			}
1473 			if ((require_italic == found_italic) && (require_bold == found_bold))
1474 			{	FI = &(GS->FI[i]);
1475 				break;
1476 			}
1477 		}
1478 	}
1479 
1480 	if (FI == 0) return (0);
1481 
1482 	return (FI);
1483 }
1484 
1485 /**
1486  * Takes a [name]/[alias] pair from the GS Fontmap and tries to load [name] as a font,
1487  * and then, provided [alias] is aliased to a font-file & not a 3rd font-name, [alias].
1488  */
ipa_font_gs_face(wmfAPI * API,wmfFont * font,wmfGS_FontInfo * FI)1489 static FT_Face ipa_font_gs_face (wmfAPI* API,wmfFont* font,wmfGS_FontInfo* FI)
1490 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
1491 
1492 	FT_Face face = 0;
1493 
1494 	char* aalias = 0;
1495 
1496 	if (FI == 0) return (0);
1497 
1498 	face = ipa_font_face (API,font,FI->name);
1499 
1500 	if (face) return (face);
1501 
1502 	if (FI->alias[0] != '/') return (0);
1503 
1504 	aalias = ipa_font_gs_alias (&(font_data->GS),FI->alias+1);
1505 
1506 	if (aalias[0] != '(')
1507 	{	WMF_DEBUG (API,"font lookup is too complicated! Giving up...");
1508 		return (0);
1509 	}
1510 
1511 	face = ipa_font_face (API,font,FI->alias+1);
1512 
1513 	return (face);
1514 }
1515 
1516 /**
1517  * Takes a postscript font name and:
1518  *
1519  * (1) Check to see whether font has been cached; if so: return (ipa_font_face_cached ())
1520  * (2) Check for font in XML table; if found:
1521  *    (a) ipa_font_face_open ()
1522  *    (b) return (ipa_font_face_cached ())
1523  * (3) Check for font with file in GS table; if so:
1524  *    (a) search for font file in font search path; if found:
1525  *       ( i) ipa_font_face_open ()
1526  *       (ii) return (ipa_font_face_cached ())
1527  * (4) Check for font in internal table; if found:
1528  *    (a) ipa_font_face_open ()
1529  *    (b) return (ipa_font_face_cached ())
1530  * (5) return (0)
1531  */
ipa_font_face(wmfAPI * API,wmfFont * font,char * ps_name)1532 static FT_Face ipa_font_face (wmfAPI* API,wmfFont* font,char* ps_name)
1533 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
1534 
1535 	FT_Face face = 0;
1536 
1537 	unsigned int i;
1538 
1539 	char* name = 0;
1540 	char* suffix = 0;
1541 	char* glyphs = 0;
1542 	char* metrics = 0;
1543 
1544 	/* (1) Check to see whether font has been cached; if so: return (ipa_font_face_cached ())
1545 	 */
1546 	face = ipa_font_face_cached (API,font,ps_name);
1547 
1548 	if (face) return (face);
1549 
1550 	/* (2) Check for font in XML table
1551 	 */
1552 	glyphs = 0;
1553 	metrics = 0;
1554 	for (i = 0; i < font_data->FD.len; i++)
1555 	{	if (font_data->FD.FI[i].name == 0) continue;
1556 		if (strcmp (ps_name,font_data->FD.FI[i].name) == 0)
1557 		{	glyphs  = font_data->FD.FI[i].glyphs;
1558 			metrics = font_data->FD.FI[i].metrics;
1559 			break;
1560 		}
1561 	}
1562 
1563 	if (glyphs)
1564 	{	face = ipa_font_face_open (API,ps_name,glyphs,metrics);
1565 
1566 		if (face) return (ipa_font_face_cached (API,font,ps_name));
1567 	}
1568 
1569 	/* (3) Check for font with file in GS table
1570 	 */
1571 	name = 0;
1572 	for (i = 0; i < font_data->GS.len; i++)
1573 	{	if (strcmp (ps_name,font_data->GS.FI[i].name) == 0)
1574 		{	if (font_data->GS.FI[i].alias[0] == '(')
1575 			{	name = wmf_strdup (API,font_data->GS.FI[i].alias + 1);
1576 			}
1577 			break;
1578 		}
1579 	}
1580 
1581 	glyphs = 0;
1582 	if (name)
1583 	{	name[strlen (name) - 1] = 0;
1584 
1585 		glyphs = ipa_font_path_find (API,name);
1586 	}
1587 
1588 	metrics = 0;
1589 	if (glyphs)
1590 	{	if (strlen (name) > 3)
1591 		{	suffix = name + strlen (name) - 4;
1592 			if ((strcmp (suffix,".pfa") == 0) || (strcmp (suffix,".pfb") == 0))
1593 			{	strcpy (suffix,".afm");
1594 				metrics = ipa_font_path_find (API,name);
1595 			}
1596 		}
1597 
1598 		face = ipa_font_face_open (API,ps_name,glyphs,metrics);
1599 	}
1600 
1601 	if (name) wmf_free (API,name);
1602 
1603 	if (glyphs)  wmf_free (API,glyphs);
1604 	if (metrics) wmf_free (API,metrics);
1605 
1606 	if (face) return (ipa_font_face_cached (API,font,ps_name));
1607 
1608 	/* (4) Check for font in internal table
1609 	 */
1610 	name = 0;
1611 	i = 0;
1612 	while (font_data->ps[i].name)
1613 	{	if (strcmp (ps_name,font_data->ps[i].name) == 0)
1614 		{	name = wmf_strdup (API,font_data->ps[i].mapping);
1615 			break;
1616 		}
1617 		i++;
1618 	}
1619 
1620 	glyphs = 0;
1621 	if (name)
1622 	{	glyphs = ipa_font_path_find (API,name);
1623 	}
1624 
1625 	metrics = 0;
1626 	if (glyphs)
1627 	{	if (strlen (name) > 3)
1628 		{	suffix = name + strlen (name) - 4;
1629 			if ((strcmp (suffix,".pfa") == 0) || (strcmp (suffix,".pfb") == 0))
1630 			{	strcpy (suffix,".afm");
1631 				metrics = ipa_font_path_find (API,name);
1632 			}
1633 		}
1634 
1635 		face = ipa_font_face_open (API,ps_name,glyphs,metrics);
1636 	}
1637 
1638 	if (name) wmf_free (API,name);
1639 
1640 	if (glyphs)  wmf_free (API,glyphs);
1641 	if (metrics) wmf_free (API,metrics);
1642 
1643 	if (face) return (ipa_font_face_cached (API,font,ps_name));
1644 
1645 	/* (5) return (0)
1646 	 */
1647 	return (0);
1648 }
1649 
1650 /**
1651  * Opens the font with freetype and caches postscript name, glyphs path & FT font face
1652  */
ipa_font_face_open(wmfAPI * API,char * ps_name,char * glyphs,char * metrics)1653 static FT_Face ipa_font_face_open (wmfAPI* API,char* ps_name,char* glyphs,char* metrics)
1654 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
1655 
1656 	wmfFT_CacheEntry entry;
1657 
1658 	FT_Face face = 0;
1659 
1660 	struct stat stat_buf;
1661 
1662 #ifdef _WIN32
1663 	glyphs = remap_font_file_name (API,glyphs);
1664 #endif
1665 	if (stat (glyphs,&stat_buf))
1666 	{	WMF_ERROR (API,"unable to stat font file:");
1667 		WMF_ERROR (API,glyphs);
1668 		API->err = wmf_E_BadFile;
1669 #ifdef _WIN32
1670 		wmf_free (API,glyphs);
1671 #endif
1672 		return (0);
1673 	}
1674 
1675 	if (FT_New_Face (font_data->Library,glyphs,0,&face) != 0)
1676 	{	WMF_ERROR (API,"Failed to open font:");
1677 		WMF_ERROR (API,glyphs);
1678 		API->err = wmf_E_DeviceError;
1679 #ifdef _WIN32
1680 		wmf_free (API,glyphs);
1681 #endif
1682 		return (0);
1683 	}
1684 
1685 #ifdef _WIN32
1686 	metrics = remap_font_file_name (API,metrics);
1687 #endif
1688 	if (metrics)
1689 	{	if (stat (metrics,&stat_buf))
1690 		{	WMF_DEBUG (API,"unable to stat font metrics file:");
1691 			WMF_DEBUG (API,metrics);
1692 		}
1693 		else
1694 		{	if (FT_Attach_File (face,metrics) != 0)
1695 			{	WMF_DEBUG (API,"unable to load font metrics file:");
1696 				WMF_DEBUG (API,metrics);
1697 			}
1698 		}
1699 	}
1700 
1701 	/* Select encoding (I'm very uncertain about this!): - [TODO] ??
1702 	 */
1703 	if (FT_Select_Charmap (face,ft_encoding_adobe_standard) == 0)
1704 	{	WMF_DEBUG (API,glyphs);
1705 		WMF_DEBUG (API,"Adobe Standard Encoding");
1706 	}
1707 	else if (FT_Select_Charmap (face,ft_encoding_adobe_custom) == 0)
1708 	{	WMF_DEBUG (API,glyphs);
1709 		WMF_DEBUG (API,"Adobe Custom Encoding");
1710 	}
1711 	else if (FT_Select_Charmap (face,ft_encoding_symbol) == 0)
1712 	{	WMF_DEBUG (API,glyphs);
1713 		WMF_DEBUG (API,"Symbol Encoding");
1714 	}
1715 	else if (FT_Select_Charmap (face,ft_encoding_unicode) == 0)
1716 	{	WMF_DEBUG (API,glyphs);
1717 		WMF_DEBUG (API,"Unicode Encoding");
1718 	}
1719 	else
1720 	{	WMF_ERROR (API,"Bad encoding! (Please help me!)");
1721 		API->err = wmf_E_DeviceError;
1722 	}
1723 
1724 	entry.name = ps_name;
1725 	entry.path = glyphs;
1726 
1727 	entry.face = face;
1728 
1729 	ipa_font_add_cache (API,&entry); /* cache font name, path & face */
1730 
1731 	ipa_font_add_api (API,ps_name); /* add font name to list of fonts used */
1732 
1733 	return (face);
1734 }
1735 
1736 /**
1737  * Finds font info in cache and sets WMF's font entry appropriately.
1738  */
ipa_font_face_cached(wmfAPI * API,wmfFont * font,char * ps_name)1739 static FT_Face ipa_font_face_cached (wmfAPI* API,wmfFont* font,char* ps_name)
1740 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
1741 
1742 	wmfIPAFont* ipa_font = (wmfIPAFont*) font->user_data;
1743 
1744 	FT_Face face = 0;
1745 
1746 	unsigned int i;
1747 
1748 	/* Check cache for font
1749 	 */
1750 	i = 0;
1751 	while (font_data->cache[i].name)
1752 	{	if (strcmp (font_data->cache[i].name,ps_name) == 0)
1753 		{	face = font_data->cache[i].face;
1754 			break;
1755 		}
1756 		i++;
1757 	}
1758 
1759 	if (face)
1760 	{	ipa_font->ps_name = ps_name;
1761 		ipa_font->ft_face = face;
1762 	}
1763 
1764 	return (face);
1765 }
1766 
1767 /**
1768  * Search for file_name in font path and return full path to file as wmf_malloc() string
1769  */
ipa_font_path_find(wmfAPI * API,char * file_name)1770 static char* ipa_font_path_find (wmfAPI* API,char* file_name)
1771 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
1772 
1773 	struct stat stat_buf;
1774 
1775 	unsigned int length;
1776 	unsigned int count;
1777 	unsigned int i;
1778 
1779 	char* path = 0;
1780 
1781 	/* Determine length of string required to hold path name of font
1782 	 */
1783 	count = 0;
1784 	i = 0;
1785 	while (font_data->fontdirs[i])
1786 	{	length = strlen (font_data->fontdirs[i]);
1787 		if (count < length) count = length;
1788 		i++;
1789 	}
1790 	count += 1 + strlen (file_name) + 1;
1791 
1792 	path = (char*) wmf_malloc (API,count);
1793 
1794 	if (ERR (API))
1795 	{	WMF_DEBUG (API,"bailing...");
1796 		return (0);
1797 	}
1798 
1799 	/* Compose full font file path:
1800 	 */
1801 	i = 0;
1802 	while (font_data->fontdirs[i])
1803 	{	strcpy (path,font_data->fontdirs[i]);
1804 		strcat (path,"/");
1805 		strcat (path,file_name);
1806 		WMF_DEBUG (API,path);
1807 		if (stat (path,&stat_buf) == 0) break; /* file exists */
1808 		i++;
1809 	}
1810 
1811 	if (font_data->fontdirs[i] == 0)
1812 	{	WMF_DEBUG (API,"file not found in font path.");
1813 		wmf_free (API,path);
1814 		path = 0;
1815 	}
1816 
1817 	return (path);
1818 }
1819 
1820 /**
1821  * If after XML & GS fontmap searches the font still hasn't been matched, then use one of the 13 standard
1822  * postscript fonts (or any others that have been added via library options).
1823  */
ipa_font_std(wmfAPI * API,wmfFont * font)1824 static char* ipa_font_std (wmfAPI* API,wmfFont* font)
1825 {	wmfFontmapData* font_data = (wmfFontmapData*) ((wmfFontData*) API->font_data)->user_data;
1826 
1827 	char* mapping = 0;
1828 
1829 	unsigned int i;
1830 	unsigned int index = 0;
1831 
1832 	/* First: check for an exact match:
1833 	 */
1834 	i = 0;
1835 	while (font_data->wmf[i].name)
1836 	{	if (strcmp (font->lfFaceName,font_data->wmf[i].name) == 0)
1837 		{	mapping = font_data->wmf[i].name;
1838 			break;
1839 		}
1840 		i++;
1841 	}
1842 
1843 	/* If no exact match, check for a close (i.e., sub-string) match:
1844 	 */
1845 	if (mapping == 0)
1846 	{	i = 0;
1847 		while (font_data->sub[i].name)
1848 		{	if (wmf_strstr (font->lfFaceName,font_data->sub[i].name))
1849 			{	mapping = font_data->sub[i].mapping;
1850 				break;
1851 			}
1852 			i++;
1853 		}
1854 	}
1855 
1856 	/* If still no match, use the default:
1857 	 */
1858 	if (mapping == 0) mapping = DefaultFontMapping;
1859 
1860 	/* Check chosen mapping in list of exact names:
1861 	 */
1862 	i = 0;
1863 	while (font_data->wmf[i].name)
1864 	{	if (strcmp (mapping,font_data->wmf[i].name) == 0)
1865 		{	index = i;
1866 			break;
1867 		}
1868 		i++;
1869 	}
1870 
1871 	/* If not found then something odd has happened - probably a typo somewhere...
1872 	 */
1873 	if (font_data->wmf[i].name == 0)
1874 	{	WMF_ERROR (API,"Glitch! Unmapped font...");
1875 		API->err = wmf_E_Glitch;
1876 		return (0);
1877 	}
1878 
1879 	/* Select a new mapping (the PS font name) on basis of weight & italic parameters
1880 	 */
1881 	if (font->lfWeight > 550) /* => Bold (?? Don't ask me...) */
1882 	{	if (font->lfItalic == 1) /* Italic */
1883 		{	mapping = font_data->wmf[index].bolditalic;
1884 		}
1885 		else
1886 		{	mapping = font_data->wmf[index].bold;
1887 		}
1888 	}
1889 	else
1890 	{	if (font->lfItalic == 1) /* Italic */
1891 		{	mapping = font_data->wmf[index].italic;
1892 		}
1893 		else
1894 		{	mapping = font_data->wmf[index].normal;
1895 		}
1896 	}
1897 
1898 	return (mapping);
1899 }
1900