~ubuntu-branches/ubuntu/hardy/php5/hardy-updates

« back to all changes in this revision

Viewing changes to ext/gd/gdttf.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-10-09 03:14:32 UTC
  • Revision ID: james.westby@ubuntu.com-20051009031432-kspik3lobxstafv9
Tags: upstream-5.0.5
ImportĀ upstreamĀ versionĀ 5.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gd interface to freetype library         */
 
2
/*                                          */
 
3
/* John Ellson   ellson@lucent.com          */
 
4
 
 
5
/* $Id: gdttf.c,v 1.20.2.1 2005/01/09 21:05:16 sniper Exp $ */
 
6
 
 
7
#include "php.h"
 
8
 
 
9
#if PHP_WIN32
 
10
#include "config.w32.h"
 
11
#else
 
12
#include <php_config.h>
 
13
#endif
 
14
#if HAVE_LIBTTF && !defined(USE_GD_IMGSTRTTF)
 
15
#include <stdio.h>
 
16
#include <stdlib.h>
 
17
#include <string.h>
 
18
#include <math.h>
 
19
#include <gd.h>
 
20
#include "gdttf.h"
 
21
#include "gdcache.h"
 
22
#include <freetype.h>
 
23
 
 
24
#ifndef HAVE_GDIMAGECOLORRESOLVE
 
25
extern int gdImageColorResolve(gdImagePtr, int, int, int);
 
26
#endif
 
27
 
 
28
/* number of fonts cached before least recently used is replaced */
 
29
#define FONTCACHESIZE 6
 
30
 
 
31
/* number of character glyphs cached per font before
 
32
        least-recently-used is replaced */
 
33
#define GLYPHCACHESIZE 120
 
34
 
 
35
/* number of bitmaps cached per glyph before
 
36
        least-recently-used is replaced */
 
37
#define BITMAPCACHESIZE 8
 
38
 
 
39
/* number of antialias color lookups cached */
 
40
#define TWEENCOLORCACHESIZE 32
 
41
 
 
42
/* ptsize below which anti-aliasing is ineffective */
 
43
#define MINANTIALIASPTSIZE 0
 
44
 
 
45
/* display resolution - (Not really.  This has to be 72 or hinting is wrong) */
 
46
#define RESOLUTION 72
 
47
 
 
48
/* Number of colors used for anti-aliasing */
 
49
#undef NUMCOLORS
 
50
#define NUMCOLORS 4
 
51
 
 
52
/* Line separation as a factor of font height.
 
53
      No space between if LINESPACE = 1.00
 
54
      Line separation will be rounded up to next pixel row*/
 
55
#define LINESPACE 1.05
 
56
 
 
57
#ifndef TRUE
 
58
#define FALSE 0
 
59
#define TRUE !FALSE
 
60
#endif
 
61
 
 
62
#ifndef MAX
 
63
#define MAX(a, b) ((a)>(b)?(a):(b))
 
64
#endif
 
65
#ifndef MIN
 
66
#define MIN(a, b) ((a)<(b)?(a):(b))
 
67
#endif
 
68
 
 
69
typedef struct {
 
70
        char                            *fontname;      /* key */
 
71
        double                          ptsize;         /* key */
 
72
        double                          angle;          /* key */
 
73
        double                          sin_a, cos_a;
 
74
        TT_Engine           *engine;
 
75
        TT_Face                         face;
 
76
        TT_Face_Properties  properties;
 
77
        TT_Instance                     instance;
 
78
        TT_CharMap                      char_map_Unicode;
 
79
        TT_CharMap                      char_map_Big5;
 
80
        TT_CharMap                      char_map_Roman;
 
81
        int                                     have_char_map_Unicode;
 
82
        int                                     have_char_map_Big5;
 
83
        int                                     have_char_map_Roman;
 
84
        TT_Matrix                       matrix;
 
85
        TT_Instance_Metrics     imetrics;
 
86
        gdCache_head_t          *glyphCache;
 
87
} font_t;
 
88
 
 
89
typedef struct {
 
90
        char                            *fontname;      /* key */
 
91
        double                          ptsize;         /* key */
 
92
        double                          angle;          /* key */
 
93
        TT_Engine                       *engine;
 
94
} fontkey_t;
 
95
 
 
96
typedef struct {
 
97
        int                                     character;      /* key */
 
98
        int                                     hinting;        /* key */
 
99
        TT_Glyph                        glyph;
 
100
        TT_Glyph_Metrics        metrics;
 
101
        TT_Outline                      outline;
 
102
        TT_Pos                          oldx, oldy;
 
103
        TT_Raster_Map           Bit;
 
104
        int                                     gray_render;
 
105
        int                                     xmin, xmax, ymin, ymax;
 
106
        gdCache_head_t          *bitmapCache;
 
107
} glyph_t;
 
