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