1 /********************************************/
2 /* gd interface to freetype library         */
3 /*                                          */
4 /* John Ellson   ellson@graphviz.org        */
5 /********************************************/
6 
7 
8 /**
9  * File: FreeType font rendering
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <math.h>
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "gd.h"
22 #include "gdhelpers.h"
23 #include "gd_intern.h"
24 
25 /* 2.0.10: WIN32, not MSWIN32 */
26 #if !defined(_WIN32) && !defined(_WIN32_WCE)
27 #include <unistd.h>
28 #elif defined(_WIN32_WCE)
29 #include <wce_stdlib.h> /* getenv() */
30 #include <wce_unistd.h> /* access() */
31 #define getenv wceex_getenv
32 #define access wceex_access
33 #else /* _WIN32_WCE */
34 #include <io.h>
35 #ifndef R_OK
36 #define R_OK 04			/* Needed in Windows */
37 #endif
38 #endif
39 
40 /* number of antialised colors for indexed bitmaps */
41 #define GD_NUMCOLORS 8
42 
43 #ifdef HAVE_LIBFONTCONFIG
44 static int fontConfigFlag = 0;
45 
46 /* translate a fontconfig fontpattern into a fontpath.
47 	return NULL if OK, else return error string */
48 static char *font_pattern(char **fontpath, char *fontpattern);
49 #endif
50 
51 #ifdef HAVE_LIBFREETYPE
52 #include "entities.h"
53 static char *font_path(char **fontpath, char *name_list);
54 #endif
55 
56 /* 2.0.30: move these up here so we can build correctly without freetype
57 	but with fontconfig */
58 
59 /*
60  * The character (space) used to separate alternate fonts in the
61  * fontlist parameter to gdImageStringFT. 2.0.18: space was a
62  * poor choice for this.
63  */
64 #define LISTSEPARATOR ";"
65 
66 /*
67  * DEFAULT_FONTPATH and PATHSEPARATOR are host type dependent and
68  * are normally set by configure in config.h.  These are just
69  * some last resort values that might match some Un*x system
70  * if building this version of gd separate from graphviz.
71  */
72 
73 #ifndef DEFAULT_FONTPATH
74 #  if defined(_WIN32)
75 #    define DEFAULT_FONTPATH "C:\\WINDOWS\\FONTS;C:\\WINNT\\FONTS"
76 #  elif defined(__APPLE__) || (defined(__MWERKS__) && defined(macintosh))
77 #    define DEFAULT_FONTPATH "/usr/share/fonts/truetype:/System/Library/Fonts:/Library/Fonts"
78 #  else
79    /* default fontpath for unix systems  - whatever happened to standards ! */
80 #    define DEFAULT_FONTPATH "/usr/X11R6/lib/X11/fonts/TrueType:/usr/X11R6/lib/X11/fonts/truetype:/usr/X11R6/lib/X11/fonts/TTF:/usr/share/fonts/TrueType:/usr/share/fonts/truetype:/usr/openwin/lib/X11/fonts/TrueType:/usr/X11R6/lib/X11/fonts/Type1:/usr/lib/X11/fonts/Type1:/usr/openwin/lib/X11/fonts/Type1"
81 #  endif
82 #endif
83 
84 #ifndef PATHSEPARATOR
85 #  if defined(_WIN32)
86 #    define PATHSEPARATOR ";"
87 #  else
88 #    define PATHSEPARATOR ":"
89 #  endif
90 #endif
91 
92 
93 #ifndef TRUE
94 #define FALSE 0
95 #define TRUE !FALSE
96 #endif
97 
98 /**
99  * Function: gdImageStringTTF
100  *
101  * Alias of <gdImageStringFT>.
102  */
gdImageStringTTF(gdImage * im,int * brect,int fg,const char * fontlist,double ptsize,double angle,int x,int y,const char * string)103 BGD_DECLARE(char *) gdImageStringTTF (gdImage * im, int *brect, int fg, const char *fontlist,
104                                       double ptsize, double angle, int x, int y, const char *string)
105 {
106 	/* 2.0.6: valid return */
107 	return gdImageStringFT (im, brect, fg, fontlist, ptsize,
108 	                        angle, x, y, string);
109 }
110 
111 #ifndef HAVE_LIBFREETYPE
gdImageStringFTEx(gdImage * im,int * brect,int fg,const char * fontlist,double ptsize,double angle,int x,int y,const char * string,gdFTStringExtraPtr strex)112 BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, const char *fontlist,
113                                        double ptsize, double angle, int x, int y, const char *string,
114                                        gdFTStringExtraPtr strex)
115 {
116 	(void)im;
117 	(void)brect;
118 	(void)fg;
119 	(void)fontlist;
120 	(void)ptsize;
121 	(void)angle;
122 	(void)x;
123 	(void)y;
124 	(void)string;
125 	(void)strex;
126 
127 	return "libgd was not built with FreeType font support\n";
128 }
129 
gdImageStringFT(gdImage * im,int * brect,int fg,const char * fontlist,double ptsize,double angle,int x,int y,const char * string)130 BGD_DECLARE(char *) gdImageStringFT (gdImage * im, int *brect, int fg, const char *fontlist,
131                                      double ptsize, double angle, int x, int y, const char *string)
132 {
133 	(void)im;
134 	(void)brect;
135 	(void)fg;
136 	(void)fontlist;
137 	(void)ptsize;
138 	(void)angle;
139 	(void)x;
140 	(void)y;
141 	(void)string;
142 
143 	return "libgd was not built with FreeType font support\n";
144 }
145 #else
146 
147 #include "gdcache.h"
148 /* 2.0.16 Christophe Thomas: starting with FreeType 2.1.6, this is
149   mandatory, and it has been supported for a long while. */
150 #ifdef HAVE_FT2BUILD_H
151 #include <ft2build.h>
152 #include FT_FREETYPE_H
153 #include FT_GLYPH_H
154 #include FT_SIZES_H
155 #else
156 #include <freetype/freetype.h>
157 #include <freetype/ftglyph.h>
158 #include <freetype/ftsizes.h>
159 #endif
160 
161 /* number of fonts cached before least recently used is replaced */
162 #define FONTCACHESIZE 6
163 
164 /* number of antialias color lookups cached */
165 #define TWEENCOLORCACHESIZE 32
166 
167 /*
168  * Line separation as a factor of font height.
169  *      No space between if LINESPACE = 1.00
170  *      Line separation will be rounded up to next pixel row.
171  */
172 #define LINESPACE 1.05
173 
174 typedef struct {
175 	char *fontlist;		/* key */
176 	int flags;			/* key */
177 	char *fontpath;
178 	FT_Library *library;
179 	FT_Face face;
180 }
181 font_t;
182 
183 typedef struct {
184 	const char *fontlist;		/* key */
185 	int flags;			/* key */
186 	FT_Library *library;
187 }
188 fontkey_t;
189 
190 typedef struct {
191 	int pixel;			/* key */
192 	int bgcolor;			/* key */
193 	int fgcolor;			/* key *//* -ve means no antialias */
194 	gdImagePtr im;		/* key */
195 	int tweencolor;
196 }
197 tweencolor_t;
198 
199 typedef struct {
200 	int pixel;			/* key */
201 	int bgcolor;			/* key */
202 	int fgcolor;			/* key *//* -ve means no antialias */
203 	gdImagePtr im;		/* key */
204 }
205 tweencolorkey_t;
206 
207 /********************************************************************
208  * gdTcl_UtfToUniChar is borrowed from Tcl ...
209  */
210 /*
211  * tclUtf.c --
212  *
213  *      Routines for manipulating UTF-8 strings.
214  *
215  * Copyright (c) 1997-1998 Sun Microsystems, Inc.
216  *
217  * See the file "license.terms" for information on usage and redistribution
218  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
219  *
220  * SCCS: @(#) tclUtf.c 1.25 98/01/28 18:02:43
221  */
222 
223 /*
224  *---------------------------------------------------------------------------
225  *
226  * gdTcl_UtfToUniChar --
227  *
228  *      Extract the Tcl_UniChar represented by the UTF-8 string.  Bad
229  *      UTF-8 sequences are converted to valid Tcl_UniChars and processing
230  *      continues.  Equivalent to Plan 9 chartorune().
231  *
232  *      The caller must ensure that the source buffer is long enough that
233  *      this routine does not run off the end and dereference non-existent
234  *      memory looking for trail bytes.  If the source buffer is known to
235  *      be '\0' terminated, this cannot happen.  Otherwise, the caller
236  *      should call Tcl_UtfCharComplete() before calling this routine to
237  *      ensure that enough bytes remain in the string.
238  *
239  * Results:
240  *      *chPtr is filled with the Tcl_UniChar, and the return value is the
241  *      number of bytes from the UTF-8 string that were consumed.
242  *
243  * Side effects:
244  *      None.
245  *
246  *---------------------------------------------------------------------------
247  */
248 
249 #ifdef JISX0208
250 #include "jisx0208.h"
251 #endif
252 
comp_entities(const void * e1,const void * e2)253 static int comp_entities(const void *e1, const void *e2)
254 {
255 	struct entities_s *en1 = (struct entities_s *) e1;
256 	struct entities_s *en2 = (struct entities_s *) e2;
257 	return strcmp(en1->name, en2->name);
258 }
259 
260 extern int any2eucjp (char *, const char *, unsigned int);
261 
262 /* Persistent font cache until explicitly cleared */
263 /* Fonts can be used across multiple images */
264 
265 /* 2.0.16: thread safety (the font cache is shared) */
266 gdMutexDeclare (gdFontCacheMutex);
267 static gdCache_head_t *fontCache;
268 static FT_Library library;
269 
270 #define Tcl_UniChar int
271 #define TCL_UTF_MAX 3
272 static int
gdTcl_UtfToUniChar(const char * str,Tcl_UniChar * chPtr)273 gdTcl_UtfToUniChar (const char *str, Tcl_UniChar * chPtr)
274 /* str is the UTF8 next character pointer */
275 /* chPtr is the int for the result */
276 {
277 	int byte;
278 	char entity_name_buf[ENTITY_NAME_LENGTH_MAX+1];
279 	char *p;
280 	struct entities_s key, *res;
281 
282 	/* HTML4.0 entities in decimal form, e.g. &#197; */
283 	/*           or in hexadecimal form, e.g. &#x6C34; */
284 	byte = *((unsigned char *) str);
285 	if (byte == '&') {
286 		int i, n = 0;
287 
288 		byte = *((unsigned char *) (str + 1));
289 		if (byte == '#') {
290 			byte = *((unsigned char *) (str + 2));
291 			if (byte == 'x' || byte == 'X') {
292 				for (i = 3; i < 8; i++) {
293 					byte = *((unsigned char *) (str + i));
294 					if (byte >= 'A' && byte <= 'F')
295 						byte = byte - 'A' + 10;
296 					else if (byte >= 'a' && byte <= 'f')
297 						byte = byte - 'a' + 10;
298 					else if (byte >= '0' && byte <= '9')
299 						byte = byte - '0';
300 					else
301 						break;
302 					n = (n * 16) + byte;
303 				}
304 			} else {
305 				for (i = 2; i < 8; i++) {
306 					byte = *((unsigned char *) (str + i));
307 					if (byte >= '0' && byte <= '9')
308 						n = (n * 10) + (byte - '0');
309 					else
310 						break;
311 				}
312 			}
313 			if (byte == ';') {
314 				*chPtr = (Tcl_UniChar) n;
315 				return ++i;
316 			}
317 		} else {
318 			key.name = p = entity_name_buf;
319 			for (i = 1; i <= 1 + ENTITY_NAME_LENGTH_MAX; i++) {
320 				byte = *((unsigned char *) (str + i));
321 				if (byte == '\0')
322 					break;
323 				if (byte == ';') {
324 					*p++ = '\0';
325 					res = bsearch(&key, entities, NR_OF_ENTITIES,
326 					              sizeof(entities[0]), *comp_entities);
327 					if (res) {
328 						*chPtr = (Tcl_UniChar) res->value;
329 						return ++i;
330 					}
331 					break;
332 				}
333 				*p++ = byte;
334 			}
335 		}
336 	}
337 
338 	/*
339 	 * Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones.
340 	 */
341 
342 	byte = *((unsigned char *) str);
343 #ifdef JISX0208
344 	if (0xA1 <= byte && byte <= 0xFE) {
345 		int ku, ten;
346 
347 		ku = (byte & 0x7F) - 0x20;
348 		ten = (str[1] & 0x7F) - 0x20;
349 		if ((ku < 1 || ku > 92) || (ten < 1 || ten > 94)) {
350 			*chPtr = (Tcl_UniChar) byte;
351 			return 1;
352 		}
353 
354 		*chPtr = (Tcl_UniChar) UnicodeTbl[ku - 1][ten - 1];
355 		return 2;
356 	} else
357 #endif /* JISX0208 */
358 		if (byte < 0xC0) {
359 			/*
360 			 * Handles properly formed UTF-8 characters between
361 			 * 0x01 and 0x7F.  Also treats \0 and naked trail
362 			 * bytes 0x80 to 0xBF as valid characters representing
363 			 * themselves.
364 			 */
365 
366 			*chPtr = (Tcl_UniChar) byte;
367 			return 1;
368 		} else if (byte < 0xE0) {
369 			if ((str[1] & 0xC0) == 0x80) {
370 				/*
371 				 * Two-byte-character lead-byte followed
372 				 * by a trail-byte.
373 				 */
374 
375 				*chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6) | (str[1] & 0x3F));
376 				return 2;
377 			}
378 			/*
379 			 * A two-byte-character lead-byte not followed by trail-byte
380 			 * represents itself.
381 			 */
382 
383 			*chPtr = (Tcl_UniChar) byte;
384 			return 1;
385 		} else if (byte < 0xF0) {
386 			if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80)) {
387 				/*
388 				 * Three-byte-character lead byte followed by
389 				 * two trail bytes.
390 				 */
391 
392 				*chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12)
393 				                        | ((str[1] & 0x3F) << 6) | (str[2] & 0x3F));
394 				return 3;
395 			}
396 			/*
397 			 * A three-byte-character lead-byte not followed by
398 			 * two trail-bytes represents itself.
399 			 */
400 
401 			*chPtr = (Tcl_UniChar) byte;
402 			return 1;
403 		}
404 #if TCL_UTF_MAX > 3
405 		else {
406 			int ch, total, trail;
407 
408 			total = totalBytes[byte];
409 			trail = total - 1;
410 			if (trail > 0) {
411 				ch = byte & (0x3F >> trail);
412 				do {
413 					str++;
414 					if ((*str & 0xC0) != 0x80) {
415 						*chPtr = byte;
416 						return 1;
417 					}
418 					ch <<= 6;
419 					ch |= (*str & 0x3F);
420 					trail--;
421 				} while (trail > 0);
422 				*chPtr = ch;
423 				return total;
424 			}
425 		}
426 #endif
427 
428 	*chPtr = (Tcl_UniChar) byte;
429 	return 1;
430 }
431 
432 #ifdef HAVE_LIBRAQM
433 #include <raqm.h>
434 #endif
435 
436 typedef struct {
437 	unsigned int index;
438 	FT_Pos x_advance;
439 	FT_Pos x_offset;
440 	FT_Pos y_offset;
441 	uint32_t cluster;
442 } glyphInfo;
443 
444 static ssize_t
textLayout(uint32_t * text,int len,FT_Face face,gdFTStringExtraPtr strex,glyphInfo ** glyph_info)445 textLayout(uint32_t *text, int len,
446 		FT_Face face, gdFTStringExtraPtr strex,
447 		glyphInfo **glyph_info)
448 {
449 	size_t count;
450 	glyphInfo *info;
451 
452 	if (!len) {
453 		return 0;
454 	}
455 
456 #ifdef HAVE_LIBRAQM
457 	size_t i;
458 	raqm_glyph_t *glyphs;
459 	raqm_t *rq = raqm_create ();
460 
461 	if (!rq || !raqm_set_text (rq, text, len) ||
462 		!raqm_set_freetype_face (rq, face) ||
463 		!raqm_set_par_direction (rq, RAQM_DIRECTION_DEFAULT) ||
464 		!raqm_layout (rq)) {
465 		raqm_destroy (rq);
466 		return -1;
467 	}
468 
469 	glyphs = raqm_get_glyphs (rq, &count);
470 	if (!glyphs) {
471 		raqm_destroy (rq);
472 		return -1;
473 	}
474 
475 	info = (glyphInfo*) gdMalloc (sizeof (glyphInfo) * count);
476 	if (!info) {
477 		raqm_destroy (rq);
478 		return -1;
479 	}
480 
481 	for (i = 0; i < count; i++) {
482 		info[i].index = glyphs[i].index;
483 		info[i].x_offset = glyphs[i].x_offset;
484 		info[i].y_offset = glyphs[i].y_offset;
485 		info[i].x_advance = glyphs[i].x_advance;
486 		info[i].cluster = glyphs[i].cluster;
487 	}
488 
489 	raqm_destroy (rq);
490 #else
491 	FT_UInt glyph_index = 0, previous = 0;
492 	FT_Vector delta;
493 	FT_Error err;
494 	info = (glyphInfo*) gdMalloc (sizeof (glyphInfo) * len);
495 	if (!info) {
496 		return -1;
497 	}
498 	for (count = 0; count < len; count++) {
499 		/* Convert character code to glyph index */
500 		glyph_index = FT_Get_Char_Index (face, text[count]);
501 
502 		/* retrieve kerning distance */
503 		if (! (strex && (strex->flags & gdFTEX_DISABLE_KERNING))
504 			&& ! FT_IS_FIXED_WIDTH(face)
505 			&& FT_HAS_KERNING(face)
506 			&& previous
507 			&& glyph_index)
508 			FT_Get_Kerning (face, previous, glyph_index, ft_kerning_default, &delta);
509 		else
510 			delta.x = delta.y = 0;
511 
512 		err = FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT);
513 		if (err) {
514 			gdFree (info);
515 			return -1;
516 		}
517 		info[count].index = glyph_index;
518 		info[count].x_offset = 0;
519 		info[count].y_offset = 0;
520 		if (delta.x != 0)
521 			info[count - 1].x_advance += delta.x;
522 		info[count].x_advance = face->glyph->metrics.horiAdvance;
523 		info[count].cluster = count;
524 
525 		/* carriage returns or newlines */
526 		if (text[count] == '\r' || text[count] == '\n')
527 			previous = 0;	/* clear kerning flag */
528 		else
529 			previous = glyph_index;
530 	}
531 #endif
532 
533 	*glyph_info = info;
534 	return count <= SSIZE_MAX ? count : -1;
535 }
536 
537 /********************************************************************/
538 /* font cache functions                                             */
539 
540 static int
fontTest(void * element,void * key)541 fontTest (void *element, void *key)
542 {
543 	font_t *a = (font_t *) element;
544 	fontkey_t *b = (fontkey_t *) key;
545 
546 	return (strcmp (a->fontlist, b->fontlist) == 0 && a->flags == b->flags);
547 }
548 
549 #ifdef HAVE_LIBFONTCONFIG
useFontConfig(int flag)550 static int useFontConfig(int flag)
551 {
552 	if (fontConfigFlag) {
553 		return (!(flag & gdFTEX_FONTPATHNAME));
554 	}
555 	return flag & gdFTEX_FONTCONFIG;
556 }
557 #endif
558 
559 static void *
fontFetch(char ** error,void * key)560 fontFetch (char **error, void *key)
561 {
562 	font_t *a;
563 	fontkey_t *b = (fontkey_t *) key;
564 	char *suffix;
565 	FT_Error err;
566 	const unsigned int b_font_list_len = strlen(b->fontlist);
567 
568 	*error = NULL;
569 
570 	a = (font_t *) gdMalloc (sizeof (font_t));
571 	if (!a) {
572 		return NULL;
573 	}
574 
575 	a->fontlist = (char *) gdMalloc(b_font_list_len + 1);
576 	if (a->fontlist == NULL) {
577 		gdFree(a);
578 		return "could not alloc full list of fonts";
579 	}
580 	memcpy(a->fontlist, b->fontlist, b_font_list_len);
581 	a->fontlist[b_font_list_len] = 0;
582 
583 	a->flags = b->flags;
584 	a->library = b->library;
585 	a->fontpath = NULL;
586 
587 #ifdef HAVE_LIBFONTCONFIG
588 	if (!useFontConfig(b->flags))
589 		*error = font_path(&(a->fontpath), a->fontlist);
590 	else
591 		*error = font_pattern(&(a->fontpath), a->fontlist);
592 #else
593 	*error = font_path(&(a->fontpath), a->fontlist);
594 #endif /* HAVE_LIBFONTCONFIG */
595 	if (*error || !a->fontpath || !a->fontpath[0]) {
596 		gdFree(a->fontlist);
597 		if (a->fontpath)
598 			free(a->fontpath);
599 		gdFree(a);
600 
601 		if (!*error)
602 			*error = "font_path() returned an empty font pathname";
603 
604 		return NULL;
605 	}
606 
607 	err = FT_New_Face(*b->library, a->fontpath, 0, &a->face);
608 
609 	/* Read kerning metrics for Postscript fonts. */
610 	if (!err
611 	        && ((suffix = strstr(a->fontpath, ".pfa"))
612 	            || (suffix = strstr(a->fontpath, ".pfb")))
613 	        && ((strcpy(suffix, ".afm") && (access(a->fontpath, R_OK) == 0))
614 	            || (strcpy(suffix, ".pfm") && (access(a->fontpath, R_OK) == 0)))) {
615 		err = FT_Attach_File(a->face, a->fontpath);
616 	}
617 
618 	if (err) {
619 		gdFree (a->fontlist);
620 		free(a->fontpath);
621 		gdFree(a);
622 		*error = "Could not read font";
623 		return NULL;
624 	}
625 
626 	return (void *) a;
627 }
628 
629 static void
fontRelease(void * element)630 fontRelease (void *element)
631 {
632 	font_t *a = (font_t *) element;
633 
634 	FT_Done_Face (a->face);
635 	gdFree (a->fontlist);
636 	gdFree (a->fontpath);
637 	gdFree ((char *) element);
638 }
639 
640 /********************************************************************/
641 /* tweencolor cache functions                                            */
642 
643 static int
tweenColorTest(void * element,void * key)644 tweenColorTest (void *element, void *key)
645 {
646 	tweencolor_t *a = (tweencolor_t *) element;
647 	tweencolorkey_t *b = (tweencolorkey_t *) key;
648 
649 	return (a->pixel == b->pixel
650 	        && a->bgcolor == b->bgcolor
651 	        && a->fgcolor == b->fgcolor && a->im == b->im);
652 }
653 
654 /*
655  * Computes a color in im's color table that is part way between
656  * the background and foreground colors proportional to the gray
657  * pixel value in the range 0-GD_NUMCOLORS. The fg and bg colors must already
658  * be in the color table for palette images. For truecolor images the
659  * returned value simply has an alpha component and gdImageAlphaBlend
660  * does the work so that text can be alpha blended across a complex
661  * background (TBB; and for real in 2.0.2).
662  */
663 static void *
tweenColorFetch(char ** error,void * key)664 tweenColorFetch (char **error, void *key)
665 {
666 	tweencolor_t *a;
667 	tweencolorkey_t *b = (tweencolorkey_t *) key;
668 	int pixel, npixel, bg, fg;
669 	gdImagePtr im;
670 
671 	(void)error;
672 
673 	a = (tweencolor_t *) gdMalloc (sizeof (tweencolor_t));
674 	if (!a) {
675 		return NULL;
676 	}
677 
678 	pixel = a->pixel = b->pixel;
679 	bg = a->bgcolor = b->bgcolor;
680 	fg = a->fgcolor = b->fgcolor;
681 	im = a->im = b->im;
682 
683 	/* if fg is specified by a negative color idx, then don't antialias */
684 	if (fg < 0) {
685 		if ((pixel + pixel) >= GD_NUMCOLORS)
686 			a->tweencolor = -fg;
687 		else
688 			a->tweencolor = bg;
689 	} else {
690 		npixel = GD_NUMCOLORS - pixel;
691 		if (im->trueColor) {
692 			/* 2.0.1: use gdImageSetPixel to do the alpha blending work,
693 			   or to just store the alpha level. All we have to do here
694 			   is incorporate our knowledge of the percentage of this
695 			   pixel that is really "lit" by pushing the alpha value
696 			   up toward transparency in edge regions. */
697 			a->tweencolor = gdTrueColorAlpha (gdTrueColorGetRed (fg),
698 			                                  gdTrueColorGetGreen (fg),
699 			                                  gdTrueColorGetBlue (fg),
700 			                                  gdAlphaMax -
701 			                                  (gdTrueColorGetAlpha (fg) *
702 			                                   pixel / GD_NUMCOLORS));
703 		} else {
704 			a->tweencolor = gdImageColorResolve (im,
705 			                                     (pixel * im->red[fg] +
706 			                                      npixel * im->red[bg]) /
707 			                                     GD_NUMCOLORS,
708 			                                     (pixel * im->green[fg] +
709 			                                      npixel * im->green[bg]) /
710 			                                     GD_NUMCOLORS,
711 			                                     (pixel * im->blue[fg] +
712 			                                      npixel * im->blue[bg]) /
713 			                                     GD_NUMCOLORS);
714 		}
715 	}
716 	return (void *) a;
717 }
718 
719 static void
tweenColorRelease(void * element)720 tweenColorRelease (void *element)
721 {
722 	gdFree ((char *) element);
723 }
724 
725 /* draw_bitmap - transfers glyph bitmap to GD image */
726 static char *
gdft_draw_bitmap(gdCache_head_t * tc_cache,gdImage * im,int fg,FT_Bitmap bitmap,int pen_x,int pen_y)727 gdft_draw_bitmap (gdCache_head_t * tc_cache, gdImage * im, int fg,
728                   FT_Bitmap bitmap, int pen_x, int pen_y)
729 {
730 	unsigned char *pixel = NULL;
731 	int *tpixel = NULL;
732 	int opixel;
733 	int x, y, row, col, pc, pcr;
734 
735 	tweencolor_t *tc_elem;
736 	tweencolorkey_t tc_key;
737 
738 	/* copy to image, mapping colors */
739 	tc_key.fgcolor = fg;
740 	tc_key.im = im;
741 	/* Truecolor version; does not require the cache */
742 	if (im->trueColor) {
743 		for (row = 0; row < bitmap.rows; row++) {
744 			pc = row * bitmap.pitch;
745 			pcr = pc;
746 			y = pen_y + row;
747 			/* clip if out of bounds */
748 			/* 2.0.16: clipping rectangle, not image bounds */
749 			if ((y > im->cy2) || (y < im->cy1))
750 				continue;
751 			for (col = 0; col < bitmap.width; col++, pc++) {
752 				int level;
753 				if (bitmap.pixel_mode == ft_pixel_mode_grays) {
754 					/*
755 					 * Scale to 128 levels of alpha for gd use.
756 					 * alpha 0 is opacity, so be sure to invert at the end
757 					 */
758 					level = (bitmap.buffer[pc] * gdAlphaMax /
759 					         (bitmap.num_grays - 1));
760 				} else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
761 					/* 2.0.5: mode_mono fix from Giuliano Pochini */
762 					level =
763 					    ((bitmap.
764 					      buffer[(col >> 3) +
765 					             pcr]) & (1 << (~col & 0x07))) ?
766 					    gdAlphaTransparent : gdAlphaOpaque;
767 				} else {
768 					return "Unsupported ft_pixel_mode";
769 				}
770 				if (level == 0)  /* if background */
771 					continue;
772 
773 				if ((fg >= 0) && (im->trueColor)) {
774 					/* Consider alpha in the foreground color itself to be an
775 					   upper bound on how opaque things get, when truecolor is
776 					   available. Without truecolor this results in far too many
777 					   color indexes. */
778 					level =
779 					    level * (gdAlphaMax -
780 					             gdTrueColorGetAlpha (fg)) / gdAlphaMax;
781 				}
782 				level = gdAlphaMax - level;   /* inverting to get alpha */
783 				x = pen_x + col;
784 				/* clip if out of bounds */
785 				/* 2.0.16: clip to clipping rectangle, Matt McNabb */
786 				if ((x > im->cx2) || (x < im->cx1))
787 					continue;
788 				/* get pixel location in gd buffer */
789 				tpixel = &im->tpixels[y][x];
790 				if (fg < 0) {
791 					if (level < (gdAlphaMax / 2)) {
792 						*tpixel = -fg;
793 					}
794 				} else {
795 					if (im->alphaBlendingFlag) {
796 						opixel = *tpixel;
797 						if (gdTrueColorGetAlpha(opixel) != gdAlphaTransparent) {
798 							*tpixel = gdAlphaBlend (opixel,
799 							                        (level << 24) + (fg & 0xFFFFFF));
800 						} else {
801 							*tpixel = (level << 24) + (fg & 0xFFFFFF);
802 						}
803 					} else {
804 						*tpixel = (level << 24) + (fg & 0xFFFFFF);
805 					}
806 				}
807 			}
808 		}
809 		return (char *) NULL;
810 	}
811 	/* Non-truecolor case, restored to its more or less original form */
812 	for (row = 0; row < bitmap.rows; row++) {
813 		int pcr;
814 		pc = row * bitmap.pitch;
815 		pcr = pc;
816 		if (bitmap.pixel_mode == ft_pixel_mode_mono)
817 			pc *= 8;		/* pc is measured in bits for monochrome images */
818 
819 		y = pen_y + row;
820 
821 		/* clip if out of bounds */
822 		if (y > im->cy2 || y < im->cy1)
823 			continue;
824 
825 		for (col = 0; col < bitmap.width; col++, pc++) {
826 			if (bitmap.pixel_mode == ft_pixel_mode_grays) {
827 				/*
828 				 * Round to GD_NUMCOLORS levels of antialiasing for
829 				 * index color images since only 256 colors are
830 				 * available.
831 				 */
832 				tc_key.pixel = ((bitmap.buffer[pc] * GD_NUMCOLORS)
833 				                + bitmap.num_grays / 2)
834 				               / (bitmap.num_grays - 1);
835 			} else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
836 				/* 2.0.5: mode_mono fix from Giuliano Pochini */
837 				tc_key.pixel =
838 				    ((bitmap.
839 				      buffer[(col >> 3) +
840 				             pcr]) & (1 << (~col & 0x07))) ? GD_NUMCOLORS : 0;
841 			} else {
842 				return "Unsupported ft_pixel_mode";
843 			}
844 			if (tc_key.pixel == 0)	/* if background */
845 				continue;
846 
847 			x = pen_x + col;
848 
849 			/* clip if out of bounds */
850 			if (x > im->cx2 || x < im->cx1)
851 				continue;
852 			/* get pixel location in gd buffer */
853 			pixel = &im->pixels[y][x];
854 			if (tc_key.pixel == GD_NUMCOLORS) {
855 				/* use fg color directly. gd 2.0.2: watch out for
856 				   negative indexes (thanks to David Marwood). */
857 				*pixel = (fg < 0) ? -fg : fg;
858 			} else {
859 				/* find antialised color */
860 
861 				tc_key.bgcolor = *pixel;
862 				tc_elem = (tweencolor_t *) gdCacheGet (tc_cache, &tc_key);
863 				if (!tc_elem) return tc_cache->error;
864 				*pixel = tc_elem->tweencolor;
865 			}
866 		}
867 	}
868 	return (char *) NULL;
869 }
870 
871 /**
872  * Function: gdFreeFontCache
873  *
874  * Alias of <gdFontCacheShutdown>.
875  */
gdFreeFontCache()876 BGD_DECLARE(void) gdFreeFontCache ()
877 {
878 	gdFontCacheShutdown ();
879 }
880 
881 /**
882  * Function: gdFontCacheShutdown
883  *
884  * Shut down the font cache and free the allocated resources.
885  *
886  * Important:
887  *  This function has to be called whenever FreeType operations have been
888  *  invoked, to avoid resource leaks. It doesn't harm to call this function
889  *  multiple times.
890  */
gdFontCacheShutdown()891 BGD_DECLARE(void) gdFontCacheShutdown ()
892 {
893 	if (fontCache) {
894 		gdMutexLock(gdFontCacheMutex);
895 		gdCacheDelete (fontCache);
896 		/* 2.0.16: Gustavo Scotti: make sure we don't free this twice */
897 		fontCache = 0;
898 		gdMutexUnlock(gdFontCacheMutex);
899 		gdMutexShutdown (gdFontCacheMutex);
900 		FT_Done_FreeType (library);
901 	}
902 }
903 
904 /**
905  * Function: gdImageStringFT
906  *
907  * Render an UTF-8 string onto a gd image.
908  *
909  * Parameters:
910  *	im       - The image to draw onto.
911  *  brect    - The bounding rectangle as array of 8 integers where each pair
912  *             represents the x- and y-coordinate of a point. The points
913  *             specify the lower left, lower right, upper right and upper left
914  *             corner.
915  *	fg       - The font color.
916  *	fontlist - The semicolon delimited list of font filenames to look for.
917  *	ptsize   - The height of the font in typographical points (pt).
918  *	angle    - The angle in radian to rotate the font counter-clockwise.
919  *	x        - The x-coordinate of the basepoint (roughly the lower left corner) of the first letter.
920  *	y        - The y-coordinate of the basepoint (roughly the lower left corner) of the first letter.
921  *	string   - The string to render.
922  *
923  * Variant:
924  *  - <gdImageStringFTEx>
925  *
926  * See also:
927  *  - <gdImageString>
928  */
gdImageStringFT(gdImage * im,int * brect,int fg,const char * fontlist,double ptsize,double angle,int x,int y,const char * string)929 BGD_DECLARE(char *) gdImageStringFT (gdImage * im, int *brect, int fg, const char *fontlist,
930                                      double ptsize, double angle, int x, int y, const char *string)
931 {
932 	return gdImageStringFTEx (im, brect, fg, fontlist,
933 	                          ptsize, angle, x, y, string, 0);
934 }
935 
936 /**
937  * Function: gdFontCacheSetup
938  *
939  * Set up the font cache.
940  *
941  * This is called automatically from the string rendering functions, if it
942  * has not already been called. So there's no need to call this function
943  * explicitly.
944  */
gdFontCacheSetup(void)945 BGD_DECLARE(int) gdFontCacheSetup (void)
946 {
947 	if (fontCache) {
948 		/* Already set up */
949 		return 0;
950 	}
951 	gdMutexSetup (gdFontCacheMutex);
952 	if (FT_Init_FreeType (&library)) {
953 		gdMutexShutdown (gdFontCacheMutex);
954 		return -1;
955 	}
956 	fontCache = gdCacheCreate (FONTCACHESIZE, fontTest, fontFetch, fontRelease);
957 	if (!fontCache) {
958 		return -2;
959 	}
960 	return 0;
961 }
962 
963 /*
964   Function: gdImageStringFTEx
965 
966   gdImageStringFTEx extends the capabilities of gdImageStringFT by
967   providing a way to pass additional parameters.
968 
969   If the strex parameter is not null, it must point to a
970   gdFTStringExtra structure. As of gd 2.0.5, this structure is defined
971   as follows:
972   (start code)
973 
974   typedef struct {
975       // logical OR of gdFTEX_ values
976       int flags;
977 
978       // fine tune line spacing for '\n'
979       double linespacing;
980 
981       // Preferred character mapping
982       int charmap;
983 
984       // Rendering resolution
985       int hdpi;
986       int vdpi;
987       char *xshow;
988       char *fontpath;
989   } gdFTStringExtra, *gdFTStringExtraPtr;
990 
991   (end code)
992 
993   To output multiline text with a specific line spacing, include
994   gdFTEX_LINESPACE in the setting of flags:
995 
996     > flags |= gdFTEX_LINESPACE;
997 
998   And also set linespacing to the desired spacing, expressed as a
999   multiple of the font height. Thus a line spacing of 1.0 is the
1000   minimum to guarantee that lines of text do not collide.
1001 
1002   If gdFTEX_LINESPACE is not present, or strex is null, or
1003   gdImageStringFT is called, linespacing defaults to 1.05.
1004 
1005   To specify a preference for Unicode, Shift_JIS Big5 character
1006   encoding, set or To output multiline text with a specific line
1007   spacing, include gdFTEX_CHARMAP in the setting of flags:
1008 
1009     > flags |= gdFTEX_CHARMAP;
1010 
1011   And set charmap to the desired value, which can be any of
1012   gdFTEX_Unicode, gdFTEX_Shift_JIS, gdFTEX_Big5, or
1013   gdFTEX_Adobe_Custom. If you do not specify a preference, Unicode
1014   will be tried first. If the preferred character mapping is not found
1015   in the font, other character mappings are attempted.
1016 
1017   GD operates on the assumption that the output image will be rendered
1018   to a computer screen. By default, gd passes a resolution of 96 dpi
1019   to the freetype text rendering engine. This influences the "hinting"
1020   decisions made by the renderer. To specify a different resolution,
1021   set hdpi and vdpi accordingly (in dots per inch) and add
1022   gdFTEX_RESOLUTION to flags:
1023 
1024     > flags | gdFTEX_RESOLUTION;
1025 
1026   GD 2.0.29 and later will normally attempt to apply kerning tables,
1027   if fontconfig is available, to adjust the relative positions of
1028   consecutive characters more ideally for that pair of
1029   characters. This can be turn off by specifying the
1030   gdFTEX_DISABLE_KERNING flag:
1031 
1032     > flags | gdFTEX_DISABLE_KERNING;
1033 
1034   GD 2.0.29 and later can return a vector of individual character
1035   position advances, occasionally useful in applications that must
1036   know exactly where each character begins. This is returned in the
1037   xshow element of the gdFTStringExtra structure if the gdFTEX_XSHOW
1038   flag is set:
1039 
1040     > flags | gdFTEX_XSHOW;
1041 
1042   The caller is responsible for calling gdFree() on the xshow element
1043   after the call if gdFTEX_XSHOW is set.
1044 
1045   GD 2.0.29 and later can also return the path to the actual font file
1046   used if the gdFTEX_RETURNFONTPATHNAME flag is set. This is useful
1047   because GD 2.0.29 and above are capable of selecting a font
1048   automatically based on a fontconfig font pattern when fontconfig is
1049   available. This information is returned in the fontpath element of
1050   the gdFTStringExtra structure.
1051 
1052     > flags | gdFTEX_RETURNFONTPATHNAME;
1053 
1054   The caller is responsible for calling gdFree() on the fontpath
1055   element after the call if gdFTEX_RETURNFONTPATHNAME is set.
1056 
1057   GD 2.0.29 and later can use fontconfig to resolve font names,
1058   including fontconfig patterns, if the gdFTEX_FONTCONFIG flag is
1059   set. As a convenience, this behavior can be made the default by
1060   calling <gdFTUseFontConfig> with a nonzero value. In that situation it
1061   is not necessary to set the gdFTEX_FONTCONFIG flag on every call;
1062   however explicit font path names can still be used if the
1063   gdFTEX_FONTPATHNAME flag is set:
1064 
1065     > flags | gdFTEX_FONTPATHNAME;
1066 
1067   Unless <gdFTUseFontConfig> has been called with a nonzero value, GD
1068   2.0.29 and later will still expect the fontlist argument to the
1069   freetype text output functions to be a font file name or list
1070   thereof as in previous versions. If you do not wish to make
1071   fontconfig the default, it is still possible to force the use of
1072   fontconfig for a single call to the freetype text output functions
1073   by setting the gdFTEX_FONTCONFIG flag:
1074 
1075     > flags | gdFTEX_FONTCONFIG;
1076 
1077   GD 2.0.29 and above can use fontconfig to resolve font names,
1078   including fontconfig patterns, if the gdFTEX_FONTCONFIG flag is
1079   set. As a convenience, this behavior can be made the default by
1080   calling <gdFTUseFontConfig> with a nonzero value. In that situation it
1081   is not necessary to set the gdFTEX_FONTCONFIG flag on every call;
1082   however explicit font path names can still be used if the
1083   gdFTEX_FONTPATHNAME flag is set:
1084 
1085     > flags | gdFTEX_FONTPATHNAME;
1086 
1087   For more information, see <gdImageStringFT>.
1088 */
1089 
1090 /* the platform-independent resolution used for size and position calculations */
1091 /*    the size of the error introduced by rounding is affected by this number */
1092 #define METRIC_RES 300
1093 
gdImageStringFTEx(gdImage * im,int * brect,int fg,const char * fontlist,double ptsize,double angle,int x,int y,const char * string,gdFTStringExtraPtr strex)1094 BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, const char *fontlist,
1095                                        double ptsize, double angle, int x, int y, const char *string,
1096                                        gdFTStringExtraPtr strex)
1097 {
1098 	FT_Matrix matrix;
1099 	FT_Vector penf, oldpenf, total_min = {0,0}, total_max = {0,0}, glyph_min, glyph_max;
1100 	FT_Face face;
1101 	FT_CharMap charmap = NULL;
1102 	FT_Glyph image;
1103 	FT_GlyphSlot slot;
1104 	FT_Error err;
1105 	FT_UInt glyph_index;
1106 	double sin_a = sin (angle);
1107 	double cos_a = cos (angle);
1108 	int  i, ch;
1109 	font_t *font;
1110 	fontkey_t fontkey;
1111 	const char *next;
1112 	char *tmpstr = 0;
1113 	uint32_t *text;
1114 	glyphInfo *info = NULL;
1115 	ssize_t count;
1116 	int render = (im && (im->trueColor || (fg <= 255 && fg >= -255)));
1117 	FT_BitmapGlyph bm;
1118 	/* 2.0.13: Bob Ostermann: don't force autohint, that's just for testing
1119 	   freetype and doesn't look as good */
1120 	int render_mode = FT_LOAD_DEFAULT;
1121 	int encoding, encodingfound;
1122 	/* Now tuneable thanks to Wez Furlong */
1123 	double linespace = LINESPACE;
1124 	/* 2.0.6: put this declaration with the other declarations! */
1125 	/*
1126 	 *   make a new tweenColorCache on every call
1127 	 *   because caching colormappings between calls
1128 	 *   is not safe. If the im-pointer points to a
1129 	 *   brand new image, the cache gives out bogus
1130 	 *   colorindexes.          -- 27.06.2001 <krisku@arrak.fi>
1131 	 */
1132 	gdCache_head_t *tc_cache;
1133 	/* Tuneable horizontal and vertical resolution in dots per inch */
1134 	int hdpi, vdpi, horiAdvance, xshow_alloc = 0, xshow_pos = 0;
1135 	FT_Size platform_specific, platform_independent;
1136 
1137 	if (strex) {
1138 		if ((strex->flags & gdFTEX_LINESPACE) == gdFTEX_LINESPACE) {
1139 			linespace = strex->linespacing;
1140 		}
1141 	}
1142 	tc_cache = gdCacheCreate (TWEENCOLORCACHESIZE,
1143 	                          tweenColorTest, tweenColorFetch,
1144 	                          tweenColorRelease);
1145 
1146 	/***** initialize font library and font cache on first call ******/
1147 	if (!fontCache) {
1148 		if (gdFontCacheSetup () != 0) {
1149 			gdCacheDelete (tc_cache);
1150 			return "Failure to initialize font library";
1151 		}
1152 	}
1153 	/*****/
1154 	gdMutexLock (gdFontCacheMutex);
1155 	/* get the font (via font cache) */
1156 	fontkey.fontlist = fontlist;
1157 	if (strex)
1158 		fontkey.flags = strex->flags & (gdFTEX_FONTPATHNAME |
1159 		                                gdFTEX_FONTCONFIG);
1160 	else
1161 		fontkey.flags = 0;
1162 	fontkey.library = &library;
1163 	font = (font_t *) gdCacheGet (fontCache, &fontkey);
1164 	if (!font) {
1165 		gdCacheDelete (tc_cache);
1166 		gdMutexUnlock (gdFontCacheMutex);
1167 		return fontCache->error;
1168 	}
1169 	face = font->face;		/* shortcut */
1170 	slot = face->glyph;		/* shortcut */
1171 
1172 	if (brect) {
1173 		total_min.x = total_min.y = 0;
1174 		total_max.x = total_max.y = 0;
1175 	}
1176 
1177 	/*
1178 	 * Added hdpi and vdpi to support images at non-screen resolutions, i.e. 300 dpi TIFF,
1179 	 *    or 100h x 50v dpi FAX format. 2.0.23.
1180 	 * 2004/02/27 Mark Shackelford, mark.shackelford@acs-inc.com
1181 	 */
1182 	hdpi = GD_RESOLUTION;
1183 	vdpi = GD_RESOLUTION;
1184 	encoding = gdFTEX_Unicode;
1185 	if (strex) {
1186 		if (strex->flags & gdFTEX_RESOLUTION) {
1187 			hdpi = strex->hdpi;
1188 			vdpi = strex->vdpi;
1189 		}
1190 		if (strex->flags & gdFTEX_XSHOW) {
1191 			strex->xshow = NULL;
1192 		}
1193 		/* 2.0.12: allow explicit specification of the preferred map;
1194 		   but we still fall back if it is not available. */
1195 		if (strex->flags & gdFTEX_CHARMAP) {
1196 			encoding = strex->charmap;
1197 		}
1198 		/* 2.0.29: we can return the font path if desired */
1199 		if (strex->flags & gdFTEX_RETURNFONTPATHNAME) {
1200 			const unsigned int fontpath_len = strlen(font->fontpath);
1201 
1202 			strex->fontpath = (char *) gdMalloc(fontpath_len + 1);
1203 			if (strex->fontpath == NULL) {
1204 				gdCacheDelete(tc_cache);
1205 				gdMutexUnlock(gdFontCacheMutex);
1206 				return "could not alloc full list of fonts";
1207 			}
1208 			memcpy(strex->fontpath, font->fontpath, fontpath_len);
1209 			strex->fontpath[fontpath_len] = 0;
1210 		}
1211 	}
1212 
1213 	matrix.xx = (FT_Fixed) (cos_a * (1 << 16));
1214 	matrix.yx = (FT_Fixed) (sin_a * (1 << 16));
1215 	matrix.xy = -matrix.yx;
1216 	matrix.yy = matrix.xx;
1217 
1218 	/* set rotation transform */
1219 	FT_Set_Transform (face, &matrix, NULL);
1220 
1221 	FT_New_Size (face, &platform_independent);
1222 	FT_Activate_Size (platform_independent);
1223 	if (FT_Set_Char_Size (face, 0, (FT_F26Dot6)(ptsize*64), METRIC_RES, METRIC_RES)) {
1224 		gdCacheDelete (tc_cache);
1225 		gdMutexUnlock (gdFontCacheMutex);
1226 		return "Could not set character size";
1227 	}
1228 
1229 	if (render) {
1230 		FT_New_Size (face, &platform_specific);
1231 		FT_Activate_Size (platform_specific);
1232 		if (FT_Set_Char_Size (face, 0, (FT_F26Dot6)(ptsize*64), hdpi, vdpi)) {
1233 			gdCacheDelete (tc_cache);
1234 			gdMutexUnlock (gdFontCacheMutex);
1235 			return "Could not set character size";
1236 		}
1237 	}
1238 
1239 	if (fg < 0)
1240 		render_mode |= FT_LOAD_MONOCHROME;
1241 
1242 	/* find requested charmap */
1243 	encodingfound = 0;
1244 	for (i = 0; i < face->num_charmaps; i++) {
1245 		charmap = face->charmaps[i];
1246 
1247 #if ((defined(FREETYPE_MAJOR)) && (((FREETYPE_MAJOR == 2) && (((FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 3)) || (FREETYPE_MINOR > 1))) || (FREETYPE_MAJOR > 2)))
1248 		if (encoding == gdFTEX_Unicode) {
1249 			if (charmap->encoding == FT_ENCODING_MS_SYMBOL
1250 			        || charmap->encoding == FT_ENCODING_UNICODE
1251 			        || charmap->encoding == FT_ENCODING_ADOBE_CUSTOM
1252 			        || charmap->encoding == FT_ENCODING_ADOBE_STANDARD) {
1253 				encodingfound++;
1254 				break;
1255 			}
1256 		} else if (encoding == gdFTEX_Adobe_Custom) {
1257 			if (charmap->encoding == FT_ENCODING_ADOBE_CUSTOM) {
1258 				encodingfound++;
1259 				break;
1260 			}
1261 		} else if (encoding == gdFTEX_Big5) {
1262 			/* renamed sometime after freetype-2.1.4 */
1263 #ifndef FT_ENCODING_BIG5
1264 #define FT_ENCODING_BIG5 FT_ENCODING_MS_BIG5
1265 #endif
1266 			if (charmap->encoding == FT_ENCODING_BIG5) {
1267 				encodingfound++;
1268 				break;
1269 			}
1270 		} else if (encoding == gdFTEX_Shift_JIS) {
1271 			/* renamed sometime after freetype-2.1.4 */
1272 #ifndef FT_ENCODING_SJIS
1273 #define FT_ENCODING_SJIS FT_ENCODING_MS_SJIS
1274 #endif
1275 			if (charmap->encoding == FT_ENCODING_SJIS) {
1276 				encodingfound++;
1277 				break;
1278 			}
1279 		}
1280 #else
1281 		if (encoding == gdFTEX_Unicode) {
1282 			if ((charmap->platform_id = 3 && charmap->encoding_id == 1)     /* Windows Unicode */
1283 			        || (charmap->platform_id == 3 && charmap->encoding_id == 0) /* Windows Symbol */
1284 			        || (charmap->platform_id == 2 && charmap->encoding_id == 1) /* ISO Unicode */
1285 			        || (charmap->platform_id == 0)) {                        /* Apple Unicode */
1286 				encodingfound++;
1287 				break;
1288 			}
1289 		} else if (encoding == gdFTEX_Big5) {
1290 			if (charmap->platform_id == 3 && charmap->encoding_id == 4) {   /* Windows Big5 */
1291 				encodingfound++;
1292 				break;
1293 			}
1294 		} else if (encoding == gdFTEX_Shift_JIS) {
1295 			if (charmap->platform_id == 3 && charmap->encoding_id == 2) {   /* Windows Sjis */
1296 				encodingfound++;
1297 				break;
1298 			}
1299 		}
1300 #endif
1301 	}
1302 	if (encodingfound) {
1303 		FT_Set_Charmap(face, charmap);
1304 	} else {
1305 		/* No character set found! */
1306 		gdCacheDelete (tc_cache);
1307 		gdMutexUnlock (gdFontCacheMutex);
1308 		return "No character set found";
1309 	}
1310 
1311 #ifndef JISX0208
1312 	if (encoding == gdFTEX_Shift_JIS) {
1313 #endif
1314 		if ((tmpstr = (char *) gdMalloc (BUFSIZ))) {
1315 			any2eucjp (tmpstr, string, BUFSIZ);
1316 			next = tmpstr;
1317 		} else {
1318 			next = string;
1319 		}
1320 #ifndef JISX0208
1321 	} else {
1322 		next = string;
1323 	}
1324 #endif
1325 
1326 	oldpenf.x = oldpenf.y = 0; /* for postscript xshow operator */
1327 	penf.x = penf.y = 0;	/* running position of non-rotated glyphs */
1328 	text = (uint32_t*) gdCalloc (sizeof (uint32_t), strlen(next));
1329 	i = 0;
1330 	while (*next) {
1331 		int len;
1332 		ch = *next;
1333 		switch (encoding) {
1334 		case gdFTEX_Unicode: {
1335 			/* use UTF-8 mapping from ASCII */
1336 			len = gdTcl_UtfToUniChar (next, &ch);
1337 			/* EAM DEBUG */
1338 			/* TBB: get this exactly right: 2.1.3 *or better*, all possible cases. */
1339 			/* 2.0.24: David R. Morrison: use the more complete ifdef here. */
1340 #if ((defined(FREETYPE_MAJOR)) && (((FREETYPE_MAJOR == 2) && (((FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 3)) || (FREETYPE_MINOR > 1))) || (FREETYPE_MAJOR > 2)))
1341 			if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
1342 #else
1343 			if (charmap->platform_id == 3 && charmap->encoding_id == 0)
1344 #endif /* Freetype 2.1 or better */
1345 			{
1346 				/* I do not know the significance of the constant 0xf000. */
1347 				/* It was determined by inspection of the character codes */
1348 				/* stored in Microsoft font symbol.ttf                    */
1349 				ch |= 0xf000;
1350 			}
1351 			/* EAM DEBUG */
1352 			next += len;
1353 		}
1354 		break;
1355 		case gdFTEX_Shift_JIS: {
1356 			unsigned char c;
1357 			int jiscode;
1358 			c = *next;
1359 			if (0xA1 <= c && c <= 0xFE) {
1360 				next++;
1361 				jiscode = 0x100 * (c & 0x7F) + ((*next) & 0x7F);
1362 
1363 				ch = (jiscode >> 8) & 0xFF;
1364 				jiscode &= 0xFF;
1365 
1366 				if (ch & 1)
1367 					jiscode += 0x40 - 0x21;
1368 				else
1369 					jiscode += 0x9E - 0x21;
1370 
1371 				if (jiscode >= 0x7F)
1372 					jiscode++;
1373 				ch = (ch - 0x21) / 2 + 0x81;
1374 				if (ch >= 0xA0)
1375 					ch += 0x40;
1376 
1377 				ch = (ch << 8) + jiscode;
1378 			} else {
1379 				ch = c & 0xFF;	/* don't extend sign */
1380 			}
1381 			if (*next) next++;
1382 		}
1383 		break;
1384 		case gdFTEX_Big5: {
1385 			/*
1386 			 * Big 5 mapping:
1387 			 * use "JIS-8 half-width katakana" coding from 8-bit characters. Ref:
1388 			 * ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
1389 			 */
1390 			ch = (*next) & 0xFF;	/* don't extend sign */
1391 			next++;
1392 			if (ch >= 161	/* first code of JIS-8 pair */
1393 			        && *next) {
1394 				/* don't advance past '\0' */
1395 				/* TBB: Fix from Kwok Wah On: & 255 needed */
1396 				ch = (ch * 256) + ((*next) & 255);
1397 				next++;
1398 			}
1399 		}
1400 		break;
1401 
1402 		case gdFTEX_Adobe_Custom:
1403 		default:
1404 			ch &= 0xFF;
1405 			next++;
1406 			break;
1407 		}
1408 		text[i] = ch;
1409 		i++;
1410 	}
1411 
1412 	FT_Activate_Size (platform_independent);
1413 
1414 	count = textLayout (text , i, face, strex, &info);
1415 
1416 	if (count < 0) {
1417 		gdFree (text);
1418 		gdFree (tmpstr);
1419 		gdCacheDelete (tc_cache);
1420 		gdMutexUnlock (gdFontCacheMutex);
1421 		return "Problem doing text layout";
1422 	}
1423 
1424 	for (i = 0; i < count; i++) {
1425 		FT_Activate_Size (platform_independent);
1426 
1427 		ch = text[info[i].cluster];
1428 
1429 		/* carriage returns */
1430 		if (ch == '\r') {
1431 			penf.x = 0;
1432 			continue;
1433 		}
1434 
1435 		/* newlines */
1436 		if (ch == '\n') {
1437 			/* 2.0.13: reset penf.x. Christopher J. Grayce */
1438 			penf.x = 0;
1439 			penf.y += linespace * ptsize * 64 * METRIC_RES / 72;
1440 			penf.y &= ~63;	/* round down to 1/METRIC_RES */
1441 			continue;
1442 		}
1443 
1444 		glyph_index = info[i].index;
1445 		/* When we know the position of the second or subsequent character,
1446 		save the (kerned) advance from the preceeding character in the
1447 		xshow vector */
1448 		if (i && strex && (strex->flags & gdFTEX_XSHOW)) {
1449 			/* make sure we have enough allocation for two numbers
1450 			so we don't have to recheck for the terminating number */
1451 			if (! xshow_alloc) {
1452 				xshow_alloc = 100;
1453 				strex->xshow = gdMalloc(xshow_alloc);
1454 				if (!strex->xshow) {
1455 					if (tmpstr)
1456 						gdFree (tmpstr);
1457 					gdFree(text);
1458 					gdCacheDelete (tc_cache);
1459 					gdMutexUnlock (gdFontCacheMutex);
1460 					return "Problem allocating memory";
1461 				}
1462 				xshow_pos = 0;
1463 			} else if (xshow_pos + 20 > xshow_alloc) {
1464 				xshow_alloc += 100;
1465 				strex->xshow = gdReallocEx(strex->xshow, xshow_alloc);
1466 				if (!strex->xshow) {
1467 					if (tmpstr)
1468 						gdFree (tmpstr);
1469 					gdFree(text);
1470 					gdCacheDelete (tc_cache);
1471 					gdMutexUnlock (gdFontCacheMutex);
1472 					return "Problem allocating memory";
1473 				}
1474 			}
1475 			xshow_pos += sprintf(strex->xshow + xshow_pos, "%g ",
1476 			                     (double)(penf.x - oldpenf.x) * hdpi / (64 * METRIC_RES));
1477 		}
1478 		oldpenf.x = penf.x;
1479 
1480 		/* load glyph image into the slot (erase previous one) */
1481 		err = FT_Load_Glyph (face, glyph_index, render_mode);
1482 		if (err) {
1483 			if (tmpstr)
1484 				gdFree (tmpstr);
1485 			gdFree(text);
1486 			gdCacheDelete (tc_cache);
1487 			gdMutexUnlock (gdFontCacheMutex);
1488 			return "Problem loading glyph";
1489 		}
1490 
1491 		horiAdvance = info[i].x_advance;
1492 
1493 		if (brect) {
1494 			/* only if need brect */
1495 
1496 			glyph_min.x = penf.x + slot->metrics.horiBearingX;
1497 			glyph_min.y = penf.y - slot->metrics.horiBearingY;
1498 
1499 #if 0
1500 			if (ch == ' ') {      /* special case for trailing space */
1501 				glyph_max.x = penf.x + horiAdvance;
1502 			} else {
1503 				glyph_max.x = glyph_min.x + slot->metrics.width;
1504 			}
1505 #else
1506 			glyph_max.x = penf.x + horiAdvance;
1507 #endif
1508 			glyph_max.y = glyph_min.y + slot->metrics.height;
1509 
1510 			if (i==0) {
1511 				total_min = glyph_min;
1512 				total_max = glyph_max;
1513 			} else {
1514 				if (glyph_min.x < total_min.x)
1515 					total_min.x = glyph_min.x;
1516 				if (glyph_min.y < total_min.y)
1517 					total_min.y = glyph_min.y;
1518 				if (glyph_max.x > total_max.x)
1519 					total_max.x = glyph_max.x;
1520 				if (glyph_max.y > total_max.y)
1521 					total_max.y = glyph_max.y;
1522 			}
1523 		}
1524 
1525 		if (render) {
1526 			FT_Activate_Size (platform_specific);
1527 
1528 			/* load glyph again into the slot (erase previous one)  - this time with scaling */
1529 			err = FT_Load_Glyph (face, glyph_index, render_mode);
1530 			if (err) {
1531 				if (tmpstr)
1532 					gdFree (tmpstr);
1533 				gdFree(text);
1534 				gdCacheDelete (tc_cache);
1535 				gdMutexUnlock (gdFontCacheMutex);
1536 				return "Problem loading glyph";
1537 			}
1538 
1539 			/* load and transform glyph image */
1540 			FT_Get_Glyph (slot, &image);
1541 
1542 			if (image->format != ft_glyph_format_bitmap) {
1543 				err = FT_Glyph_To_Bitmap (&image, ft_render_mode_normal, 0, 1);
1544 				if (err) {
1545 					FT_Done_Glyph(image);
1546 					if (tmpstr)
1547 						gdFree (tmpstr);
1548 					gdFree(text);
1549 					gdCacheDelete (tc_cache);
1550 					gdMutexUnlock (gdFontCacheMutex);
1551 					return "Problem rendering glyph";
1552 				}
1553 			}
1554 
1555 			/* now, draw to our target surface */
1556 			bm = (FT_BitmapGlyph) image;
1557 			/* position rounded down to nearest pixel at current dpi
1558 			(the estimate was rounded up to next 1/METRIC_RES, so this should fit) */
1559 			FT_Pos pen_x = penf.x + info[i].x_offset;
1560 			FT_Pos pen_y = penf.y - info[i].y_offset;
1561 			gdft_draw_bitmap (tc_cache, im, fg, bm->bitmap,
1562 					  (int)(x + (pen_x * cos_a + pen_y * sin_a)*hdpi/(METRIC_RES*64) + bm->left),
1563 					  (int)(y - (pen_x * sin_a - pen_y * cos_a)*vdpi/(METRIC_RES*64) - bm->top));
1564 
1565 			FT_Done_Glyph (image);
1566 		}
1567 
1568 
1569 		penf.x += horiAdvance;
1570 	}
1571 
1572 	gdFree(text);
1573 	if (info) {
1574 		gdFree(info);
1575 	}
1576 
1577 	/* Save the (unkerned) advance from the last character in the xshow vector */
1578 	if (strex && (strex->flags & gdFTEX_XSHOW) && strex->xshow) {
1579 		sprintf(strex->xshow + xshow_pos, "%g",
1580 		        (double)(penf.x - oldpenf.x) * hdpi / (64 * METRIC_RES) );
1581 	}
1582 
1583 	if (brect) {
1584 		/* only if need brect */
1585 		double scalex = (double)hdpi / (64 * METRIC_RES);
1586 		double scaley = (double)vdpi / (64 * METRIC_RES);
1587 
1588 		/* rotate bounding rectangle, scale and round to int pixels, and translate */
1589 		brect[0] = x + (total_min.x * cos_a + total_max.y * sin_a)*scalex;
1590 		brect[1] = y - (total_min.x * sin_a - total_max.y * cos_a)*scaley;
1591 		brect[2] = x + (total_max.x * cos_a + total_max.y * sin_a)*scalex;
1592 		brect[3] = y - (total_max.x * sin_a - total_max.y * cos_a)*scaley;
1593 		brect[4] = x + (total_max.x * cos_a + total_min.y * sin_a)*scalex;
1594 		brect[5] = y - (total_max.x * sin_a - total_min.y * cos_a)*scaley;
1595 		brect[6] = x + (total_min.x * cos_a + total_min.y * sin_a)*scalex;
1596 		brect[7] = y - (total_min.x * sin_a - total_min.y * cos_a)*scaley;
1597 	}
1598 
1599 	FT_Done_Size (platform_independent);
1600 	if (render)
1601 		FT_Done_Size (platform_specific);
1602 
1603 	if (tmpstr)
1604 		gdFree (tmpstr);
1605 	gdCacheDelete (tc_cache);
1606 	gdMutexUnlock (gdFontCacheMutex);
1607 	return (char *) NULL;
1608 }
1609 
1610 #endif /* HAVE_LIBFREETYPE */
1611 
1612 #ifdef HAVE_LIBFONTCONFIG
1613 /* Code to find font path, with special mapping for Postscript font names.
1614  *
1615  * Dag Lem <dag@nimrod.no>
1616  */
1617 
1618 #include <fontconfig/fontconfig.h>
1619 
1620 /* #define NO_POSTSCRIPT_ALIAS 1 */
1621 #ifndef NO_POSTSCRIPT_ALIAS
1622 typedef struct _PostscriptAlias {
1623 	char* name;
1624 	char* family;
1625 	char* style;
1626 } PostscriptAlias;
1627 
1628 /* This table maps standard Postscript font names to URW Type 1 fonts.
1629    The mapping is converted from Ghostscript (Fontmap.GS)
1630    for use with fontconfig. */
1631 static PostscriptAlias postscript_alias[] = {
1632 	{ "AvantGarde-Book", "URW Gothic L", "Book" },
1633 	{ "AvantGarde-BookOblique", "URW Gothic L", "Book Oblique" },
1634 	{ "AvantGarde-Demi", "URW Gothic L", "Demi" },
1635 	{ "AvantGarde-DemiOblique", "URW Gothic L", "Demi Oblique" },
1636 
1637 	{ "Bookman-Demi", "URW Bookman L", "Demi Bold" },
1638 	{ "Bookman-DemiItalic", "URW Bookman L", "Demi Bold Italic" },
1639 	{ "Bookman-Light", "URW Bookman L", "Light" },
1640 	{ "Bookman-LightItalic", "URW Bookman L", "Light Italic" },
1641 
1642 	{ "Courier", "Nimbus Mono L", "Regular" },
1643 	{ "Courier-Oblique", "Nimbus Mono L", "Regular Oblique" },
1644 	{ "Courier-Bold", "Nimbus Mono L", "Bold" },
1645 	{ "Courier-BoldOblique", "Nimbus Mono L", "Bold Oblique" },
1646 
1647 	{ "Helvetica", "Nimbus Sans L", "Regular" },
1648 	{ "Helvetica-Oblique", "Nimbus Sans L", "Regular Italic" },
1649 	{ "Helvetica-Bold", "Nimbus Sans L", "Bold" },
1650 	{ "Helvetica-BoldOblique", "Nimbus Sans L", "Bold Italic" },
1651 
1652 	{ "Helvetica-Narrow", "Nimbus Sans L", "Regular Condensed" },
1653 	{ "Helvetica-Narrow-Oblique", "Nimbus Sans L", "Regular Condensed Italic" },
1654 	{ "Helvetica-Narrow-Bold", "Nimbus Sans L", "Bold Condensed" },
1655 	{ "Helvetica-Narrow-BoldOblique", "Nimbus Sans L", "Bold Condensed Italic" },
1656 
1657 	{ "NewCenturySchlbk-Roman", "Century Schoolbook L", "Roman" },
1658 	{ "NewCenturySchlbk-Italic", "Century Schoolbook L", "Italic" },
1659 	{ "NewCenturySchlbk-Bold", "Century Schoolbook L", "Bold" },
1660 	{ "NewCenturySchlbk-BoldItalic", "Century Schoolbook L", "Bold Italic" },
1661 
1662 	{ "Palatino-Roman", "URW Palladio L", "Roman" },
1663 	{ "Palatino-Italic", "URW Palladio L", "Italic" },
1664 	{ "Palatino-Bold", "URW Palladio L", "Bold" },
1665 	{ "Palatino-BoldItalic", "URW Palladio L", "Bold Italic" },
1666 
1667 	{ "Symbol", "Standard Symbols L", "Regular" },
1668 
1669 	{ "Times-Roman", "Nimbus Roman No9 L", "Regular" },
1670 	{ "Times-Italic", "Nimbus Roman No9 L", "Regular Italic" },
1671 	{ "Times-Bold", "Nimbus Roman No9 L", "Medium" },
1672 	{ "Times-BoldItalic", "Nimbus Roman No9 L", "Medium Italic" },
1673 
1674 	{ "ZapfChancery-MediumItalic", "URW Chancery L", "Medium Italic" },
1675 
1676 	{ "ZapfDingbats", "Dingbats", "" },
1677 };
1678 #endif
1679 
1680 
find_font(FcPattern * pattern)1681 static FcPattern* find_font(FcPattern* pattern)
1682 {
1683 	FcResult result;
1684 
1685 	FcConfigSubstitute(0, pattern, FcMatchPattern);
1686 	FcConfigSubstitute(0, pattern, FcMatchFont);
1687 	FcDefaultSubstitute(pattern);
1688 
1689 	return FcFontMatch(0, pattern, &result);
1690 }
1691 
1692 
1693 #ifndef NO_POSTSCRIPT_ALIAS
find_postscript_font(FcPattern ** fontpattern,char * fontname)1694 static char* find_postscript_font(FcPattern **fontpattern, char* fontname)
1695 {
1696 	FcPattern* font = NULL;
1697 	size_t i;
1698 
1699 	*fontpattern = NULL;
1700 	for (i = 0; i < sizeof(postscript_alias)/sizeof(*postscript_alias); i++) {
1701 		if (strcmp(fontname, postscript_alias[i].name) == 0) {
1702 			FcChar8* family;
1703 
1704 			FcPattern* pattern =
1705 			    FcPatternBuild(0,
1706 			                   FC_FAMILY, FcTypeString, postscript_alias[i].family,
1707 			                   FC_STYLE, FcTypeString, postscript_alias[i].style,
1708 			                   (char*)0);
1709 			font = find_font(pattern);
1710 			FcPatternDestroy(pattern);
1711 
1712 			if (!font)
1713 				return "fontconfig: Couldn't find font.";
1714 			if (FcPatternGetString(font, FC_FAMILY, 0, &family) != FcResultMatch) {
1715 				FcPatternDestroy(font);
1716 				return "fontconfig: Couldn't retrieve font family name.";
1717 			}
1718 
1719 			/* Check whether we got the font family we wanted. */
1720 			if (strcmp((const char *)family, postscript_alias[i].family) != 0) {
1721 				FcPatternDestroy(font);
1722 				return "fontconfig: Didn't find expected font family. Perhaps URW Type 1 fonts need installing?";
1723 			}
1724 			break;
1725 		}
1726 	}
1727 
1728 	*fontpattern = font;
1729 	return NULL;
1730 }
1731 #endif
1732 
font_pattern(char ** fontpath,char * fontpattern)1733 static char * font_pattern(char **fontpath, char *fontpattern)
1734 {
1735 	FcPattern* font = NULL;
1736 	FcChar8* file;
1737 	FcPattern* pattern;
1738 #ifndef NO_POSTSCRIPT_ALIAS
1739 	char *error;
1740 #endif
1741 
1742 	*fontpath = NULL;
1743 #ifndef NO_POSTSCRIPT_ALIAS
1744 	error = find_postscript_font(&font, fontpattern);
1745 
1746 	if (!font) {
1747 		if (error)
1748 			return error;
1749 #endif
1750 		pattern = FcNameParse((const FcChar8 *)fontpattern);
1751 		font = find_font(pattern);
1752 		FcPatternDestroy(pattern);
1753 #ifndef NO_POSTSCRIPT_ALIAS
1754 	}
1755 #endif
1756 
1757 	if (!font)
1758 		return "fontconfig: Couldn't find font.";
1759 	if (FcPatternGetString(font, FC_FILE, 0, &file) != FcResultMatch) {
1760 		FcPatternDestroy(font);
1761 		return "fontconfig: Couldn't retrieve font file name.";
1762 	} else {
1763 		const unsigned int file_len = strlen((const char *)file);
1764 
1765 		*fontpath = (char *) gdMalloc(file_len + 1);
1766 		if (*fontpath == NULL) {
1767 			return "could not alloc font path";
1768 		}
1769 		memcpy(*fontpath, (const char *)file, file_len);
1770 		(*fontpath)[file_len] = 0;
1771 	}
1772 	FcPatternDestroy(font);
1773 
1774 	return NULL;
1775 }
1776 
1777 #endif /* HAVE_LIBFONTCONFIG */
1778 
1779 #ifdef HAVE_LIBFREETYPE
1780 /* Look up font using font names as file names. */
font_path(char ** fontpath,char * name_list)1781 static char * font_path(char **fontpath, char *name_list)
1782 {
1783 	int font_found = 0;
1784 	char *fontsearchpath, *fontlist;
1785 	char *fullname = NULL;
1786 	char *name, *dir;
1787 	char *path;
1788 	char *strtok_ptr = NULL;
1789 	const unsigned int name_list_len = strlen(name_list);
1790 
1791 	/*
1792 	 * Search the pathlist for any of a list of font names.
1793 	 */
1794 	*fontpath = NULL;
1795 	fontsearchpath = getenv ("GDFONTPATH");
1796 	if (!fontsearchpath)
1797 		fontsearchpath = DEFAULT_FONTPATH;
1798 	path = (char *) gdMalloc(sizeof(char) * strlen(fontsearchpath) + 1);
1799 	if( path == NULL ) {
1800 		return "could not alloc full list of fonts";
1801 	}
1802 	path[0] = 0;
1803 
1804 	fontlist = (char *) gdMalloc(name_list_len + 1);
1805 	if (fontlist == NULL) {
1806 		gdFree(path);
1807 		return "could not alloc full list of fonts";
1808 	}
1809 	memcpy(fontlist, name_list, name_list_len);
1810 	fontlist[name_list_len] = 0;
1811 
1812 	/*
1813 	 * Must use gd_strtok_r else pointer corrupted by strtok in nested loop.
1814 	 */
1815 	for (name = gd_strtok_r (fontlist, LISTSEPARATOR, &strtok_ptr); name;
1816 	        name = gd_strtok_r (0, LISTSEPARATOR, &strtok_ptr)) {
1817 		char *path_ptr = NULL;
1818 
1819 		/* make a fresh copy each time - strtok corrupts it. */
1820 		sprintf (path, "%s", fontsearchpath);
1821 		/*
1822 		 * Allocate an oversized buffer that is guaranteed to be
1823 		 * big enough for all paths to be tested.
1824 		 */
1825 		/* 2.0.22: Thorben Kundinger: +8 is needed, not +6. */
1826 		fullname = gdReallocEx(fullname,
1827 		                      strlen (fontsearchpath) + strlen (name) + 8);
1828 		if (!fullname) {
1829 			gdFree(fontlist);
1830 			gdFree(path);
1831 			return "could not alloc full path of font";
1832 		}
1833 		/* if name is an absolute or relative pathname then test directly */
1834 		if (strchr (name, '/')
1835 		        || (name[0] != 0 && name[1] == ':'
1836 		            && (name[2] == '/' || name[2] == '\\')))
1837 		{
1838 			sprintf (fullname, "%s", name);
1839 			if (access (fullname, R_OK) == 0) {
1840 				font_found++;
1841 				break;
1842 			}
1843 		}
1844 		for (dir = gd_strtok_r (path, PATHSEPARATOR, &path_ptr); dir;
1845 		        dir = gd_strtok_r (0, PATHSEPARATOR, &path_ptr)) {
1846 			if (strchr (name, '.')) {
1847 				sprintf (fullname, "%s/%s", dir, name);
1848 				if (access (fullname, R_OK) == 0) {
1849 					font_found++;
1850 					break;
1851 				} else {
1852 					continue;
1853 				}
1854 			}
1855 			sprintf (fullname, "%s/%s.ttf", dir, name);
1856 			if (access (fullname, R_OK) == 0) {
1857 				font_found++;
1858 				break;
1859 			}
1860 			sprintf (fullname, "%s/%s.pfa", dir, name);
1861 			if (access (fullname, R_OK) == 0) {
1862 				font_found++;
1863 				break;
1864 			}
1865 			sprintf (fullname, "%s/%s.pfb", dir, name);
1866 			if (access (fullname, R_OK) == 0) {
1867 				font_found++;
1868 				break;
1869 			}
1870 			sprintf (fullname, "%s/%s.dfont", dir, name);
1871 			if (access (fullname, R_OK) == 0) {
1872 				font_found++;
1873 				break;
1874 			}
1875 		}
1876 
1877 		if (font_found)
1878 			break;
1879 	}
1880 	gdFree (path);
1881 	if (fontlist != NULL) {
1882 		gdFree (fontlist);
1883 		fontlist = NULL;
1884 	}
1885 	if (!font_found) {
1886 		gdFree (fullname);
1887 		return "Could not find/open font";
1888 	}
1889 
1890 	*fontpath = fullname;
1891 	return NULL;
1892 }
1893 #endif
1894 
1895 /**
1896  * Function: gdFTUseFontConfig
1897  *
1898  * Enable or disable fontconfig by default.
1899  *
1900  * If GD is built without libfontconfig support, this function is a NOP.
1901  *
1902  * Parameters:
1903  *  flag - Zero to disable, nonzero to enable.
1904  *
1905  * See also:
1906  *  - <gdImageStringFTEx>
1907  */
gdFTUseFontConfig(int flag)1908 BGD_DECLARE(int) gdFTUseFontConfig(int flag)
1909 {
1910 #ifdef HAVE_LIBFONTCONFIG
1911 	fontConfigFlag = flag;
1912 	return 1;
1913 #else
1914 	(void)flag;
1915 	return 0;
1916 #endif /* HAVE_LIBFONTCONFIG */
1917 }
1918