108
 
 
109
typedef struct {
 
110
        int                                     character;      /* key */
 
111
        int                                     hinting;        /* key */
 
112
        int                                     gray_render;
 
113
        font_t                          *font;
 
114
} glyphkey_t;
 
115
 
 
116
typedef struct {
 
117
        int                                     xoffset;        /* key */
 
118
        int                                     yoffset;        /* key */
 
119
        char                            *bitmap;
 
120
} bitmap_t;
 
121
 
 
122
typedef struct {
 
123
        int                                     xoffset;        /* key */
 
124
        int                                     yoffset;        /* key */
 
125
        glyph_t                         *glyph;
 
126
} bitmapkey_t;
 
127
 
 
128
typedef struct {
 
129
    unsigned char       pixel;          /* key */
 
130
    unsigned char       bgcolor;        /* key */
 
131
    int                                 fgcolor;        /* key */ /* -ve means no antialias */
 
132
    gdImagePtr          im;                     /* key */
 
133
    unsigned char       tweencolor;
 
134
} tweencolor_t;
 
135
 
 
136
typedef struct {
 
137
    unsigned char       pixel;      /* key */
 
138
    unsigned char       bgcolor;    /* key */
 
139
    int                                 fgcolor;    /* key */ /* -ve means no antialias */
 
140
    gdImagePtr          im;                     /* key */
 
141
} tweencolorkey_t;
 
142
 
 
143
/* forward declarations so that glyphCache can be initialized by font code */
 
144
static int glyphTest ( void *element, void *key );
 
145
static void *glyphFetch ( char **error, void *key );
 
146
static void glyphRelease( void *element );
 
147
 
 
148
/* forward declarations so that bitmapCache can be initialized by glyph code */
 
149
static int bitmapTest ( void *element, void *key );
 
150
static void *bitmapFetch ( char **error, void *key );
 
151
static void bitmapRelease( void *element );
 
152
 
 
153
/* local prototype */
 
154
char *gdttfchar(gdImage *im, int fg, font_t *font, int x, int y, TT_F26Dot6 x1,  TT_F26Dot6 y1, TT_F26Dot6 *advance, TT_BBox **bbox, char **next);
 
155
 
 
156
 
 
157
 
 
158
/********************************************************************
 
159
 * gdTcl_UtfToUniChar is borrowed from ...
 
160
 */
 
161
/*
 
162
 * tclUtf.c --
 
163
 *
 
164
 *      Routines for manipulating UTF-8 strings.
 
165
 *
 
166
 * Copyright (c) 1997-1998 Sun Microsystems, Inc.
 
167
 *
 
168
 * See the file "license.terms" for information on usage and redistribution
 
169
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
170
 *
 
171
 * SCCS: @(#) tclUtf.c 1.25 98/01/28 18:02:43
 
172
 */
 
173
 
 
174
/*
 
175
 *---------------------------------------------------------------------------
 
176
 *
 
177
 * gdTcl_UtfToUniChar --
 
178
 *
 
179
 *      Extract the Tcl_UniChar represented by the UTF-8 string.  Bad
 
180
 *      UTF-8 sequences are converted to valid Tcl_UniChars and processing
 
181
 *      continues.  Equivalent to Plan 9 chartorune().
 
182
 *
 
183
 *      The caller must ensure that the source buffer is long enough that
 
184
 *      this routine does not run off the end and dereference non-existent
 
185
 *      memory looking for trail bytes.  If the source buffer is known to
 
186
 *      be '\0' terminated, this cannot happen.  Otherwise, the caller
 
187
 *      should call Tcl_UtfCharComplete() before calling this routine to
 
188
 *      ensure that enough bytes remain in the string.
 
189
 *
 
190
 * Results:
 
191
 *      *chPtr is filled with the Tcl_UniChar, and the return value is the
 
192
 *      number of bytes from the UTF-8 string that were consumed.
 
193
 *
 
194
 * Side effects:
 
195
 *      None.
 
196
 *
 
197
 *---------------------------------------------------------------------------
 
198
 */
 
199
 
 
200
#ifndef CHARSET_EBCDIC
 
201
#define ASC(ch) (ch)
 
202
#else /*CHARSET_EBCDIC*/
 
203
#define ASC(ch) os_toascii[(unsigned char) (ch)]
 
204
#endif /*CHARSET_EBCDIC*/
 
205
 
 
206
#define Tcl_UniChar int
 
207
#define TCL_UTF_MAX 3
 
208
static int gdTcl_UtfToUniChar(char *str, Tcl_UniChar *chPtr)
 
209
/* str is the UTF8 next character pointer */
 
210
/* chPtr is the int for the result */
 
