1
/********************************************/
2
/* gd interface to freetype library */
4
/* John Ellson ellson@lucent.com */
5
/********************************************/
13
char * gdImageStringTTF(gdImage *im, int *brect, int fg, char *fontname,
14
double ptsize, double angle, int x, int y, char *string)
16
return "libgd was not built with TrueType font support\n";
23
/* number of fonts cached before least recently used is replaced */
24
#define FONTCACHESIZE 6
26
/* number of character glyphs cached per font before
27
least-recently-used is replaced */
28
#define GLYPHCACHESIZE 120
30
/* number of bitmaps cached per glyph before
31
least-recently-used is replaced */
32
#define BITMAPCACHESIZE 8
34
/* number of antialias color lookups cached */
35
#define TWEENCOLORCACHESIZE 32
37
/* ptsize below which anti-aliasing is ineffective */
38
#define MINANTIALIASPTSIZE 0
40
/* display resolution - (Not really. This has to be 96 or hinting is wrong) */
43
/* Number of colors used for anti-aliasing */
46
/* Line separation as a factor of font height.
47
No space between if LINESPACE = 1.00
48
Line separation will be rounded up to next pixel row*/
49
#define LINESPACE 1.05
56
#define MAX(a,b) ((a)>(b)?(a):(b))
57
#define MIN(a,b) ((a)<(b)?(a):(b))
60
char *fontname; /* key */
61
double ptsize; /* key */
62
double angle; /* key */
66
TT_Face_Properties properties;
68
TT_CharMap char_map_Unicode, char_map_Big5, char_map_Sjis, char_map_Roman;
69
int have_char_map_Unicode, have_char_map_Big5, have_char_map_Sjis, have_char_map_Roman;
71
TT_Instance_Metrics imetrics;
72
gdCache_head_t *glyphCache;
76
char *fontname; /* key */
77
double ptsize; /* key */
78
double angle; /* key */
83
int character; /* key */
84
int hinting; /* key */
86
TT_Glyph_Metrics metrics;
91
int xmin, xmax, ymin, ymax;
92
gdCache_head_t *bitmapCache;
96
int character; /* key */
97
int hinting; /* key */
102
int xoffset; /* key */
103
int yoffset; /* key */
108
int xoffset; /* key */
109
int yoffset; /* key */
114
unsigned char pixel; /* key */
115
unsigned char bgcolor; /* key */
116
int fgcolor; /* key */ /* -ve means no antialias */
117
gdImagePtr im; /* key */
118
unsigned char tweencolor;
122
unsigned char pixel; /* key */
123
unsigned char bgcolor; /* key */
124
int fgcolor; /* key */ /* -ve means no antialias */
125
gdImagePtr im; /* key */
128
/* forward declarations so that glyphCache can be initialized by font code */
129
static int glyphTest ( void *element, void *key );
130
static void *glyphFetch ( char **error, void *key );
131
static void glyphRelease( void *element );
133
/* forward declarations so that bitmapCache can be initialized by glyph code */
134
static int bitmapTest ( void *element, void *key );
135
static void *bitmapFetch ( char **error, void *key );
136
static void bitmapRelease( void *element );
138
/********************************************************************
139
* gdTcl_UtfToUniChar is borrowed from ...
144
* Routines for manipulating UTF-8 strings.
146
* Copyright (c) 1997-1998 Sun Microsystems, Inc.
148
* See the file "license.terms" for information on usage and redistribution
149
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
151
* SCCS: @(#) tclUtf.c 1.25 98/01/28 18:02:43
155
*---------------------------------------------------------------------------
157
* gdTcl_UtfToUniChar --
159
* Extract the Tcl_UniChar represented by the UTF-8 string. Bad
160
* UTF-8 sequences are converted to valid Tcl_UniChars and processing
161
* continues. Equivalent to Plan 9 chartorune().
163
* The caller must ensure that the source buffer is long enough that
164
* this routine does not run off the end and dereference non-existent
165
* memory looking for trail bytes. If the source buffer is known to
166
* be '\0' terminated, this cannot happen. Otherwise, the caller
167
* should call Tcl_UtfCharComplete() before calling this routine to
168
* ensure that enough bytes remain in the string.
171
* *chPtr is filled with the Tcl_UniChar, and the return value is the
172
* number of bytes from the UTF-8 string that were consumed.
177
*---------------------------------------------------------------------------
181
#include "jisx0208.h"
184
#define Tcl_UniChar int
185
#define TCL_UTF_MAX 3
187
gdTcl_UtfToUniChar(char *str, Tcl_UniChar *chPtr)
188
/* str is the UTF8 next character pointer */
189
/* chPtr is the int for the result */
193
/* HTML4.0 entities in decimal form, e.g. Å */
194
byte = *((unsigned char *) str);
198
byte = *((unsigned char *) (str+1));
200
for (i = 2; i < 8; i++) {
201
byte = *((unsigned char *) (str+i));
202
if (byte >= '0' && byte <= '9') {
203
n = (n * 10) + (byte - '0');
209
*chPtr = (Tcl_UniChar) n;
216
* Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones.
219
byte = *((unsigned char *) str);
221
if (0xA1 <= byte && byte <= 0xFE) {
222
int jiscode, ku, ten;
224
jiscode = 0x100 * (byte & 0x7F) + (str[1] & 0x7F);
225
ku = (jiscode >> 8) - 0x20;
226
ten = (jiscode % 256) - 0x20;
227
if ( (ku < 1 || ku > 92) || (ten < 1 || ten > 94) ) {
228
*chPtr = (Tcl_UniChar) byte;
232
*chPtr = (Tcl_UniChar) UnicodeTbl[ku - 1][ten - 1];
235
#endif /* JISX0208 */
238
* Handles properly formed UTF-8 characters between 0x01 and 0x7F.
239
* Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
240
* characters representing themselves.
243
*chPtr = (Tcl_UniChar) byte;
245
} else if (byte < 0xE0) {
246
if ((str[1] & 0xC0) == 0x80) {
248
* Two-byte-character lead-byte followed by a trail-byte.
251
*chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6) | (str[1] & 0x3F));
255
* A two-byte-character lead-byte not followed by trail-byte
259
*chPtr = (Tcl_UniChar) byte;
261
} else if (byte < 0xF0) {
262
if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80)) {
264
* Three-byte-character lead byte followed by two trail bytes.
267
*chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12)
268
| ((str[1] & 0x3F) << 6) | (str[2] & 0x3F));
272
* A three-byte-character lead-byte not followed by two trail-bytes
276
*chPtr = (Tcl_UniChar) byte;
281
int ch, total, trail;
283
total = totalBytes[byte];
286
ch = byte & (0x3F >> trail);
289
if ((*str & 0xC0) != 0x80) {
303
*chPtr = (Tcl_UniChar) byte;
307
/********************************************************************/
308
/* font cache functions */
311
fontTest ( void *element, void *key )
313
font_t *a=(font_t *)element;
314
fontkey_t *b=(fontkey_t *)key;
316
return ( strcmp(a->fontname, b->fontname) == 0
317
&& a->ptsize == b->ptsize
318
&& a->angle == b->angle);
322
fontFetch ( char **error, void *key )
326
fontkey_t *b=(fontkey_t *)key;
328
short platform, encoding;
330
a = (font_t *)malloc(sizeof(font_t));
331
a->fontname = (char *)malloc(strlen(b->fontname) + 1);
332
strcpy(a->fontname,b->fontname);
333
a->ptsize = b->ptsize;
335
a->sin_a = sin(a->angle);
336
a->cos_a = cos(a->angle);
337
a->engine = b->engine;
338
if ((err = TT_Open_Face(*b->engine, a->fontname, &a->face))) {
339
if (err == TT_Err_Could_Not_Open_File) {
340
*error = "Could not find/open font";
343
*error = "Could not read font";
347
/* get face properties and allocate preload arrays */
348
TT_Get_Face_Properties(a->face, &a->properties);
350
/* create instance */
351
if (TT_New_Instance(a->face, &a->instance)) {
352
*error = "Could not create face instance";
356
if (TT_Set_Instance_Resolutions(a->instance, RESOLUTION, RESOLUTION)) {
357
*error = "Could not set device resolutions";
361
if (TT_Set_Instance_CharSize(a->instance, (TT_F26Dot6)(a->ptsize*64))) {
362
*error = "Could not set character size";
366
TT_Get_Instance_Metrics(a->instance, &a->imetrics);
369
/* FIXME - This mapping stuff is imcomplete - where is the spec? */
371
n = TT_Get_CharMap_Count(a->face);
374
a->have_char_map_Unicode = 0;
375
a->have_char_map_Big5 = 0;
376
a->have_char_map_Sjis = 0;
377
a->have_char_map_Roman = 0;
378
for (i = 0; i < n; i++) {
379
TT_Get_CharMap_ID(a->face, i, &platform, &encoding);
380
if ((platform == 3 && encoding == 1) /* Windows Unicode */
381
|| (platform == 3 && encoding == 0) /* Windows
384
|| (platform == 2 && encoding == 1) /* ISO Unicode */
385
|| (platform == 0)) { /* Apple Unicode */
386
TT_Get_CharMap(a->face, i, &a->char_map_Unicode);
387
a->have_char_map_Unicode = 1;
389
} else if (platform == 3 && encoding == 4) { /* Windows Big5 */
390
TT_Get_CharMap(a->face, i, &a->char_map_Big5);
391
a->have_char_map_Big5 = 1;
393
} else if (platform == 3 && encoding == 2) { /* Windows Sjis */
394
TT_Get_CharMap(a->face, i, &a->char_map_Sjis);
395
a->have_char_map_Sjis = 1;
397
} else if ((platform == 1 && encoding == 0) /* Apple Roman */
398
|| (platform == 2 && encoding == 0)) { /* ISO ASCII */
399
TT_Get_CharMap(a->face, i, &a->char_map_Roman);
400
a->have_char_map_Roman = 1;
406
*error = "Unable to find a CharMap that I can handle";
410
a->matrix.xx = (TT_Fixed) (a->cos_a * (1<<16));
411
a->matrix.yx = (TT_Fixed) (a->sin_a * (1<<16));
412
a->matrix.xy = - a->matrix.yx;
413
a->matrix.yy = a->matrix.xx;
415
a->glyphCache = gdCacheCreate( GLYPHCACHESIZE,
416
glyphTest, glyphFetch, glyphRelease);
422
fontRelease( void *element )
424
font_t *a=(font_t *)element;
426
gdCacheDelete(a->glyphCache);
427
TT_Done_Instance(a->instance);
428
TT_Close_Face(a->face);
430
free( (char *)element );
433
/********************************************************************/
434
/* glyph cache functions */
437
glyphTest ( void *element, void *key )
439
glyph_t *a=(glyph_t *)element;
440
glyphkey_t *b=(glyphkey_t *)key;
442
return (a->character == b->character
443
&& a->hinting == b->hinting);
447
glyphFetch ( char **error, void *key )
450
glyphkey_t *b=(glyphkey_t *)key;
453
int crect[8], xmin, xmax, ymin, ymax;
456
a = (glyph_t *)malloc(sizeof(glyph_t));
457
a->character = b->character;
458
a->hinting = b->hinting;
459
a->gray_render = (b->font->ptsize < MINANTIALIASPTSIZE)?FALSE:TRUE;
460
a->oldx = a->oldy = 0;
462
/* create glyph container */
463
if ((TT_New_Glyph(b->font->face, &a->glyph))) {
464
*error = "Could not create glyph container";
468
flags = TTLOAD_SCALE_GLYPH;
469
if (a->hinting && b->font->angle == 0.0) {
470
flags |= TTLOAD_HINT_GLYPH;
472
if (b->font->have_char_map_Unicode) {
473
glyph_code = TT_Char_Index(b->font->char_map_Unicode, a->character);
474
} else if (a->character < 161 && b->font->have_char_map_Roman) {
475
glyph_code = TT_Char_Index(b->font->char_map_Roman, a->character);
476
} else if ( b->font->have_char_map_Big5) {
477
glyph_code = TT_Char_Index(b->font->char_map_Big5, a->character);
478
} else if ( b->font->have_char_map_Sjis) {
479
glyph_code = TT_Char_Index(b->font->char_map_Sjis, a->character);
481
if ((err=TT_Load_Glyph(b->font->instance, a->glyph, glyph_code, flags))) {
482
*error = "TT_Load_Glyph problem";
486
TT_Get_Glyph_Metrics(a->glyph, &a->metrics);
487
if (b->font->angle != 0.0) {
488
TT_Get_Glyph_Outline(a->glyph, &a->outline);
489
TT_Transform_Outline(&a->outline, &b->font->matrix);
492
/* calculate bitmap size */
493
xmin = a->metrics.bbox.xMin -64;
494
ymin = a->metrics.bbox.yMin -64;
495
xmax = a->metrics.bbox.xMax +64;
496
ymax = a->metrics.bbox.yMax +64;
498
cos_a = b->font->cos_a;
499
sin_a = b->font->sin_a;
500
crect[0] = (int)(xmin * cos_a - ymin * sin_a);
501
crect[1] = (int)(xmin * sin_a + ymin * cos_a);
502
crect[2] = (int)(xmax * cos_a - ymin * sin_a);
503
crect[3] = (int)(xmax * sin_a + ymin * cos_a);
504
crect[4] = (int)(xmax * cos_a - ymax * sin_a);
505
crect[5] = (int)(xmax * sin_a + ymax * cos_a);
506
crect[6] = (int)(xmin * cos_a - ymax * sin_a);
507
crect[7] = (int)(xmin * sin_a + ymax * cos_a);
508
a->xmin = MIN(MIN(crect[0],crect[2]),MIN(crect[4],crect[6]));
509
a->xmax = MAX(MAX(crect[0],crect[2]),MAX(crect[4],crect[6]));
510
a->ymin = MIN(MIN(crect[1],crect[3]),MIN(crect[5],crect[7]));
511
a->ymax = MAX(MAX(crect[1],crect[3]),MAX(crect[5],crect[7]));
513
/* allocate bitmap large enough for character */
514
a->Bit.rows = (a->ymax - a->ymin + 32 + 64) / 64;
515
a->Bit.width = (a->xmax - a->xmin + 32 + 64) / 64;
516
a->Bit.flow = TT_Flow_Up;
517
if (a->gray_render) {
518
a->Bit.cols = a->Bit.width; /* 1 byte per pixel */
521
a->Bit.cols = (a->Bit.width + 7) / 8; /* 1 bit per pixel */
523
a->Bit.cols = (a->Bit.cols + 3) & ~3; /* pad to 32 bits */
524
a->Bit.size = a->Bit.rows * a->Bit.cols; /* # of bytes in buffer */
525
a->Bit.bitmap = NULL;
527
a->bitmapCache = gdCacheCreate( BITMAPCACHESIZE,
528
bitmapTest, bitmapFetch, bitmapRelease);
534
glyphRelease( void *element )
536
glyph_t *a=(glyph_t *)element;
538
gdCacheDelete(a->bitmapCache);
539
TT_Done_Glyph( a->glyph );
540
free( (char *)element );
543
/********************************************************************/
544
/* bitmap cache functions */
547
bitmapTest ( void *element, void *key )
549
bitmap_t *a=(bitmap_t *)element;
550
bitmapkey_t *b=(bitmapkey_t *)key;
552
if (a->xoffset == b->xoffset && a->yoffset == b->yoffset) {
553
b->glyph->Bit.bitmap = a->bitmap;
560
bitmapFetch ( char **error, void *key )
563
bitmapkey_t *b=(bitmapkey_t *)key;
565
a = (bitmap_t *)malloc(sizeof(bitmap_t));
566
a->xoffset = b->xoffset;
567
a->yoffset = b->yoffset;
569
b->glyph->Bit.bitmap = a->bitmap = (char *)malloc(b->glyph->Bit.size);
570
memset(a->bitmap, 0, b->glyph->Bit.size);
572
if (b->glyph->gray_render) {
573
TT_Get_Glyph_Pixmap(b->glyph->glyph, &b->glyph->Bit,
574
a->xoffset, a->yoffset);
577
TT_Get_Glyph_Bitmap(b->glyph->glyph, &b->glyph->Bit,
578
a->xoffset, a->yoffset);
584
bitmapRelease( void *element )
586
bitmap_t *a=(bitmap_t *)element;
589
free( (char *)element );
592
/********************************************************************/
593
/* tweencolor cache functions */
596
tweenColorTest (void *element, void *key)
598
tweencolor_t *a=(tweencolor_t *)element;
599
tweencolorkey_t *b=(tweencolorkey_t *)key;
601
return (a->pixel == b->pixel
602
&& a->bgcolor == b->bgcolor
603
&& a->fgcolor == b->fgcolor
608
tweenColorFetch (char **error, void *key)
611
tweencolorkey_t *b=(tweencolorkey_t *)key;
612
int pixel, npixel, bg, fg;
615
a = (tweencolor_t *)malloc(sizeof(tweencolor_t));
616
pixel = a->pixel = b->pixel;
617
bg = a->bgcolor = b->bgcolor;
618
fg = a->fgcolor = b->fgcolor;
621
/* if fg is specified by a negative color idx, then don't antialias */
625
npixel = NUMCOLORS - pixel;
626
a->tweencolor = gdImageColorResolve(im,
627
(pixel * im->red [fg] + npixel * im->red [bg]) / NUMCOLORS,
628
(pixel * im->green[fg] + npixel * im->green[bg]) / NUMCOLORS,
629
(pixel * im->blue [fg] + npixel * im->blue [bg]) / NUMCOLORS);
636
tweenColorRelease(void *element)
638
free((char *)element);
641
/********************************************************************/
642
/* gdttfchar - render one character onto a gd image */
645
gdttfchar(gdImage *im, int fg, font_t *font,
646
int x, int y, /* string start pos in pixels */
647
TT_F26Dot6 x1, TT_F26Dot6 y1, /* char start offset (*64) from x,y */
654
int x2, y2; /* char start pos in pixels */
655
int x3, y3; /* current pixel pos */
656
unsigned char *pixel;
660
bitmapkey_t bitmapkey;
661
tweencolor_t *tweencolor;
662
tweencolorkey_t tweencolorkey;
664
/****** set up tweenColorCache on first call ************/
665
static gdCache_head_t *tweenColorCache;
667
if (! tweenColorCache)
668
tweenColorCache = gdCacheCreate(TWEENCOLORCACHESIZE,
669
tweenColorTest, tweenColorFetch, tweenColorRelease);
672
if (font->have_char_map_Unicode) { /* use UTF-8 mapping from ASCII */
673
len = gdTcl_UtfToUniChar(*next, &ch);
676
if (font->have_char_map_Sjis) {
680
c = (unsigned char)(**next);
681
if ( 0xA1 <= c && c <= 0xFE ) {
683
jiscode = 0x100 * ((c)&0x7F) + ((**next)&0x7F);
685
ch = (jiscode >> 8) & 0xFF;
688
if (ch & 1) jiscode += 0x40 - 0x21;
689
else jiscode += 0x9E - 0x21;
691
if (jiscode >= 0x7F) jiscode++;
692
ch = (ch - 0x21) / 2 + 0x81;
693
if (ch >= 0xA0) ch += 0x40;
695
ch = (ch << 8) + jiscode;
697
ch = (**next) & 255; /* don't extend sign */
702
* use "JIS-8 half-width katakana" coding from 8-bit characters. Ref:
703
* ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
705
ch = (**next) & 255; /* don't extend sign */
707
if (ch >= 161 /* first code of JIS-8 pair */
708
&& **next) { /* don't advance past '\0' */
709
ch = (ch * 256) + **next;
714
glyphkey.character = ch;
715
glyphkey.hinting = 1;
716
glyphkey.font = font;
717
glyph = (glyph_t *)gdCacheGet(font->glyphCache, &glyphkey);
719
return font->glyphCache->error;
721
*bbox = &glyph->metrics.bbox;
722
*advance = glyph->metrics.advance;
724
/* if null *im, or invalid color, then assume user just wants brect */
725
if (!im || fg > 255 || fg < -255)
728
/* render (via cache) a bitmap for the current fractional offset */
729
bitmapkey.xoffset = ((x1+32) & 63) - 32 - ((glyph->xmin+32) & -64);
730
bitmapkey.yoffset = ((y1+32) & 63) - 32 - ((glyph->ymin+32) & -64);
731
bitmapkey.glyph = glyph;
732
gdCacheGet(glyph->bitmapCache, &bitmapkey);
734
/* copy to gif, mapping colors */
735
x2 = x + (((glyph->xmin+32) & -64) + ((x1+32) & -64)) / 64;
736
y2 = y - (((glyph->ymin+32) & -64) + ((y1+32) & -64)) / 64;
737
tweencolorkey.fgcolor = fg;
738
tweencolorkey.im = im;
739
for (row = 0; row < glyph->Bit.rows; row++) {
740
if (glyph->gray_render)
741
pc = row * glyph->Bit.cols;
743
pc = row * glyph->Bit.cols * 8;
745
if (y3 >= im->sy || y3 < 0) continue;
746
for (col = 0; col < glyph->Bit.width; col++, pc++) {
747
if (glyph->gray_render) {
748
tweencolorkey.pixel =
749
*((unsigned char *)(glyph->Bit.bitmap) + pc);
751
tweencolorkey.pixel =
752
(((*((unsigned char *)(glyph->Bit.bitmap) + pc/8))
755
/* if not background */
756
if (tweencolorkey.pixel > 0) {
758
if (x3 >= im->sx || x3 < 0) continue;
759
pixel = &im->pixels[y3][x3];
760
tweencolorkey.bgcolor = *pixel;
761
tweencolor = (tweencolor_t *)gdCacheGet(
762
tweenColorCache, &tweencolorkey);
763
*pixel = tweencolor->tweencolor;
770
extern int any2eucjp(unsigned char *, unsigned char *, unsigned int);
772
/********************************************************************/
773
/* gdImageStringTTF - render a utf8 string onto a gd image */
775
char * gdImageStringTTF(gdImage *im, int *brect, int fg, char *fontname,
776
double ptsize, double angle, int x, int y, char *string)
778
TT_F26Dot6 ur_x=0, ur_y=0, ll_x=0, ll_y=0;
779
TT_F26Dot6 advance_x, advance_y, advance, x1, y1;
786
/* 1.7.2: initialize this variable. */
789
/****** initialize font engine on first call ************/
790
static gdCache_head_t *fontCache;
791
static TT_Engine engine;
794
if (TT_Init_FreeType(&engine)) {
795
return "Failure to initialize font engine";
797
fontCache = gdCacheCreate( FONTCACHESIZE,
798
fontTest, fontFetch, fontRelease);
802
/* get the font (via font cache) */
803
fontkey.fontname = fontname;
804
fontkey.ptsize = ptsize;
805
fontkey.angle = angle;
806
fontkey.engine = &engine;
807
font = (font_t *)gdCacheGet(fontCache, &fontkey);
809
return fontCache->error;
814
advance_x = advance_y = 0;
817
if (font->have_char_map_Sjis) {
819
if (tmpstr = (unsigned char *)malloc(BUFSIZ)) {
820
any2eucjp(tmpstr, string, BUFSIZ);
831
/* carriage returns */
839
advance_y -= (TT_F26Dot6)(font->imetrics.y_ppem * LINESPACE * 64);
840
advance_y = (advance_y-32) & -64; /* round to next pixel row */
845
x1 = (TT_F26Dot6)(advance_x * cos_a - advance_y * sin_a);
846
y1 = (TT_F26Dot6)(advance_x * sin_a + advance_y * cos_a);
848
if ((error=gdttfchar(im, fg, font, x, y, x1, y1, &advance, &bbox, &next)))
851
if (! i++) { /* if first character, init BB corner values */
858
if (! advance_x) ll_x = MIN(bbox->xMin, ll_x);
859
ll_y = MIN(advance_y + bbox->yMin, ll_y);
860
ur_x = MAX(advance_x + bbox->xMax, ur_x);
861
if (! advance_y) ur_y = MAX(bbox->yMax, ur_y);
863
advance_x += advance;
866
/* rotate bounding rectangle */
867
brect[0] = (int)(ll_x * cos_a - ll_y * sin_a);
868
brect[1] = (int)(ll_x * sin_a + ll_y * cos_a);
869
brect[2] = (int)(ur_x * cos_a - ll_y * sin_a);
870
brect[3] = (int)(ur_x * sin_a + ll_y * cos_a);
871
brect[4] = (int)(ur_x * cos_a - ur_y * sin_a);
872
brect[5] = (int)(ur_x * sin_a + ur_y * cos_a);
873
brect[6] = (int)(ll_x * cos_a - ur_y * sin_a);
874
brect[7] = (int)(ll_x * sin_a + ur_y * cos_a);
876
/* scale, round and offset brect */
879
brect[i] = x + (brect[i] + 32) / 64;
881
brect[i] = y - (brect[i] + 32) / 64;
885
if ( tmpstr ) free(tmpstr);
889
#endif /* HAVE_LIBTTF */