1
2 /********************************************/
3 /* gd interface to freetype library */
4 /* */
5 /* John Ellson ellson@lucent.com */
6 /********************************************/
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <math.h>
12 #include "gd.h"
13 #include "gdhelpers.h"
14
15 #ifndef MSWIN32
16 #include <unistd.h>
17 #else
18 #define R_OK 2
19 #endif
20
21 /* number of antialised colors for indexed bitmaps */
22 #define NUMCOLORS 8
23
24 char *
gdImageStringTTF(gdImage * im,int * brect,int fg,char * fontlist,double ptsize,double angle,int x,int y,char * string)25 gdImageStringTTF (gdImage * im, int *brect, int fg, char *fontlist,
26 double ptsize, double angle, int x, int y, char *string)
27 {
28 return gdImageStringFT (im, brect, fg, fontlist, ptsize,
29 angle, x, y, string);
30 }
31
32 #ifndef HAVE_LIBFREETYPE
33 char *
gdImageStringFT(gdImage * im,int * brect,int fg,char * fontlist,double ptsize,double angle,int x,int y,char * string)34 gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
35 double ptsize, double angle, int x, int y, char *string)
36 {
37 return "libgd was not built with FreeType font support\n";
38 }
39 #else
40
41 #include "gdcache.h"
42 #include <ft2build.h>
43 #include FT_FREETYPE_H
44 #include FT_GLYPH_H
45 /* number of fonts cached before least recently used is replaced */
46 #define FONTCACHESIZE 6
47
48 /* number of antialias color lookups cached */
49 #define TWEENCOLORCACHESIZE 32
50
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 */
56 #define LINESPACE 1.05
57
58 /*
59 * The character (space) used to separate alternate fonts in the
60 * fontlist parameter to gdImageStringFT.
61 */
62 #define LISTSEPARATOR " "
63
64 /*
65 * DEFAULT_FONTPATH and PATHSEPARATOR are host type dependent and
66 * are normally set by configure in gvconfig.h. These are just
67 * some last resort values that might match some Un*x system
68 * if building this version of gd separate from graphviz.
69 */
70 #ifndef DEFAULT_FONTPATH
71 #define DEFAULT_FONTPATH "/usr/share/fonts/truetype"
72 #endif
73 #ifndef PATHSEPARATOR
74 #define PATHSEPARATOR ":"
75 #endif
76
77 #ifndef TRUE
78 #define FALSE 0
79 #define TRUE !FALSE
80 #endif
81
82 #define MAX(a,b) ((a)>(b)?(a):(b))
83 #define MIN(a,b) ((a)<(b)?(a):(b))
84
85 typedef struct
86 {
87 char *fontlist; /* key */
88 FT_Library *library;
89 FT_Face face;
90 FT_Bool have_char_map_unicode, have_char_map_big5, have_char_map_sjis,
91 have_char_map_apple_roman;
92 gdCache_head_t *glyphCache;
93 }
94 font_t;
95
96 typedef struct
97 {
98 char *fontlist; /* key */
99 FT_Library *library;
100 }
101 fontkey_t;
102
103 typedef struct
104 {
105 int pixel; /* key */
106 int bgcolor; /* key */
107 int fgcolor; /* key *//* -ve means no antialias */
108 gdImagePtr im; /* key */
109 int tweencolor;
110 }
111 tweencolor_t;
112
113 typedef struct
114 {
115 int pixel; /* key */
116 int bgcolor; /* key */
117 int fgcolor; /* key *//* -ve means no antialias */
118 gdImagePtr im; /* key */
119 }
120 tweencolorkey_t;
121
122 /********************************************************************
123 * gdTcl_UtfToUniChar is borrowed from Tcl ...
124 */
125 /*
126 * tclUtf.c --
127 *
128 * Routines for manipulating UTF-8 strings.
129 *
130 * Copyright (c) 1997-1998 Sun Microsystems, Inc.
131 *
132 * See the file "license.terms" for information on usage and redistribution
133 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
134 *
135 * SCCS: @(#) tclUtf.c 1.25 98/01/28 18:02:43
136 */
137
138 /*
139 *---------------------------------------------------------------------------
140 *
141 * gdTcl_UtfToUniChar --
142 *
143 * Extract the Tcl_UniChar represented by the UTF-8 string. Bad
144 * UTF-8 sequences are converted to valid Tcl_UniChars and processing
145 * continues. Equivalent to Plan 9 chartorune().
146 *
147 * The caller must ensure that the source buffer is long enough that
148 * this routine does not run off the end and dereference non-existent
149 * memory looking for trail bytes. If the source buffer is known to
150 * be '\0' terminated, this cannot happen. Otherwise, the caller
151 * should call Tcl_UtfCharComplete() before calling this routine to
152 * ensure that enough bytes remain in the string.
153 *
154 * Results:
155 * *chPtr is filled with the Tcl_UniChar, and the return value is the
156 * number of bytes from the UTF-8 string that were consumed.
157 *
158 * Side effects:
159 * None.
160 *
161 *---------------------------------------------------------------------------
162 */
163
164 #ifdef JISX0208
165 #include "jisx0208.h"
166 #endif
167
168 #define Tcl_UniChar int
169 #define TCL_UTF_MAX 3
170 static int
gdTcl_UtfToUniChar(char * str,Tcl_UniChar * chPtr)171 gdTcl_UtfToUniChar (char *str, Tcl_UniChar * chPtr)
172 /* str is the UTF8 next character pointer */
173 /* chPtr is the int for the result */
174 {
175 int byte;
176
177 /* HTML4.0 entities in decimal form, e.g. Å */
178 byte = *((unsigned char *) str);
179 if (byte == '&')
180 {
181 int i, n = 0;
182
183 byte = *((unsigned char *) (str + 1));
184 if (byte == '#')
185 {
186 for (i = 2; i < 8; i++)
187 {
188 byte = *((unsigned char *) (str + i));
189 if (byte >= '0' && byte <= '9')
190 {
191 n = (n * 10) + (byte - '0');
192 }
193 else
194 break;
195 }
196 if (byte == ';')
197 {
198 *chPtr = (Tcl_UniChar) n;
199 return ++i;
200 }
201 }
202 }
203
204 /*
205 * Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones.
206 */
207
208 byte = *((unsigned char *) str);
209 #ifdef JISX0208
210 if (0xA1 <= byte && byte <= 0xFE)
211 {
212 int ku, ten;
213
214 ku = (byte & 0x7F) - 0x20;
215 ten = (str[1] & 0x7F) - 0x20;
216 if ((ku < 1 || ku > 92) || (ten < 1 || ten > 94))
217 {
218 *chPtr = (Tcl_UniChar) byte;
219 return 1;
220 }
221
222 *chPtr = (Tcl_UniChar) UnicodeTbl[ku - 1][ten - 1];
223 return 2;
224 }
225 else
226 #endif /* JISX0208 */
227 if (byte < 0xC0)
228 {
229 /*
230 * Handles properly formed UTF-8 characters between
231 * 0x01 and 0x7F. Also treats \0 and naked trail
232 * bytes 0x80 to 0xBF as valid characters representing
233 * themselves.
234 */
235
236 *chPtr = (Tcl_UniChar) byte;
237 return 1;
238 }
239 else if (byte < 0xE0)
240 {
241 if ((str[1] & 0xC0) == 0x80)
242 {
243 /*
244 * Two-byte-character lead-byte followed
245 * by a trail-byte.
246 */
247
248 *chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6)
249 | (str[1] & 0x3F));
250 return 2;
251 }
252 /*
253 * A two-byte-character lead-byte not followed by trail-byte
254 * represents itself.
255 */
256
257 *chPtr = (Tcl_UniChar) byte;
258 return 1;
259 }
260 else if (byte < 0xF0)
261 {
262 if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80))
263 {
264 /*
265 * Three-byte-character lead byte followed by
266 * two trail bytes.
267 */
268
269 *chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12)
270 | ((str[1] & 0x3F) << 6) | (str[2] & 0x3F));
271 return 3;
272 }
273 /*
274 * A three-byte-character lead-byte not followed by
275 * two trail-bytes represents itself.
276 */
277
278 *chPtr = (Tcl_UniChar) byte;
279 return 1;
280 }
281 #if TCL_UTF_MAX > 3
282 else
283 {
284 int ch, total, trail;
285
286 total = totalBytes[byte];
287 trail = total - 1;
288 if (trail > 0)
289 {
290 ch = byte & (0x3F >> trail);
291 do
292 {
293 str++;
294 if ((*str & 0xC0) != 0x80)
295 {
296 *chPtr = byte;
297 return 1;
298 }
299 ch <<= 6;
300 ch |= (*str & 0x3F);
301 trail--;
302 }
303 while (trail > 0);
304 *chPtr = ch;
305 return total;
306 }
307 }
308 #endif
309
310 *chPtr = (Tcl_UniChar) byte;
311 return 1;
312 }
313
314 /********************************************************************/
315 /* font cache functions */
316
317 static int
fontTest(void * element,void * key)318 fontTest (void *element, void *key)
319 {
320 font_t *a = (font_t *) element;
321 fontkey_t *b = (fontkey_t *) key;
322
323 return (strcmp (a->fontlist, b->fontlist) == 0);
324 }
325
326 static void *
fontFetch(char ** error,void * key)327 fontFetch (char **error, void *key)
328 {
329 font_t *a;
330 fontkey_t *b = (fontkey_t *) key;
331 int n;
332 int font_found = 0;
333 unsigned short platform, encoding;
334 char *fontsearchpath, *fontlist;
335 char *fullname = NULL;
336 char *name, *path, *dir;
337 char dummy = 0;
338 char *strtok_ptr = &dummy;
339 FT_Error err;
340 FT_CharMap found = 0;
341 FT_CharMap charmap;
342
343 a = (font_t *) gdMalloc (sizeof (font_t));
344 a->fontlist = strdup (b->fontlist);
345 a->library = b->library;
346
347 /*
348 * Search the pathlist for any of a list of font names.
349 */
350 fontsearchpath = getenv ("GDFONTPATH");
351 if (!fontsearchpath)
352 fontsearchpath = DEFAULT_FONTPATH;
353 path = strdup (fontsearchpath);
354 fontlist = strdup (a->fontlist);
355
356 /*
357 * Must use gd_strtok_r else pointer corrupted by strtok in nested loop.
358 */
359 for (name = gd_strtok_r (fontlist, LISTSEPARATOR, &strtok_ptr); name;
360 name = gd_strtok_r (0, LISTSEPARATOR, &strtok_ptr))
361 {
362
363 /*
364 * Allocate an oversized buffer that is guaranteed to be
365 * big enough for all paths to be tested.
366 */
367 fullname = gdRealloc (fullname,
368 strlen (fontsearchpath) + strlen (name) + 6);
369 /* if name is an absolute filename then test directly */
370 if (*name == '/')
371 {
372 sprintf (fullname, "%s", name);
373 if (access (fullname, R_OK) == 0)
374 {
375 font_found++;
376 break;
377 }
378 }
379 for (dir = strtok (path, PATHSEPARATOR); dir;
380 dir = strtok (0, PATHSEPARATOR))
381 {
382 sprintf (fullname, "%s/%s.ttf", dir, name);
383 if (access (fullname, R_OK) == 0)
384 {
385 font_found++;
386 break;
387 }
388 }
389 if (font_found)
390 break;
391 }
392 gdFree (path);
393 gdFree (fontlist);
394 if (!font_found)
395 {
396 *error = "Could not find/open font";
397 gdFree (fullname);
398 gdFree (a);
399 return NULL;
400 }
401
402 err = FT_New_Face (*b->library, fullname, 0, &a->face);
403 gdFree (fullname);
404 if (err)
405 {
406 *error = "Could not read font";
407 gdFree (a);
408 return NULL;
409 }
410
411 /* FIXME - This mapping stuff is imcomplete - where is the spec? */
412
413 a->have_char_map_unicode = 0;
414 a->have_char_map_big5 = 0;
415 a->have_char_map_sjis = 0;
416 a->have_char_map_apple_roman = 0;
417 for (n = 0; n < a->face->num_charmaps; n++)
418 {
419 charmap = a->face->charmaps[n];
420 platform = charmap->platform_id;
421 encoding = charmap->encoding_id;
422 if ((platform == 3 && encoding == 1) /* Windows Unicode */
423 || (platform == 3 && encoding == 0) /* Windows Symbol */
424 || (platform == 2 && encoding == 1) /* ISO Unicode */
425 || (platform == 0))
426 { /* Apple Unicode */
427 a->have_char_map_unicode = 1;
428 found = charmap;
429 }
430 else if (platform == 3 && encoding == 4)
431 { /* Windows Big5 */
432 a->have_char_map_big5 = 1;
433 found = charmap;
434 }
435 else if (platform == 3 && encoding == 2)
436 { /* Windows Sjis */
437 a->have_char_map_sjis = 1;
438 found = charmap;
439 }
440 else if ((platform == 1 && encoding == 0) /* Apple Roman */
441 || (platform == 2 && encoding == 0))
442 { /* ISO ASCII */
443 a->have_char_map_apple_roman = 1;
444 found = charmap;
445 }
446 }
447 if (!found)
448 {
449 *error = "Unable to find a CharMap that I can handle";
450 gdFree (a);
451 return NULL;
452 }
453
454 return (void *) a;
455 }
456
457 static void
fontRelease(void * element)458 fontRelease (void *element)
459 {
460 font_t *a = (font_t *) element;
461
462 FT_Done_Face (a->face);
463 gdFree (a->fontlist);
464 gdFree ((char *) element);
465 }
466
467 /********************************************************************/
468 /* tweencolor cache functions */
469
470 static int
tweenColorTest(void * element,void * key)471 tweenColorTest (void *element, void *key)
472 {
473 tweencolor_t *a = (tweencolor_t *) element;
474 tweencolorkey_t *b = (tweencolorkey_t *) key;
475
476 return (a->pixel == b->pixel
477 && a->bgcolor == b->bgcolor
478 && a->fgcolor == b->fgcolor
479 && a->im == b->im);
480 }
481
482 /*
483 * Computes a color in im's color table that is part way between
484 * the background and foreground colors proportional to the gray
485 * pixel value in the range 0-NUMCOLORS. The fg and bg colors must already
486 * be in the color table.
487 */
488 static void *
tweenColorFetch(char ** error,void * key)489 tweenColorFetch (char **error, void *key)
490 {
491 tweencolor_t *a;
492 tweencolorkey_t *b = (tweencolorkey_t *) key;
493 int pixel, npixel, bg, fg;
494 gdImagePtr im;
495
496 (void)error;
497
498 a = (tweencolor_t *) gdMalloc (sizeof (tweencolor_t));
499 pixel = a->pixel = b->pixel;
500 bg = a->bgcolor = b->bgcolor;
501 fg = a->fgcolor = b->fgcolor;
502 im = b->im;
503
504 /* if fg is specified by a negative color idx, then don't antialias */
505 if (fg < 0)
506 {
507 a->tweencolor = -fg;
508 }
509 else
510 {
511 npixel = NUMCOLORS - pixel;
512 if (im->trueColor)
513 {
514 /* 2.0.1: use gdImageSetPixel to do the alpha blending work,
515 or to just store the alpha level. All we have to do here
516 is incorporate our knowledge of the percentage of this
517 pixel that is really "lit" by pushing the alpha value
518 up toward transparency in edge regions. */
519 a->tweencolor = gdTrueColorAlpha (
520 gdTrueColorGetRed (fg),
521 gdTrueColorGetGreen (fg),
522 gdTrueColorGetBlue (fg),
523 gdAlphaMax - (gdTrueColorGetAlpha (fg) * pixel / NUMCOLORS));
524 }
525 else
526 {
527 a->tweencolor = gdImageColorResolve (im,
528 (pixel * im->red[fg] + npixel * im->red[bg]) / NUMCOLORS,
529 (pixel * im->green[fg] + npixel * im->green[bg]) / NUMCOLORS,
530 (pixel * im->blue[fg] + npixel * im->blue[bg]) / NUMCOLORS);
531 }
532 }
533 return (void *) a;
534 }
535
536 static void
tweenColorRelease(void * element)537 tweenColorRelease (void *element)
538 {
539 gdFree ((char *) element);
540 }
541
542 /* draw_bitmap - transfers glyph bitmap to GD image */
543 static char *
gdft_draw_bitmap(gdImage * im,int fg,FT_Bitmap bitmap,int pen_x,int pen_y)544 gdft_draw_bitmap (gdImage * im, int fg, FT_Bitmap bitmap, int pen_x, int pen_y)
545 {
546 unsigned char *pixel = 0;
547 int *tpixel = 0;
548 int x, y, pc;
549 unsigned row, col;
550
551 tweencolor_t *tc_elem;
552 tweencolorkey_t tc_key;
553
554 /* initialize tweenColorCache on first call */
555 static gdCache_head_t *tc_cache;
556
557 if (!tc_cache)
558 {
559 tc_cache = gdCacheCreate (TWEENCOLORCACHESIZE,
560 tweenColorTest, tweenColorFetch, tweenColorRelease);
561 }
562
563 /* copy to image, mapping colors */
564 tc_key.fgcolor = fg;
565 tc_key.im = im;
566 for (row = 0; row < bitmap.rows; row++)
567 {
568 pc = row * bitmap.pitch;
569 y = pen_y + row;
570
571 /* clip if out of bounds */
572 if (y >= im->sy || y < 0)
573 continue;
574
575 for (col = 0; col < bitmap.width; col++, pc++)
576 {
577 const int trueColor = im->trueColor;
578 if (bitmap.pixel_mode == ft_pixel_mode_grays)
579 {
580 /*
581 * Round to NUMCOLORS levels of antialiasing for
582 * index color images since only 256 colors are
583 * available.
584 */
585 tc_key.pixel = ((bitmap.buffer[pc] * NUMCOLORS)
586 + bitmap.num_grays / 2)
587 / (bitmap.num_grays - 1);
588 }
589 else if (bitmap.pixel_mode == ft_pixel_mode_mono)
590 {
591 tc_key.pixel = ((bitmap.buffer[pc / 8]
592 << (pc % 8)) & 128) ? NUMCOLORS : 0;
593 }
594 else
595 {
596 return "Unsupported ft_pixel_mode";
597 }
598
599 if (tc_key.pixel > 0)
600 { /* if not background */
601 x = pen_x + col;
602
603 /* clip if out of bounds */
604 if (x >= im->sx || x < 0)
605 continue;
606 /* get pixel location in gd buffer */
607 if (trueColor)
608 {
609 tpixel = &im->tpixels[y][x];
610 }
611 else
612 {
613 pixel = &im->pixels[y][x];
614 }
615 if (tc_key.pixel == NUMCOLORS)
616 {
617 /* use fg color directly */
618 if (trueColor)
619 {
620 *tpixel = fg;
621 }
622 else
623 {
624 *pixel = fg;
625 }
626 }
627 else
628 {
629 tc_elem = (tweencolor_t *) gdCacheGet (tc_cache, &tc_key);
630 if (!tc_elem) return tc_cache->error;
631 /* find antialised color */
632 if (trueColor)
633 {
634 tc_key.bgcolor = *tpixel;
635 *tpixel = tc_elem->tweencolor;
636 }
637 else
638 {
639 tc_key.bgcolor = *pixel;
640 *pixel = tc_elem->tweencolor;
641 }
642 }
643 }
644 }
645 }
646 return (char *) NULL;
647 }
648
649 static int
gdroundupdown(FT_F26Dot6 v1,int updown)650 gdroundupdown (FT_F26Dot6 v1, int updown)
651 {
652 return (!updown)
653 ? (v1 < 0 ? ((v1 - 63) >> 6) : v1 >> 6)
654 : (v1 > 0 ? ((v1 + 63) >> 6) : v1 >> 6);
655 }
656
657 #pragma GCC visibility push(hidden)
658 extern int any2eucjp (char *, char *, unsigned int);
659 #pragma GCC visibility pop
660
661 /********************************************************************/
662 /* gdImageStringFT - render a utf8 string onto a gd image */
663
664 char *
gdImageStringFT(gdImage * im,int * brect,int fg,char * fontlist,double ptsize,double angle,int x,int y,char * string)665 gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
666 double ptsize, double angle, int x, int y, char *string)
667 {
668 FT_BBox bbox, glyph_bbox;
669 FT_Matrix matrix;
670 FT_Vector pen, delta, penf;
671 FT_Face face;
672 FT_Glyph image;
673 FT_GlyphSlot slot;
674 FT_Error err;
675 FT_Bool use_kerning;
676 FT_UInt glyph_index, previous;
677 double sin_a = sin (angle);
678 double cos_a = cos (angle);
679 int len, i = 0, ch;
680 int x1 = 0, y1 = 0;
681 font_t *font;
682 fontkey_t fontkey;
683 char *next;
684 char *tmpstr = NULL;
685 int render = (im && (im->trueColor || (fg <= 255 && fg >= -255)));
686 FT_BitmapGlyph bm;
687
688 /***** initialize font library and font cache on first call ******/
689 static gdCache_head_t *fontCache;
690 static FT_Library library;
691
692 if (!fontCache)
693 {
694 if (FT_Init_FreeType (&library))
695 {
696 return "Failure to initialize font library";
697 }
698 fontCache = gdCacheCreate (FONTCACHESIZE,
699 fontTest, fontFetch, fontRelease);
700 }
701 /*****/
702
703 /* get the font (via font cache) */
704 fontkey.fontlist = fontlist;
705 fontkey.library = &library;
706 font = (font_t *) gdCacheGet (fontCache, &fontkey);
707 if (!font)
708 {
709 return fontCache->error;
710 }
711 face = font->face; /* shortcut */
712 slot = face->glyph; /* shortcut */
713
714 if (FT_Set_Char_Size (face, 0, (FT_F26Dot6) (ptsize * 64),
715 GD_RESOLUTION, GD_RESOLUTION))
716 {
717 return "Could not set character size";
718 }
719
720 matrix.xx = (FT_Fixed) (cos_a * (1 << 16));
721 matrix.yx = (FT_Fixed) (sin_a * (1 << 16));
722 matrix.xy = -matrix.yx;
723 matrix.yy = matrix.xx;
724
725 penf.x = penf.y = 0; /* running position of non-rotated string */
726 pen.x = pen.y = 0; /* running position of rotated string */
727 bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0;
728
729 use_kerning = FT_HAS_KERNING (face);
730 previous = 0;
731
732 #ifndef JISX0208
733 if (font->have_char_map_sjis)
734 {
735 #endif
736 if ((tmpstr = (char *) gdMalloc (BUFSIZ)))
737 {
738 any2eucjp (tmpstr, string, BUFSIZ);
739 next = tmpstr;
740 }
741 else
742 {
743 next = string;
744 }
745 #ifndef JISX0208
746 }
747 else
748 {
749 next = string;
750 }
751 #endif
752 while (*next)
753 {
754 ch = *next;
755
756 /* carriage returns */
757 if (ch == '\r')
758 {
759 penf.x = 0;
760 x1 = (penf.x * cos_a - penf.y * sin_a + 32) / 64;
761 y1 = (penf.x * sin_a + penf.y * cos_a + 32) / 64;
762 pen.x = pen.y = 0;
763 previous = 0; /* clear kerning flag */
764 next++;
765 continue;
766 }
767 /* newlines */
768 if (ch == '\n')
769 {
770 penf.y -= face->size->metrics.height * LINESPACE;
771 penf.y = (penf.y - 32) & -64; /* round to next pixel row */
772 x1 = (penf.x * cos_a - penf.y * sin_a + 32) / 64;
773 y1 = (penf.x * sin_a + penf.y * cos_a + 32) / 64;
774 pen.x = pen.y = 0;
775 previous = 0; /* clear kerning flag */
776 next++;
777 continue;
778 }
779
780 if (font->have_char_map_unicode)
781 {
782 /* use UTF-8 mapping from ASCII */
783 len = gdTcl_UtfToUniChar (next, &ch);
784 next += len;
785 }
786 else if (font->have_char_map_sjis)
787 {
788 unsigned char c;
789 int jiscode;
790
791 c = *next;
792 if (0xA1 <= c && c <= 0xFE)
793 {
794 next++;
795 jiscode = 0x100 * (c & 0x7F) + ((*next) & 0x7F);
796
797 ch = (jiscode >> 8) & 0xFF;
798 jiscode &= 0xFF;
799
800 if (ch & 1)
801 jiscode += 0x40 - 0x21;
802 else
803 jiscode += 0x9E - 0x21;
804
805 if (jiscode >= 0x7F)
806 jiscode++;
807 ch = (ch - 0x21) / 2 + 0x81;
808 if (ch >= 0xA0)
809 ch += 0x40;
810
811 ch = (ch << 8) + jiscode;
812 }
813 else
814 {
815 ch = c & 0xFF; /* don't extend sign */
816 }
817 if (*next) next++;
818 }
819 else
820 {
821 /*
822 * Big 5 mapping:
823 * use "JIS-8 half-width katakana" coding from 8-bit characters. Ref:
824 * ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
825 */
826 ch = (*next) & 0xFF; /* don't extend sign */
827 next++;
828 if (ch >= 161 /* first code of JIS-8 pair */
829 && *next)
830 { /* don't advance past '\0' */
831 /* TBB: Fix from Kwok Wah On: & 255 needed */
832 ch = (ch * 256) + ((*next) & 255);
833 next++;
834 }
835 }
836
837 /* Convert character code to glyph index */
838 glyph_index = FT_Get_Char_Index (face, ch);
839
840 /* retrieve kerning distance and move pen position */
841 if (use_kerning && previous && glyph_index)
842 {
843 FT_Get_Kerning (face, previous, glyph_index,
844 ft_kerning_default, &delta);
845 pen.x += delta.x;
846 }
847
848 /* load glyph image into the slot (erase previous one) */
849 err = FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT);
850 if (err)
851 {
852 gdFree (tmpstr);
853 return "Problem loading glyph";
854 }
855
856 /* transform glyph image */
857 FT_Get_Glyph (slot, &image);
858 if (brect)
859 { /* only if need brect */
860 FT_Glyph_Get_CBox (image, ft_glyph_bbox_gridfit, &glyph_bbox);
861 if (!i)
862 { /* if first character, init BB corner values */
863 bbox.xMin = bbox.yMin = (1 << 30) - 1;
864 bbox.xMax = bbox.yMax = -bbox.xMin;
865 }
866 glyph_bbox.xMin += penf.x;
867 glyph_bbox.yMin += penf.y;
868 glyph_bbox.xMax += penf.x;
869 glyph_bbox.yMax += penf.y;
870 if (bbox.xMin > glyph_bbox.xMin)
871 bbox.xMin = glyph_bbox.xMin;
872 if (bbox.yMin > glyph_bbox.yMin)
873 bbox.yMin = glyph_bbox.yMin;
874 if (bbox.xMax < glyph_bbox.xMax)
875 bbox.xMax = glyph_bbox.xMax;
876 if (bbox.yMax < glyph_bbox.yMax)
877 bbox.yMax = glyph_bbox.yMax;
878 i++;
879 }
880
881 /* transform glyph image */
882 FT_Glyph_Transform (image, &matrix, 0);
883
884 if (render)
885 {
886 if (image->format != ft_glyph_format_bitmap)
887 {
888 err = FT_Glyph_To_Bitmap (&image, ft_render_mode_normal, 0, 1);
889 if (err)
890 {
891 gdFree (tmpstr);
892 return "Problem rendering glyph";
893 }
894 }
895
896 /* now, draw to our target surface */
897 bm = (FT_BitmapGlyph) image;
898 gdft_draw_bitmap (im, fg, bm->bitmap,
899 x + x1 + ((pen.x + 31) >> 6) + bm->left,
900 y - y1 + ((pen.y + 31) >> 6) - bm->top);
901 }
902
903 /* record current glyph index for kerning */
904 previous = glyph_index;
905
906 /* increment pen position */
907 pen.x += image->advance.x >> 10;
908 pen.y -= image->advance.y >> 10;
909
910 penf.x += slot->metrics.horiAdvance;
911
912 FT_Done_Glyph (image);
913 }
914
915 if (brect)
916 { /* only if need brect */
917 /* For perfect rounding, must get sin(a + pi/4) and sin(a - pi/4). */
918 double d1 = sin (angle + 0.78539816339744830962);
919 double d2 = sin (angle - 0.78539816339744830962);
920
921 /* rotate bounding rectangle */
922 brect[0] = (int) (bbox.xMin * cos_a - bbox.yMin * sin_a);
923 brect[1] = (int) (bbox.xMin * sin_a + bbox.yMin * cos_a);
924 brect[2] = (int) (bbox.xMax * cos_a - bbox.yMin * sin_a);
925 brect[3] = (int) (bbox.xMax * sin_a + bbox.yMin * cos_a);
926 brect[4] = (int) (bbox.xMax * cos_a - bbox.yMax * sin_a);
927 brect[5] = (int) (bbox.xMax * sin_a + bbox.yMax * cos_a);
928 brect[6] = (int) (bbox.xMin * cos_a - bbox.yMax * sin_a);
929 brect[7] = (int) (bbox.xMin * sin_a + bbox.yMax * cos_a);
930
931 /* scale, round and offset brect */
932 brect[0] = x + gdroundupdown (brect[0], d2 > 0);
933 brect[1] = y - gdroundupdown (brect[1], d1 < 0);
934 brect[2] = x + gdroundupdown (brect[2], d1 > 0);
935 brect[3] = y - gdroundupdown (brect[3], d2 > 0);
936 brect[4] = x + gdroundupdown (brect[4], d2 < 0);
937 brect[5] = y - gdroundupdown (brect[5], d1 > 0);
938 brect[6] = x + gdroundupdown (brect[6], d1 < 0);
939 brect[7] = y - gdroundupdown (brect[7], d2 < 0);
940 }
941
942 gdFree (tmpstr);
943 return (char *) NULL;
944 }
945
946 #endif /* HAVE_LIBFREETYPE */
947