211
{
 
212
        int byte;
 
213
 
 
214
        /* HTML4.0 entities in decimal form, e.g. &#197; */
 
215
        byte = *((unsigned char *) str);
 
216
        if (byte == '&') {
 
217
                int i, n = 0;
 
218
 
 
219
                byte = *((unsigned char *) (str+1));
 
220
                if (byte == '#') {
 
221
                        for (i = 2; i < 8; i++) {
 
222
                                byte = *((unsigned char *) (str+i));
 
223
                                if (byte >= '0' && byte <= '9') {
 
224
                                        n = (n * 10) + (byte - '0');
 
225
                                } else {
 
226
                                        break;
 
227
                                }
 
228
                        }
 
229
                        if (byte == ';') {
 
230
                                *chPtr = (Tcl_UniChar) n;
 
231
                                return ++i;
 
232
                        }
 
233
                }
 
234
        }
 
235
 
 
236
        /* Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones. */
 
237
 
 
238
        byte = ASC(*((unsigned char *) str));
 
239
        if (byte < 0xC0) {
 
240
                /*
 
241
                 * Handles properly formed UTF-8 characters between 0x01 and 0x7F.
 
242
                 * Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
 
243
                 * characters representing themselves.
 
244
                 */
 
245
 
 
246
                *chPtr = (Tcl_UniChar) byte;
 
247
                return 1;
 
248
        } else if (byte < 0xE0) {
 
249
                if ((ASC(str[1]) & 0xC0) == 0x80) {
 
250
                        /* Two-byte-character lead-byte followed by a trail-byte. */
 
251
 
 
252
                        *chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6) | (ASC(str[1]) & 0x3F));
 
253
                        return 2;
 
254
                }
 
255
                /*
 
256
                 * A two-byte-character lead-byte not followed by trail-byte
 
257
                 * represents itself.
 
258
                 */
 
259
 
 
260
                *chPtr = (Tcl_UniChar) byte;
 
261
                return 1;
 
262
        } else if (byte < 0xF0) {
 
263
                if (((ASC(str[1]) & 0xC0) == 0x80) && ((ASC(str[2]) & 0xC0) == 0x80)) {
 
264
                    /* Three-byte-character lead byte followed by two trail bytes. */
 
265
 
 
266
                        *chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12) | ((ASC(str[1]) & 0x3F) << 6) | (ASC(str[2]) & 0x3F));
 
267
                        return 3;
 
268
                }
 
269
                /* A three-byte-character lead-byte not followed by two trail-bytes represents itself. */
 
270
 
 
271
                *chPtr = (Tcl_UniChar) byte;
 
272
                return 1;
 
273
        }
 
274
#if TCL_UTF_MAX > 3
 
275
        else {
 
276
                int ch, total, trail;
 
277
 
 
278
                total = totalBytes[byte];
 
279
                trail = total - 1;
 
280
                if (trail > 0) {
 
281
                        ch = byte & (0x3F >> trail);
 
282
                        do {
 
283
                                str++;
 
284
                                if ((ASC(*str) & 0xC0) != 0x80) {
 
285
                                        *chPtr = byte;
 
286
                                        return 1;
 
287
                                }
 
288
                                ch <<= 6;
 
289
                                ch |= (ASC(*str) & 0x3F);
 
290
                                trail--;
 
291
                        } while (trail > 0);
 
292
                        *chPtr = ch;
 
293
                        return total;
 
294
                }
 
295
        }
 
296
#endif
 
297
 
 
298
        *chPtr = (Tcl_UniChar) byte;
 
299
        return 1;
 
300
}
 
301
 
 
302
/********************************************************************/
 
303
/* font cache functions                                             */
 
304
 
 
305
static int fontTest ( void *element, void *key )
 
306
{
 
307
        font_t *a = (font_t *)element;
 
308
        fontkey_t *b = (fontkey_t *)key;
 
309
 
 
310
        return (strcmp(a->fontname, b->fontname) == 0 && a->ptsize == b->ptsize && a->angle == b->angle);
 
311
}
 
312
 
 
313
static void * fontFetch ( char **error, void *key )
 
