summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlia Alshanetsky <iliaa@php.net>2003-12-25 22:12:12 +0000
committerIlia Alshanetsky <iliaa@php.net>2003-12-25 22:12:12 +0000
commit8d6cfb797bfc612205bbe070b19f582e5729c3ce (patch)
tree18c4f999271416476771939bb2d01d89a2d0a256
parent1dec2d85d6da1c7883b567993ffbe69019173a0a (diff)
downloadphp-git-8d6cfb797bfc612205bbe070b19f582e5729c3ce.tar.gz
Synchronized bundled GD library with GD 2.0.17
. GD is now thread-safe thanks to wrappers around freetype library . Significant optimization to png writing code. . Miscellaneous fixes. Fixed memory leak inside php_imagettftext_common() Make ext/gd compile with GD 2.0.17+ (gdFreeFontCache() is not avaliable)
-rw-r--r--ext/gd/config.m41
-rw-r--r--ext/gd/gd.c16
-rw-r--r--ext/gd/libgd/gd.c27
-rw-r--r--ext/gd/libgd/gd.h12
-rw-r--r--ext/gd/libgd/gd_gd2.c2
-rw-r--r--ext/gd/libgd/gd_io.c2
-rw-r--r--ext/gd/libgd/gd_io_file.c2
-rw-r--r--ext/gd/libgd/gd_jpeg.c5
-rw-r--r--ext/gd/libgd/gd_png.c29
-rw-r--r--ext/gd/libgd/gd_topal.c15
-rw-r--r--ext/gd/libgd/gdft.c148
-rw-r--r--ext/gd/libgd/gdhelpers.h14
12 files changed, 190 insertions, 83 deletions
diff --git a/ext/gd/config.m4 b/ext/gd/config.m4
index aacb084e13..05e406cb0b 100644
--- a/ext/gd/config.m4
+++ b/ext/gd/config.m4
@@ -258,6 +258,7 @@ AC_DEFUN(PHP_GD_CHECK_VERSION,[
PHP_CHECK_LIBRARY(gd, gdImageColorResolve, [AC_DEFINE(HAVE_GDIMAGECOLORRESOLVE, 1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
PHP_CHECK_LIBRARY(gd, gdImageGifCtx, [AC_DEFINE(HAVE_GD_GIF_CTX, 1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
PHP_CHECK_LIBRARY(gd, gdCacheCreate, [AC_DEFINE(HAVE_GD_CACHE_CREATE, 1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
+ PHP_CHECK_LIBRARY(gd, gdFontCacheShutdown, [AC_DEFINE(HAVE_GD_THREAD_SAFE, 1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
])
dnl
diff --git a/ext/gd/gd.c b/ext/gd/gd.c
index 08c208db40..a13b211923 100644
--- a/ext/gd/gd.c
+++ b/ext/gd/gd.c
@@ -442,14 +442,18 @@ PHP_MINIT_FUNCTION(gd)
#if HAVE_LIBGD20 && HAVE_GD_STRINGFT
PHP_RSHUTDOWN_FUNCTION(gd)
{
+#if defined(HAVE_GD_THREAD_SAFE) || defined(HAVE_GD_BUNDLED)
+ gdFontCacheShutdown();
+#else
gdFreeFontCache();
+#endif
return SUCCESS;
}
#endif
/* }}} */
#if HAVE_GD_BUNDLED
-#define PHP_GD_VERSION_STRING "bundled (2.0.15 compatible)"
+#define PHP_GD_VERSION_STRING "bundled (2.0.17 compatible)"
#elif HAVE_LIBGD20
#define PHP_GD_VERSION_STRING "2.0 or higher"
#elif HAVE_GDIMAGECOLORRESOLVE
@@ -3077,7 +3081,7 @@ static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode, int
char *error = NULL;
int argc;
#if HAVE_GD_STRINGFTEX
- gdFTStringExtra strex;
+ gdFTStringExtra strex = {0};
#endif
#if !HAVE_GD_STRINGFTEX
@@ -3120,7 +3124,6 @@ static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode, int
HashPosition pos;
convert_to_array_ex(EXT);
- memset(&strex, 0, sizeof(strex));
/* walk the assoc array */
zend_hash_internal_pointer_reset_ex(HASH_OF(*EXT), &pos);
@@ -3156,8 +3159,11 @@ static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode, int
l = strlen(str);
#ifdef VIRTUAL_DIR
- if (virtual_filepath(Z_STRVAL_PP(FONTNAME), (char **) &fontname TSRMLS_CC)) {
- fontname = (unsigned char *) Z_STRVAL_PP(FONTNAME);
+ {
+ char tmp_font_path[MAXPATHLEN];
+ if (VCWD_REALPATH(Z_STRVAL_PP(FONTNAME), tmp_font_path)) {
+ fontname = (unsigned char *) Z_STRVAL_PP(FONTNAME);
+ }
}
#else
fontname = (unsigned char *) Z_STRVAL_PP(FONTNAME);
diff --git a/ext/gd/libgd/gd.c b/ext/gd/libgd/gd.c
index 9b9413320c..4fb3c4f0c8 100644
--- a/ext/gd/libgd/gd.c
+++ b/ext/gd/libgd/gd.c
@@ -94,7 +94,7 @@ static int gdFullAlphaBlend(int dst, int src);
static int gdLayerOverlay(int dst, int src);
static int gdAlphaBlendColor(int b1, int b2, int a1, int a2);
static int gdAlphaOverlayColor(int src, int dst, int max);
-static int gdImageGetTrueColorPixel(gdImagePtr im, int x, int y);
+int gdImageGetTrueColorPixel(gdImagePtr im, int x, int y);
void php_gd_error_ex(int type, const char *format, ...)
{
@@ -751,7 +751,7 @@ void gdImageSetPixel (gdImagePtr im, int x, int y, int color)
}
}
-static int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
+int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
{
int p = gdImageGetPixel(im, x, y);
@@ -2255,20 +2255,12 @@ void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int
sty = (int *) gdMalloc (sizeof (int) * srcH);
accum = 0;
+ /* Fixed by Mao Morimoto 2.0.16 */
for (i = 0; (i < srcW); i++) {
- int got;
- accum += (double) dstW / (double) srcW;
- got = (int) floor (accum);
- stx[i] = got;
- accum -= got;
+ stx[i] = dstW * (i+1) / srcW - dstW * i / srcW ;
}
- accum = 0;
for (i = 0; (i < srcH); i++) {
- int got;
- accum += (double) dstH / (double) srcH;
- got = (int) floor (accum);
- sty[i] = got;
- accum -= got;
+ sty[i] = dstH * (i+1) / srcH - dstH * i / srcH ;
}
for (i = 0; (i < gdMaxColors); i++) {
colorMap[i] = (-1);
@@ -3019,6 +3011,15 @@ void gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
maxy = p[i].y;
}
}
+
+ /* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
+ if (miny < 0) {
+ miny = 0;
+ }
+ if (maxy >= gdImageSY(im)) {
+ maxy = gdImageSY(im) - 1;
+ }
+
/* Fix in 1.3: count a vertex only once */
for (y = miny; y <= maxy; y++) {
/*1.4 int interLast = 0; */
diff --git a/ext/gd/libgd/gd.h b/ext/gd/libgd/gd.h
index 4742fd5ab9..20f5561378 100644
--- a/ext/gd/libgd/gd.h
+++ b/ext/gd/libgd/gd.h
@@ -295,8 +295,16 @@ void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s,
void gdImageString16(gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color);
void gdImageStringUp16(gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color);
-/* clean up after using fonts in gdImageStringFT() */
-void gdFreeFontCache();
+/* 2.0.16: for thread-safe use of gdImageStringFT and friends,
+ * call this before allowing any thread to call gdImageStringFT.
+ * Otherwise it is invoked by the first thread to invoke
+ * gdImageStringFT, with a very small but real risk of a race condition.
+ * Return 0 on success, nonzero on failure to initialize freetype.
+ */
+int gdFontCacheSetup(void);
+
+/* Optional: clean up after application is done using fonts in gdImageStringFT(). */
+void gdFontCacheShutdown(void);
/* Calls gdImageStringFT. Provided for backwards compatibility only. */
char *gdImageStringTTF(gdImage *im, int *brect, int fg, char *fontlist,
diff --git a/ext/gd/libgd/gd_gd2.c b/ext/gd/libgd/gd_gd2.c
index 5034afec60..2fdbdd44d5 100644
--- a/ext/gd/libgd/gd_gd2.c
+++ b/ext/gd/libgd/gd_gd2.c
@@ -539,7 +539,7 @@ gdImagePtr gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w,
}
} else {
ch = gdGetC(in);
- if (ch == EOF) {
+ if ((int)ch == EOF) {
ch = 0;
}
}
diff --git a/ext/gd/libgd/gd_io.c b/ext/gd/libgd/gd_io.c
index 9dbd1862a2..6a39e16eb1 100644
--- a/ext/gd/libgd/gd_io.c
+++ b/ext/gd/libgd/gd_io.c
@@ -3,7 +3,7 @@
/*
* io.c
*
- * Implements the imple I/O 'helper' routines.
+ * Implements the simple I/O 'helper' routines.
*
* Not really essential, but these routines were used extensively in GD,
* so they were moved here. They also make IOCtx calls look better...
diff --git a/ext/gd/libgd/gd_io_file.c b/ext/gd/libgd/gd_io_file.c
index 4544489890..8318a45969 100644
--- a/ext/gd/libgd/gd_io_file.c
+++ b/ext/gd/libgd/gd_io_file.c
@@ -34,8 +34,6 @@ typedef struct fileIOCtx
FILE *f;
} fileIOCtx;
-struct fileIOCtx *fileIOCtxPtr;
-
gdIOCtx *newFileCtx (FILE * f);
static int fileGetbuf (gdIOCtx *, void *, int);
diff --git a/ext/gd/libgd/gd_jpeg.c b/ext/gd/libgd/gd_jpeg.c
index a2b8b62d90..ce5d84a0fb 100644
--- a/ext/gd/libgd/gd_jpeg.c
+++ b/ext/gd/libgd/gd_jpeg.c
@@ -328,6 +328,11 @@ gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile)
php_gd_error("gd-jpeg: warning: jpeg_finish_decompress reports suspended data source");
}
+ /* Thanks to Truxton Fulton */
+ if (cinfo.err->num_warnings > 0) {
+ goto error;
+ }
+
jpeg_destroy_decompress (&cinfo);
gdFree (row);
diff --git a/ext/gd/libgd/gd_png.c b/ext/gd/libgd/gd_png.c
index 35c16e7af9..dbb139fc61 100644
--- a/ext/gd/libgd/gd_png.c
+++ b/ext/gd/libgd/gd_png.c
@@ -622,28 +622,39 @@ void gdImagePngCtxEx (gdImagePtr im, gdIOCtx * outfile, int level)
*/
if (im->trueColor) {
+ /* performance optimizations by Phong Tran */
int channels = im->saveAlphaFlag ? 4 : 3;
/* Our little 7-bit alpha channel trick costs us a bit here. */
png_bytep *row_pointers;
+ unsigned char* pOutputRow;
+ int **ptpixels = im->tpixels;
+ int *pThisRow;
+ unsigned char a;
+ int thisPixel;
+ png_bytep *prow_pointers;
+ int saveAlphaFlag = im->saveAlphaFlag;
+
row_pointers = safe_emalloc(sizeof(png_bytep), height, 0);
+ prow_pointers = row_pointers;
for (j = 0; j < height; ++j) {
- int bo = 0;
- row_pointers[j] = (png_bytep) safe_emalloc(width, channels, 0);
+ *prow_pointers = (png_bytep) safe_emalloc(width, channels, 0);
+ pOutputRow = *prow_pointers++;
+ pThisRow = *ptpixels++;
for (i = 0; i < width; ++i) {
- unsigned char a;
- row_pointers[j][bo++] = gdTrueColorGetRed(im->tpixels[j][i]);
- row_pointers[j][bo++] = gdTrueColorGetGreen(im->tpixels[j][i]);
- row_pointers[j][bo++] = gdTrueColorGetBlue(im->tpixels[j][i]);
- if (im->saveAlphaFlag) {
+ thisPixel = *pThisRow++;
+ *pOutputRow++ = gdTrueColorGetRed(thisPixel);
+ *pOutputRow++ = gdTrueColorGetGreen(thisPixel);
+ *pOutputRow++ = gdTrueColorGetBlue(thisPixel);
+ if (saveAlphaFlag) {
/* convert the 7-bit alpha channel to an 8-bit alpha channel.
* We do a little bit-flipping magic, repeating the MSB
* as the LSB, to ensure that 0 maps to 0 and
* 127 maps to 255. We also have to invert to match
* PNG's convention in which 255 is opaque.
*/
- a = gdTrueColorGetAlpha(im->tpixels[j][i]);
+ a = gdTrueColorGetAlpha(thisPixel);
/* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */
- row_pointers[j][bo++] = 255 - ((a << 1) + (a >> 6));
+ *pOutputRow++ = 255 - ((a << 1) + (a >> 6));
}
}
}
diff --git a/ext/gd/libgd/gd_topal.c b/ext/gd/libgd/gd_topal.c
index 77fb4139b2..b60a055aef 100644
--- a/ext/gd/libgd/gd_topal.c
+++ b/ext/gd/libgd/gd_topal.c
@@ -703,7 +703,7 @@ LOCAL (void)
histptr histp;
int c0, c1, c2;
int c0min, c0max, c1min, c1max, c2min, c2max;
- long count;
+ long count = 0;
long total = 0;
long c0total = 0;
long c1total = 0;
@@ -735,9 +735,16 @@ LOCAL (void)
cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total >> 1)) / total);
cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total >> 1)) / total);
#else
- im->red[icolor] = (int) ((c0total + (total >> 1)) / total);
- im->green[icolor] = (int) ((c1total + (total >> 1)) / total);
- im->blue[icolor] = (int) ((c2total + (total >> 1)) / total);
+ /* 2.0.16: Paul den Dulk found an occasion where total can be 0 */
+ if (count) {
+ im->red[icolor] = (int) ((c0total + (total >> 1)) / total);
+ im->green[icolor] = (int) ((c1total + (total >> 1)) / total);
+ im->blue[icolor] = (int) ((c2total + (total >> 1)) / total);
+ } else {
+ im->red[icolor] = 255;
+ im->green[icolor] = 255;
+ im->blue[icolor] = 255;
+ }
#endif
}
diff --git a/ext/gd/libgd/gdft.c b/ext/gd/libgd/gdft.c
index b94a56a3cf..4d34d5ec9f 100644
--- a/ext/gd/libgd/gdft.c
+++ b/ext/gd/libgd/gdft.c
@@ -92,8 +92,12 @@ gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
* if building this version of gd separate from graphviz.
*/
#ifndef DEFAULT_FONTPATH
+#if defined(__APPLE__) || (defined(__MWERKS__) && defined(macintosh))
+#define DEFAULT_FONTPATH "/usr/share/fonts/truetype:/System/Library/Fonts:/Library/Fonts"
+#else
#define DEFAULT_FONTPATH "/usr/share/fonts/truetype"
#endif
+#endif
#ifndef PATHSEPARATOR
#define PATHSEPARATOR ":"
#endif
@@ -408,26 +412,18 @@ static void *fontFetch (char **error, void *key)
}
}
- snprintf(fullname, sizeof(fullname) - 1, "%s/%s", dir, name);
- if (access(fullname, R_OK) == 0) {
- font_found++;
- break;
- }
- snprintf(fullname, sizeof(fullname) - 1, "%s/%s.ttf", dir, name);
- if (access(fullname, R_OK) == 0) {
- font_found++;
- break;
- }
- snprintf(fullname, sizeof(fullname) - 1, "%s/%s.pfa", dir, name);
- if (access(fullname, R_OK) == 0) {
- font_found++;
- break;
- }
- snprintf(fullname, sizeof(fullname) - 1, "%s/%s.pfb", dir, name);
- if (access(fullname, R_OK) == 0) {
- font_found++;
- break;
- }
+#define GD_CHECK_FONT_PATH(ext) \
+ snprintf(fullname, sizeof(fullname) - 1, "%s/%s%s", dir, name, ext); \
+ if (access(fullname, R_OK) == 0) { \
+ font_found++; \
+ break; \
+ } \
+
+ GD_CHECK_FONT_PATH("");
+ GD_CHECK_FONT_PATH(".ttf");
+ GD_CHECK_FONT_PATH(".pfa");
+ GD_CHECK_FONT_PATH(".pfb");
+ GD_CHECK_FONT_PATH(".dfont");
}
gdFree(path);
path = NULL;
@@ -458,6 +454,16 @@ static void *fontFetch (char **error, void *key)
}
/* FIXME - This mapping stuff is imcomplete - where is the spec? */
+ /* EAM - It's worse than that. It's pointless to match character encodings here.
+ * As currently written, the stored a->face->charmap only matches one of
+ * the actual charmaps and we cannot know at this stage if it is the right
+ * one. We should just skip all this stuff, and check in gdImageStringFTEx
+ * if some particular charmap is preferred and if so whether it is held in
+ * one of the a->face->charmaps[0..num_charmaps].
+ * And why is it so bad not to find any recognized charmap? The user may
+ * still know what mapping to use, even if we do not. In that case we can
+ * just use the map in a->face->charmaps[num_charmaps] and be done with it.
+ */
a->have_char_map_unicode = 0;
a->have_char_map_big5 = 0;
@@ -467,6 +473,20 @@ static void *fontFetch (char **error, void *key)
charmap = a->face->charmaps[n];
platform = charmap->platform_id;
encoding = charmap->encoding_id;
+
+/* EAM DEBUG - Newer versions of libfree2 make it easier by defining encodings */
+#ifdef FT_ENCODING_MS_SYMBOL
+ if (charmap->encoding == FT_ENCODING_MS_SYMBOL
+ || charmap->encoding == FT_ENCODING_ADOBE_CUSTOM
+ || charmap->encoding == FT_ENCODING_ADOBE_STANDARD) {
+ a->have_char_map_unicode = 1;
+ found = charmap;
+ a->face->charmap = charmap;
+ return (void *)a;
+ }
+#endif /* FT_ENCODING_MS_SYMBOL */
+/* EAM DEBUG */
+
if ((platform == 3 && encoding == 1) /* Windows Unicode */
|| (platform == 3 && encoding == 0) /* Windows Symbol */
|| (platform == 2 && encoding == 1) /* ISO Unicode */
@@ -511,16 +531,12 @@ static void fontRelease (void *element)
/********************************************************************/
/* tweencolor cache functions */
-static int
-tweenColorTest (void *element, void *key)
+static int tweenColorTest (void *element, void *key)
{
- tweencolor_t *a = (tweencolor_t *) element;
- tweencolorkey_t *b = (tweencolorkey_t *) key;
+ tweencolor_t *a = (tweencolor_t *) element;
+ tweencolorkey_t *b = (tweencolorkey_t *) key;
- return (a->pixel == b->pixel
- && a->bgcolor == b->bgcolor
- && a->fgcolor == b->fgcolor
- && a->im == b->im);
+ return (a->pixel == b->pixel && a->bgcolor == b->bgcolor && a->fgcolor == b->fgcolor && a->im == b->im);
}
/*
@@ -610,7 +626,8 @@ gdft_draw_bitmap (gdCache_head_t *tc_cache, gdImage * im, int fg, FT_Bitmap bitm
pcr = pc;
y = pen_y + row;
/* clip if out of bounds */
- if (y >= im->sy || y < 0)
+ /* 2.0.16: clipping rectangle, not image bounds */
+ if ((y > im->cy2) || (y < im->cy1))
continue;
for (col = 0; col < bitmap.width; col++, pc++)
{
@@ -645,7 +662,8 @@ gdft_draw_bitmap (gdCache_head_t *tc_cache, gdImage * im, int fg, FT_Bitmap bitm
level = gdAlphaMax - level;
x = pen_x + col;
/* clip if out of bounds */
- if (x >= im->sx || x < 0)
+ /* 2.0.16: clip to clipping rectangle, Matt McNabb */
+ if ((x > im->cx2) || (x < im->cx1))
continue;
/* get pixel location in gd buffer */
tpixel = &im->tpixels[y][x];
@@ -745,30 +763,47 @@ gdroundupdown (FT_F26Dot6 v1, int updown)
extern int any2eucjp (char *, char *, unsigned int);
/* Persistent font cache until explicitly cleared */
-/* Fonts can be used across multiple images */
+/* Fonts can be used across multiple images */
+
+/* 2.0.16: thread safety (the font cache is shared) */
+gdMutexDeclare(gdFontCacheMutex);
static gdCache_head_t *fontCache = NULL;
static FT_Library library;
-void
-gdFreeFontCache()
+void gdFontCacheShutdown()
{
- if (fontCache)
- {
- gdCacheDelete(fontCache);
- fontCache = NULL;
- FT_Done_FreeType(library);
- }
+ if (fontCache) {
+ gdMutexShutdown(gdFontCacheMutex);
+ gdCacheDelete(fontCache);
+ fontCache = NULL;
+ FT_Done_FreeType(library);
+ }
+}
+
+int gdFontCacheSetup(void)
+{
+ if (fontCache) {
+ /* Already set up */
+ return 0;
+ }
+ gdMutexSetup(gdFontCacheMutex);
+ if (FT_Init_FreeType(&library)) {
+ gdMutexShutdown(gdFontCacheMutex);
+ return -1;
+ }
+ fontCache = gdCacheCreate (FONTCACHESIZE, fontTest, fontFetch, fontRelease);
+ return 0;
}
+
/********************************************************************/
/* gdImageStringFT - render a utf8 string onto a gd image */
char *
-gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
+gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
double ptsize, double angle, int x, int y, char *string)
{
- return gdImageStringFTEx(im, brect, fg, fontlist,
- ptsize, angle, x, y, string, 0);
+ return gdImageStringFTEx(im, brect, fg, fontlist, ptsize, angle, x, y, string, 0);
}
char *
@@ -815,20 +850,21 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
/***** initialize font library and font cache on first call ******/
if (!fontCache) {
- if (FT_Init_FreeType (&library)) {
- gdCacheDelete( tc_cache );
+ if (gdFontCacheSetup() != 0) {
+ gdCacheDelete(tc_cache);
return "Failure to initialize font library";
}
- fontCache = gdCacheCreate(FONTCACHESIZE, fontTest, fontFetch, fontRelease);
}
/*****/
-
+
+ gdMutexLock(gdFontCacheMutex);
/* get the font (via font cache) */
fontkey.fontlist = fontlist;
fontkey.library = &library;
font = (font_t *) gdCacheGet (fontCache, &fontkey);
if (!font) {
gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
return fontCache->error;
}
face = font->face; /* shortcut */
@@ -836,6 +872,7 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
if (FT_Set_Char_Size (face, 0, (FT_F26Dot6) (ptsize * 64), GD_RESOLUTION, GD_RESOLUTION)) {
gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
return "Could not set character size";
}
@@ -887,6 +924,7 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
}
if (!mfound) {
/* No character set found! */
+ gdMutexUnlock(gdFontCacheMutex);
return "No character set found";
}
@@ -928,6 +966,21 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
next++;
continue;
}
+
+/* EAM DEBUG */
+#ifdef FT_ENCODING_MS_SYMBOL
+ if (font->face->charmap->encoding == FT_ENCODING_MS_SYMBOL) {
+ /* I do not know the significance of the constant 0xf000.
+ * It was determined by inspection of the character codes
+ * stored in Microsoft font symbol.
+ */
+ len = gdTcl_UtfToUniChar (next, &ch);
+ ch |= 0xf000;
+ next += len;
+ } else
+#endif /* FT_ENCODING_MS_SYMBOL */
+/* EAM DEBUG */
+
switch (m) {
case gdFTEX_Unicode:
if (font->have_char_map_unicode) {
@@ -1005,6 +1058,7 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
gdFree(tmpstr);
}
gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
return "Problem loading glyph";
}
@@ -1047,6 +1101,7 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
gdFree(tmpstr);
}
gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
return "Problem rendering glyph";
}
@@ -1097,6 +1152,7 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
gdFree(tmpstr);
}
gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
return (char *) NULL;
}
diff --git a/ext/gd/libgd/gdhelpers.h b/ext/gd/libgd/gdhelpers.h
index 2544e88060..33223318f1 100644
--- a/ext/gd/libgd/gdhelpers.h
+++ b/ext/gd/libgd/gdhelpers.h
@@ -21,5 +21,19 @@ extern char *gd_strtok_r(char *s, char *sep, char **state);
#define gdPFree(ptr) pefree(ptr, 1)
#define gdPEstrdup(ptr) pestrdup(ptr, 1)
+#ifdef ZTS
+#define gdMutexDeclare(x) MUTEX_T x
+#define gdMutexSetup(x) x = tsrm_mutex_alloc()
+#define gdMutexShutdown(x) tsrm_mutex_free(x)
+#define gdMutexLock(x) tsrm_mutex_lock(x)
+#define gdMutexUnlock(x) tsrm_mutex_unlock(x)
+#else
+#define gdMutexDeclare(x)
+#define gdMutexSetup(x)
+#define gdMutexShutdown(x)
+#define gdMutexLock(x)
+#define gdMutexUnlock(x)
+#endif
+
#endif /* GDHELPERS_H */