Blame src/gdft.c

Packit ed3af9
Packit ed3af9
/********************************************/
Packit ed3af9
/* gd interface to freetype library         */
Packit ed3af9
/*                                          */
Packit ed3af9
/* John Ellson   ellson@graphviz.org        */
Packit ed3af9
/********************************************/
Packit ed3af9
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * File: FreeType font rendering
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
#include <stdio.h>
Packit ed3af9
#include <stdlib.h>
Packit ed3af9
#include <string.h>
Packit ed3af9
#include <math.h>
Packit ed3af9
Packit ed3af9
#ifdef HAVE_CONFIG_H
Packit ed3af9
#include "config.h"
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#include "gd.h"
Packit ed3af9
#include "gdhelpers.h"
Packit ed3af9
#include "gd_intern.h"
Packit ed3af9
Packit ed3af9
/* 2.0.10: WIN32, not MSWIN32 */
Packit ed3af9
#if !defined(_WIN32) && !defined(_WIN32_WCE)
Packit ed3af9
#include <unistd.h>
Packit ed3af9
#elif defined(_WIN32_WCE)
Packit ed3af9
#include <wce_stdlib.h> /* getenv() */
Packit ed3af9
#include <wce_unistd.h> /* access() */
Packit ed3af9
#define getenv wceex_getenv
Packit ed3af9
#define access wceex_access
Packit ed3af9
#else /* _WIN32_WCE */
Packit ed3af9
#include <io.h>
Packit ed3af9
#ifndef R_OK
Packit ed3af9
#define R_OK 04			/* Needed in Windows */
Packit ed3af9
#endif
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
/* number of antialised colors for indexed bitmaps */
Packit ed3af9
#define GD_NUMCOLORS 8
Packit ed3af9
Packit ed3af9
#ifdef HAVE_LIBFONTCONFIG
Packit ed3af9
static int fontConfigFlag = 0;
Packit ed3af9
Packit ed3af9
/* translate a fontconfig fontpattern into a fontpath.
Packit ed3af9
	return NULL if OK, else return error string */
Packit ed3af9
static char *font_pattern(char **fontpath, char *fontpattern);
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#ifdef HAVE_LIBFREETYPE
Packit ed3af9
#include "entities.h"
Packit ed3af9
static char *font_path(char **fontpath, char *name_list);
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
/* 2.0.30: move these up here so we can build correctly without freetype
Packit ed3af9
	but with fontconfig */
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
 * The character (space) used to separate alternate fonts in the
Packit ed3af9
 * fontlist parameter to gdImageStringFT. 2.0.18: space was a
Packit ed3af9
 * poor choice for this.
Packit ed3af9
 */
Packit ed3af9
#define LISTSEPARATOR ";"
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
 * DEFAULT_FONTPATH and PATHSEPARATOR are host type dependent and
Packit ed3af9
 * are normally set by configure in config.h.  These are just
Packit ed3af9
 * some last resort values that might match some Un*x system
Packit ed3af9
 * if building this version of gd separate from graphviz.
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
#ifndef DEFAULT_FONTPATH
Packit ed3af9
#  ifdef NETWARE
Packit ed3af9
#    define DEFAULT_FONTPATH "sys:/java/nwgfx/lib/x11/fonts/ttf;."
Packit ed3af9
#  elif defined(_WIN32)
Packit ed3af9
#    define DEFAULT_FONTPATH "C:\\WINDOWS\\FONTS;C:\\WINNT\\FONTS"
Packit ed3af9
#  elif defined(__APPLE__) || (defined(__MWERKS__) && defined(macintosh))
Packit ed3af9
#    define DEFAULT_FONTPATH "/usr/share/fonts/truetype:/System/Library/Fonts:/Library/Fonts"
Packit ed3af9
#  else
Packit ed3af9
   /* default fontpath for unix systems  - whatever happened to standards ! */
Packit ed3af9
#    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"
Packit ed3af9
#  endif
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#ifndef PATHSEPARATOR
Packit ed3af9
#  if defined(NETWARE) || defined(_WIN32)
Packit ed3af9
#    define PATHSEPARATOR ";"
Packit ed3af9
#  else
Packit ed3af9
#    define PATHSEPARATOR ":"
Packit ed3af9
#  endif
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
Packit ed3af9
#ifndef TRUE
Packit ed3af9
#define FALSE 0
Packit ed3af9
#define TRUE !FALSE
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageStringTTF
Packit ed3af9
 *
Packit ed3af9
 * Alias of <gdImageStringFT>.
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(char *) gdImageStringTTF (gdImage * im, int *brect, int fg, char *fontlist,
Packit ed3af9
                                      double ptsize, double angle, int x, int y, char *string)
Packit ed3af9
{
Packit ed3af9
	/* 2.0.6: valid return */
Packit ed3af9
	return gdImageStringFT (im, brect, fg, fontlist, ptsize,
Packit ed3af9
	                        angle, x, y, string);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#ifndef HAVE_LIBFREETYPE
Packit ed3af9
BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist,
Packit ed3af9
                                       double ptsize, double angle, int x, int y, char *string,
Packit ed3af9
                                       gdFTStringExtraPtr strex)
Packit ed3af9
{
Packit ed3af9
	(void)im;
Packit ed3af9
	(void)brect;
Packit ed3af9
	(void)fg;
Packit ed3af9
	(void)fontlist;
Packit ed3af9
	(void)ptsize;
Packit ed3af9
	(void)angle;
Packit ed3af9
	(void)x;
Packit ed3af9
	(void)y;
Packit ed3af9
	(void)string;
Packit ed3af9
	(void)strex;
Packit ed3af9
Packit ed3af9
	return "libgd was not built with FreeType font support\n";
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
BGD_DECLARE(char *) gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
Packit ed3af9
                                     double ptsize, double angle, int x, int y, char *string)
Packit ed3af9
{
Packit ed3af9
	(void)im;
Packit ed3af9
	(void)brect;
Packit ed3af9
	(void)fg;
Packit ed3af9
	(void)fontlist;
Packit ed3af9
	(void)ptsize;
Packit ed3af9
	(void)angle;
Packit ed3af9
	(void)x;
Packit ed3af9
	(void)y;
Packit ed3af9
	(void)string;
Packit ed3af9
Packit ed3af9
	return "libgd was not built with FreeType font support\n";
Packit ed3af9
}
Packit ed3af9
#else
Packit ed3af9
Packit ed3af9
#include "gdcache.h"
Packit ed3af9
/* 2.0.16 Christophe Thomas: starting with FreeType 2.1.6, this is
Packit ed3af9
  mandatory, and it has been supported for a long while. */
Packit ed3af9
#ifdef HAVE_FT2BUILD_H
Packit ed3af9
#include <ft2build.h>
Packit ed3af9
#include FT_FREETYPE_H
Packit ed3af9
#include FT_GLYPH_H
Packit ed3af9
#include FT_SIZES_H
Packit ed3af9
#else
Packit ed3af9
#include <freetype/freetype.h>
Packit ed3af9
#include <freetype/ftglyph.h>
Packit ed3af9
#include <freetype/ftsizes.h>
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
/* number of fonts cached before least recently used is replaced */
Packit ed3af9
#define FONTCACHESIZE 6
Packit ed3af9
Packit ed3af9
/* number of antialias color lookups cached */
Packit ed3af9
#define TWEENCOLORCACHESIZE 32
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
 * Line separation as a factor of font height.
Packit ed3af9
 *      No space between if LINESPACE = 1.00
Packit ed3af9
 *      Line separation will be rounded up to next pixel row.
Packit ed3af9
 */
Packit ed3af9
#define LINESPACE 1.05
Packit ed3af9
Packit ed3af9
typedef struct {
Packit ed3af9
	char *fontlist;		/* key */
Packit ed3af9
	int flags;			/* key */
Packit ed3af9
	char *fontpath;
Packit ed3af9
	FT_Library *library;
Packit ed3af9
	FT_Face face;
Packit ed3af9
}
Packit ed3af9
font_t;
Packit ed3af9
Packit ed3af9
typedef struct {
Packit ed3af9
	char *fontlist;		/* key */
Packit ed3af9
	int flags;			/* key */
Packit ed3af9
	FT_Library *library;
Packit ed3af9
}
Packit ed3af9
fontkey_t;
Packit ed3af9
Packit ed3af9
typedef struct {
Packit ed3af9
	int pixel;			/* key */
Packit ed3af9
	int bgcolor;			/* key */
Packit ed3af9
	int fgcolor;			/* key *//* -ve means no antialias */
Packit ed3af9
	gdImagePtr im;		/* key */
Packit ed3af9
	int tweencolor;
Packit ed3af9
}
Packit ed3af9
tweencolor_t;
Packit ed3af9
Packit ed3af9
typedef struct {
Packit ed3af9
	int pixel;			/* key */
Packit ed3af9
	int bgcolor;			/* key */
Packit ed3af9
	int fgcolor;			/* key *//* -ve means no antialias */
Packit ed3af9
	gdImagePtr im;		/* key */
Packit ed3af9
}
Packit ed3af9
tweencolorkey_t;
Packit ed3af9
Packit ed3af9
/********************************************************************
Packit ed3af9
 * gdTcl_UtfToUniChar is borrowed from Tcl ...
Packit ed3af9
 */