314
{
 
315
        TT_Error        err;
 
316
        font_t          *a;
 
317
        fontkey_t       *b = (fontkey_t *)key;
 
318
        int             i, n, map_found;
 
319
        short           platform, encoding;
 
320
        TSRMLS_FETCH();
 
321
 
 
322
        a = (font_t *)pemalloc(sizeof(font_t), 1);
 
323
#ifdef VIRTUAL_DIR
 
324
        /* a->fontname will be freed in fontRelease() later on */
 
325
        if (virtual_filepath(b->fontname, &a->fontname TSRMLS_CC)) {
 
326
                *error = "Could not find/open font";
 
327
                pefree(a, 1);
 
328
                return NULL;
 
329
        }
 
330
#else
 
331
        a->fontname = (char *)pemalloc(strlen(b->fontname) + 1, 1);
 
332
        strcpy(a->fontname, b->fontname);
 
333
#endif
 
334
        a->ptsize = b->ptsize;
 
335
        a->angle = b->angle;
 
336
        a->sin_a = sin(a->angle);
 
337
        a->cos_a = cos(a->angle);
 
338
        a->engine = b->engine;
 
339
        if ((err = TT_Open_Face(*b->engine, a->fontname, &a->face))) {
 
340
                if (err == TT_Err_Could_Not_Open_File) {
 
341
                        *error = "Could not find/open font";
 
342
                } else {
 
343
                        *error = "Could not read font";
 
344
                }
 
345
                pefree(a, 1);
 
346
                return NULL;
 
347
        }
 
348
        /* get face properties and allocate preload arrays */
 
349
        TT_Get_Face_Properties(a->face, &a->properties);
 
350
 
 
351
        /* create instance */
 
352
        if (TT_New_Instance(a->face, &a->instance)) {
 
353
                *error = "Could not create face instance";
 
354
                pefree(a, 1);
 
355
                return NULL;
 
356
        }
 
357
 
 
358
        if (TT_Set_Instance_Resolutions(a->instance, RESOLUTION, RESOLUTION)) {
 
359
                *error = "Could not set device resolutions";
 
360
                pefree(a, 1);
 
361
                return NULL;
 
362
        }
 
363
 
 
364
        if (TT_Set_Instance_CharSize(a->instance, (TT_F26Dot6)(a->ptsize*64))) {
 
365
                *error = "Could not set character size";
 
366
                pefree(a, 1);
 
367
                return NULL;
 
368
        }
 
369
 
 
370
        TT_Get_Instance_Metrics(a->instance, &a->imetrics);
 
371
 
 
372
        /* First, look for a Unicode charmap */
 
373
        n = TT_Get_CharMap_Count(a->face);
 
374
 
 
375
        for (i = 0; i < n; i++) {
 
376
                TT_Get_CharMap_ID(a->face, i, &platform, &encoding);
 
377
                if ((platform == 3 && encoding == 1)           /* Windows Unicode */
 
378
                        || (platform == 2 && encoding == 1)
 
379
                        || (platform == 0)) {        /* ?? Unicode */
 
380
                        TT_Get_CharMap(a->face, i, &a->char_map_Unicode);
 
381
                        a->have_char_map_Unicode = 1;
 
382
                        map_found++;
 
383
                } else if (platform == 3 && encoding == 4) {   /* Windows Big5 */
 
384
                        TT_Get_CharMap(a->face, i, &a->char_map_Big5);
 
385
                        a->have_char_map_Big5 = 1;
 
386
                        map_found++;
 
387
                } else if (platform == 1 && encoding == 0) {   /* Apple Roman */
 
388
                        TT_Get_CharMap(a->face, i, &a->char_map_Roman);
 
389
                        a->have_char_map_Roman = 1;
 
390
                        map_found++;
 
391
                }
 
392
        }
 
393
 
 
394
        if (!map_found) {
 
395
                *error = "Unable to find a CharMap that I can handle";
 
396
                pefree(a, 1);
 
397
                return NULL;
 
398
        }
 
399
 
 
400
        a->matrix.xx = (TT_Fixed) (a->cos_a * (1<<16));
 
401
        a->matrix.yx = (TT_Fixed) (a->sin_a * (1<<16));
 
402
        a->matrix.xy = - a->matrix.yx;
 
403
        a->matrix.yy = a->matrix.xx;
 
404
 
 
405
        a->glyphCache = gdCacheCreate(GLYPHCACHESIZE, glyphTest, glyphFetch, glyphRelease);
 
406
 
 
407
        return (void *)a;
 
408
}
 
409
 
 
410
static void fontRelease( void *element )
 
411
{
 
412
        font_t *a = (font_t *)element;
 
413
 
 
414
        gdCacheDelete(a->glyphCache);
 
415
        TT_Done_Instance(a->instance);
 
416
        TT_Close_Face(a->face);
 
417
        pefree(a->fontname, 1);
 
418
        pefree((char *)element, 1);
 
419
}
 
420
 
 
421
/********************************************************************/
 
422
/* glyph cache functions                                            */
 
423
 
 
424
static int glyphTest ( void *element, void *key )
 
425
{
 
426
        glyph_t *a = (glyph_t *)element;
 
427
        glyphkey_t *b = (glyphkey_t *)key;
 
428
 
 
429
        return (a->character == b->character && a->hinting == b->hinting && a->gray_render == b->gray_render);
 
430
}
 
431
 
 
432
static void * glyphFetch ( char **error, void *key )
 
