1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

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)
This commit is contained in:
Ilia Alshanetsky
2003-12-25 22:12:12 +00:00
parent 1dec2d85d6
commit 8d6cfb797b
12 changed files with 190 additions and 83 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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; */

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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...

View File

@@ -34,8 +34,6 @@ typedef struct fileIOCtx
FILE *f;
} fileIOCtx;
struct fileIOCtx *fileIOCtxPtr;
gdIOCtx *newFileCtx (FILE * f);
static int fileGetbuf (gdIOCtx *, void *, int);

View File

@@ -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);

View File

@@ -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));
}
}
}

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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 */