Packit ed3af9
/*
Packit ed3af9
 * tclUtf.c --
Packit ed3af9
 *
Packit ed3af9
 *      Routines for manipulating UTF-8 strings.
Packit ed3af9
 *
Packit ed3af9
 * Copyright (c) 1997-1998 Sun Microsystems, Inc.
Packit ed3af9
 *
Packit ed3af9
 * See the file "license.terms" for information on usage and redistribution
Packit ed3af9
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
Packit ed3af9
 *
Packit ed3af9
 * SCCS: @(#) tclUtf.c 1.25 98/01/28 18:02:43
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
 *---------------------------------------------------------------------------
Packit ed3af9
 *
Packit ed3af9
 * gdTcl_UtfToUniChar --
Packit ed3af9
 *
Packit ed3af9
 *      Extract the Tcl_UniChar represented by the UTF-8 string.  Bad
Packit ed3af9
 *      UTF-8 sequences are converted to valid Tcl_UniChars and processing
Packit ed3af9
 *      continues.  Equivalent to Plan 9 chartorune().
Packit ed3af9
 *
Packit ed3af9
 *      The caller must ensure that the source buffer is long enough that
Packit ed3af9
 *      this routine does not run off the end and dereference non-existent
Packit ed3af9
 *      memory looking for trail bytes.  If the source buffer is known to
Packit ed3af9
 *      be '\0' terminated, this cannot happen.  Otherwise, the caller
Packit ed3af9
 *      should call Tcl_UtfCharComplete() before calling this routine to
Packit ed3af9
 *      ensure that enough bytes remain in the string.
Packit ed3af9
 *
Packit ed3af9
 * Results:
Packit ed3af9
 *      *chPtr is filled with the Tcl_UniChar, and the return value is the
Packit ed3af9
 *      number of bytes from the UTF-8 string that were consumed.
Packit ed3af9
 *
Packit ed3af9
 * Side effects:
Packit ed3af9
 *      None.
Packit ed3af9
 *
Packit ed3af9
 *---------------------------------------------------------------------------
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
#ifdef JISX0208
Packit ed3af9
#include "jisx0208.h"
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
static int comp_entities(const void *e1, const void *e2)
Packit ed3af9
{
Packit ed3af9
	struct entities_s *en1 = (struct entities_s *) e1;
Packit ed3af9
	struct entities_s *en2 = (struct entities_s *) e2;
Packit ed3af9
	return strcmp(en1->name, en2->name);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
extern int any2eucjp (char *, char *, unsigned int);
Packit ed3af9
Packit ed3af9
/* Persistent font cache until explicitly cleared */
Packit ed3af9
/* Fonts can be used across multiple images */
Packit ed3af9
Packit ed3af9
/* 2.0.16: thread safety (the font cache is shared) */
Packit ed3af9
gdMutexDeclare (gdFontCacheMutex);
Packit ed3af9
static gdCache_head_t *fontCache;
Packit ed3af9
static FT_Library library;
Packit ed3af9
Packit ed3af9
#define Tcl_UniChar int
Packit ed3af9
#define TCL_UTF_MAX 3
Packit ed3af9
static int
Packit ed3af9
gdTcl_UtfToUniChar (char *str, Tcl_UniChar * chPtr)
Packit ed3af9
/* str is the UTF8 next character pointer */
Packit ed3af9
/* chPtr is the int for the result */
Packit ed3af9
{
Packit ed3af9
	int byte;
Packit ed3af9
	char entity_name_buf[ENTITY_NAME_LENGTH_MAX+1];
Packit ed3af9
	char *p;
Packit ed3af9
	struct entities_s key, *res;
Packit ed3af9
Packit ed3af9
	/* HTML4.0 entities in decimal form, e.g. Å */
Packit ed3af9
	/*           or in hexadecimal form, e.g. 水 */
Packit ed3af9
	byte = *((unsigned char *) str);
Packit ed3af9
	if (byte == '&') {
Packit ed3af9
		int i, n = 0;
Packit ed3af9
Packit ed3af9
		byte = *((unsigned char *) (str + 1));
Packit ed3af9
		if (byte == '#') {
Packit ed3af9
			byte = *((unsigned char *) (str + 2));
Packit ed3af9
			if (byte == 'x' || byte == 'X') {
Packit ed3af9
				for (i = 3; i < 8; i++) {
Packit ed3af9
					byte = *((unsigned char *) (str + i));
Packit ed3af9
					if (byte >= 'A' && byte <= 'F')
Packit ed3af9
						byte = byte - 'A' + 10;
Packit ed3af9
					else if (byte >= 'a' && byte <= 'f')
Packit ed3af9
						byte = byte - 'a' + 10;
Packit ed3af9
					else if (byte >= '0' && byte <= '9')
Packit ed3af9
						byte = byte - '0';
Packit ed3af9
					else
Packit ed3af9
						break;
Packit ed3af9
					n = (n * 16) + byte;
Packit ed3af9
				}
Packit ed3af9
			} else {
Packit ed3af9
				for (i = 2; i < 8; i++) {
Packit ed3af9
					byte = *((unsigned char *) (str + i));
Packit ed3af9
					if (byte >= '0' && byte <= '9')
Packit ed3af9
						n = (n * 10) + (byte - '0');
Packit ed3af9
					else
Packit ed3af9
						break;
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
			if (byte == ';') {
Packit ed3af9
				*chPtr = (Tcl_UniChar) n;
Packit ed3af9
				return ++i;
Packit ed3af9
			}
Packit ed3af9
		} else {
Packit ed3af9
			key.name = p = entity_name_buf;
Packit ed3af9
			for (i = 1; i <= 1 + ENTITY_NAME_LENGTH_MAX; i++) {
Packit ed3af9
				byte = *((unsigned char *) (str + i));
Packit ed3af9
				if (byte == '\0')
Packit ed3af9
					break;
Packit ed3af9
				if (byte == ';') {
Packit ed3af9
					*p++ = '\0';
Packit ed3af9
					res = bsearch(&key, entities, NR_OF_ENTITIES,
Packit ed3af9
					              sizeof(entities[0]), *comp_entities);
Packit ed3af9
					if (res) {
Packit ed3af9
						*chPtr = (Tcl_UniChar) res->value;
Packit ed3af9
						return ++i;
Packit ed3af9
					}
Packit ed3af9
					break;
Packit ed3af9
				}
Packit ed3af9
				*p++ = byte;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/*
Packit ed3af9
	 * Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones.
Packit ed3af9
	 */
Packit ed3af9
Packit ed3af9
	byte = *((unsigned char *) str);
Packit ed3af9
#ifdef JISX0208
Packit ed3af9
	if (0xA1 <= byte && byte <= 0xFE) {
Packit ed3af9
		int ku, ten;
Packit ed3af9
Packit ed3af9
		ku = (byte & 0x7F) - 0x20;
Packit ed3af9
		ten = (str[1] & 0x7F) - 0x20;
Packit ed3af9
		if ((ku < 1 || ku > 92) || (ten < 1 || ten > 94)) {
Packit ed3af9
			*chPtr = (Tcl_UniChar) byte;
Packit ed3af9
			return 1;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		*chPtr = (Tcl_UniChar) UnicodeTbl[ku - 1][ten - 1];
Packit ed3af9
		return 2;
Packit ed3af9
	} else
Packit ed3af9
#endif /* JISX0208 */
Packit ed3af9
		if (byte < 0xC0) {
Packit ed3af9
			/*
Packit ed3af9
			 * Handles properly formed UTF-8 characters between
Packit ed3af9
			 * 0x01 and 0x7F.  Also treats \0 and naked trail
Packit ed3af9
			 * bytes 0x80 to 0xBF as valid characters representing
Packit ed3af9
			 * themselves.
Packit ed3af9
			 */
Packit ed3af9
Packit ed3af9
			*chPtr = (Tcl_UniChar) byte;
Packit ed3af9
			return 1;
Packit ed3af9
		} else if (byte < 0xE0) {
Packit ed3af9
			if ((str[1] & 0xC0) == 0x80) {
Packit ed3af9
				/*
Packit ed3af9
				 * Two-byte-character lead-byte followed
Packit ed3af9
				 * by a trail-byte.
Packit ed3af9
				 */
Packit ed3af9
Packit ed3af9
				*chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6) | (str[1] & 0x3F));
Packit ed3af9
				return 2;
Packit ed3af9
			}
Packit ed3af9
			/*
Packit ed3af9
			 * A two-byte-character lead-byte not followed by trail-byte
Packit ed3af9
			 * represents itself.
Packit ed3af9
			 */
Packit ed3af9
Packit ed3af9
			*chPtr = (Tcl_UniChar) byte;
Packit ed3af9
			return 1;
Packit ed3af9
		} else if (byte < 0xF0) {
Packit ed3af9
			if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80)) {
Packit ed3af9
				/*
Packit ed3af9
				 * Three-byte-character lead byte followed by
Packit ed3af9
				 * two trail bytes.
Packit ed3af9
				 */
Packit ed3af9
Packit ed3af9
				*chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12)
Packit ed3af9
				                        | ((str[1] & 0x3F) << 6) | (str[2] & 0x3F));
Packit ed3af9
				return 3;
Packit ed3af9
			}
Packit ed3af9
			/*
Packit ed3af9
			 * A three-byte-character lead-byte not followed by
Packit ed3af9
			 * two trail-bytes represents itself.
Packit ed3af9
			 */
Packit ed3af9
Packit ed3af9
			*chPtr = (Tcl_UniChar) byte;
Packit ed3af9
			return 1;
Packit ed3af9
		}
Packit ed3af9
#if TCL_UTF_MAX > 3
Packit ed3af9
		else {
Packit ed3af9
			int ch, total, trail;
Packit ed3af9
Packit ed3af9
			total = totalBytes[byte];
Packit ed3af9
			trail = total - 1;
Packit ed3af9
			if (trail > 0) {
Packit ed3af9
				ch = byte & (0x3F >> trail);
Packit ed3af9
				do {
Packit ed3af9
					str++;
Packit ed3af9
					if ((*str & 0xC0) != 0x80) {
Packit ed3af9
						*chPtr = byte;
Packit ed3af9
						return 1;
Packit ed3af9
					}
Packit ed3af9
					ch <<= 6;
Packit ed3af9
					ch |= (*str & 0x3F);
Packit ed3af9
					trail--;
Packit ed3af9
				} while (trail > 0);
Packit ed3af9
				*chPtr = ch;
Packit ed3af9
				return total;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
	*chPtr = (Tcl_UniChar) byte;
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/********************************************************************/
Packit ed3af9
/* font cache functions                                             */
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
fontTest (void *element, void *key)
Packit ed3af9
{
Packit ed3af9
	font_t *a = (font_t *) element;
Packit ed3af9
	fontkey_t *b = (fontkey_t *) key;
Packit ed3af9
Packit ed3af9
	return (strcmp (a->fontlist, b->fontlist) == 0 && a->flags == b->flags);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#ifdef HAVE_LIBFONTCONFIG
Packit ed3af9
static int useFontConfig(int flag)
Packit ed3af9
{
Packit ed3af9
	if (fontConfigFlag) {
Packit ed3af9
		return (!(flag & gdFTEX_FONTPATHNAME));
Packit ed3af9
	}
Packit ed3af9
	return flag & gdFTEX_FONTCONFIG;
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
static void *
Packit ed3af9
fontFetch (char **error, void *key)
Packit ed3af9
{
Packit ed3af9
	font_t *a;
Packit ed3af9
	fontkey_t *b = (fontkey_t *) key;
Packit ed3af9
	char *suffix;
Packit ed3af9
	FT_Error err;
Packit ed3af9
	const unsigned int b_font_list_len = strlen(b->fontlist);
Packit ed3af9
Packit ed3af9
	*error = NULL;
Packit ed3af9
Packit ed3af9
	a = (font_t *) gdMalloc (sizeof (font_t));
Packit ed3af9
	if (!a) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	a->fontlist = (char *) gdMalloc(b_font_list_len + 1);
Packit ed3af9
	if (a->fontlist == NULL) {
Packit ed3af9
		gdFree(a);
Packit ed3af9
		return "could not alloc full list of fonts";
Packit ed3af9
	}
Packit ed3af9
	strncpy(a->fontlist, b->fontlist, b_font_list_len);
Packit ed3af9
	a->fontlist[b_font_list_len] = 0;
Packit ed3af9
Packit ed3af9
	a->flags = b->flags;
Packit ed3af9
	a->library = b->library;
Packit ed3af9
	a->fontpath = NULL;
Packit ed3af9
Packit ed3af9
#ifdef HAVE_LIBFONTCONFIG
Packit ed3af9
	if (!useFontConfig(b->flags))
Packit ed3af9
		*error = font_path(&(a->fontpath), a->fontlist);
Packit ed3af9
	else
Packit ed3af9
		*error = font_pattern(&(a->fontpath), a->fontlist);
Packit ed3af9
#else
Packit ed3af9
	*error = font_path(&(a->fontpath), a->fontlist);
Packit ed3af9
#endif /* HAVE_LIBFONTCONFIG */
Packit ed3af9
	if (*error || !a->fontpath || !a->fontpath[0]) {
Packit ed3af9
		gdFree(a->fontlist);
Packit ed3af9
		if (a->fontpath)
Packit ed3af9
			free(a->fontpath);
Packit ed3af9
		gdFree(a);
Packit ed3af9
Packit ed3af9
		if (!*error)
Packit ed3af9
			*error = "font_path() returned an empty font pathname";
Packit ed3af9
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	err = FT_New_Face(*b->library, a->fontpath, 0, &a->face);
Packit ed3af9
Packit ed3af9
	/* Read kerning metrics for Postscript fonts. */
Packit ed3af9
	if (!err
Packit ed3af9
	        && ((suffix = strstr(a->fontpath, ".pfa"))
Packit ed3af9
	            || (suffix = strstr(a->fontpath, ".pfb")))
Packit ed3af9
	        && ((strcpy(suffix, ".afm") && (access(a->fontpath, R_OK) == 0))
Packit ed3af9
	            || (strcpy(suffix, ".pfm") && (access(a->fontpath, R_OK) == 0)))) {
Packit ed3af9
		err = FT_Attach_File(a->face, a->fontpath);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (err) {
Packit ed3af9
		gdFree (a->fontlist);
Packit ed3af9
		free(a->fontpath);
Packit ed3af9
		gdFree(a);
Packit ed3af9
		*error = "Could not read font";
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return (void *) a;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static void
Packit ed3af9
fontRelease (void *element)
Packit ed3af9
{
Packit ed3af9
	font_t *a = (font_t *) element;
Packit ed3af9
Packit ed3af9
	FT_Done_Face (a->face);
Packit ed3af9
	gdFree (a->fontlist);
Packit ed3af9
	gdFree (a->fontpath);
Packit ed3af9
	gdFree ((char *) element);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/********************************************************************/
Packit ed3af9
/* tweencolor cache functions                                            */
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
tweenColorTest (void *element, void *key)
Packit ed3af9
{
Packit ed3af9
	tweencolor_t *a = (tweencolor_t *) element;
Packit ed3af9
	tweencolorkey_t *b = (tweencolorkey_t *) key;
Packit ed3af9
Packit ed3af9
	return (a->pixel == b->pixel
Packit ed3af9
	        && a->bgcolor == b->bgcolor
Packit ed3af9
	        && a->fgcolor == b->fgcolor && a->im == b->im);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
 * Computes a color in im's color table that is part way between
Packit ed3af9
 * the background and foreground colors proportional to the gray
Packit ed3af9
 * pixel value in the range 0-GD_NUMCOLORS. The fg and bg colors must already
Packit ed3af9
 * be in the color table for palette images. For truecolor images the
Packit ed3af9
 * returned value simply has an alpha component and gdImageAlphaBlend
Packit ed3af9
 * does the work so that text can be alpha blended across a complex
Packit ed3af9
 * background (TBB; and for real in 2.0.2).
Packit ed3af9
 */
Packit ed3af9
static void *
Packit ed3af9
tweenColorFetch (char **error, void *key)
Packit ed3af9
{
Packit ed3af9
	tweencolor_t *a;
Packit ed3af9
	tweencolorkey_t *b = (tweencolorkey_t *) key;
Packit ed3af9
	int pixel, npixel, bg, fg;
Packit ed3af9
	gdImagePtr im;
Packit ed3af9
Packit ed3af9
	(void)error;
Packit ed3af9
Packit ed3af9
	a = (tweencolor_t *) gdMalloc (sizeof (tweencolor_t));
Packit ed3af9
	if (!a) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	pixel = a->pixel = b->pixel;
Packit ed3af9
	bg = a->bgcolor = b->bgcolor;
Packit ed3af9
	fg = a->fgcolor = b->fgcolor;
Packit ed3af9
	im = a->im = b->im;
Packit ed3af9
Packit ed3af9
	/* if fg is specified by a negative color idx, then don't antialias */
Packit ed3af9
	if (fg < 0) {
Packit ed3af9
		if ((pixel + pixel) >= GD_NUMCOLORS)
Packit ed3af9
			a->tweencolor = -fg;
Packit ed3af9
		else
Packit ed3af9
			a->tweencolor = bg;
Packit ed3af9
	} else {
Packit ed3af9
		npixel = GD_NUMCOLORS - pixel;
Packit ed3af9
		if (im->trueColor) {
Packit ed3af9
			/* 2.0.1: use gdImageSetPixel to do the alpha blending work,
Packit ed3af9
			   or to just store the alpha level. All we have to do here
Packit ed3af9
			   is incorporate our knowledge of the percentage of this
Packit ed3af9
			   pixel that is really "lit" by pushing the alpha value
Packit ed3af9
			   up toward transparency in edge regions. */
Packit ed3af9
			a->tweencolor = gdTrueColorAlpha (gdTrueColorGetRed (fg),
Packit ed3af9
			                                  gdTrueColorGetGreen (fg),
Packit ed3af9
			                                  gdTrueColorGetBlue (fg),
Packit ed3af9
			                                  gdAlphaMax -
Packit ed3af9
			                                  (gdTrueColorGetAlpha (fg) *
Packit ed3af9
			                                   pixel / GD_NUMCOLORS));
Packit ed3af9
		} else {
Packit ed3af9
			a->tweencolor = gdImageColorResolve (im,
Packit ed3af9
			                                     (pixel * im->red[fg] +
Packit ed3af9
			                                      npixel * im->red[bg]) /
Packit ed3af9
			                                     GD_NUMCOLORS,
Packit ed3af9
			                                     (pixel * im->green[fg] +
Packit ed3af9
			                                      npixel * im->green[bg]) /
Packit ed3af9
			                                     GD_NUMCOLORS,
Packit ed3af9
			                                     (pixel * im->blue[fg] +
Packit ed3af9
			                                      npixel * im->blue[bg]) /
Packit ed3af9
			                                     GD_NUMCOLORS);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	return (void *) a;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static void
Packit ed3af9
tweenColorRelease (void *element)
Packit ed3af9
{
Packit ed3af9
	gdFree ((char *) element);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* draw_bitmap - transfers glyph bitmap to GD image */
Packit ed3af9
static char *
Packit ed3af9
gdft_draw_bitmap (gdCache_head_t * tc_cache, gdImage * im, int fg,
Packit ed3af9
                  FT_Bitmap bitmap, int pen_x, int pen_y)
Packit ed3af9
{
Packit ed3af9
	unsigned char *pixel = NULL;
Packit ed3af9
	int *tpixel = NULL;
Packit ed3af9
	int opixel;
Packit ed3af9
	int x, y, row, col, pc, pcr;
Packit ed3af9
Packit ed3af9
	tweencolor_t *tc_elem;
Packit ed3af9
	tweencolorkey_t tc_key;
Packit ed3af9
Packit ed3af9
	/* copy to image, mapping colors */
Packit ed3af9
	tc_key.fgcolor = fg;
Packit ed3af9
	tc_key.im = im;
Packit ed3af9
	/* Truecolor version; does not require the cache */
Packit ed3af9
	if (im->trueColor) {
Packit ed3af9
		for (row = 0; row < bitmap.rows; row++) {
Packit ed3af9
			pc = row * bitmap.pitch;
Packit ed3af9
			pcr = pc;
Packit ed3af9
			y = pen_y + row;
Packit ed3af9
			/* clip if out of bounds */
Packit ed3af9
			/* 2.0.16: clipping rectangle, not image bounds */
Packit ed3af9
			if ((y > im->cy2) || (y < im->cy1))
Packit ed3af9
				continue;
Packit ed3af9
			for (col = 0; col < bitmap.width; col++, pc++) {
Packit ed3af9
				int level;
Packit ed3af9
				if (bitmap.pixel_mode == ft_pixel_mode_grays) {
Packit ed3af9
					/*
Packit ed3af9
					 * Scale to 128 levels of alpha for gd use.
Packit ed3af9
					 * alpha 0 is opacity, so be sure to invert at the end
Packit ed3af9
					 */
Packit ed3af9
					level = (bitmap.buffer[pc] * gdAlphaMax /
Packit ed3af9
					         (bitmap.num_grays - 1));
Packit ed3af9
				} else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
Packit ed3af9
					/* 2.0.5: mode_mono fix from Giuliano Pochini */
Packit ed3af9
					level =
Packit ed3af9
					    ((bitmap.
Packit ed3af9
					      buffer[(col >> 3) +
Packit ed3af9
					             pcr]) & (1 << (~col & 0x07))) ?
Packit ed3af9
					    gdAlphaTransparent : gdAlphaOpaque;
Packit ed3af9
				} else {
Packit ed3af9
					return "Unsupported ft_pixel_mode";
Packit ed3af9
				}
Packit ed3af9
				if (level == 0)  /* if background */
Packit ed3af9
					continue;
Packit ed3af9
Packit ed3af9
				if ((fg >= 0) && (im->trueColor)) {
Packit ed3af9
					/* Consider alpha in the foreground color itself to be an
Packit ed3af9
					   upper bound on how opaque things get, when truecolor is
Packit ed3af9
					   available. Without truecolor this results in far too many
Packit ed3af9
					   color indexes. */
Packit ed3af9
					level =
Packit ed3af9
					    level * (gdAlphaMax -
Packit ed3af9
					             gdTrueColorGetAlpha (fg)) / gdAlphaMax;
Packit ed3af9
				}
Packit ed3af9
				level = gdAlphaMax - level;   /* inverting to get alpha */
Packit ed3af9
				x = pen_x + col;
Packit ed3af9
				/* clip if out of bounds */
Packit ed3af9
				/* 2.0.16: clip to clipping rectangle, Matt McNabb */
Packit ed3af9
				if ((x > im->cx2) || (x < im->cx1))
Packit ed3af9
					continue;
Packit ed3af9
				/* get pixel location in gd buffer */
Packit ed3af9
				tpixel = &im->tpixels[y][x];
Packit ed3af9
				if (fg < 0) {
Packit ed3af9
					if (level < (gdAlphaMax / 2)) {
Packit ed3af9
						*tpixel = -fg;
Packit ed3af9
					}
Packit ed3af9
				} else {
Packit ed3af9
					if (im->alphaBlendingFlag) {
Packit ed3af9
						opixel = *tpixel;
Packit ed3af9
						if (gdTrueColorGetAlpha(opixel) != gdAlphaTransparent) {
Packit ed3af9
							*tpixel = gdAlphaBlend (opixel,
Packit ed3af9
							                        (level << 24) + (fg & 0xFFFFFF));
Packit ed3af9
						} else {
Packit ed3af9
							*tpixel = (level << 24) + (fg & 0xFFFFFF);
Packit ed3af9
						}
Packit ed3af9
					} else {
Packit ed3af9
						*tpixel = (level << 24) + (fg & 0xFFFFFF);
Packit ed3af9
					}
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		return (char *) NULL;
Packit ed3af9
	}
Packit ed3af9
	/* Non-truecolor case, restored to its more or less original form */
Packit ed3af9
	for (row = 0; row < bitmap.rows; row++) {
Packit ed3af9
		int pcr;
Packit ed3af9
		pc = row * bitmap.pitch;
Packit ed3af9
		pcr = pc;
Packit ed3af9
		if (bitmap.pixel_mode == ft_pixel_mode_mono)
Packit ed3af9
			pc *= 8;		/* pc is measured in bits for monochrome images */
Packit ed3af9
Packit ed3af9
		y = pen_y + row;
Packit ed3af9
Packit ed3af9
		/* clip if out of bounds */
Packit ed3af9
		if (y > im->cy2 || y < im->cy1)
Packit ed3af9
			continue;
Packit ed3af9
Packit ed3af9
		for (col = 0; col < bitmap.width; col++, pc++) {
Packit ed3af9
			if (bitmap.pixel_mode == ft_pixel_mode_grays) {
Packit ed3af9
				/*
Packit ed3af9
				 * Round to GD_NUMCOLORS levels of antialiasing for
Packit ed3af9
				 * index color images since only 256 colors are
Packit ed3af9
				 * available.
Packit ed3af9
				 */
Packit ed3af9
				tc_key.pixel = ((bitmap.buffer[pc] * GD_NUMCOLORS)
Packit ed3af9
				                + bitmap.num_grays / 2)
Packit ed3af9
				               / (bitmap.num_grays - 1);
Packit ed3af9
			} else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
Packit ed3af9
				/* 2.0.5: mode_mono fix from Giuliano Pochini */
Packit ed3af9
				tc_key.pixel =
Packit ed3af9
				    ((bitmap.
Packit ed3af9
				      buffer[(col >> 3) +
Packit ed3af9
				             pcr]) & (1 << (~col & 0x07))) ? GD_NUMCOLORS : 0;
Packit ed3af9
			} else {
Packit ed3af9
				return "Unsupported ft_pixel_mode";
Packit ed3af9
			}
Packit ed3af9
			if (tc_key.pixel == 0)	/* if background */
Packit ed3af9
				continue;
Packit ed3af9
Packit ed3af9
			x = pen_x + col;
Packit ed3af9
Packit ed3af9
			/* clip if out of bounds */
Packit ed3af9
			if (x > im->cx2 || x < im->cx1)
Packit ed3af9
				continue;
Packit ed3af9
			/* get pixel location in gd buffer */
Packit ed3af9
			pixel = &im->pixels[y][x];
Packit ed3af9
			if (tc_key.pixel == GD_NUMCOLORS) {
Packit ed3af9
				/* use fg color directly. gd 2.0.2: watch out for
Packit ed3af9
				   negative indexes (thanks to David Marwood). */
Packit ed3af9
				*pixel = (fg < 0) ? -fg : fg;
Packit ed3af9
			} else {
Packit ed3af9
				/* find antialised color */
Packit ed3af9
Packit ed3af9
				tc_key.bgcolor = *pixel;
Packit ed3af9
				tc_elem = (tweencolor_t *) gdCacheGet (tc_cache, &tc_key);
Packit ed3af9
				if (!tc_elem) return tc_cache->error;
Packit ed3af9
				*pixel = tc_elem->tweencolor;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	return (char *) NULL;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdFreeFontCache
Packit ed3af9
 *
Packit ed3af9
 * Alias of <gdFontCacheShutdown>.
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(void) gdFreeFontCache ()
Packit ed3af9
{
Packit ed3af9
	gdFontCacheShutdown ();
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdFontCacheShutdown
Packit ed3af9
 *
Packit ed3af9
 * Shut down the font cache and free the allocated resources.
Packit ed3af9
 *
Packit ed3af9
 * Important:
Packit ed3af9
 *  This function has to be called whenever FreeType operations have been
Packit ed3af9
 *  invoked, to avoid resource leaks. It doesn't harm to call this function
Packit ed3af9
 *  multiple times.
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(void) gdFontCacheShutdown ()
Packit ed3af9
{
Packit ed3af9
	if (fontCache) {
Packit ed3af9
		gdMutexLock(gdFontCacheMutex);
Packit ed3af9
		gdCacheDelete (fontCache);
Packit ed3af9
		/* 2.0.16: Gustavo Scotti: make sure we don't free this twice */
Packit ed3af9
		fontCache = 0;
Packit ed3af9
		gdMutexUnlock(gdFontCacheMutex);
Packit ed3af9
		gdMutexShutdown (gdFontCacheMutex);
Packit ed3af9
		FT_Done_FreeType (library);
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageStringFT
Packit ed3af9
 *
Packit ed3af9
 * Render an UTF-8 string onto a gd image.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *	im       - The image to draw onto.
Packit ed3af9
 *  brect    - The bounding rectangle as array of 8 integers where each pair
Packit ed3af9
 *             represents the x- and y-coordinate of a point. The points
Packit ed3af9
 *             specify the lower left, lower right, upper right and upper left
Packit ed3af9
 *             corner.
Packit ed3af9
 *	fg       - The font color.
Packit ed3af9
 *	fontlist - The semicolon delimited list of font filenames to look for.
Packit ed3af9
 *	ptsize   - The height of the font in typographical points (pt).
Packit ed3af9
 *	angle    - The angle in radian to rotate the font counter-clockwise.
Packit ed3af9
 *	x        - The x-coordinate of the basepoint (roughly the lower left corner) of the first letter.
Packit ed3af9
 *	y        - The y-coordinate of the basepoint (roughly the lower left corner) of the first letter.
Packit ed3af9
 *	string   - The string to render.
Packit ed3af9
 *
Packit ed3af9
 * Variant:
Packit ed3af9
 *  - <gdImageStringFTEx>
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *  - <gdImageString>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(char *) gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
Packit ed3af9
                                     double ptsize, double angle, int x, int y, char *string)
Packit ed3af9
{
Packit ed3af9
	return gdImageStringFTEx (im, brect, fg, fontlist,
Packit ed3af9
	                          ptsize, angle, x, y, string, 0);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdFontCacheSetup
Packit ed3af9
 *
Packit ed3af9
 * Set up the font cache.
Packit ed3af9
 *
Packit ed3af9
 * This is called automatically from the string rendering functions, if it
Packit ed3af9
 * has not already been called. So there's no need to call this function
Packit ed3af9
 * explicitly.
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdFontCacheSetup (void)
Packit ed3af9
{
Packit ed3af9
	if (fontCache) {
Packit ed3af9
		/* Already set up */
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
	gdMutexSetup (gdFontCacheMutex);
Packit ed3af9
	if (FT_Init_FreeType (&library)) {
Packit ed3af9
		gdMutexShutdown (gdFontCacheMutex);
Packit ed3af9
		return -1;
Packit ed3af9
	}
Packit ed3af9
	fontCache = gdCacheCreate (FONTCACHESIZE, fontTest, fontFetch, fontRelease);
Packit ed3af9
	if (!fontCache) {
Packit ed3af9
		return -2;
Packit ed3af9
	}
Packit ed3af9
	return 0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageStringFTEx
Packit ed3af9
Packit ed3af9
  gdImageStringFTEx extends the capabilities of gdImageStringFT by
Packit ed3af9
  providing a way to pass additional parameters.
Packit ed3af9
Packit ed3af9
  If the strex parameter is not null, it must point to a
Packit ed3af9
  gdFTStringExtra structure. As of gd 2.0.5, this structure is defined
Packit ed3af9
  as follows:
Packit ed3af9
  (start code)
Packit ed3af9
Packit ed3af9
  typedef struct {
Packit ed3af9
      // logical OR of gdFTEX_ values
Packit ed3af9
      int flags;
Packit ed3af9
   
Packit ed3af9
      // fine tune line spacing for '\n'
Packit ed3af9
      double linespacing;
Packit ed3af9
   
Packit ed3af9
      // Preferred character mapping
Packit ed3af9
      int charmap;
Packit ed3af9
   
Packit ed3af9
      // Rendering resolution
Packit ed3af9
      int hdpi;
Packit ed3af9
      int vdpi;
Packit ed3af9
      char *xshow;
Packit ed3af9
      char *fontpath;
Packit ed3af9
  } gdFTStringExtra, *gdFTStringExtraPtr;
Packit ed3af9
Packit ed3af9
  (end code)
Packit ed3af9
Packit ed3af9
  To output multiline text with a specific line spacing, include
Packit ed3af9
  gdFTEX_LINESPACE in the setting of flags:
Packit ed3af9
Packit ed3af9
    > flags |= gdFTEX_LINESPACE;
Packit ed3af9
Packit ed3af9
  And also set linespacing to the desired spacing, expressed as a
Packit ed3af9
  multiple of the font height. Thus a line spacing of 1.0 is the
Packit ed3af9
  minimum to guarantee that lines of text do not collide.
Packit ed3af9
Packit ed3af9
  If gdFTEX_LINESPACE is not present, or strex is null, or
Packit ed3af9
  gdImageStringFT is called, linespacing defaults to 1.05.
Packit ed3af9
Packit ed3af9
  To specify a preference for Unicode, Shift_JIS Big5 character
Packit ed3af9
  encoding, set or To output multiline text with a specific line
Packit ed3af9
  spacing, include gdFTEX_CHARMAP in the setting of flags:
Packit ed3af9
Packit ed3af9
    > flags |= gdFTEX_CHARMAP;
Packit ed3af9
Packit ed3af9
  And set charmap to the desired value, which can be any of
Packit ed3af9
  gdFTEX_Unicode, gdFTEX_Shift_JIS, gdFTEX_Big5, or
Packit ed3af9
  gdFTEX_Adobe_Custom. If you do not specify a preference, Unicode
Packit ed3af9
  will be tried first. If the preferred character mapping is not found
Packit ed3af9
  in the font, other character mappings are attempted.
Packit ed3af9
Packit ed3af9
  GD operates on the assumption that the output image will be rendered
Packit ed3af9
  to a computer screen. By default, gd passes a resolution of 96 dpi
Packit ed3af9
  to the freetype text rendering engine. This influences the "hinting"
Packit ed3af9
  decisions made by the renderer. To specify a different resolution,
Packit ed3af9
  set hdpi and vdpi accordingly (in dots per inch) and add
Packit ed3af9
  gdFTEX_RESOLUTION to flags:
Packit ed3af9
Packit ed3af9
    > flags | gdFTEX_RESOLUTION;
Packit ed3af9
Packit ed3af9
  GD 2.0.29 and later will normally attempt to apply kerning tables,
Packit ed3af9
  if fontconfig is available, to adjust the relative positions of
Packit ed3af9
  consecutive characters more ideally for that pair of
Packit ed3af9
  characters. This can be turn off by specifying the
Packit ed3af9
  gdFTEX_DISABLE_KERNING flag:
Packit ed3af9
Packit ed3af9
    > flags | gdFTEX_DISABLE_KERNING;
Packit ed3af9
Packit ed3af9
  GD 2.0.29 and later can return a vector of individual character
Packit ed3af9
  position advances, occasionally useful in applications that must
Packit ed3af9
  know exactly where each character begins. This is returned in the
Packit ed3af9
  xshow element of the gdFTStringExtra structure if the gdFTEX_XSHOW
Packit ed3af9
  flag is set:
Packit ed3af9
Packit ed3af9
    > flags | gdFTEX_XSHOW;
Packit ed3af9
Packit ed3af9
  The caller is responsible for calling gdFree() on the xshow element
Packit ed3af9
  after the call if gdFTEX_XSHOW is set.
Packit ed3af9
Packit ed3af9
  GD 2.0.29 and later can also return the path to the actual font file
Packit ed3af9
  used if the gdFTEX_RETURNFONTPATHNAME flag is set. This is useful
Packit ed3af9
  because GD 2.0.29 and above are capable of selecting a font
Packit ed3af9
  automatically based on a fontconfig font pattern when fontconfig is
Packit ed3af9
  available. This information is returned in the fontpath element of
Packit ed3af9
  the gdFTStringExtra structure.
Packit ed3af9
Packit ed3af9
    > flags | gdFTEX_RETURNFONTPATHNAME;
Packit ed3af9
Packit ed3af9
  The caller is responsible for calling gdFree() on the fontpath
Packit ed3af9
  element after the call if gdFTEX_RETURNFONTPATHNAME is set.
Packit ed3af9
Packit ed3af9
  GD 2.0.29 and later can use fontconfig to resolve font names,
Packit ed3af9
  including fontconfig patterns, if the gdFTEX_FONTCONFIG flag is
Packit ed3af9
  set. As a convenience, this behavior can be made the default by
Packit ed3af9
  calling <gdFTUseFontConfig> with a nonzero value. In that situation it
Packit ed3af9
  is not necessary to set the gdFTEX_FONTCONFIG flag on every call;
Packit ed3af9
  however explicit font path names can still be used if the
Packit ed3af9
  gdFTEX_FONTPATHNAME flag is set:
Packit ed3af9
Packit ed3af9
    > flags | gdFTEX_FONTPATHNAME;
Packit ed3af9
Packit ed3af9
  Unless <gdFTUseFontConfig> has been called with a nonzero value, GD
Packit ed3af9
  2.0.29 and later will still expect the fontlist argument to the
Packit ed3af9
  freetype text output functions to be a font file name or list
Packit ed3af9
  thereof as in previous versions. If you do not wish to make
Packit ed3af9
  fontconfig the default, it is still possible to force the use of
Packit ed3af9
  fontconfig for a single call to the freetype text output functions
Packit ed3af9
  by setting the gdFTEX_FONTCONFIG flag:
Packit ed3af9
Packit ed3af9
    > flags | gdFTEX_FONTCONFIG;
Packit ed3af9
Packit ed3af9
  GD 2.0.29 and above can use fontconfig to resolve font names,
Packit ed3af9
  including fontconfig patterns, if the gdFTEX_FONTCONFIG flag is
Packit ed3af9
  set. As a convenience, this behavior can be made the default by
Packit ed3af9
  calling <gdFTUseFontConfig> with a nonzero value. In that situation it
Packit ed3af9
  is not necessary to set the gdFTEX_FONTCONFIG flag on every call;
Packit ed3af9
  however explicit font path names can still be used if the
Packit ed3af9
  gdFTEX_FONTPATHNAME flag is set:
Packit ed3af9
Packit ed3af9
    > flags | gdFTEX_FONTPATHNAME;
Packit ed3af9
Packit ed3af9
  For more information, see <gdImageStringFT>. 
Packit ed3af9
*/
Packit ed3af9
Packit ed3af9
/* the platform-independent resolution used for size and position calculations */
Packit ed3af9
/*    the size of the error introduced by rounding is affected by this number */
Packit ed3af9
#define METRIC_RES 300
Packit ed3af9
Packit ed3af9
BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist,
Packit ed3af9
                                       double ptsize, double angle, int x, int y, char *string,
Packit ed3af9
                                       gdFTStringExtraPtr strex)
Packit ed3af9
{
Packit ed3af9
	FT_Matrix matrix;
Packit ed3af9
	FT_Vector penf, oldpenf, delta, total_min = {0,0}, total_max = {0,0}, glyph_min, glyph_max;
Packit ed3af9
	FT_Face face;
Packit ed3af9
	FT_CharMap charmap = NULL;
Packit ed3af9
	FT_Glyph image;
Packit ed3af9
	FT_GlyphSlot slot;
Packit ed3af9
	FT_Error err;
Packit ed3af9
	FT_UInt glyph_index, previous;
Packit ed3af9
	double sin_a = sin (angle);
Packit ed3af9
	double cos_a = cos (angle);
Packit ed3af9
	int len, i, ch;
Packit ed3af9
	font_t *font;
Packit ed3af9
	fontkey_t fontkey;
Packit ed3af9
	char *next;
Packit ed3af9
	char *tmpstr = 0;
Packit ed3af9
	int render = (im && (im->trueColor || (fg <= 255 && fg >= -255)));
Packit ed3af9
	FT_BitmapGlyph bm;
Packit ed3af9
	/* 2.0.13: Bob Ostermann: don't force autohint, that's just for testing
Packit ed3af9
	   freetype and doesn't look as good */
Packit ed3af9
	int render_mode = FT_LOAD_DEFAULT;
Packit ed3af9
	int encoding, encodingfound;
Packit ed3af9
	/* Now tuneable thanks to Wez Furlong */
Packit ed3af9
	double linespace = LINESPACE;
Packit ed3af9
	/* 2.0.6: put this declaration with the other declarations! */
Packit ed3af9
	/*
Packit ed3af9
	 *   make a new tweenColorCache on every call
Packit ed3af9
	 *   because caching colormappings between calls
Packit ed3af9
	 *   is not safe. If the im-pointer points to a
Packit ed3af9
	 *   brand new image, the cache gives out bogus
Packit ed3af9
	 *   colorindexes.          -- 27.06.2001 <krisku@arrak.fi>
Packit ed3af9
	 */
Packit ed3af9
	gdCache_head_t *tc_cache;
Packit ed3af9
	/* Tuneable horizontal and vertical resolution in dots per inch */
Packit ed3af9
	int hdpi, vdpi, horiAdvance, xshow_alloc = 0, xshow_pos = 0;
Packit ed3af9
	FT_Size platform_specific, platform_independent;
Packit ed3af9
Packit ed3af9
	if (strex) {
Packit ed3af9
		if ((strex->flags & gdFTEX_LINESPACE) == gdFTEX_LINESPACE) {
Packit ed3af9
			linespace = strex->linespacing;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	tc_cache = gdCacheCreate (TWEENCOLORCACHESIZE,
Packit ed3af9
	                          tweenColorTest, tweenColorFetch,
Packit ed3af9
	                          tweenColorRelease);
Packit ed3af9
Packit ed3af9
	/***** initialize font library and font cache on first call ******/
Packit ed3af9
	if (!fontCache) {
Packit ed3af9
		if (gdFontCacheSetup () != 0) {
Packit ed3af9
			gdCacheDelete (tc_cache);
Packit ed3af9
			return "Failure to initialize font library";
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	/*****/
Packit ed3af9
	gdMutexLock (gdFontCacheMutex);
Packit ed3af9
	/* get the font (via font cache) */
Packit ed3af9
	fontkey.fontlist = fontlist;
Packit ed3af9
	if (strex)
Packit ed3af9
		fontkey.flags = strex->flags & (gdFTEX_FONTPATHNAME |
Packit ed3af9
		                                gdFTEX_FONTCONFIG);
Packit ed3af9
	else
Packit ed3af9
		fontkey.flags = 0;
Packit ed3af9
	fontkey.library = &library;
Packit ed3af9
	font = (font_t *) gdCacheGet (fontCache, &fontkey);
Packit ed3af9
	if (!font) {
Packit ed3af9
		gdCacheDelete (tc_cache);
Packit ed3af9
		gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
		return fontCache->error;
Packit ed3af9
	}
Packit ed3af9
	face = font->face;		/* shortcut */
Packit ed3af9
	slot = face->glyph;		/* shortcut */
Packit ed3af9
Packit ed3af9
	if (brect) {
Packit ed3af9
		total_min.x = total_min.y = 0;
Packit ed3af9
		total_max.x = total_max.y = 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/*
Packit ed3af9
	 * Added hdpi and vdpi to support images at non-screen resolutions, i.e. 300 dpi TIFF,
Packit ed3af9
	 *    or 100h x 50v dpi FAX format. 2.0.23.
Packit ed3af9
	 * 2004/02/27 Mark Shackelford, mark.shackelford@acs-inc.com
Packit ed3af9
	 */
Packit ed3af9
	hdpi = GD_RESOLUTION;
Packit ed3af9
	vdpi = GD_RESOLUTION;
Packit ed3af9
	encoding = gdFTEX_Unicode;
Packit ed3af9
	if (strex) {
Packit ed3af9
		if (strex->flags & gdFTEX_RESOLUTION) {
Packit ed3af9
			hdpi = strex->hdpi;
Packit ed3af9
			vdpi = strex->vdpi;
Packit ed3af9
		}
Packit ed3af9
		if (strex->flags & gdFTEX_XSHOW) {
Packit ed3af9
			strex->xshow = NULL;
Packit ed3af9
		}
Packit ed3af9
		/* 2.0.12: allow explicit specification of the preferred map;
Packit ed3af9
		   but we still fall back if it is not available. */
Packit ed3af9
		if (strex->flags & gdFTEX_CHARMAP) {
Packit ed3af9
			encoding = strex->charmap;
Packit ed3af9
		}
Packit ed3af9
		/* 2.0.29: we can return the font path if desired */
Packit ed3af9
		if (strex->flags & gdFTEX_RETURNFONTPATHNAME) {
Packit ed3af9
			const unsigned int fontpath_len = strlen(font->fontpath);
Packit ed3af9
Packit ed3af9
			strex->fontpath = (char *) gdMalloc(fontpath_len + 1);
Packit ed3af9
			if (strex->fontpath == NULL) {
Packit ed3af9
				gdCacheDelete(tc_cache);
Packit ed3af9
				gdMutexUnlock(gdFontCacheMutex);
Packit ed3af9
				return "could not alloc full list of fonts";
Packit ed3af9
			}
Packit ed3af9
			strncpy(strex->fontpath, font->fontpath, fontpath_len);
Packit ed3af9
			strex->fontpath[fontpath_len] = 0;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	matrix.xx = (FT_Fixed) (cos_a * (1 << 16));
Packit ed3af9
	matrix.yx = (FT_Fixed) (sin_a * (1 << 16));
Packit ed3af9
	matrix.xy = -matrix.yx;
Packit ed3af9
	matrix.yy = matrix.xx;
Packit ed3af9
Packit ed3af9
	/* set rotation transform */
Packit ed3af9
	FT_Set_Transform (face, &matrix, NULL);
Packit ed3af9
Packit ed3af9
	FT_New_Size (face, &platform_independent);
Packit ed3af9
	FT_Activate_Size (platform_independent);
Packit ed3af9
	if (FT_Set_Char_Size (face, 0, (FT_F26Dot6)(ptsize*64), METRIC_RES, METRIC_RES)) {
Packit ed3af9
		gdCacheDelete (tc_cache);
Packit ed3af9
		gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
		return "Could not set character size";
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (render) {
Packit ed3af9
		FT_New_Size (face, &platform_specific);
Packit ed3af9
		FT_Activate_Size (platform_specific);
Packit ed3af9
		if (FT_Set_Char_Size (face, 0, (FT_F26Dot6)(ptsize*64), hdpi, vdpi)) {
Packit ed3af9
			gdCacheDelete (tc_cache);
Packit ed3af9
			gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
			return "Could not set character size";
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (fg < 0)
Packit ed3af9
		render_mode |= FT_LOAD_MONOCHROME;
Packit ed3af9
Packit ed3af9
	/* find requested charmap */
Packit ed3af9
	encodingfound = 0;
Packit ed3af9
	for (i = 0; i < face->num_charmaps; i++) {
Packit ed3af9
		charmap = face->charmaps[i];
Packit ed3af9
Packit ed3af9
#if ((defined(FREETYPE_MAJOR)) && (((FREETYPE_MAJOR == 2) && (((FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 3)) || (FREETYPE_MINOR > 1))) || (FREETYPE_MAJOR > 2)))
Packit ed3af9
		if (encoding == gdFTEX_Unicode) {
Packit ed3af9
			if (charmap->encoding == FT_ENCODING_MS_SYMBOL
Packit ed3af9
			        || charmap->encoding == FT_ENCODING_UNICODE
Packit ed3af9
			        || charmap->encoding == FT_ENCODING_ADOBE_CUSTOM
Packit ed3af9
			        || charmap->encoding == FT_ENCODING_ADOBE_STANDARD) {
Packit ed3af9
				encodingfound++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		} else if (encoding == gdFTEX_Adobe_Custom) {
Packit ed3af9
			if (charmap->encoding == FT_ENCODING_ADOBE_CUSTOM) {
Packit ed3af9
				encodingfound++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		} else if (encoding == gdFTEX_Big5) {
Packit ed3af9
			/* renamed sometime after freetype-2.1.4 */
Packit ed3af9
#ifndef FT_ENCODING_BIG5
Packit ed3af9
#define FT_ENCODING_BIG5 FT_ENCODING_MS_BIG5
Packit ed3af9
#endif
Packit ed3af9
			if (charmap->encoding == FT_ENCODING_BIG5) {
Packit ed3af9
				encodingfound++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		} else if (encoding == gdFTEX_Shift_JIS) {
Packit ed3af9
			/* renamed sometime after freetype-2.1.4 */
Packit ed3af9
#ifndef FT_ENCODING_SJIS
Packit ed3af9
#define FT_ENCODING_SJIS FT_ENCODING_MS_SJIS
Packit ed3af9
#endif
Packit ed3af9
			if (charmap->encoding == FT_ENCODING_SJIS) {
Packit ed3af9
				encodingfound++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
#else
Packit ed3af9
		if (encoding == gdFTEX_Unicode) {
Packit ed3af9
			if ((charmap->platform_id = 3 && charmap->encoding_id == 1)     /* Windows Unicode */
Packit ed3af9
			        || (charmap->platform_id == 3 && charmap->encoding_id == 0) /* Windows Symbol */
Packit ed3af9
			        || (charmap->platform_id == 2 && charmap->encoding_id == 1) /* ISO Unicode */
Packit ed3af9
			        || (charmap->platform_id == 0)) {                        /* Apple Unicode */
Packit ed3af9
				encodingfound++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		} else if (encoding == gdFTEX_Big5) {
Packit ed3af9
			if (charmap->platform_id == 3 && charmap->encoding_id == 4) {   /* Windows Big5 */
Packit ed3af9
				encodingfound++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		} else if (encoding == gdFTEX_Shift_JIS) {
Packit ed3af9
			if (charmap->platform_id == 3 && charmap->encoding_id == 2) {   /* Windows Sjis */
Packit ed3af9
				encodingfound++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
#endif
Packit ed3af9
	}
Packit ed3af9
	if (encodingfound) {
Packit ed3af9
		FT_Set_Charmap(face, charmap);
Packit ed3af9
	} else {
Packit ed3af9
		/* No character set found! */
Packit ed3af9
		gdCacheDelete (tc_cache);
Packit ed3af9
		gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
		return "No character set found";
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
#ifndef JISX0208
Packit ed3af9
	if (encoding == gdFTEX_Shift_JIS) {
Packit ed3af9
#endif
Packit ed3af9
		if ((tmpstr = (char *) gdMalloc (BUFSIZ))) {
Packit ed3af9
			any2eucjp (tmpstr, string, BUFSIZ);
Packit ed3af9
			next = tmpstr;
Packit ed3af9
		} else {
Packit ed3af9
			next = string;
Packit ed3af9
		}
Packit ed3af9
#ifndef JISX0208
Packit ed3af9
	} else {
Packit ed3af9
		next = string;
Packit ed3af9
	}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
	oldpenf.x = oldpenf.y = 0; /* for postscript xshow operator */
Packit ed3af9
	penf.x = penf.y = 0;	/* running position of non-rotated glyphs */
Packit ed3af9
	previous = 0;		/* index of previous glyph for kerning calculations */
Packit ed3af9
	for (i=0; *next; i++) {
Packit ed3af9
		FT_Activate_Size (platform_independent);
Packit ed3af9
Packit ed3af9
		ch = *next;
Packit ed3af9
Packit ed3af9
		/* carriage returns */
Packit ed3af9
		if (ch == '\r') {
Packit ed3af9
			penf.x = 0;
Packit ed3af9
			previous = 0;		/* clear kerning flag */
Packit ed3af9
			next++;
Packit ed3af9
			continue;
Packit ed3af9
		}
Packit ed3af9
		/* newlines */
Packit ed3af9
		if (ch == '\n') {
Packit ed3af9
			/* 2.0.13: reset penf.x. Christopher J. Grayce */
Packit ed3af9
			penf.x = 0;
Packit ed3af9
			penf.y += linespace * ptsize * 64 * METRIC_RES / 72;
Packit ed3af9
			penf.y &= ~63;	/* round down to 1/METRIC_RES */
Packit ed3af9
			previous = 0;		/* clear kerning flag */
Packit ed3af9
			next++;
Packit ed3af9
			continue;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
Packit ed3af9
		switch (encoding) {
Packit ed3af9
		case gdFTEX_Unicode: {
Packit ed3af9
			/* use UTF-8 mapping from ASCII */
Packit ed3af9
			len = gdTcl_UtfToUniChar (next, &ch);
Packit ed3af9
			/* EAM DEBUG */
Packit ed3af9
			/* TBB: get this exactly right: 2.1.3 *or better*, all possible cases. */
Packit ed3af9
			/* 2.0.24: David R. Morrison: use the more complete ifdef here. */
Packit ed3af9
#if ((defined(FREETYPE_MAJOR)) && (((FREETYPE_MAJOR == 2) && (((FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 3)) || (FREETYPE_MINOR > 1))) || (FREETYPE_MAJOR > 2)))
Packit ed3af9
			if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
Packit ed3af9
#else
Packit ed3af9
			if (charmap->platform_id == 3 && charmap->encoding_id == 0)
Packit ed3af9
#endif /* Freetype 2.1 or better */
Packit ed3af9
			{
Packit ed3af9
				/* I do not know the significance of the constant 0xf000. */
Packit ed3af9
				/* It was determined by inspection of the character codes */
Packit ed3af9
				/* stored in Microsoft font symbol.ttf                    */
Packit ed3af9
				ch |= 0xf000;
Packit ed3af9
			}
Packit ed3af9
			/* EAM DEBUG */
Packit ed3af9
			next += len;
Packit ed3af9
		}
Packit ed3af9
		break;
Packit ed3af9
		case gdFTEX_Shift_JIS: {
Packit ed3af9
			unsigned char c;
Packit ed3af9
			int jiscode;
Packit ed3af9
			c = *next;
Packit ed3af9
			if (0xA1 <= c && c <= 0xFE) {
Packit ed3af9
				next++;
Packit ed3af9
				jiscode = 0x100 * (c & 0x7F) + ((*next) & 0x7F);
Packit ed3af9
Packit ed3af9
				ch = (jiscode >> 8) & 0xFF;
Packit ed3af9
				jiscode &= 0xFF;
Packit ed3af9
Packit ed3af9
				if (ch & 1)
Packit ed3af9
					jiscode += 0x40 - 0x21;
Packit ed3af9
				else
Packit ed3af9
					jiscode += 0x9E - 0x21;
Packit ed3af9
Packit ed3af9
				if (jiscode >= 0x7F)
Packit ed3af9
					jiscode++;
Packit ed3af9
				ch = (ch - 0x21) / 2 + 0x81;
Packit ed3af9
				if (ch >= 0xA0)
Packit ed3af9
					ch += 0x40;
Packit ed3af9
Packit ed3af9
				ch = (ch << 8) + jiscode;
Packit ed3af9
			} else {
Packit ed3af9
				ch = c & 0xFF;	/* don't extend sign */
Packit ed3af9
			}
Packit ed3af9
			if (*next) next++;
Packit ed3af9
		}
Packit ed3af9
		break;
Packit ed3af9
		case gdFTEX_Big5: {
Packit ed3af9
			/*
Packit ed3af9
			 * Big 5 mapping:
Packit ed3af9
			 * use "JIS-8 half-width katakana" coding from 8-bit characters. Ref:
Packit ed3af9
			 * ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
Packit ed3af9
			 */
Packit ed3af9
			ch = (*next) & 0xFF;	/* don't extend sign */
Packit ed3af9
			next++;
Packit ed3af9
			if (ch >= 161	/* first code of JIS-8 pair */
Packit ed3af9
			        && *next) {
Packit ed3af9
				/* don't advance past '\0' */
Packit ed3af9
				/* TBB: Fix from Kwok Wah On: & 255 needed */
Packit ed3af9
				ch = (ch * 256) + ((*next) & 255);
Packit ed3af9
				next++;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		break;
Packit ed3af9
Packit ed3af9
		case gdFTEX_Adobe_Custom:
Packit ed3af9
		default:
Packit ed3af9
			ch &= 0xFF;
Packit ed3af9
			next++;
Packit ed3af9
			break;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		/* Convert character code to glyph index */
Packit ed3af9
		glyph_index = FT_Get_Char_Index (face, ch);
Packit ed3af9
Packit ed3af9
		/* retrieve kerning distance */
Packit ed3af9
		if ( ! (strex && (strex->flags & gdFTEX_DISABLE_KERNING))
Packit ed3af9
		        && ! FT_IS_FIXED_WIDTH(face)
Packit ed3af9
		        && FT_HAS_KERNING(face)
Packit ed3af9
		        && previous
Packit ed3af9
		        && glyph_index)
Packit ed3af9
			FT_Get_Kerning (face, previous, glyph_index, ft_kerning_default, &delta);
Packit ed3af9
		else
Packit ed3af9
			delta.x = delta.y = 0;
Packit ed3af9
Packit ed3af9
		penf.x += delta.x;
Packit ed3af9
Packit ed3af9
		/* When we know the position of the second or subsequent character,
Packit ed3af9
		save the (kerned) advance from the preceeding character in the
Packit ed3af9
		xshow vector */
Packit ed3af9
		if (i && strex && (strex->flags & gdFTEX_XSHOW)) {
Packit ed3af9
			/* make sure we have enough allocation for two numbers
Packit ed3af9
			so we don't have to recheck for the terminating number */
Packit ed3af9
			if (! xshow_alloc) {
Packit ed3af9
				xshow_alloc = 100;
Packit ed3af9
				strex->xshow = gdMalloc(xshow_alloc);
Packit ed3af9
				if (!strex->xshow) {
Packit ed3af9
					if (tmpstr)
Packit ed3af9
						gdFree (tmpstr);
Packit ed3af9
					gdCacheDelete (tc_cache);
Packit ed3af9
					gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
					return "Problem allocating memory";
Packit ed3af9
				}
Packit ed3af9
				xshow_pos = 0;
Packit ed3af9
			} else if (xshow_pos + 20 > xshow_alloc) {
Packit ed3af9
				xshow_alloc += 100;
Packit ed3af9
				strex->xshow = gdReallocEx(strex->xshow, xshow_alloc);
Packit ed3af9
				if (!strex->xshow) {
Packit ed3af9
					if (tmpstr)
Packit ed3af9
						gdFree (tmpstr);
Packit ed3af9
					gdCacheDelete (tc_cache);
Packit ed3af9
					gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
					return "Problem allocating memory";
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
			xshow_pos += sprintf(strex->xshow + xshow_pos, "%g ",
Packit ed3af9
			                     (double)(penf.x - oldpenf.x) * hdpi / (64 * METRIC_RES));
Packit ed3af9
		}
Packit ed3af9
		oldpenf.x = penf.x;
Packit ed3af9
Packit ed3af9
		/* load glyph image into the slot (erase previous one) */
Packit ed3af9
		err = FT_Load_Glyph (face, glyph_index, render_mode);
Packit ed3af9
		if (err) {
Packit ed3af9
			if (tmpstr)
Packit ed3af9
				gdFree (tmpstr);
Packit ed3af9
			gdCacheDelete (tc_cache);
Packit ed3af9
			gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
			return "Problem loading glyph";
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		horiAdvance = slot->metrics.horiAdvance;
Packit ed3af9
Packit ed3af9
		if (brect) {
Packit ed3af9
			/* only if need brect */
Packit ed3af9
Packit ed3af9
			glyph_min.x = penf.x + slot->metrics.horiBearingX;
Packit ed3af9
			glyph_min.y = penf.y - slot->metrics.horiBearingY;
Packit ed3af9
Packit ed3af9
#if 0
Packit ed3af9
			if (ch == ' ') {      /* special case for trailing space */
Packit ed3af9
				glyph_max.x = penf.x + horiAdvance;
Packit ed3af9
			} else {
Packit ed3af9
				glyph_max.x = glyph_min.x + slot->metrics.width;
Packit ed3af9
			}
Packit ed3af9
#else
Packit ed3af9
			glyph_max.x = penf.x + horiAdvance;
Packit ed3af9
#endif
Packit ed3af9
			glyph_max.y = glyph_min.y + slot->metrics.height;
Packit ed3af9
Packit ed3af9
			if (i==0) {
Packit ed3af9
				total_min = glyph_min;
Packit ed3af9
				total_max = glyph_max;
Packit ed3af9
			} else {
Packit ed3af9
				if (glyph_min.x < total_min.x)
Packit ed3af9
					total_min.x = glyph_min.x;
Packit ed3af9
				if (glyph_min.y < total_min.y)
Packit ed3af9
					total_min.y = glyph_min.y;
Packit ed3af9
				if (glyph_max.x > total_max.x)
Packit ed3af9
					total_max.x = glyph_max.x;
Packit ed3af9
				if (glyph_max.y > total_max.y)
Packit ed3af9
					total_max.y = glyph_max.y;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if (render) {
Packit ed3af9
			FT_Activate_Size (platform_specific);
Packit ed3af9
Packit ed3af9
			/* load glyph again into the slot (erase previous one)  - this time with scaling */
Packit ed3af9
			err = FT_Load_Glyph (face, glyph_index, render_mode);
Packit ed3af9
			if (err) {
Packit ed3af9
				if (tmpstr)
Packit ed3af9
					gdFree (tmpstr);
Packit ed3af9
				gdCacheDelete (tc_cache);
Packit ed3af9
				gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
				return "Problem loading glyph";
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			/* load and transform glyph image */
Packit ed3af9
			FT_Get_Glyph (slot, &image);
Packit ed3af9
Packit ed3af9
			if (image->format != ft_glyph_format_bitmap) {
Packit ed3af9
				err = FT_Glyph_To_Bitmap (&image, ft_render_mode_normal, 0, 1);
Packit ed3af9
				if (err) {
Packit ed3af9
					FT_Done_Glyph(image);
Packit ed3af9
					if (tmpstr)
Packit ed3af9
						gdFree (tmpstr);
Packit ed3af9
					gdCacheDelete (tc_cache);
Packit ed3af9
					gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
					return "Problem rendering glyph";
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			/* now, draw to our target surface */
Packit ed3af9
			bm = (FT_BitmapGlyph) image;
Packit ed3af9
			/* position rounded down to nearest pixel at current dpi
Packit ed3af9
			(the estimate was rounded up to next 1/METRIC_RES, so this should fit) */
Packit ed3af9
			gdft_draw_bitmap (tc_cache, im, fg, bm->bitmap,
Packit ed3af9
			                  (int)(x + (penf.x * cos_a + penf.y * sin_a)*hdpi/(METRIC_RES*64) + bm->left),
Packit ed3af9
			                  (int)(y - (penf.x * sin_a - penf.y * cos_a)*vdpi/(METRIC_RES*64) - bm->top));
Packit ed3af9
Packit ed3af9
			FT_Done_Glyph (image);
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		/* record current glyph index for kerning */
Packit ed3af9
		previous = glyph_index;
Packit ed3af9
Packit ed3af9
		penf.x += horiAdvance;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* Save the (unkerned) advance from the last character in the xshow vector */
Packit ed3af9
	if (strex && (strex->flags & gdFTEX_XSHOW) && strex->xshow) {
Packit ed3af9
		sprintf(strex->xshow + xshow_pos, "%g",
Packit ed3af9
		        (double)(penf.x - oldpenf.x) * hdpi / (64 * METRIC_RES) );
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (brect) {
Packit ed3af9
		/* only if need brect */
Packit ed3af9
		double scalex = (double)hdpi / (64 * METRIC_RES);
Packit ed3af9
		double scaley = (double)vdpi / (64 * METRIC_RES);
Packit ed3af9
Packit ed3af9
		/* increase by 1 pixel to allow for rounding */
Packit ed3af9
		total_min.x -= METRIC_RES;
Packit ed3af9
		total_min.y -= METRIC_RES;
Packit ed3af9
		total_max.x += METRIC_RES;
Packit ed3af9
		total_max.y += METRIC_RES;
Packit ed3af9
Packit ed3af9
		/* rotate bounding rectangle, scale and round to int pixels, and translate */
Packit ed3af9
		brect[0] = x + (total_min.x * cos_a + total_max.y * sin_a)*scalex;
Packit ed3af9
		brect[1] = y - (total_min.x * sin_a - total_max.y * cos_a)*scaley;
Packit ed3af9
		brect[2] = x + (total_max.x * cos_a + total_max.y * sin_a)*scalex;
Packit ed3af9
		brect[3] = y - (total_max.x * sin_a - total_max.y * cos_a)*scaley;
Packit ed3af9
		brect[4] = x + (total_max.x * cos_a + total_min.y * sin_a)*scalex;
Packit ed3af9
		brect[5] = y - (total_max.x * sin_a - total_min.y * cos_a)*scaley;
Packit ed3af9
		brect[6] = x + (total_min.x * cos_a + total_min.y * sin_a)*scalex;
Packit ed3af9
		brect[7] = y - (total_min.x * sin_a - total_min.y * cos_a)*scaley;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	FT_Done_Size (platform_independent);
Packit ed3af9
	if (render)
Packit ed3af9
		FT_Done_Size (platform_specific);
Packit ed3af9
Packit ed3af9
	if (tmpstr)
Packit ed3af9
		gdFree (tmpstr);
Packit ed3af9
	gdCacheDelete (tc_cache);
Packit ed3af9
	gdMutexUnlock (gdFontCacheMutex);
Packit ed3af9
	return (char *) NULL;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#endif /* HAVE_LIBFREETYPE */
Packit ed3af9
Packit ed3af9
#ifdef HAVE_LIBFONTCONFIG
Packit ed3af9
/* Code to find font path, with special mapping for Postscript font names.
Packit ed3af9
 *
Packit ed3af9
 * Dag Lem <dag@nimrod.no>
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
#include <fontconfig/fontconfig.h>
Packit ed3af9
Packit ed3af9
/* #define NO_POSTSCRIPT_ALIAS 1 */
Packit ed3af9
#ifndef NO_POSTSCRIPT_ALIAS
Packit ed3af9
typedef struct _PostscriptAlias {
Packit ed3af9
	char* name;
Packit ed3af9
	char* family;
Packit ed3af9
	char* style;
Packit ed3af9
} PostscriptAlias;
Packit ed3af9
Packit ed3af9
/* This table maps standard Postscript font names to URW Type 1 fonts.
Packit ed3af9
   The mapping is converted from Ghostscript (Fontmap.GS)
Packit ed3af9
   for use with fontconfig. */
Packit ed3af9
static PostscriptAlias postscript_alias[] = {
Packit ed3af9
	{ "AvantGarde-Book", "URW Gothic L", "Book" },
Packit ed3af9
	{ "AvantGarde-BookOblique", "URW Gothic L", "Book Oblique" },
Packit ed3af9
	{ "AvantGarde-Demi", "URW Gothic L", "Demi" },
Packit ed3af9
	{ "AvantGarde-DemiOblique", "URW Gothic L", "Demi Oblique" },
Packit ed3af9
Packit ed3af9
	{ "Bookman-Demi", "URW Bookman L", "Demi Bold" },
Packit ed3af9
	{ "Bookman-DemiItalic", "URW Bookman L", "Demi Bold Italic" },
Packit ed3af9
	{ "Bookman-Light", "URW Bookman L", "Light" },
Packit ed3af9
	{ "Bookman-LightItalic", "URW Bookman L", "Light Italic" },
Packit ed3af9
Packit ed3af9
	{ "Courier", "Nimbus Mono L", "Regular" },
Packit ed3af9
	{ "Courier-Oblique", "Nimbus Mono L", "Regular Oblique" },
Packit ed3af9
	{ "Courier-Bold", "Nimbus Mono L", "Bold" },
Packit ed3af9
	{ "Courier-BoldOblique", "Nimbus Mono L", "Bold Oblique" },
Packit ed3af9
Packit ed3af9
	{ "Helvetica", "Nimbus Sans L", "Regular" },
Packit ed3af9
	{ "Helvetica-Oblique", "Nimbus Sans L", "Regular Italic" },
Packit ed3af9
	{ "Helvetica-Bold", "Nimbus Sans L", "Bold" },
Packit ed3af9
	{ "Helvetica-BoldOblique", "Nimbus Sans L", "Bold Italic" },
Packit ed3af9
Packit ed3af9
	{ "Helvetica-Narrow", "Nimbus Sans L", "Regular Condensed" },
Packit ed3af9
	{ "Helvetica-Narrow-Oblique", "Nimbus Sans L", "Regular Condensed Italic" },
Packit ed3af9
	{ "Helvetica-Narrow-Bold", "Nimbus Sans L", "Bold Condensed" },
Packit ed3af9
	{ "Helvetica-Narrow-BoldOblique", "Nimbus Sans L", "Bold Condensed Italic" },
Packit ed3af9
Packit ed3af9
	{ "NewCenturySchlbk-Roman", "Century Schoolbook L", "Roman" },
Packit ed3af9
	{ "NewCenturySchlbk-Italic", "Century Schoolbook L", "Italic" },
Packit ed3af9
	{ "NewCenturySchlbk-Bold", "Century Schoolbook L", "Bold" },
Packit ed3af9
	{ "NewCenturySchlbk-BoldItalic", "Century Schoolbook L", "Bold Italic" },
Packit ed3af9
Packit ed3af9
	{ "Palatino-Roman", "URW Palladio L", "Roman" },
Packit ed3af9
	{ "Palatino-Italic", "URW Palladio L", "Italic" },
Packit ed3af9
	{ "Palatino-Bold", "URW Palladio L", "Bold" },
Packit ed3af9
	{ "Palatino-BoldItalic", "URW Palladio L", "Bold Italic" },
Packit ed3af9
Packit ed3af9
	{ "Symbol", "Standard Symbols L", "Regular" },
Packit ed3af9
Packit ed3af9
	{ "Times-Roman", "Nimbus Roman No9 L", "Regular" },
Packit ed3af9
	{ "Times-Italic", "Nimbus Roman No9 L", "Regular Italic" },
Packit ed3af9
	{ "Times-Bold", "Nimbus Roman No9 L", "Medium" },
Packit ed3af9
	{ "Times-BoldItalic", "Nimbus Roman No9 L", "Medium Italic" },
Packit ed3af9
Packit ed3af9
	{ "ZapfChancery-MediumItalic", "URW Chancery L", "Medium Italic" },
Packit ed3af9
Packit ed3af9
	{ "ZapfDingbats", "Dingbats", "" },
Packit ed3af9
};
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
Packit ed3af9
static FcPattern* find_font(FcPattern* pattern)
Packit ed3af9
{
Packit ed3af9
	FcResult result;
Packit ed3af9
Packit ed3af9
	FcConfigSubstitute(0, pattern, FcMatchPattern);
Packit ed3af9
	FcConfigSubstitute(0, pattern, FcMatchFont);
Packit ed3af9
	FcDefaultSubstitute(pattern);
Packit ed3af9
Packit ed3af9
	return FcFontMatch(0, pattern, &result);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
#ifndef NO_POSTSCRIPT_ALIAS
Packit ed3af9
static char* find_postscript_font(FcPattern **fontpattern, char* fontname)
Packit ed3af9
{
Packit ed3af9
	FcPattern* font = NULL;
Packit ed3af9
	size_t i;
Packit ed3af9
Packit ed3af9
	*fontpattern = NULL;
Packit ed3af9
	for (i = 0; i < sizeof(postscript_alias)/sizeof(*postscript_alias); i++) {
Packit ed3af9
		if (strcmp(fontname, postscript_alias[i].name) == 0) {
Packit ed3af9
			FcChar8* family;
Packit ed3af9
Packit ed3af9
			FcPattern* pattern =
Packit ed3af9
			    FcPatternBuild(0,
Packit ed3af9
			                   FC_FAMILY, FcTypeString, postscript_alias[i].family,
Packit ed3af9
			                   FC_STYLE, FcTypeString, postscript_alias[i].style,
Packit ed3af9
			                   (char*)0);
Packit ed3af9
			font = find_font(pattern);
Packit ed3af9
			FcPatternDestroy(pattern);
Packit ed3af9
Packit ed3af9
			if (!font)
Packit ed3af9
				return "fontconfig: Couldn't find font.";
Packit ed3af9
			if (FcPatternGetString(font, FC_FAMILY, 0, &family) != FcResultMatch) {
Packit ed3af9
				FcPatternDestroy(font);
Packit ed3af9
				return "fontconfig: Couldn't retrieve font family name.";
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			/* Check whether we got the font family we wanted. */
Packit ed3af9
			if (strcmp((const char *)family, postscript_alias[i].family) != 0) {
Packit ed3af9
				FcPatternDestroy(font);
Packit ed3af9
				return "fontconfig: Didn't find expected font family. Perhaps URW Type 1 fonts need installing?";
Packit ed3af9
			}
Packit ed3af9
			break;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	*fontpattern = font;
Packit ed3af9
	return NULL;
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
static char * font_pattern(char **fontpath, char *fontpattern)
Packit ed3af9
{
Packit ed3af9
	FcPattern* font = NULL;
Packit ed3af9
	FcChar8* file;
Packit ed3af9
	FcPattern* pattern;
Packit ed3af9
#ifndef NO_POSTSCRIPT_ALIAS
Packit ed3af9
	char *error;
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
	*fontpath = NULL;
Packit ed3af9
#ifndef NO_POSTSCRIPT_ALIAS
Packit ed3af9
	error = find_postscript_font(&font, fontpattern);
Packit ed3af9
Packit ed3af9
	if (!font) {
Packit ed3af9
		if (error)
Packit ed3af9
			return error;
Packit ed3af9
#endif
Packit ed3af9
		pattern = FcNameParse((const FcChar8 *)fontpattern);
Packit ed3af9
		font = find_font(pattern);
Packit ed3af9
		FcPatternDestroy(pattern);
Packit ed3af9
#ifndef NO_POSTSCRIPT_ALIAS
Packit ed3af9
	}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
	if (!font)
Packit ed3af9
		return "fontconfig: Couldn't find font.";
Packit ed3af9
	if (FcPatternGetString(font, FC_FILE, 0, &file) != FcResultMatch) {
Packit ed3af9
		FcPatternDestroy(font);
Packit ed3af9
		return "fontconfig: Couldn't retrieve font file name.";
Packit ed3af9
	} else {
Packit ed3af9
		const unsigned int file_len = strlen((const char *)file);
Packit ed3af9
Packit ed3af9
		*fontpath = (char *) gdMalloc(file_len + 1);
Packit ed3af9
		if (*fontpath == NULL) {
Packit ed3af9
			return "could not alloc font path";
Packit ed3af9
		}
Packit ed3af9
		strncpy(*fontpath, (const char *)file, file_len);
Packit ed3af9
		(*fontpath)[file_len] = 0;
Packit ed3af9
	}
Packit ed3af9
	FcPatternDestroy(font);
Packit ed3af9
Packit ed3af9
	return NULL;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#endif /* HAVE_LIBFONTCONFIG */
Packit ed3af9
Packit ed3af9
#ifdef HAVE_LIBFREETYPE
Packit ed3af9
/* Look up font using font names as file names. */
Packit ed3af9
static char * font_path(char **fontpath, char *name_list)
Packit ed3af9
{
Packit ed3af9
	int font_found = 0;
Packit ed3af9
	char *fontsearchpath, *fontlist;
Packit ed3af9
	char *fullname = NULL;
Packit ed3af9
	char *name, *dir;
Packit ed3af9
	char *path;
Packit ed3af9
	char *strtok_ptr = NULL;
Packit ed3af9
	const unsigned int name_list_len = strlen(name_list);
Packit ed3af9
Packit ed3af9
	/*
Packit ed3af9
	 * Search the pathlist for any of a list of font names.
Packit ed3af9
	 */
Packit ed3af9
	*fontpath = NULL;
Packit ed3af9
	fontsearchpath = getenv ("GDFONTPATH");
Packit ed3af9
	if (!fontsearchpath)
Packit ed3af9
		fontsearchpath = DEFAULT_FONTPATH;
Packit ed3af9
	path = (char *) gdMalloc(sizeof(char) * strlen(fontsearchpath) + 1);
Packit ed3af9
	if( path == NULL ) {
Packit ed3af9
		return "could not alloc full list of fonts";
Packit ed3af9
	}
Packit ed3af9
	path[0] = 0;
Packit ed3af9
Packit ed3af9
	fontlist = (char *) gdMalloc(name_list_len + 1);
Packit ed3af9
	if (fontlist == NULL) {
Packit ed3af9
		gdFree(path);
Packit ed3af9
		return "could not alloc full list of fonts";
Packit ed3af9
	}
Packit ed3af9
	strncpy(fontlist, name_list, name_list_len);
Packit ed3af9
	fontlist[name_list_len] = 0;
Packit ed3af9
Packit ed3af9
	/*
Packit ed3af9
	 * Must use gd_strtok_r else pointer corrupted by strtok in nested loop.
Packit ed3af9
	 */
Packit ed3af9
	for (name = gd_strtok_r (fontlist, LISTSEPARATOR, &strtok_ptr); name;
Packit ed3af9
	        name = gd_strtok_r (0, LISTSEPARATOR, &strtok_ptr)) {
Packit ed3af9
		char *path_ptr = NULL;
Packit ed3af9
Packit ed3af9
		/* make a fresh copy each time - strtok corrupts it. */
Packit ed3af9
		sprintf (path, "%s", fontsearchpath);
Packit ed3af9
		/*
Packit ed3af9
		 * Allocate an oversized buffer that is guaranteed to be
Packit ed3af9
		 * big enough for all paths to be tested.
Packit ed3af9
		 */
Packit ed3af9
		/* 2.0.22: Thorben Kundinger: +8 is needed, not +6. */
Packit ed3af9
		fullname = gdReallocEx(fullname,
Packit ed3af9
		                      strlen (fontsearchpath) + strlen (name) + 8);
Packit ed3af9
		if (!fullname) {
Packit ed3af9
			gdFree(fontlist);
Packit ed3af9
			gdFree(path);
Packit ed3af9
			return "could not alloc full path of font";
Packit ed3af9
		}
Packit ed3af9
		/* if name is an absolute or relative pathname then test directly */
Packit ed3af9
#ifdef NETWARE
Packit ed3af9
		/* netware uses the format "volume:/path" or the standard "/path" */
Packit ed3af9
		if (name[0] != 0 && (strstr(name, ":/") || name[0] == '/'))
Packit ed3af9
#else
Packit ed3af9
		if (strchr (name, '/')
Packit ed3af9
		        || (name[0] != 0 && name[1] == ':'
Packit ed3af9
		            && (name[2] == '/' || name[2] == '\\')))
Packit ed3af9
#endif
Packit ed3af9
		{
Packit ed3af9
			sprintf (fullname, "%s", name);
Packit ed3af9
			if (access (fullname, R_OK) == 0) {
Packit ed3af9
				font_found++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		for (dir = gd_strtok_r (path, PATHSEPARATOR, &path_ptr); dir;
Packit ed3af9
		        dir = gd_strtok_r (0, PATHSEPARATOR, &path_ptr)) {
Packit ed3af9
			if (strchr (name, '.')) {
Packit ed3af9
				sprintf (fullname, "%s/%s", dir, name);
Packit ed3af9
				if (access (fullname, R_OK) == 0) {
Packit ed3af9
					font_found++;
Packit ed3af9
					break;
Packit ed3af9
				} else {
Packit ed3af9
					continue;
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
			sprintf (fullname, "%s/%s.ttf", dir, name);
Packit ed3af9
			if (access (fullname, R_OK) == 0) {
Packit ed3af9
				font_found++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
			sprintf (fullname, "%s/%s.pfa", dir, name);
Packit ed3af9
			if (access (fullname, R_OK) == 0) {
Packit ed3af9
				font_found++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
			sprintf (fullname, "%s/%s.pfb", dir, name);
Packit ed3af9
			if (access (fullname, R_OK) == 0) {
Packit ed3af9
				font_found++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
			sprintf (fullname, "%s/%s.dfont", dir, name);
Packit ed3af9
			if (access (fullname, R_OK) == 0) {
Packit ed3af9
				font_found++;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if (font_found)
Packit ed3af9
			break;
Packit ed3af9
	}
Packit ed3af9
	gdFree (path);
Packit ed3af9
	if (fontlist != NULL) {
Packit ed3af9
		gdFree (fontlist);
Packit ed3af9
		fontlist = NULL;
Packit ed3af9
	}
Packit ed3af9
	if (!font_found) {
Packit ed3af9
		gdFree (fullname);
Packit ed3af9
		return "Could not find/open font";
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	*fontpath = fullname;
Packit ed3af9
	return NULL;
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdFTUseFontConfig
Packit ed3af9
 *
Packit ed3af9
 * Enable or disable fontconfig by default.
Packit ed3af9
 *
Packit ed3af9
 * If GD is built without libfontconfig support, this function is a NOP.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *  flag - Zero to disable, nonzero to enable.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *  - <gdImageStringFTEx>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdFTUseFontConfig(int flag)
Packit ed3af9
{
Packit ed3af9
#ifdef HAVE_LIBFONTCONFIG
Packit ed3af9
	fontConfigFlag = flag;
Packit ed3af9
	return 1;
Packit ed3af9
#else
Packit ed3af9
	(void)flag;
Packit ed3af9
	return 0;
Packit ed3af9
#endif /* HAVE_LIBFONTCONFIG */
Packit ed3af9
}
Packit ed3af9