433
{
 
434
        glyph_t         *a;
 
435
        glyphkey_t      *b = (glyphkey_t *)key;
 
436
        short           glyph_code;
 
437
        int             flags, err;
 
438
        int             crect[8], xmin, xmax, ymin, ymax;
 
439
        double          cos_a, sin_a;
 
440
 
 
441
        a = (glyph_t *)pemalloc(sizeof(glyph_t), 1);
 
442
        a->character = b->character;
 
443
        a->hinting = b->hinting;
 
444
        a->gray_render = b->gray_render;
 
445
        a->oldx = a->oldy = 0;
 
446
 
 
447
        /* create glyph container */
 
448
        if ((TT_New_Glyph(b->font->face, &a->glyph))) {
 
449
                *error = "Could not create glyph container";
 
450
                pefree(a, 1);
 
451
                return NULL;
 
452
        }
 
453
 
 
454
        flags = TTLOAD_SCALE_GLYPH;
 
455
        if (a->hinting && b->font->angle == 0.0) {
 
456
                flags |= TTLOAD_HINT_GLYPH;
 
457
        }
 
458
        if (b->font->have_char_map_Unicode) {
 
459
                glyph_code = TT_Char_Index(b->font->char_map_Unicode, a->character);
 
460
        } else if (a->character < 161 && b->font->have_char_map_Roman) {
 
461
                glyph_code = TT_Char_Index(b->font->char_map_Roman, a->character);
 
462
        } else if ( b->font->have_char_map_Big5) {
 
463
                glyph_code = TT_Char_Index(b->font->char_map_Big5, a->character);
 
464
        }
 
465
        if ((err=TT_Load_Glyph(b->font->instance, a->glyph, glyph_code, flags))) {
 
466
                *error = "TT_Load_Glyph problem";
 
467
                pefree(a, 1);
 
468
                return NULL;
 
469
        }
 
470
 
 
471
        TT_Get_Glyph_Metrics(a->glyph, &a->metrics);
 
472
        if (b->font->angle != 0.0) {
 
473
                TT_Get_Glyph_Outline(a->glyph, &a->outline);
 
474
                TT_Transform_Outline(&a->outline, &b->font->matrix);
 
475
        }
 
476
 
 
477
        /* calculate bitmap size */
 
478
        xmin = a->metrics.bbox.xMin -64;
 
479
        ymin = a->metrics.bbox.yMin -64;
 
480
        xmax = a->metrics.bbox.xMax +64;
 
481
        ymax = a->metrics.bbox.yMax +64;
 
482
 
 
483
        cos_a = b->font->cos_a;
 
484
        sin_a = b->font->sin_a;
 
485
        crect[0] = (int)(xmin * cos_a - ymin * sin_a);
 
486
        crect[1] = (int)(xmin * sin_a + ymin * cos_a);
 
487
        crect[2] = (int)(xmax * cos_a - ymin * sin_a);
 
488
        crect[3] = (int)(xmax * sin_a + ymin * cos_a);
 
489
        crect[4] = (int)(xmax * cos_a - ymax * sin_a);
 
490
        crect[5] = (int)(xmax * sin_a + ymax * cos_a);
 
491
        crect[6] = (int)(xmin * cos_a - ymax * sin_a);
 
492
        crect[7] = (int)(xmin * sin_a + ymax * cos_a);
 
493
        a->xmin = MIN(MIN(crect[0], crect[2]), MIN(crect[4], crect[6]));
 
494
        a->xmax = MAX(MAX(crect[0], crect[2]), MAX(crect[4], crect[6]));
 
495
        a->ymin = MIN(MIN(crect[1], crect[3]), MIN(crect[5], crect[7]));
 
496
        a->ymax = MAX(MAX(crect[1], crect[3]), MAX(crect[5], crect[7]));
 
497
 
 
498
        /* allocate bitmap large enough for character */
 
499
        a->Bit.rows = (a->ymax - a->ymin + 32 + 64) / 64;
 
500
        a->Bit.width = (a->xmax - a->xmin + 32 + 64) / 64;
 
501
        a->Bit.flow = TT_Flow_Up;
 
502
        if (a->gray_render) {
 
503
                a->Bit.cols = a->Bit.width;               /* 1 byte per pixel */
 
504
        } else {
 
505
                a->Bit.cols = (a->Bit.width + 7) / 8;     /* 1 bit per pixel */
 
506
        }
 
507
        a->Bit.cols = (a->Bit.cols + 3) & ~3;         /* pad to 32 bits */
 
508
        a->Bit.size = a->Bit.rows * a->Bit.cols;      /* # of bytes in buffer */
 
509
        a->Bit.bitmap = NULL;
 
510
 
 
511
        a->bitmapCache = gdCacheCreate(BITMAPCACHESIZE, bitmapTest, bitmapFetch, bitmapRelease);
 
512
 
 
513
        return (void *)a;
 
514
}
 
515
 
 
516
static void glyphRelease( void *element )
 
517
{
 
518
        glyph_t *a = (glyph_t *)element;
 
519
 
 
520
        gdCacheDelete(a->bitmapCache);
 
521
        TT_Done_Glyph(a->glyph);
 
522
        pefree((char *)element, 1);
 
523
}
 
524
 
 
525
/********************************************************************/
 
526
/* bitmap cache functions                                            */
 
527
 
 
528
static int bitmapTest ( void *element, void *key )
 
529
{
 
530
        bitmap_t *a = (bitmap_t *)element;
 
531
        bitmapkey_t *b = (bitmapkey_t *)key;
 
532
 
 
533
        if (a->xoffset == b->xoffset && a->yoffset == b->yoffset) {
 
534
                b->glyph->Bit.bitmap = a->bitmap;
 
535
                return TRUE;
 
536
        }
 
537
        return FALSE;
 
538
}
 
539
 
 
540
static void * bitmapFetch ( char **error, void *key )
 
541
{
 
542
        bitmap_t        *a;
 
543
        bitmapkey_t     *b = (bitmapkey_t *)key;
 
544
 
 
545
        a = (bitmap_t *)pemalloc(sizeof(bitmap_t), 1);
 
546
        a->xoffset = b->xoffset;
 
547
        a->yoffset = b->yoffset;
 
548
 
 
549
        b->glyph->Bit.bitmap = a->bitmap = (char *)pemalloc(b->glyph->Bit.size, 1);
 
550
        memset(a->bitmap, 0, b->glyph->Bit.size);
 
551
        /* render glyph */
 
552
        if (b->glyph->gray_render) {
 
553
                TT_Get_Glyph_Pixmap(b->glyph->glyph, &b->glyph->Bit, a->xoffset, a->yoffset);
 
554
        } else {
 
555
                TT_Get_Glyph_Bitmap(b->glyph->glyph, &b->glyph->Bit, a->xoffset, a->yoffset);
 
556
        }
 
557
        return (void *)a;
 
558
}
 
559
 
 
560
static void bitmapRelease( void *element )
 
561
{
 
562
        bitmap_t *a = (bitmap_t *)element;
 
563
 
 
564
        pefree(a->bitmap, 1);
 
565
        pefree((char *)element, 1);
 
566
}
 
567
 
 
568
/********************************************************************/
 
569
/* tweencolor cache functions                                            */
 
570
 
 
571
static int tweenColorTest (void *element, void *key)
 
572
{
 
573
        tweencolor_t *a = (tweencolor_t *)element;
 
574
        tweencolorkey_t *b = (tweencolorkey_t *)key;
 
575
 
 
576
        return (a->pixel == b->pixel && a->bgcolor == b->bgcolor && a->fgcolor == b->fgcolor && a->im == b->im);
 
577
}
 
578
 
 
579
static void * tweenColorFetch (char **error, void *key)
 
580
{
 
581
        tweencolor_t *a;
 
582
        tweencolorkey_t *b = (tweencolorkey_t *)key;
 
583
        int pixel, npixel, bg, fg;
 
584
        gdImagePtr im;
 
585
 
 
586
        a = (tweencolor_t *)pemalloc(sizeof(tweencolor_t), 1);
 
587
        pixel = a->pixel = b->pixel;
 
588
        bg = a->bgcolor = b->bgcolor;
 
589
        fg = a->fgcolor = b->fgcolor;
 
590
        im = b->im;
 
591
 
 
592
        /* if fg is specified by a negative color idx, then don't antialias */
 
593
        if (fg < 0) {
 
594
                a->tweencolor = -fg;
 
595
        } else {
 
596
                npixel = NUMCOLORS - pixel;
 
597
                a->tweencolor = gdImageColorResolve(im,
 
598
                        (pixel * im->red  [fg] + npixel * im->red  [bg]) / NUMCOLORS,
 
599
                        (pixel * im->green[fg] + npixel * im->green[bg]) / NUMCOLORS,
 
600
                        (pixel * im->blue [fg] + npixel * im->blue [bg]) / NUMCOLORS);
 
601
        }
 
602
        *error = NULL;
 
603
        return (void *)a;
 
604
}
 
605
 
 
606
static void tweenColorRelease(void *element)
 
607
{
 
608
        pefree((char *)element, 1);
 
609
}
 
610
 
 
611
/********************************************************************/
 
612
/* gdttfchar -  render one character onto a gd image                */
 
613
 
 
614
static int OneTime = 0;
 
615
static gdCache_head_t   *tweenColorCache;
 
616
 
 
617
char *
 
618
gdttfchar(gdImage *im, int fg, font_t *font,
 
619
        int x, int y,                                   /* string start pos in pixels */
 
620
        TT_F26Dot6 x1,  TT_F26Dot6 y1,  /* char start offset (*64) from x,y */
 
621
        TT_F26Dot6 *advance,
 
622
        TT_BBox **bbox,
 
623
        char **next)
 
624
{
 
625
        int pc, ch, len;
 
626
        int row, col;
 
627
        int x2, y2;     /* char start pos in pixels */
 
628
        int x3, y3;     /* current pixel pos */
 
629
        unsigned char *pixel;
 
630
 
 
631
        glyph_t *glyph;
 
632
        glyphkey_t glyphkey;
 
633
        bitmapkey_t bitmapkey;
 
634
        tweencolor_t *tweencolor;
 
635
        tweencolorkey_t tweencolorkey;
 
636
 
 
637
        /****** set up tweenColorCache on first call ************/
 
638
        if (!OneTime) {
 
639
                tweenColorCache = gdCacheCreate(TWEENCOLORCACHESIZE, tweenColorTest, tweenColorFetch, tweenColorRelease);
 
640
                OneTime++;
 
641
        }
 
642
        /**************/
 
643
 
 
644
        if (font->have_char_map_Unicode) { /* use UTF-8 mapping from ASCII */
 
645
                len = gdTcl_UtfToUniChar(*next, &ch);
 
646
                *next += len;
 
647
        } else {
 
648
                /*
 
649
                 * Big 5 mapping:
 
650
                 * use "JIS-8 half-width katakana" coding from 8-bit characters.  Ref:
 
651
                 * ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
 
652
                 */
 
653
                ch = (**next) & 255;         /* don't extend sign */
 
654
                (*next)++;
 
655
                if (ch >= 161                /* first code of JIS-8 pair */
 
656
                        && **next) {                /* don't advance past '\0' */
 
657
                        ch = (ch * 256) + **next;
 
658
                        (*next)++;
 
659
                }
 
660
        }
 
661
 
 
662
        glyphkey.character = ch;
 
663
        glyphkey.hinting = 1;
 
664
        /* if fg is specified by a negative color idx, then don't antialias */
 
665
        glyphkey.gray_render = ((font->ptsize < MINANTIALIASPTSIZE) || (fg < 0)) ? FALSE  : TRUE;
 
666
        glyphkey.font = font;
 
667
        glyph = (glyph_t *)gdCacheGet(font->glyphCache, &glyphkey);
 
668
        if (!glyph) {
 
669
                return font->glyphCache->error;
 
670
        }
 
671
 
 
672
        *bbox = &glyph->metrics.bbox;
 
673
        *advance = glyph->metrics.advance;
 
674
 
 
675
        /* if null *im, or invalid color,  then assume user just wants brect */
 
676
        if (!im || fg > 255 || fg < -255) {
 
677
                return (char *)NULL;
 
678
        }
 
679
 
 
680
        /* render (via cache) a bitmap for the current fractional offset */
 
681
        bitmapkey.xoffset = ((x1+32) & 63) - 32 - ((glyph->xmin+32) & -64);
 
682
        bitmapkey.yoffset = ((y1+32) & 63) - 32 - ((glyph->ymin+32) & -64);
 
683
        bitmapkey.glyph = glyph;
 
684
        gdCacheGet(glyph->bitmapCache, &bitmapkey);
 
685
 
 
686
        /* copy to gif, mapping colors */
 
687
        x2 = x + (((glyph->xmin+32) & -64) + ((x1+32) & -64)) / 64;
 
688
        y2 = y - (((glyph->ymin+32) & -64) + ((y1+32) & -64)) / 64;
 
689
        tweencolorkey.fgcolor = fg;
 
690
        tweencolorkey.im = im;
 
691
        for (row = 0; row < glyph->Bit.rows; row++) {
 
692
                if (glyph->gray_render) {
 
693
                        pc = row * glyph->Bit.cols;
 
694
                } else {
 
695
                        pc = row * glyph->Bit.cols * 8;
 
696
                }
 
697
                y3 = y2 - row;
 
698
                if (y3 >= im->sy || y3 < 0) {
 
699
                        continue;
 
700
                }
 
701
                for (col = 0; col < glyph->Bit.width; col++, pc++) {
 
702
                        if (glyph->gray_render) {
 
703
                                tweencolorkey.pixel = *((unsigned char *)(glyph->Bit.bitmap) + pc);
 
704
                        } else {
 
705
                                tweencolorkey.pixel = (((*((unsigned char *)(glyph->Bit.bitmap) + pc/8)) << (pc%8))&128)?4:0;
 
706
                        }
 
707
                        /* if not background */
 
708
                        if (tweencolorkey.pixel > 0) {
 
709
                                x3 = x2 + col;
 
710
                                if (x3 >= im->sx || x3 < 0) {
 
711
                                        continue;
 
712
                                }
 
713
#if HAVE_LIBGD20
 
714
                                if (im->trueColor) {
 
715
                                        pixel = &im->tpixels[y3][x3];
 
716
                                } else
 
717
#endif
 
718
                                {
 
719
#if HAVE_LIBGD13
 
720
                                        pixel = &im->pixels[y3][x3];
 
721
#else
 
722
                                        pixel = &im->pixels[x3][y3];
 
723
#endif
 
724
                                }
 
725
                                tweencolorkey.bgcolor = *pixel;
 
726
                                tweencolor = (tweencolor_t *)gdCacheGet(tweenColorCache, &tweencolorkey);
 
727
                                *pixel = tweencolor->tweencolor;
 
728
                        }
 
729
                }
 
730
        }
 
731
        return (char *)NULL;
 
732
}
 
733
 
 
734
/********************************************************************/
 
735
/* gdttf -  render a utf8 string onto a gd image                                        */
 
736
 
 
737
char * gdttf(gdImage *im, int *brect, int fg, char *fontname, double ptsize, double angle, int x, int y, char *str)
 
738
{
 
739
        TT_F26Dot6 ur_x = 0, ur_y = 0, ll_x = 0, ll_y = 0;
 
740
        TT_F26Dot6 advance_x, advance_y, advance, x1, y1;
 
741
        TT_BBox *bbox;
 
742
        double sin_a, cos_a;
 
743
        int i=0, ch;
 
744
        font_t *font;
 
745
        fontkey_t fontkey;
 
746
        char *error, *next;
 
747
 
 
748
        /****** initialize font engine on first call ************/
 
749
        static gdCache_head_t   *fontCache;
 
750
        static TT_Engine        engine;
 
751
 
 
752
        if (!fontCache) {
 
753
                if (TT_Init_FreeType(&engine)) {
 
754
                        return "Failure to initialize font engine";
 
755
                }
 
756
                fontCache = gdCacheCreate(FONTCACHESIZE, fontTest, fontFetch, fontRelease);
 
757
        }
 
758
        /**************/
 
759
 
 
760
        /* get the font (via font cache) */
 
761
        fontkey.fontname = fontname;
 
762
        fontkey.ptsize = ptsize;
 
763
        fontkey.angle = angle;
 
764
        fontkey.engine = &engine;
 
765
        font = (font_t *)gdCacheGet(fontCache, &fontkey);
 
766
        if (!font) {
 
767
                return fontCache->error;
 
768
        }
 
769
        sin_a = font->sin_a;
 
770
        cos_a = font->cos_a;
 
771
        advance_x = advance_y = 0;
 
772
 
 
773
        next = str;
 
774
        while (*next) {
 
775
                ch = *next;
 
776
 
 
777
                /* carriage returns */
 
778
                if (ch == '\r') {
 
779
                        advance_x = 0;
 
780
                        next++;
 
781
                        continue;
 
782
                }
 
783
                /* newlines */
 
784
                if (ch == '\n') {
 
785
                        advance_y -= (TT_F26Dot6)(font->imetrics.y_ppem * LINESPACE * 64);
 
786
                        advance_y = (advance_y-32) & -64; /* round to next pixel row */
 
787
                        next++;
 
788
                        continue;
 
789
                }
 
790
 
 
791
                x1 = (TT_F26Dot6)(advance_x * cos_a - advance_y * sin_a);
 
792
                y1 = (TT_F26Dot6)(advance_x * sin_a + advance_y * cos_a);
 
793
 
 
794
                if ((error = gdttfchar(im, fg, font, x, y, x1, y1, &advance, &bbox, &next))) {
 
795
                        return error;
 
796
                }
 
797
 
 
798
                if (!i++) { /* if first character, init BB corner values */
 
799
                        ll_x = bbox->xMin;
 
800
                        ll_y = bbox->yMin;
 
801
                        ur_x = bbox->xMax;
 
802
                        ur_y = bbox->yMax;
 
803
                } else {
 
804
                        if (!advance_x) {
 
805
                                ll_x = MIN(bbox->xMin, ll_x);
 
806
                        }
 
807
                        ll_y = MIN(advance_y + bbox->yMin, ll_y);
 
808
                        ur_x = MAX(advance_x + bbox->xMax, ur_x);
 
809
                        if (!advance_y) {
 
810
                                ur_y = MAX(bbox->yMax, ur_y);
 
811
                        }
 
812
                }
 
813
                advance_x += advance;
 
814
        }
 
815
 
 
816
        /* rotate bounding rectangle */
 
817
        brect[0] = (int)(ll_x * cos_a - ll_y * sin_a);
 
818
        brect[1] = (int)(ll_x * sin_a + ll_y * cos_a);
 
819
        brect[2] = (int)(ur_x * cos_a - ll_y * sin_a);
 
820
        brect[3] = (int)(ur_x * sin_a + ll_y * cos_a);
 
821
        brect[4] = (int)(ur_x * cos_a - ur_y * sin_a);
 
822
        brect[5] = (int)(ur_x * sin_a + ur_y * cos_a);
 
823
        brect[6] = (int)(ll_x * cos_a - ur_y * sin_a);
 
824
        brect[7] = (int)(ll_x * sin_a + ur_y * cos_a);
 
825
 
 
826
        /* scale, round and offset brect */
 
827
        i = 0;
 
828
        while (i < 8) {
 
829
                brect[i] = x + (brect[i] + 32) / 64;
 
830
                i++;
 
831
                brect[i] = y - (brect[i] + 32) / 64;
 
832
                i++;
 
833
        }
 
834
 
 
835
    return (char *)NULL;
 
836
}
 
837
 
 
838
#endif /* HAVE_LIBTTF */
 
839
 
 
840
/*
 
841
 * Local variables:
 
842
 * tab-width: 4
 
843
 * c-basic-offset: 4
 
844
 * End:
 
845
 */