1 /*
2   SDL_ttf:  A companion library to SDL for working with TrueType (tm) fonts
3   Copyright (C) 2001-2018 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #include <math.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <ft2build.h>
28 #include FT_FREETYPE_H
29 #include FT_OUTLINE_H
30 #include FT_STROKER_H
31 #include FT_GLYPH_H
32 #include FT_TRUETYPE_IDS_H
33 
34 #include "SDL.h"
35 #include "SDL_endian.h"
36 #include "SDL_ttf.h"
37 
38 #ifdef HAVE_RAQM
39 #include "raqm.h"
40 #endif
41 
42 /* FIXME: Right now we assume the gray-scale renderer Freetype is using
43    supports 256 shades of gray, but we should instead key off of num_grays
44    in the result FT_Bitmap after the FT_Render_Glyph() call. */
45 #define NUM_GRAYS       256
46 
47 /* Handy routines for converting from fixed point */
48 #define FT_FLOOR(X) ((X & -64) / 64)
49 #define FT_CEIL(X)  (((X + 63) & -64) / 64)
50 
51 #define CACHED_METRICS  0x10
52 #define CACHED_BITMAP   0x01
53 #define CACHED_PIXMAP   0x02
54 
55 /* Cached glyph information */
56 typedef struct cached_glyph {
57     int stored;
58     FT_UInt index;
59     FT_Bitmap bitmap;
60     FT_Bitmap pixmap;
61     int minx;
62     int maxx;
63     int miny;
64     int maxy;
65     int yoffset;
66     int advance;
67     Uint32 cached;
68 } c_glyph;
69 
70 /* The structure used to hold internal font information */
71 struct _TTF_Font {
72     /* Freetype2 maintains all sorts of useful info itself */
73     FT_Face face;
74 
75     /* We'll cache these ourselves */
76     int height;
77     int ascent;
78     int descent;
79     int lineskip;
80 
81     /* The font style */
82     int face_style;
83     int style;
84     int outline;
85 
86     /* Whether kerning is desired */
87     int kerning;
88 
89     /* Extra width in glyph bounds for text styles */
90     int glyph_overhang;
91     float glyph_italics;
92 
93     /* Information in the font for underlining */
94     int underline_offset;
95     int underline_height;
96 
97     /* Cache for style-transformed glyphs */
98     c_glyph *current;
99     c_glyph cache[257]; /* 257 is a prime */
100 
101     /* We are responsible for closing the font stream */
102     SDL_RWops *src;
103     int freesrc;
104     FT_Open_Args args;
105 
106     /* For non-scalable formats, we must remember which font index size */
107     int font_size_family;
108 
109     /* really just flags passed into FT_Load_Glyph */
110     int hinting;
111 };
112 
113 /* Handle a style only if the font does not already handle it */
114 #define TTF_HANDLE_STYLE_BOLD(font) (((font)->style & TTF_STYLE_BOLD) && \
115                                     !((font)->face_style & TTF_STYLE_BOLD))
116 #define TTF_HANDLE_STYLE_ITALIC(font) (((font)->style & TTF_STYLE_ITALIC) && \
117                                       !((font)->face_style & TTF_STYLE_ITALIC))
118 #define TTF_HANDLE_STYLE_UNDERLINE(font) ((font)->style & TTF_STYLE_UNDERLINE)
119 #define TTF_HANDLE_STYLE_STRIKETHROUGH(font) ((font)->style & TTF_STYLE_STRIKETHROUGH)
120 
121 /* Font styles that does not impact glyph drawing */
122 #define TTF_STYLE_NO_GLYPH_CHANGE   (TTF_STYLE_UNDERLINE | TTF_STYLE_STRIKETHROUGH)
123 
124 /* The FreeType font engine/library */
125 static FT_Library library;
126 static int TTF_initialized = 0;
127 static int TTF_byteswapped = 0;
128 
129 #define TTF_CHECKPOINTER(p, errval)                 \
130     if (!TTF_initialized) {                   \
131         TTF_SetError("Library not initialized");        \
132         return errval;                      \
133     }                               \
134     if (!p) {                         \
135         TTF_SetError("Passed a NULL pointer");          \
136         return errval;                      \
137     }
138 
139 /* Gets the top row of the underline. The outline
140    is taken into account.
141 */
TTF_underline_top_row(TTF_Font * font)142 static int TTF_underline_top_row(TTF_Font *font)
143 {
144     /* With outline, the underline_offset is underline_offset+outline. */
145     /* So, we don't have to remove the top part of the outline height. */
146     return font->ascent - font->underline_offset - 1;
147 }
148 
149 /* Gets the top row of the underline. for a given glyph. The outline
150    is taken into account.
151    Need to update row according to height difference between font and glyph:
152    font_value - font->ascent + glyph->maxy
153 */
TTF_Glyph_underline_top_row(TTF_Font * font,c_glyph * glyph)154 static int TTF_Glyph_underline_top_row(TTF_Font *font, c_glyph *glyph)
155 {
156     return glyph->maxy - font->underline_offset - 1;
157 }
158 
159 /* Gets the bottom row of the underline. The outline
160    is taken into account.
161 */
TTF_underline_bottom_row(TTF_Font * font)162 static int TTF_underline_bottom_row(TTF_Font *font)
163 {
164     int row = TTF_underline_top_row(font) + font->underline_height;
165     if (font->outline > 0) {
166         /* Add underline_offset outline offset and */
167         /* the bottom part of the outline. */
168         row += font->outline * 2;
169     }
170     return row;
171 }
172 
173 /* Gets the bottom row of the underline. for a given glyph. The outline
174    is taken into account.
175    Need to update row according to height difference between font and glyph:
176    font_value - font->ascent + glyph->maxy
177 */
TTF_Glyph_underline_bottom_row(TTF_Font * font,c_glyph * glyph)178 static int TTF_Glyph_underline_bottom_row(TTF_Font *font, c_glyph *glyph)
179 {
180     return TTF_underline_bottom_row(font) - font->ascent + glyph->maxy;
181 }
182 
183 /* Gets the top row of the strikethrough. The outline
184    is taken into account.
185 */
TTF_strikethrough_top_row(TTF_Font * font)186 static int TTF_strikethrough_top_row(TTF_Font *font)
187 {
188     /* With outline, the first text row is 'outline'. */
189     /* So, we don't have to remove the top part of the outline height. */
190     return font->height / 2;
191 }
192 
193 /* Gets the top row of the strikethrough for a given glyph. The outline
194    is taken into account.
195    Need to update row according to height difference between font and glyph:
196    font_value - font->ascent + glyph->maxy
197 */
TTF_Glyph_strikethrough_top_row(TTF_Font * font,c_glyph * glyph)198 static int TTF_Glyph_strikethrough_top_row(TTF_Font *font, c_glyph *glyph)
199 {
200     return TTF_strikethrough_top_row(font) - font->ascent + glyph->maxy;
201 }
202 
TTF_initLineMectrics(const TTF_Font * font,const SDL_Surface * textbuf,const int row,Uint8 ** pdst,int * pheight)203 static void TTF_initLineMectrics(const TTF_Font *font, const SDL_Surface *textbuf, const int row, Uint8 **pdst, int *pheight)
204 {
205     Uint8 *dst;
206     int height;
207 
208     dst = (Uint8 *)textbuf->pixels;
209     if (row > 0) {
210         dst += row * textbuf->pitch;
211     }
212 
213     height = font->underline_height;
214     /* Take outline into account */
215     if (font->outline > 0) {
216         height += font->outline * 2;
217     }
218     *pdst = dst;
219     *pheight = height;
220 }
221 
222 /* Draw a solid line of underline_height (+ optional outline)
223    at the given row. The row value must take the
224    outline into account.
225 */
TTF_drawLine_Solid(const TTF_Font * font,const SDL_Surface * textbuf,const int row)226 static void TTF_drawLine_Solid(const TTF_Font *font, const SDL_Surface *textbuf, const int row)
227 {
228     int line;
229     Uint8 *dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
230     Uint8 *dst;
231     int height;
232 
233     TTF_initLineMectrics(font, textbuf, row, &dst, &height);
234 
235     /* Draw line */
236     for (line=height; line>0 && dst < dst_check; --line) {
237         /* 1 because 0 is the bg color */
238         SDL_memset(dst, 1, textbuf->w);
239         dst += textbuf->pitch;
240     }
241 }
242 
243 /* Draw a shaded line of underline_height (+ optional outline)
244    at the given row. The row value must take the
245    outline into account.
246 */
TTF_drawLine_Shaded(const TTF_Font * font,const SDL_Surface * textbuf,const int row)247 static void TTF_drawLine_Shaded(const TTF_Font *font, const SDL_Surface *textbuf, const int row)
248 {
249     int line;
250     Uint8 *dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
251     Uint8 *dst;
252     int height;
253 
254     TTF_initLineMectrics(font, textbuf, row, &dst, &height);
255 
256     /* Draw line */
257     for (line=height; line>0 && dst < dst_check; --line) {
258         SDL_memset(dst, NUM_GRAYS - 1, textbuf->w);
259         dst += textbuf->pitch;
260     }
261 }
262 
263 /* Draw a blended line of underline_height (+ optional outline)
264    at the given row. The row value must take the
265    outline into account.
266 */
TTF_drawLine_Blended(const TTF_Font * font,const SDL_Surface * textbuf,const int row,const Uint32 color)267 static void TTF_drawLine_Blended(const TTF_Font *font, const SDL_Surface *textbuf, const int row, const Uint32 color)
268 {
269     int line;
270     Uint32 *dst_check = (Uint32*)textbuf->pixels + textbuf->pitch/4 * textbuf->h;
271     Uint8 *dst8; /* destination, byte version */
272     Uint32 *dst;
273     int height;
274     int col;
275     Uint32 pixel = color | 0xFF000000; /* Amask */
276 
277     TTF_initLineMectrics(font, textbuf, row, &dst8, &height);
278     dst = (Uint32 *) dst8;
279 
280     /* Draw line */
281     for (line=height; line>0 && dst < dst_check; --line) {
282         for (col=0; col < textbuf->w; ++col) {
283             dst[col] = pixel;
284         }
285         dst += textbuf->pitch/4;
286     }
287 }
288 
289 /* rcg06192001 get linked library's version. */
TTF_Linked_Version(void)290 const SDL_version *TTF_Linked_Version(void)
291 {
292     static SDL_version linked_version;
293     SDL_TTF_VERSION(&linked_version);
294     return(&linked_version);
295 }
296 
297 /* This function tells the library whether UNICODE text is generally
298    byteswapped.  A UNICODE BOM character at the beginning of a string
299    will override this setting for that string.
300  */
TTF_ByteSwappedUNICODE(int swapped)301 void TTF_ByteSwappedUNICODE(int swapped)
302 {
303     TTF_byteswapped = swapped;
304 }
305 
TTF_SetFTError(const char * msg,FT_Error error)306 static void TTF_SetFTError(const char *msg, FT_Error error)
307 {
308 #ifdef USE_FREETYPE_ERRORS
309 #undef FTERRORS_H
310 #define FT_ERRORDEF(e, v, s)  { e, s },
311     static const struct
312     {
313       int          err_code;
314       const char*  err_msg;
315     } ft_errors[] = {
316 #include <freetype/fterrors.h>
317     };
318     int i;
319     const char *err_msg;
320     char buffer[1024];
321 
322     err_msg = NULL;
323     for (i=0; i<((sizeof ft_errors)/(sizeof ft_errors[0])); ++i) {
324         if (error == ft_errors[i].err_code) {
325             err_msg = ft_errors[i].err_msg;
326             break;
327         }
328     }
329     if (!err_msg) {
330         err_msg = "unknown FreeType error";
331     }
332     TTF_SetError("%s: %s", msg, err_msg);
333 #else
334     TTF_SetError("%s", msg);
335 #endif /* USE_FREETYPE_ERRORS */
336 }
337 
338 static FT_Error Find_Glyph( TTF_Font* font, Uint32 ch, int want );
339 static Uint32 UTF8_getch(const char **src, size_t *srclen);
340 
341 #ifndef HAVE_RAQM
342 typedef struct {
343     int index;
344     int x_offset;
345     int x_advance;
346     int y_offset;
347 } raqm_glyph_t;
348 
349 typedef struct {
350   raqm_glyph_t* g_info;
351 } raqm_t;
352 
raqm_destroy(raqm_t * rq)353 void raqm_destroy(raqm_t *rq)
354 {
355   free(rq->g_info);
356   free(rq);
357 }
358 #endif
359 
360 static FT_Error Find_GlyphByIndex( TTF_Font* font, Uint16 idx, int want );
361 
text_layout(const char * text,size_t textlen,TTF_Font * font,raqm_t ** rq,raqm_glyph_t ** g_info,size_t * glyph_count)362 int text_layout(const char *text, size_t textlen, TTF_Font *font,
363                 raqm_t **rq, raqm_glyph_t **g_info, size_t *glyph_count)
364 {
365 #ifdef HAVE_RAQM
366     *rq = raqm_create();
367     if ( *rq == NULL )
368     {
369         return -1;
370     }
371 
372     if ( !raqm_set_text_utf8(*rq, text, textlen) )
373     {
374         raqm_destroy(*rq);
375         return -1;
376     }
377 
378 
379     if ( !raqm_set_freetype_face(*rq, font->face) )
380     {
381         raqm_destroy(*rq);
382         return -1;
383     }
384 
385     if ( !raqm_set_par_direction(*rq, RAQM_DIRECTION_DEFAULT) )
386     {
387         raqm_destroy(*rq);
388         return -1;
389     }
390 
391     if ( !raqm_layout(*rq) )
392     {
393         raqm_destroy(*rq);
394         return -1;
395     }
396 
397     *g_info = raqm_get_glyphs(*rq, glyph_count);
398     if ( *g_info == NULL )
399     {
400         raqm_destroy(*rq);
401         return -1;
402     }
403 
404     return 0;
405 #else
406     int xstart;
407     c_glyph *glyph;
408     FT_Error error;
409     FT_Long use_kerning;
410     FT_UInt prev_index = 0;
411     size_t count = 0;
412 
413     /* check kerning */
414     use_kerning = FT_HAS_KERNING( font->face ) && font->kerning;
415 
416     *rq = (raqm_t*) malloc(sizeof(raqm_t));
417     *g_info = (raqm_glyph_t*) malloc(sizeof(raqm_glyph_t) * (textlen));
418     (*rq)->g_info = *g_info;
419 
420     xstart = 0;
421     for ( count = 0; textlen > 0; count++ ) {
422         Uint16 c = UTF8_getch(&text, &textlen);
423         if ( c == UNICODE_BOM_NATIVE || c == UNICODE_BOM_SWAPPED ) {
424             continue;
425         }
426 
427         FT_UInt index = FT_Get_Char_Index( font->face, c );
428         error = Find_GlyphByIndex(font, index, CACHED_METRICS|CACHED_BITMAP);
429         if ( error ) {
430             TTF_SetFTError("Couldn't find glyph", error);
431             raqm_destroy(*rq);
432             *glyph_count = 0;
433             return -1;
434         }
435         glyph = font->current;
436 
437         (*g_info)[count].index = glyph->index;
438         (*g_info)[count].y_offset = 0;
439         (*g_info)[count].x_offset = 0;
440         (*g_info)[count].x_advance = glyph->advance;
441 
442         /* do kerning, if possible AC-Patch */
443         if ( use_kerning && prev_index && glyph->index ) {
444             FT_Vector delta;
445             FT_Get_Kerning( font->face, prev_index, (*g_info)->index, ft_kerning_default, &delta );
446             xstart += delta.x >> 6;
447             (*g_info)[count - 1].x_advance += delta.x;
448         }
449     }
450 
451     *glyph_count = count;
452 
453     return 0;
454 #endif
455 }
456 
457 
TTF_Init(void)458 int TTF_Init(void)
459 {
460     int status = 0;
461 
462     if (!TTF_initialized) {
463         FT_Error error = FT_Init_FreeType(&library);
464         if (error) {
465             TTF_SetFTError("Couldn't init FreeType engine", error);
466             status = -1;
467         }
468     }
469     if (status == 0) {
470         ++TTF_initialized;
471     }
472     return status;
473 }
474 
RWread(FT_Stream stream,unsigned long offset,unsigned char * buffer,unsigned long count)475 static unsigned long RWread(
476     FT_Stream stream,
477     unsigned long offset,
478     unsigned char* buffer,
479     unsigned long count
480 )
481 {
482     SDL_RWops *src;
483 
484     src = (SDL_RWops *)stream->descriptor.pointer;
485     SDL_RWseek(src, (int)offset, RW_SEEK_SET);
486     if (count == 0) {
487         return 0;
488     }
489     return (unsigned long)SDL_RWread(src, buffer, 1, (int)count);
490 }
491 
TTF_OpenFontIndexRW(SDL_RWops * src,int freesrc,int ptsize,long index)492 TTF_Font* TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index)
493 {
494     TTF_Font* font;
495     FT_Error error;
496     FT_Face face;
497     FT_Fixed scale;
498     FT_Stream stream;
499     FT_CharMap found;
500     Sint64 position;
501     int i;
502 
503     if (!TTF_initialized) {
504         TTF_SetError("Library not initialized");
505         if (src && freesrc) {
506             SDL_RWclose(src);
507         }
508         return NULL;
509     }
510 
511     if (!src) {
512         TTF_SetError("Passed a NULL font source");
513         return NULL;
514     }
515 
516     /* Check to make sure we can seek in this stream */
517     position = SDL_RWtell(src);
518     if (position < 0) {
519         TTF_SetError("Can't seek in stream");
520         if (freesrc) {
521             SDL_RWclose(src);
522         }
523         return NULL;
524     }
525 
526     font = (TTF_Font*)SDL_malloc(sizeof *font);
527     if (font == NULL) {
528         TTF_SetError("Out of memory");
529         if (freesrc) {
530             SDL_RWclose(src);
531         }
532         return NULL;
533     }
534     SDL_memset(font, 0, sizeof(*font));
535 
536     font->src = src;
537     font->freesrc = freesrc;
538 
539     stream = (FT_Stream)SDL_malloc(sizeof(*stream));
540     if (stream == NULL) {
541         TTF_SetError("Out of memory");
542         TTF_CloseFont(font);
543         return NULL;
544     }
545     SDL_memset(stream, 0, sizeof(*stream));
546 
547     stream->read = RWread;
548     stream->descriptor.pointer = src;
549     stream->pos = (unsigned long)position;
550     stream->size = (unsigned long)(SDL_RWsize(src) - position);
551 
552     font->args.flags = FT_OPEN_STREAM;
553     font->args.stream = stream;
554 
555     error = FT_Open_Face(library, &font->args, index, &font->face);
556     if (error) {
557         TTF_SetFTError("Couldn't load font file", error);
558         TTF_CloseFont(font);
559         return NULL;
560     }
561     face = font->face;
562 
563     /* Set charmap for loaded font */
564     found = 0;
565 #if 0 /* Font debug code */
566     for (i = 0; i < face->num_charmaps; i++) {
567         FT_CharMap charmap = face->charmaps[i];
568         printf("Found charmap: platform id %d, encoding id %d\n", charmap->platform_id, charmap->encoding_id);
569     }
570 #endif
571     if (!found) {
572         for (i = 0; i < face->num_charmaps; i++) {
573             FT_CharMap charmap = face->charmaps[i];
574             if (charmap->platform_id == 3 && charmap->encoding_id == 10) { /* UCS-4 Unicode */
575                 found = charmap;
576                 break;
577             }
578         }
579     }
580     if (!found) {
581         for (i = 0; i < face->num_charmaps; i++) {
582             FT_CharMap charmap = face->charmaps[i];
583             if ((charmap->platform_id == 3 && charmap->encoding_id == 1) /* Windows Unicode */
584              || (charmap->platform_id == 3 && charmap->encoding_id == 0) /* Windows Symbol */
585              || (charmap->platform_id == 2 && charmap->encoding_id == 1) /* ISO Unicode */
586              || (charmap->platform_id == 0)) { /* Apple Unicode */
587                 found = charmap;
588                 break;
589             }
590         }
591     }
592     if (found) {
593         /* If this fails, continue using the default charmap */
594         FT_Set_Charmap(face, found);
595     }
596 
597     /* Make sure that our font face is scalable (global metrics) */
598     if (FT_IS_SCALABLE(face)) {
599         /* Set the character size and use default DPI (72) */
600         error = FT_Set_Char_Size(font->face, 0, ptsize * 64, 0, 0);
601         if (error) {
602             TTF_SetFTError("Couldn't set font size", error);
603             TTF_CloseFont(font);
604             return NULL;
605         }
606 
607         /* Get the scalable font metrics for this font */
608         scale = face->size->metrics.y_scale;
609         font->ascent  = FT_CEIL(FT_MulFix(face->ascender, scale));
610         font->descent = FT_CEIL(FT_MulFix(face->descender, scale));
611         font->height  = font->ascent - font->descent + /* baseline */ 1;
612         font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
613         font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
614         font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
615 
616     } else {
617         /* Non-scalable font case.  ptsize determines which family
618          * or series of fonts to grab from the non-scalable format.
619          * It is not the point size of the font.
620          * */
621         if (ptsize >= font->face->num_fixed_sizes)
622             ptsize = font->face->num_fixed_sizes - 1;
623         font->font_size_family = ptsize;
624         error = FT_Set_Pixel_Sizes(face,
625                 face->available_sizes[ptsize].width,
626                 face->available_sizes[ptsize].height);
627 
628         /* With non-scalale fonts, Freetype2 likes to fill many of the
629          * font metrics with the value of 0.  The size of the
630          * non-scalable fonts must be determined differently
631          * or sometimes cannot be determined.
632          * */
633         font->ascent = face->available_sizes[ptsize].height;
634         font->descent = 0;
635         font->height = face->available_sizes[ptsize].height;
636         font->lineskip = FT_CEIL(font->ascent);
637         font->underline_offset = FT_FLOOR(face->underline_position);
638         font->underline_height = FT_FLOOR(face->underline_thickness);
639     }
640 
641     if (font->underline_height < 1) {
642         font->underline_height = 1;
643     }
644 
645 #ifdef DEBUG_FONTS
646     printf("Font metrics:\n");
647     printf("\tascent = %d, descent = %d\n",
648         font->ascent, font->descent);
649     printf("\theight = %d, lineskip = %d\n",
650         font->height, font->lineskip);
651     printf("\tunderline_offset = %d, underline_height = %d\n",
652         font->underline_offset, font->underline_height);
653     printf("\tunderline_top_row = %d, strikethrough_top_row = %d\n",
654         TTF_underline_top_row(font), TTF_strikethrough_top_row(font));
655 #endif
656 
657     /* Initialize the font face style */
658     font->face_style = TTF_STYLE_NORMAL;
659     if (font->face->style_flags & FT_STYLE_FLAG_BOLD) {
660         font->face_style |= TTF_STYLE_BOLD;
661     }
662     if (font->face->style_flags & FT_STYLE_FLAG_ITALIC) {
663         font->face_style |= TTF_STYLE_ITALIC;
664     }
665 
666     /* Set the default font style */
667     font->style = font->face_style;
668     font->outline = 0;
669     font->kerning = 1;
670     font->glyph_overhang = face->size->metrics.y_ppem / 10;
671     /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
672     font->glyph_italics = 0.207f;
673     font->glyph_italics *= font->height;
674 
675     return font;
676 }
677 
TTF_OpenFontRW(SDL_RWops * src,int freesrc,int ptsize)678 TTF_Font* TTF_OpenFontRW(SDL_RWops *src, int freesrc, int ptsize)
679 {
680     return TTF_OpenFontIndexRW(src, freesrc, ptsize, 0);
681 }
682 
TTF_OpenFontIndex(const char * file,int ptsize,long index)683 TTF_Font* TTF_OpenFontIndex(const char *file, int ptsize, long index)
684 {
685     SDL_RWops *rw = SDL_RWFromFile(file, "rb");
686     if (rw == NULL) {
687         return NULL;
688     }
689     return TTF_OpenFontIndexRW(rw, 1, ptsize, index);
690 }
691 
TTF_OpenFont(const char * file,int ptsize)692 TTF_Font* TTF_OpenFont(const char *file, int ptsize)
693 {
694     return TTF_OpenFontIndex(file, ptsize, 0);
695 }
696 
Flush_Glyph(c_glyph * glyph)697 static void Flush_Glyph(c_glyph* glyph)
698 {
699     glyph->stored = 0;
700     glyph->index = 0;
701     if (glyph->bitmap.buffer) {
702         SDL_free(glyph->bitmap.buffer);
703         glyph->bitmap.buffer = 0;
704     }
705     if (glyph->pixmap.buffer) {
706         SDL_free(glyph->pixmap.buffer);
707         glyph->pixmap.buffer = 0;
708     }
709     glyph->cached = 0;
710 }
711 
Flush_Cache(TTF_Font * font)712 static void Flush_Cache(TTF_Font* font)
713 {
714     int i;
715     int size = sizeof(font->cache) / sizeof(font->cache[0]);
716 
717     for (i = 0; i < size; ++i) {
718         if (font->cache[i].cached) {
719             Flush_Glyph(&font->cache[i]);
720         }
721 
722     }
723 }
724 
Load_Glyph(TTF_Font * font,Uint32 ch,c_glyph * cached,int want)725 static FT_Error Load_Glyph(TTF_Font* font, Uint32 ch, c_glyph* cached, int want)
726 {
727     FT_Face face;
728     FT_Error error;
729     FT_GlyphSlot glyph;
730     FT_Glyph_Metrics* metrics;
731     FT_Outline* outline;
732 
733     if (!font || !font->face) {
734         return FT_Err_Invalid_Handle;
735     }
736 
737     face = font->face;
738 
739     /* Load the glyph */
740     if (!cached->index) {
741         cached->index = FT_Get_Char_Index(face, ch);
742     }
743     error = FT_Load_Glyph(face, cached->index, FT_LOAD_DEFAULT | font->hinting);
744     if (error) {
745         return error;
746     }
747 
748     /* Get our glyph shortcuts */
749     glyph = face->glyph;
750     metrics = &glyph->metrics;
751     outline = &glyph->outline;
752 
753     /* Get the glyph metrics if desired */
754     if ((want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS)) {
755         if (FT_IS_SCALABLE(face)) {
756             /* Get the bounding box */
757             cached->minx = FT_FLOOR(metrics->horiBearingX);
758             cached->maxx = FT_CEIL(metrics->horiBearingX + metrics->width);
759             cached->maxy = FT_FLOOR(metrics->horiBearingY);
760             cached->miny = cached->maxy - FT_CEIL(metrics->height);
761             cached->yoffset = font->ascent - cached->maxy;
762             cached->advance = metrics->horiAdvance;
763         } else {
764             /* Get the bounding box for non-scalable format.
765              * Again, freetype2 fills in many of the font metrics
766              * with the value of 0, so some of the values we
767              * need must be calculated differently with certain
768              * assumptions about non-scalable formats.
769              * */
770             cached->minx = FT_FLOOR(metrics->horiBearingX);
771             cached->maxx = FT_CEIL(metrics->horiBearingX + metrics->width);
772             cached->maxy = FT_FLOOR(metrics->horiBearingY);
773             cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height);
774             cached->yoffset = 0;
775             cached->advance = metrics->horiAdvance;
776         }
777 
778         /* Adjust for bold and italic text */
779         if (TTF_HANDLE_STYLE_BOLD(font)) {
780             cached->maxx += font->glyph_overhang;
781         }
782         if (TTF_HANDLE_STYLE_ITALIC(font)) {
783             cached->maxx += (int)SDL_ceil(font->glyph_italics);
784         }
785         cached->stored |= CACHED_METRICS;
786     }
787 
788     if (((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
789          ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP))) {
790         int mono = (want & CACHED_BITMAP);
791         int i;
792         FT_Bitmap* src;
793         FT_Bitmap* dst;
794         FT_Glyph bitmap_glyph = NULL;
795 
796         /* Handle the italic style */
797         if (TTF_HANDLE_STYLE_ITALIC(font)) {
798             FT_Matrix shear;
799 
800             shear.xx = 1 << 16;
801             shear.xy = (int) (font->glyph_italics * (1 << 16)) / font->height;
802             shear.yx = 0;
803             shear.yy = 1 << 16;
804 
805             FT_Outline_Transform(outline, &shear);
806         }
807 
808         /* Render as outline */
809         if ((font->outline > 0) && glyph->format != FT_GLYPH_FORMAT_BITMAP) {
810             FT_Stroker stroker;
811             FT_Get_Glyph(glyph, &bitmap_glyph);
812             error = FT_Stroker_New(library, &stroker);
813             if (error) {
814                 return error;
815             }
816             FT_Stroker_Set(stroker, font->outline * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
817             FT_Glyph_Stroke(&bitmap_glyph, stroker, 1 /* delete the original glyph */);
818             FT_Stroker_Done(stroker);
819             /* Render the glyph */
820             error = FT_Glyph_To_Bitmap(&bitmap_glyph, mono ? ft_render_mode_mono : ft_render_mode_normal, 0, 1);
821             if (error) {
822                 FT_Done_Glyph(bitmap_glyph);
823                 return error;
824             }
825             src = &((FT_BitmapGlyph)bitmap_glyph)->bitmap;
826         } else {
827             /* Render the glyph */
828             error = FT_Render_Glyph(glyph, mono ? ft_render_mode_mono : ft_render_mode_normal);
829             if (error) {
830                 return error;
831             }
832             src = &glyph->bitmap;
833         }
834         /* Copy over information to cache */
835         if (mono) {
836             dst = &cached->bitmap;
837         } else {
838             dst = &cached->pixmap;
839         }
840         SDL_memcpy(dst, src, sizeof(*dst));
841 
842         /* FT_Render_Glyph() and .fon fonts always generate a
843          * two-color (black and white) glyphslot surface, even
844          * when rendered in ft_render_mode_normal. */
845         /* FT_IS_SCALABLE() means that the font is in outline format,
846          * but does not imply that outline is rendered as 8-bit
847          * grayscale, because embedded bitmap/graymap is preferred
848          * (see FT_LOAD_DEFAULT section of FreeType2 API Reference).
849          * FT_Render_Glyph() canreturn two-color bitmap or 4/16/256-
850          * color graymap according to the format of embedded bitmap/
851          * graymap. */
852         if (src->pixel_mode == FT_PIXEL_MODE_MONO) {
853             dst->pitch *= 8;
854         } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY2) {
855             dst->pitch *= 4;
856         } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY4) {
857             dst->pitch *= 2;
858         }
859 
860         /* Adjust for bold and italic text */
861         if (TTF_HANDLE_STYLE_BOLD(font)) {
862             int bump = font->glyph_overhang;
863             dst->pitch += bump;
864             dst->width += bump;
865         }
866         if (TTF_HANDLE_STYLE_ITALIC(font)) {
867             int bump = (int)SDL_ceil(font->glyph_italics);
868             dst->pitch += bump;
869             dst->width += bump;
870         }
871 
872         if (dst->rows != 0) {
873             dst->buffer = (unsigned char *)SDL_malloc(dst->pitch * dst->rows);
874             if (!dst->buffer) {
875                 return FT_Err_Out_Of_Memory;
876             }
877             SDL_memset(dst->buffer, 0, dst->pitch * dst->rows);
878 
879             for (i = 0; i < src->rows; i++) {
880                 int soffset = i * src->pitch;
881                 int doffset = i * dst->pitch;
882                 if (mono) {
883                     unsigned char *srcp = src->buffer + soffset;
884                     unsigned char *dstp = dst->buffer + doffset;
885                     int j;
886                     if (src->pixel_mode == FT_PIXEL_MODE_MONO) {
887                         for (j = 0; j < src->width; j += 8) {
888                             unsigned char c = *srcp++;
889                             *dstp++ = (c&0x80) >> 7;
890                             c <<= 1;
891                             *dstp++ = (c&0x80) >> 7;
892                             c <<= 1;
893                             *dstp++ = (c&0x80) >> 7;
894                             c <<= 1;
895                             *dstp++ = (c&0x80) >> 7;
896                             c <<= 1;
897                             *dstp++ = (c&0x80) >> 7;
898                             c <<= 1;
899                             *dstp++ = (c&0x80) >> 7;
900                             c <<= 1;
901                             *dstp++ = (c&0x80) >> 7;
902                             c <<= 1;
903                             *dstp++ = (c&0x80) >> 7;
904                         }
905                     }  else if (src->pixel_mode == FT_PIXEL_MODE_GRAY2) {
906                         for (j = 0; j < src->width; j += 4) {
907                             unsigned char c = *srcp++;
908                             *dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
909                             c <<= 2;
910                             *dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
911                             c <<= 2;
912                             *dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
913                             c <<= 2;
914                             *dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
915                         }
916                     } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY4) {
917                         for (j = 0; j < src->width; j += 2) {
918                             unsigned char c = *srcp++;
919                             *dstp++ = (((c&0xF0) >> 4) >= 0x8) ? 1 : 0;
920                             c <<= 4;
921                             *dstp++ = (((c&0xF0) >> 4) >= 0x8) ? 1 : 0;
922                         }
923                     } else {
924                         for (j = 0; j < src->width; j++) {
925                             unsigned char c = *srcp++;
926                             *dstp++ = (c >= 0x80) ? 1 : 0;
927                         }
928                     }
929                 } else if (src->pixel_mode == FT_PIXEL_MODE_MONO) {
930                     /* This special case wouldn't
931                      * be here if the FT_Render_Glyph()
932                      * function wasn't buggy when it tried
933                      * to render a .fon font with 256
934                      * shades of gray.  Instead, it
935                      * returns a black and white surface
936                      * and we have to translate it back
937                      * to a 256 gray shaded surface.
938                      * */
939                     unsigned char *srcp = src->buffer + soffset;
940                     unsigned char *dstp = dst->buffer + doffset;
941                     unsigned char c;
942                     int j, k;
943                     for (j = 0; j < src->width; j += 8) {
944                         c = *srcp++;
945                         for (k = 0; k < 8; ++k) {
946                             if ((c&0x80) >> 7) {
947                                 *dstp++ = NUM_GRAYS - 1;
948                             } else {
949                                 *dstp++ = 0x00;
950                             }
951                             c <<= 1;
952                         }
953                     }
954                 } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY2) {
955                     unsigned char *srcp = src->buffer + soffset;
956                     unsigned char *dstp = dst->buffer + doffset;
957                     unsigned char c;
958                     int j, k;
959                     for (j = 0; j < src->width; j += 4) {
960                         c = *srcp++;
961                         for (k = 0; k < 4; ++k) {
962                             if ((c&0xA0) >> 6) {
963                                 *dstp++ = NUM_GRAYS * ((c&0xA0) >> 6) / 3 - 1;
964                             } else {
965                                 *dstp++ = 0x00;
966                             }
967                             c <<= 2;
968                         }
969                     }
970                 } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY4) {
971                     unsigned char *srcp = src->buffer + soffset;
972                     unsigned char *dstp = dst->buffer + doffset;
973                     unsigned char c;
974                     int j, k;
975                     for (j = 0; j < src->width; j += 2) {
976                         c = *srcp++;
977                         for (k = 0; k < 2; ++k) {
978                             if ((c&0xF0) >> 4) {
979                                 *dstp++ = NUM_GRAYS * ((c&0xF0) >> 4) / 15 - 1;
980                             } else {
981                                 *dstp++ = 0x00;
982                             }
983                             c <<= 4;
984                         }
985                     }
986                 } else {
987                     SDL_memcpy(dst->buffer+doffset,
988                            src->buffer+soffset, src->pitch);
989                 }
990             }
991         }
992 
993         /* Handle the bold style */
994         if (TTF_HANDLE_STYLE_BOLD(font)) {
995             int row;
996             int col;
997             int offset;
998             int pixel;
999             Uint8* pixmap;
1000 
1001             /* The pixmap is a little hard, we have to add and clamp */
1002             for (row = dst->rows - 1; row >= 0; --row) {
1003                 pixmap = (Uint8*) dst->buffer + row * dst->pitch;
1004                 for (offset=1; offset <= font->glyph_overhang; ++offset) {
1005                     for (col = dst->width - 1; col > 0; --col) {
1006                         if (mono) {
1007                             pixmap[col] |= pixmap[col-1];
1008                         } else {
1009                             pixel = (pixmap[col] + pixmap[col-1]);
1010                             if (pixel > NUM_GRAYS - 1) {
1011                                 pixel = NUM_GRAYS - 1;
1012                             }
1013                             pixmap[col] = (Uint8) pixel;
1014                         }
1015                     }
1016                 }
1017             }
1018         }
1019 
1020         /* Mark that we rendered this format */
1021         if (mono) {
1022             cached->stored |= CACHED_BITMAP;
1023         } else {
1024             cached->stored |= CACHED_PIXMAP;
1025         }
1026 
1027         /* Free outlined glyph */
1028         if (bitmap_glyph) {
1029             FT_Done_Glyph(bitmap_glyph);
1030         }
1031     }
1032 
1033     /* We're done, mark this glyph cached */
1034     cached->cached = ch;
1035 
1036     return 0;
1037 }
1038 
Find_Glyph(TTF_Font * font,Uint32 ch,int want)1039 static FT_Error Find_Glyph(TTF_Font* font, Uint32 ch, int want)
1040 {
1041     int retval = 0;
1042     int hsize = sizeof(font->cache) / sizeof(font->cache[0]);
1043 
1044     int h = ch % hsize;
1045     font->current = &font->cache[h];
1046 
1047     if (font->current->cached != ch)
1048         Flush_Glyph(font->current);
1049 
1050     if ((font->current->stored & want) != want) {
1051         retval = Load_Glyph(font, ch, font->current, want);
1052     }
1053     return retval;
1054 }
1055 
Find_GlyphByIndex(TTF_Font * font,Uint16 idx,int want)1056 static FT_Error Find_GlyphByIndex( TTF_Font* font, Uint16 idx, int want )
1057 {
1058     int retval = 0;
1059     int hsize = sizeof( font->cache ) / sizeof( font->cache[0] );
1060 
1061     int h = idx % hsize;
1062     font->current = &font->cache[h];
1063 
1064     if (font->current->cached != idx)
1065         Flush_Glyph( font->current );
1066 
1067     if ( (font->current->stored & want) != want ) {
1068         font->current->index = idx;
1069         retval = Load_Glyph( font, idx, font->current, want );
1070     }
1071     return retval;
1072 }
1073 
TTF_CloseFont(TTF_Font * font)1074 void TTF_CloseFont(TTF_Font* font)
1075 {
1076     if (font) {
1077         Flush_Cache(font);
1078         if (font->face) {
1079             FT_Done_Face(font->face);
1080         }
1081         if (font->args.stream) {
1082             SDL_free(font->args.stream);
1083         }
1084         if (font->freesrc) {
1085             SDL_RWclose(font->src);
1086         }
1087         SDL_free(font);
1088     }
1089 }
1090 
1091 /* Gets the number of bytes needed to convert a Latin-1 string to UTF-8 */
LATIN1_to_UTF8_len(const char * text)1092 static size_t LATIN1_to_UTF8_len(const char *text)
1093 {
1094     size_t bytes = 1;
1095     while (*text) {
1096         Uint8 ch = *(Uint8*)text++;
1097         if (ch <= 0x7F) {
1098             bytes += 1;
1099         } else {
1100             bytes += 2;
1101         }
1102     }
1103     return bytes;
1104 }
1105 
1106 /* Gets the number of bytes needed to convert a UCS2 string to UTF-8 */
UCS2_to_UTF8_len(const Uint16 * text)1107 static size_t UCS2_to_UTF8_len(const Uint16 *text)
1108 {
1109     size_t bytes = 1;
1110     while (*text) {
1111         Uint16 ch = *text++;
1112         if (ch <= 0x7F) {
1113             bytes += 1;
1114         } else if (ch <= 0x7FF) {
1115             bytes += 2;
1116         } else {
1117             bytes += 3;
1118         }
1119     }
1120     return bytes;
1121 }
1122 
1123 /* Convert a Latin-1 string to a UTF-8 string */
LATIN1_to_UTF8(const char * src,Uint8 * dst)1124 static void LATIN1_to_UTF8(const char *src, Uint8 *dst)
1125 {
1126     while (*src) {
1127         Uint8 ch = *(Uint8*)src++;
1128         if (ch <= 0x7F) {
1129             *dst++ = ch;
1130         } else {
1131             *dst++ = 0xC0 | ((ch >> 6) & 0x1F);
1132             *dst++ = 0x80 | (ch & 0x3F);
1133         }
1134     }
1135     *dst = '\0';
1136 }
1137 
1138 /* Convert a UCS-2 string to a UTF-8 string */
UCS2_to_UTF8(const Uint16 * src,Uint8 * dst)1139 static void UCS2_to_UTF8(const Uint16 *src, Uint8 *dst)
1140 {
1141     int swapped = TTF_byteswapped;
1142 
1143     while (*src) {
1144         Uint16 ch = *src++;
1145         if (ch == UNICODE_BOM_NATIVE) {
1146             swapped = 0;
1147             continue;
1148         }
1149         if (ch == UNICODE_BOM_SWAPPED) {
1150             swapped = 1;
1151             continue;
1152         }
1153         if (swapped) {
1154             ch = SDL_Swap16(ch);
1155         }
1156         if (ch <= 0x7F) {
1157             *dst++ = (Uint8) ch;
1158         } else if (ch <= 0x7FF) {
1159             *dst++ = 0xC0 | (Uint8) ((ch >> 6) & 0x1F);
1160             *dst++ = 0x80 | (Uint8) (ch & 0x3F);
1161         } else {
1162             *dst++ = 0xE0 | (Uint8) ((ch >> 12) & 0x0F);
1163             *dst++ = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
1164             *dst++ = 0x80 | (Uint8) (ch & 0x3F);
1165         }
1166     }
1167     *dst = '\0';
1168 }
1169 
1170 /* Gets a unicode value from a UTF-8 encoded string and advance the string */
1171 #define UNKNOWN_UNICODE 0xFFFD
UTF8_getch(const char ** src,size_t * srclen)1172 static Uint32 UTF8_getch(const char **src, size_t *srclen)
1173 {
1174     const Uint8 *p = *(const Uint8**)src;
1175     size_t left = 0;
1176     SDL_bool overlong = SDL_FALSE;
1177     SDL_bool underflow = SDL_FALSE;
1178     Uint32 ch = UNKNOWN_UNICODE;
1179 
1180     if (*srclen == 0) {
1181         return UNKNOWN_UNICODE;
1182     }
1183     if (p[0] >= 0xFC) {
1184         if ((p[0] & 0xFE) == 0xFC) {
1185             if (p[0] == 0xFC && (p[1] & 0xFC) == 0x80) {
1186                 overlong = SDL_TRUE;
1187             }
1188             ch = (Uint32) (p[0] & 0x01);
1189             left = 5;
1190         }
1191     } else if (p[0] >= 0xF8) {
1192         if ((p[0] & 0xFC) == 0xF8) {
1193             if (p[0] == 0xF8 && (p[1] & 0xF8) == 0x80) {
1194                 overlong = SDL_TRUE;
1195             }
1196             ch = (Uint32) (p[0] & 0x03);
1197             left = 4;
1198         }
1199     } else if (p[0] >= 0xF0) {
1200         if ((p[0] & 0xF8) == 0xF0) {
1201             if (p[0] == 0xF0 && (p[1] & 0xF0) == 0x80) {
1202                 overlong = SDL_TRUE;
1203             }
1204             ch = (Uint32) (p[0] & 0x07);
1205             left = 3;
1206         }
1207     } else if (p[0] >= 0xE0) {
1208         if ((p[0] & 0xF0) == 0xE0) {
1209             if (p[0] == 0xE0 && (p[1] & 0xE0) == 0x80) {
1210                 overlong = SDL_TRUE;
1211             }
1212             ch = (Uint32) (p[0] & 0x0F);
1213             left = 2;
1214         }
1215     } else if (p[0] >= 0xC0) {
1216         if ((p[0] & 0xE0) == 0xC0) {
1217             if ((p[0] & 0xDE) == 0xC0) {
1218                 overlong = SDL_TRUE;
1219             }
1220             ch = (Uint32) (p[0] & 0x1F);
1221             left = 1;
1222         }
1223     } else {
1224         if ((p[0] & 0x80) == 0x00) {
1225             ch = (Uint32) p[0];
1226         }
1227     }
1228     ++*src;
1229     --*srclen;
1230     while (left > 0 && *srclen > 0) {
1231         ++p;
1232         if ((p[0] & 0xC0) != 0x80) {
1233             ch = UNKNOWN_UNICODE;
1234             break;
1235         }
1236         ch <<= 6;
1237         ch |= (p[0] & 0x3F);
1238         ++*src;
1239         --*srclen;
1240         --left;
1241     }
1242     if (left > 0) {
1243         underflow = SDL_TRUE;
1244     }
1245     /* Technically overlong sequences are invalid and should not be interpreted.
1246        However, it doesn't cause a security risk here and I don't see any harm in
1247        displaying them. The application is responsible for any other side effects
1248        of allowing overlong sequences (e.g. string compares failing, etc.)
1249        See bug 1931 for sample input that triggers this.
1250     */
1251     /*if (overlong) return UNKNOWN_UNICODE;*/
1252     if (underflow ||
1253         (ch >= 0xD800 && ch <= 0xDFFF) ||
1254         (ch == 0xFFFE || ch == 0xFFFF) || ch > 0x10FFFF) {
1255         ch = UNKNOWN_UNICODE;
1256     }
1257     return ch;
1258 }
1259 
TTF_FontHeight(const TTF_Font * font)1260 int TTF_FontHeight(const TTF_Font *font)
1261 {
1262     return(font->height);
1263 }
1264 
TTF_FontAscent(const TTF_Font * font)1265 int TTF_FontAscent(const TTF_Font *font)
1266 {
1267     return(font->ascent);
1268 }
1269 
TTF_FontDescent(const TTF_Font * font)1270 int TTF_FontDescent(const TTF_Font *font)
1271 {
1272     return(font->descent);
1273 }
1274 
TTF_FontLineSkip(const TTF_Font * font)1275 int TTF_FontLineSkip(const TTF_Font *font)
1276 {
1277     return(font->lineskip);
1278 }
1279 
TTF_GetFontKerning(const TTF_Font * font)1280 int TTF_GetFontKerning(const TTF_Font *font)
1281 {
1282     return(font->kerning);
1283 }
1284 
TTF_SetFontKerning(TTF_Font * font,int allowed)1285 void TTF_SetFontKerning(TTF_Font *font, int allowed)
1286 {
1287     font->kerning = allowed;
1288 }
1289 
TTF_FontFaces(const TTF_Font * font)1290 long TTF_FontFaces(const TTF_Font *font)
1291 {
1292     return(font->face->num_faces);
1293 }
1294 
TTF_FontFaceIsFixedWidth(const TTF_Font * font)1295 int TTF_FontFaceIsFixedWidth(const TTF_Font *font)
1296 {
1297     return(FT_IS_FIXED_WIDTH(font->face));
1298 }
1299 
TTF_FontFaceFamilyName(const TTF_Font * font)1300 char *TTF_FontFaceFamilyName(const TTF_Font *font)
1301 {
1302     return(font->face->family_name);
1303 }
1304 
TTF_FontFaceStyleName(const TTF_Font * font)1305 char *TTF_FontFaceStyleName(const TTF_Font *font)
1306 {
1307     return(font->face->style_name);
1308 }
1309 
TTF_GlyphIsProvided(const TTF_Font * font,Uint16 ch)1310 int TTF_GlyphIsProvided(const TTF_Font *font, Uint16 ch)
1311 {
1312   return(FT_Get_Char_Index(font->face, ch));
1313 }
1314 
TTF_GlyphMetrics(TTF_Font * font,Uint16 ch,int * minx,int * maxx,int * miny,int * maxy,int * advance)1315 int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch,
1316                      int* minx, int* maxx, int* miny, int* maxy, int* advance)
1317 {
1318     FT_Error error;
1319 
1320     error = Find_Glyph(font, ch, CACHED_METRICS);
1321     if (error) {
1322         TTF_SetFTError("Couldn't find glyph", error);
1323         return -1;
1324     }
1325 
1326     if (minx) {
1327         *minx = font->current->minx;
1328     }
1329     if (maxx) {
1330         *maxx = font->current->maxx;
1331         if (TTF_HANDLE_STYLE_BOLD(font)) {
1332             *maxx += font->glyph_overhang;
1333         }
1334     }
1335     if (miny) {
1336         *miny = font->current->miny;
1337     }
1338     if (maxy) {
1339         *maxy = font->current->maxy;
1340     }
1341     if (advance) {
1342         *advance = FT_CEIL(font->current->advance);
1343         if (TTF_HANDLE_STYLE_BOLD(font)) {
1344             *advance += font->glyph_overhang;
1345         }
1346     }
1347     return 0;
1348 }
1349 
TTF_SizeText(TTF_Font * font,const char * text,int * w,int * h)1350 int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h)
1351 {
1352     int status = -1;
1353     Uint8 *utf8;
1354 
1355     TTF_CHECKPOINTER(text, -1);
1356 
1357     utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
1358     if (utf8) {
1359         LATIN1_to_UTF8(text, utf8);
1360         status = TTF_SizeUTF8(font, (char *)utf8, w, h);
1361         SDL_stack_free(utf8);
1362     } else {
1363         SDL_OutOfMemory();
1364     }
1365     return status;
1366 }
1367 
CalculateSize(TTF_Font * font,raqm_glyph_t * g_info,size_t glyph_count,int * w,int * h)1368 static int CalculateSize(TTF_Font *font, raqm_glyph_t *g_info, size_t glyph_count, int *w, int*h)
1369 {
1370     int status;
1371     int x, z;
1372     int minx, maxx;
1373     int miny, maxy;
1374     c_glyph *glyph;
1375     FT_Error error;
1376     FT_UInt prev_index = 0;
1377     int outline_delta = 0;
1378     int i;
1379 
1380     /* Initialize everything to 0 */
1381     status = 0;
1382     minx = maxx = 0;
1383     miny = maxy = 0;
1384 
1385     /* Init outline handling */
1386     if (font->outline > 0) {
1387         outline_delta = font->outline * 2;
1388     }
1389 
1390     /* Load each character and sum it's bounding box */
1391     x= 0;
1392     for (i = 0; i < glyph_count; i++) {
1393         error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS);
1394         if (error) {
1395             TTF_SetFTError("Couldn't find glyph", error);
1396             return -1;
1397         }
1398         glyph = font->current;
1399 
1400         z = x + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
1401         if (minx > z) {
1402             minx = z;
1403         }
1404         if (TTF_HANDLE_STYLE_BOLD(font)) {
1405             x += font->glyph_overhang;
1406         }
1407         if (glyph->advance > glyph->maxx) {
1408             z = x + FT_FLOOR(g_info[i].x_advance);
1409         } else {
1410             z = x + FT_FLOOR(g_info[i].x_offset) + glyph->maxx;
1411         }
1412         if (maxx < z) {
1413             maxx = z;
1414         }
1415         x += FT_FLOOR(g_info[i].x_advance);
1416 
1417         if (glyph->miny < miny) {
1418             miny = glyph->miny;
1419         }
1420         if (glyph->maxy > maxy) {
1421             maxy = glyph->maxy;
1422         }
1423         prev_index = g_info[i].index;
1424     }
1425 
1426     /* Fill the bounds rectangle */
1427     if (w) {
1428         /* Add outline extra width */
1429         *w = (maxx - minx) + outline_delta;
1430     }
1431     if (h) {
1432         /* Some fonts descend below font height (FletcherGothicFLF) */
1433         /* Add outline extra height */
1434         *h = (font->ascent - miny) + outline_delta;
1435         if (*h < font->height) {
1436             *h = font->height;
1437         }
1438         /* Update height according to the needs of the underline style */
1439         if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
1440             int bottom_row = TTF_underline_bottom_row(font);
1441             if (*h < bottom_row) {
1442                 *h = bottom_row;
1443             }
1444         }
1445     }
1446     return status;
1447 }
1448 
TTF_SizeUTF8(TTF_Font * font,const char * text,int * w,int * h)1449 int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h)
1450 {
1451     size_t textlen;
1452     raqm_t *rq = NULL;
1453     raqm_glyph_t *g_info = NULL;
1454     size_t glyph_count = 0;
1455 
1456     TTF_CHECKPOINTER(text, -1);
1457 
1458     textlen = SDL_strlen(text);
1459 
1460     /* Shape text */
1461     if (text_layout(text, textlen, font, &rq, &g_info, &glyph_count) < 0)
1462     {
1463       return 0;
1464     }
1465     else
1466     {
1467     /* Calculate the size */
1468       int size = CalculateSize(font, g_info, glyph_count, w, h);
1469       raqm_destroy(rq);
1470       return size;
1471     }
1472 }
1473 
TTF_SizeUNICODE(TTF_Font * font,const Uint16 * text,int * w,int * h)1474 int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h)
1475 {
1476     int status = -1;
1477     Uint8 *utf8;
1478 
1479     TTF_CHECKPOINTER(text, -1);
1480 
1481     utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
1482     if (utf8) {
1483         UCS2_to_UTF8(text, utf8);
1484         status = TTF_SizeUTF8(font, (char *)utf8, w, h);
1485         SDL_stack_free(utf8);
1486     } else {
1487         SDL_OutOfMemory();
1488     }
1489     return status;
1490 }
1491 
TTF_RenderText_Solid(TTF_Font * font,const char * text,SDL_Color fg)1492 SDL_Surface *TTF_RenderText_Solid(TTF_Font *font,
1493                 const char *text, SDL_Color fg)
1494 {
1495     SDL_Surface *surface = NULL;
1496     Uint8 *utf8;
1497 
1498     TTF_CHECKPOINTER(text, NULL);
1499 
1500     utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
1501     if (utf8) {
1502         LATIN1_to_UTF8(text, utf8);
1503         surface = TTF_RenderUTF8_Solid(font, (char *)utf8, fg);
1504         SDL_stack_free(utf8);
1505     } else {
1506         SDL_OutOfMemory();
1507     }
1508     return surface;
1509 }
1510 
TTF_RenderUTF8_Solid(TTF_Font * font,const char * text,SDL_Color fg)1511 SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font,
1512                 const char *text, SDL_Color fg)
1513 {
1514     SDL_bool first;
1515     int xstart;
1516     int width;
1517     int height;
1518     SDL_Surface* textbuf;
1519     SDL_Palette* palette;
1520     Uint8* src;
1521     Uint8* dst;
1522     Uint8 *dst_check;
1523     int row, col;
1524     int i;
1525     c_glyph *glyph;
1526 
1527     raqm_t *rq = NULL;
1528     raqm_glyph_t *g_info = NULL;
1529     size_t glyph_count = 0;
1530 
1531     FT_Bitmap *current;
1532     FT_Error error;
1533     FT_UInt prev_index = 0;
1534     size_t textlen;
1535     TTF_CHECKPOINTER(text, NULL);
1536 
1537     textlen = SDL_strlen(text);
1538 
1539     /* Shape text */
1540 
1541     if (text_layout(text, textlen, font, &rq, &g_info, &glyph_count) < 0)
1542     {
1543       TTF_SetError( "Text layout failed" );
1544       return NULL;
1545     }
1546 
1547     /* Get the dimensions of the text surface */
1548     if ( ( CalculateSize(font, g_info, glyph_count, &width, &height) < 0 ) || !width ) {
1549         TTF_SetError("Text has zero width");
1550         raqm_destroy(rq);
1551         return NULL;
1552     }
1553 
1554     /* Create the target surface */
1555     textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
1556     if (textbuf == NULL) {
1557         raqm_destroy(rq);
1558         return NULL;
1559     }
1560 
1561     /* Adding bound checking to avoid all kinds of memory corruption errors
1562        that may occur. */
1563     dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
1564 
1565     /* Fill the palette with the foreground color */
1566     palette = textbuf->format->palette;
1567     palette->colors[0].r = 255 - fg.r;
1568     palette->colors[0].g = 255 - fg.g;
1569     palette->colors[0].b = 255 - fg.b;
1570     palette->colors[1].r = fg.r;
1571     palette->colors[1].g = fg.g;
1572     palette->colors[1].b = fg.b;
1573     palette->colors[1].a = fg.a ? fg.a : SDL_ALPHA_OPAQUE;
1574     SDL_SetColorKey(textbuf, SDL_TRUE, 0);
1575 
1576     /* Load and render each glyph */
1577     first = SDL_TRUE;
1578     xstart = 0;
1579     for (i = 0; i < glyph_count; i++) {
1580         int y_offset;
1581         error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS|CACHED_BITMAP);
1582         if (error) {
1583             TTF_SetFTError("Couldn't find glyph", error);
1584             SDL_FreeSurface(textbuf);
1585             raqm_destroy(rq);
1586             return NULL;
1587         }
1588         glyph = font->current;
1589         y_offset = glyph->yoffset - FT_FLOOR(g_info[i].y_offset);
1590         current = &glyph->bitmap;
1591         /* Ensure the width of the pixmap is correct. On some cases,
1592          * freetype may report a larger pixmap than possible.*/
1593         width = current->width;
1594         if (font->outline <= 0 && width > glyph->maxx - glyph->minx) {
1595             width = glyph->maxx - glyph->minx;
1596         }
1597         /* Compensate for wrap around bug with negative minx's */
1598         if (first && (glyph->minx < 0)) {
1599             xstart -= glyph->minx;
1600         }
1601         first = SDL_FALSE;
1602 
1603         for (row = 0; row < current->rows; ++row) {
1604             /* Make sure we don't go either over, or under the
1605              * limit */
1606             if ( row+y_offset < 0 ) {
1607                 continue;
1608             }
1609             if ( row+y_offset >= textbuf->h ) {
1610                 continue;
1611             }
1612             dst = (Uint8*) textbuf->pixels +
1613                 (row+y_offset) * textbuf->pitch +
1614                 xstart + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
1615             src = current->buffer + row * current->pitch;
1616             for (col = width; col > 0 && dst < dst_check; --col) {
1617                 *dst++ |= *src++;
1618             }
1619         }
1620 
1621         xstart += FT_FLOOR(g_info[i].x_advance);
1622         if (TTF_HANDLE_STYLE_BOLD(font)) {
1623             xstart += font->glyph_overhang;
1624         }
1625         prev_index = g_info[i].index;
1626     }
1627 
1628     /* Handle the underline style */
1629     if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
1630         row = TTF_underline_top_row(font);
1631         TTF_drawLine_Solid(font, textbuf, row);
1632     }
1633 
1634     /* Handle the strikethrough style */
1635     if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
1636         row = TTF_strikethrough_top_row(font);
1637         TTF_drawLine_Solid(font, textbuf, row);
1638     }
1639 
1640     raqm_destroy(rq);
1641 
1642     return textbuf;
1643 }
1644 
TTF_RenderUNICODE_Solid(TTF_Font * font,const Uint16 * text,SDL_Color fg)1645 SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font,
1646                 const Uint16 *text, SDL_Color fg)
1647 {
1648     SDL_Surface *surface = NULL;
1649     Uint8 *utf8;
1650 
1651     TTF_CHECKPOINTER(text, NULL);
1652 
1653     utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
1654     if (utf8) {
1655         UCS2_to_UTF8(text, utf8);
1656         surface = TTF_RenderUTF8_Solid(font, (char *)utf8, fg);
1657         SDL_stack_free(utf8);
1658     } else {
1659         SDL_OutOfMemory();
1660     }
1661     return surface;
1662 }
1663 
TTF_RenderGlyph_Solid(TTF_Font * font,Uint16 ch,SDL_Color fg)1664 SDL_Surface *TTF_RenderGlyph_Solid(TTF_Font *font, Uint16 ch, SDL_Color fg)
1665 {
1666     Uint16 ucs2[2];
1667     Uint8 utf8[4];
1668 
1669     ucs2[0] = ch;
1670     ucs2[1] = 0;
1671     UCS2_to_UTF8(ucs2, utf8);
1672     return TTF_RenderUTF8_Solid(font, (char *)utf8, fg);
1673 }
1674 
TTF_RenderText_Shaded(TTF_Font * font,const char * text,SDL_Color fg,SDL_Color bg)1675 SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font,
1676                 const char *text, SDL_Color fg, SDL_Color bg)
1677 {
1678     SDL_Surface *surface = NULL;
1679     Uint8 *utf8;
1680 
1681     TTF_CHECKPOINTER(text, NULL);
1682 
1683     utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
1684     if (utf8) {
1685         LATIN1_to_UTF8(text, utf8);
1686         surface = TTF_RenderUTF8_Shaded(font, (char *)utf8, fg, bg);
1687         SDL_stack_free(utf8);
1688     } else {
1689         SDL_OutOfMemory();
1690     }
1691     return surface;
1692 }
1693 
1694 /* Convert the UTF-8 text to UNICODE and render it
1695 */
TTF_RenderUTF8_Shaded(TTF_Font * font,const char * text,SDL_Color fg,SDL_Color bg)1696 SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font,
1697                 const char *text, SDL_Color fg, SDL_Color bg)
1698 {
1699     SDL_bool first;
1700     int xstart;
1701     int width;
1702     int height;
1703     int i;
1704     SDL_Surface* textbuf;
1705     SDL_Palette* palette;
1706     int index;
1707     int rdiff;
1708     int gdiff;
1709     int bdiff;
1710     int adiff;
1711     Uint8* src;
1712     Uint8* dst;
1713     Uint8* dst_check;
1714     int row, col;
1715     FT_Bitmap* current;
1716     c_glyph *glyph;
1717 
1718     raqm_t *rq = NULL;
1719     raqm_glyph_t *g_info = NULL;
1720     size_t glyph_count = 0;
1721 
1722     size_t textlen;
1723     FT_Error error;
1724     FT_UInt prev_index = 0;
1725 
1726     TTF_CHECKPOINTER(text, NULL);
1727 
1728     textlen = SDL_strlen(text);
1729     /* Shape text */
1730 
1731     if (text_layout(text, textlen, font, &rq, &g_info, &glyph_count) < 0)
1732     {
1733       TTF_SetError("Text layout failed");
1734       return NULL;
1735     }
1736 
1737     /* Get the dimensions of the text surface */
1738     if ( ( CalculateSize(font, g_info, glyph_count, &width, &height) < 0 ) || !width ) {
1739         raqm_destroy(rq);
1740         TTF_SetError("Text has zero width");
1741         return NULL;
1742     }
1743 
1744     /* Create the target surface */
1745     textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
1746     if (textbuf == NULL) {
1747         raqm_destroy(rq);
1748         return NULL;
1749     }
1750 
1751     /* Adding bound checking to avoid all kinds of memory corruption errors
1752        that may occur. */
1753     dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
1754 
1755     /* Support alpha blending */
1756     if (!fg.a) {
1757         fg.a = SDL_ALPHA_OPAQUE;
1758     }
1759     if (!bg.a) {
1760         bg.a = SDL_ALPHA_OPAQUE;
1761     }
1762     if (fg.a != SDL_ALPHA_OPAQUE || bg.a != SDL_ALPHA_OPAQUE) {
1763         SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
1764     }
1765 
1766     /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
1767     palette = textbuf->format->palette;
1768     rdiff = fg.r - bg.r;
1769     gdiff = fg.g - bg.g;
1770     bdiff = fg.b - bg.b;
1771     adiff = fg.a - bg.a;
1772 
1773     for (index = 0; index < NUM_GRAYS; ++index) {
1774         palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1);
1775         palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1);
1776         palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1);
1777         palette->colors[index].a = bg.a + (index*adiff) / (NUM_GRAYS-1);
1778     }
1779 
1780     /* Load and render each glyph */
1781     first = SDL_TRUE;
1782     xstart = 0;
1783     for (i = 0; i < glyph_count; i++) {
1784         int y_offset;
1785         error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS|CACHED_PIXMAP);
1786         if (error) {
1787             TTF_SetFTError("Couldn't find glyph", error);
1788             SDL_FreeSurface(textbuf);
1789             raqm_destroy(rq);
1790             return NULL;
1791         }
1792         glyph = font->current;
1793         y_offset = glyph->yoffset - FT_FLOOR(g_info[i].y_offset);
1794         /* Ensure the width of the pixmap is correct. On some cases,
1795          * freetype may report a larger pixmap than possible.*/
1796         width = glyph->pixmap.width;
1797         if (font->outline <= 0 && width > glyph->maxx - glyph->minx) {
1798             width = glyph->maxx - glyph->minx;
1799         }
1800         /* Compensate for the wrap around with negative minx's */
1801         if (first && (glyph->minx < 0)) {
1802             xstart -= glyph->minx;
1803         }
1804         first = SDL_FALSE;
1805 
1806         current = &glyph->pixmap;
1807         for (row = 0; row < current->rows; ++row) {
1808             /* Make sure we don't go either over, or under the
1809              * limit */
1810             if ( row+ y_offset < 0 ) {
1811                 continue;
1812             }
1813             if ( row+ y_offset >= textbuf->h ) {
1814                 continue;
1815             }
1816             dst = (Uint8*) textbuf->pixels +
1817                 (row+y_offset) * textbuf->pitch +
1818                 xstart + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
1819             src = current->buffer + row * current->pitch;
1820             for (col = width; col > 0 && dst < dst_check; --col) {
1821                 *dst++ |= *src++;
1822             }
1823         }
1824 
1825         xstart += FT_FLOOR(g_info[i].x_advance);
1826         if (TTF_HANDLE_STYLE_BOLD(font)) {
1827             xstart += font->glyph_overhang;
1828         }
1829         prev_index = g_info[i].index;
1830     }
1831 
1832     /* Handle the underline style */
1833     if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
1834         row = TTF_underline_top_row(font);
1835         TTF_drawLine_Shaded(font, textbuf, row);
1836     }
1837 
1838     /* Handle the strikethrough style */
1839     if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
1840         row = TTF_strikethrough_top_row(font);
1841         TTF_drawLine_Shaded(font, textbuf, row);
1842     }
1843     raqm_destroy(rq);
1844     return textbuf;
1845 }
1846 
TTF_RenderUNICODE_Shaded(TTF_Font * font,const Uint16 * text,SDL_Color fg,SDL_Color bg)1847 SDL_Surface* TTF_RenderUNICODE_Shaded(TTF_Font* font,
1848                        const Uint16* text,
1849                        SDL_Color fg,
1850                        SDL_Color bg)
1851 {
1852     SDL_Surface *surface = NULL;
1853     Uint8 *utf8;
1854 
1855     TTF_CHECKPOINTER(text, NULL);
1856 
1857     utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
1858     if (utf8) {
1859         UCS2_to_UTF8(text, utf8);
1860         surface = TTF_RenderUTF8_Shaded(font, (char *)utf8, fg, bg);
1861         SDL_stack_free(utf8);
1862     } else {
1863         SDL_OutOfMemory();
1864     }
1865     return surface;
1866 }
1867 
TTF_RenderGlyph_Shaded(TTF_Font * font,Uint16 ch,SDL_Color fg,SDL_Color bg)1868 SDL_Surface* TTF_RenderGlyph_Shaded(TTF_Font* font,
1869                      Uint16 ch,
1870                      SDL_Color fg,
1871                      SDL_Color bg)
1872 {
1873     Uint16 ucs2[2];
1874     Uint8 utf8[4];
1875 
1876     ucs2[0] = ch;
1877     ucs2[1] = 0;
1878     UCS2_to_UTF8(ucs2, utf8);
1879     return TTF_RenderUTF8_Shaded(font, (char *)utf8, fg, bg);
1880 }
1881 
TTF_RenderText_Blended(TTF_Font * font,const char * text,SDL_Color fg)1882 SDL_Surface *TTF_RenderText_Blended(TTF_Font *font,
1883                 const char *text, SDL_Color fg)
1884 {
1885     SDL_Surface *surface = NULL;
1886     Uint8 *utf8;
1887 
1888     TTF_CHECKPOINTER(text, NULL);
1889 
1890     utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
1891     if (utf8) {
1892         LATIN1_to_UTF8(text, utf8);
1893         surface = TTF_RenderUTF8_Blended(font, (char *)utf8, fg);
1894         SDL_stack_free(utf8);
1895     } else {
1896         SDL_OutOfMemory();
1897     }
1898     return surface;
1899 }
1900 
TTF_RenderUTF8_Blended(TTF_Font * font,const char * text,SDL_Color fg)1901 SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
1902                 const char *text, SDL_Color fg)
1903 {
1904     SDL_bool first;
1905     int i;
1906     int xstart;
1907     int width, height;
1908     SDL_Surface *textbuf;
1909     Uint8 alpha;
1910     Uint8 alpha_table[256];
1911     Uint32 pixel;
1912     Uint8 *src;
1913     Uint32 *dst;
1914     Uint32 *dst_check;
1915     int row, col;
1916     c_glyph *glyph;
1917 
1918     raqm_t *rq = NULL;
1919     raqm_glyph_t *g_info = NULL;
1920     size_t glyph_count = 0;
1921 
1922     FT_Error error;
1923     FT_UInt prev_index = 0;
1924     size_t textlen;
1925 
1926     TTF_CHECKPOINTER(text, NULL);
1927 
1928     textlen = SDL_strlen(text);
1929     /* Shape text */
1930     if (text_layout(text, textlen, font, &rq, &g_info, &glyph_count) < 0)
1931     {
1932       TTF_SetError("Text layout failed");
1933       return NULL;
1934     }
1935 
1936     /* Get the dimensions of the text surface */
1937     if ( ( CalculateSize(font, g_info, glyph_count, &width, &height) < 0 ) || !width ) {
1938         raqm_destroy(rq);
1939         TTF_SetError("Text has zero width");
1940         return(NULL);
1941     }
1942 
1943     /* Create the target surface */
1944     textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,
1945                                0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
1946     if (textbuf == NULL) {
1947         raqm_destroy(rq);
1948         TTF_SetError("SDL_Surface creation failed");
1949         return NULL;
1950     }
1951 
1952     /* Adding bound checking to avoid all kinds of memory corruption errors
1953        that may occur. */
1954     dst_check = (Uint32*)textbuf->pixels + textbuf->pitch/4 * textbuf->h;
1955 
1956     /* Support alpha blending */
1957     if (!fg.a) {
1958         fg.a = SDL_ALPHA_OPAQUE;
1959     }
1960     if (fg.a == SDL_ALPHA_OPAQUE) {
1961         for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
1962             alpha_table[i] = (Uint8)i;
1963         }
1964     } else {
1965         for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
1966             alpha_table[i] = (Uint8)(i * fg.a / 255);
1967         }
1968         SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
1969     }
1970 
1971     /* Load and render each glyph */
1972     first = SDL_TRUE;
1973     xstart = 0;
1974     pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
1975     SDL_FillRect(textbuf, NULL, pixel); /* Initialize with fg and 0 alpha */
1976 
1977     for (i = 0; i < glyph_count; i++) {
1978         int y_offset;
1979         error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS|CACHED_PIXMAP);
1980         if (error) {
1981             TTF_SetFTError("Couldn't find glyph", error);
1982             SDL_FreeSurface(textbuf);
1983             raqm_destroy(rq);
1984             return NULL;
1985         }
1986         glyph = font->current;
1987         y_offset = glyph->yoffset - FT_FLOOR(g_info[i].y_offset);
1988         /* Ensure the width of the pixmap is correct. On some cases,
1989          * freetype may report a larger pixmap than possible.*/
1990         width = glyph->pixmap.width;
1991         if (font->outline <= 0 && width > glyph->maxx - glyph->minx) {
1992             width = glyph->maxx - glyph->minx;
1993         }
1994 
1995         for (row = 0; row < glyph->pixmap.rows; ++row) {
1996             /* Make sure we don't go either over, or under the
1997              * limit */
1998             if ( row+y_offset < 0 ) {
1999                 continue;
2000             }
2001             if ( row+y_offset >= textbuf->h ) {
2002                 continue;
2003             }
2004             dst = (Uint32*) textbuf->pixels +
2005                 (row+y_offset) * textbuf->pitch/4 +
2006                 xstart + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
2007 
2008             /* Added code to adjust src pointer for pixmaps to
2009              * account for pitch.
2010              * */
2011             dst_check = (Uint32*) textbuf->pixels + (row + y_offset + 1) * textbuf->pitch/4;
2012             src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row);
2013             for (col = width; col>0 && dst < dst_check; --col) {
2014                 alpha = *src++;
2015                 *dst++ |= pixel | ((Uint32)alpha_table[alpha] << 24);
2016             }
2017         }
2018 
2019         xstart += FT_FLOOR(g_info[i].x_advance);
2020         if (TTF_HANDLE_STYLE_BOLD(font)) {
2021             xstart += font->glyph_overhang;
2022         }
2023         prev_index = g_info[i].index;
2024     }
2025 
2026     /* Handle the underline style */
2027     if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
2028         row = TTF_underline_top_row(font);
2029         TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
2030     }
2031 
2032     /* Handle the strikethrough style */
2033     if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
2034         row = TTF_strikethrough_top_row(font);
2035         TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
2036     }
2037 
2038     raqm_destroy(rq);
2039     return(textbuf);
2040 }
2041 
TTF_RenderUNICODE_Blended(TTF_Font * font,const Uint16 * text,SDL_Color fg)2042 SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font,
2043                 const Uint16 *text, SDL_Color fg)
2044 {
2045     SDL_Surface *surface = NULL;
2046     Uint8 *utf8;
2047 
2048     TTF_CHECKPOINTER(text, NULL);
2049 
2050     utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
2051     if (utf8) {
2052         UCS2_to_UTF8(text, utf8);
2053         surface = TTF_RenderUTF8_Blended(font, (char *)utf8, fg);
2054         SDL_stack_free(utf8);
2055     } else {
2056         SDL_OutOfMemory();
2057     }
2058     return surface;
2059 }
2060 
2061 
TTF_RenderText_Blended_Wrapped(TTF_Font * font,const char * text,SDL_Color fg,Uint32 wrapLength)2062 SDL_Surface *TTF_RenderText_Blended_Wrapped(TTF_Font *font, const char *text, SDL_Color fg, Uint32 wrapLength)
2063 {
2064     SDL_Surface *surface = NULL;
2065     Uint8 *utf8;
2066 
2067     TTF_CHECKPOINTER(text, NULL);
2068 
2069     utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
2070     if (utf8) {
2071         LATIN1_to_UTF8(text, utf8);
2072         surface = TTF_RenderUTF8_Blended_Wrapped(font, (char *)utf8, fg, wrapLength);
2073         SDL_stack_free(utf8);
2074     } else {
2075         SDL_OutOfMemory();
2076     }
2077     return surface;
2078 }
2079 
CharacterIsDelimiter(char c,const char * delimiters)2080 static SDL_bool CharacterIsDelimiter(char c, const char *delimiters)
2081 {
2082     while (*delimiters) {
2083         if (c == *delimiters) {
2084             return SDL_TRUE;
2085         }
2086         ++delimiters;
2087     }
2088     return SDL_FALSE;
2089 }
2090 
2091 /* Don't define this until we have a release where we can change font rendering
2092 #define TTF_USE_LINESKIP
2093  */
TTF_RenderUTF8_Blended_Wrapped(TTF_Font * font,const char * text,SDL_Color fg,Uint32 wrapLength)2094 SDL_Surface *TTF_RenderUTF8_Blended_Wrapped(TTF_Font *font,
2095                                     const char *text, SDL_Color fg, Uint32 wrapLength)
2096 {
2097     SDL_bool first;
2098     int i;
2099     int xstart;
2100     int width, height;
2101     SDL_Surface *textbuf;
2102     Uint8 alpha;
2103     Uint8 alpha_table[256];
2104     Uint32 pixel;
2105     Uint8 *src;
2106     Uint32 *dst;
2107     Uint32 *dst_check;
2108     int row, col;
2109     c_glyph *glyph;
2110 
2111     raqm_t *rq = NULL;
2112     raqm_glyph_t *g_info = NULL;
2113     size_t glyph_count = 0;
2114 
2115     FT_Error error;
2116     FT_UInt prev_index = 0;
2117 #ifndef TTF_USE_LINESKIP
2118     const int lineSpace = 2;
2119 #endif
2120     int line, numLines, rowSize;
2121     char *str, **strLines, **newLines;
2122     size_t textlen;
2123 
2124     TTF_CHECKPOINTER(text, NULL);
2125 
2126     textlen = SDL_strlen(text);
2127     /* Shape text */
2128     if (text_layout(text,textlen, font, &rq, &g_info, &glyph_count) < 0)
2129     {
2130         TTF_SetError("Text layout failed");
2131         return NULL;
2132     }
2133 
2134     /* Get the dimensions of the text surface */
2135      if ( ( CalculateSize(font, g_info, glyph_count, &width, &height) < 0 ) || !width ) {
2136         raqm_destroy(rq);
2137         TTF_SetError("Text has zero width");
2138         return(NULL);
2139     }
2140 
2141     numLines = 1;
2142     str = NULL;
2143     strLines = NULL;
2144     if (wrapLength > 0 && *text) {
2145         const char *wrapDelims = " \t\r\n";
2146         int w, h;
2147         char *spot, *tok, *next_tok, *end;
2148         char delim;
2149         size_t str_len = SDL_strlen(text);
2150 
2151         numLines = 0;
2152 
2153         str = SDL_stack_alloc(char, str_len+1);
2154         if (str == NULL) {
2155             raqm_destroy(rq);
2156             TTF_SetError("Out of memory");
2157             return(NULL);
2158         }
2159 
2160         SDL_strlcpy(str, text, str_len+1);
2161         tok = str;
2162         end = str + str_len;
2163         do {
2164             newLines = (char **)SDL_realloc(strLines, (numLines+1)*sizeof(*strLines));
2165             if (!newLines) {
2166                 raqm_destroy(rq);
2167                 TTF_SetError("Out of memory");
2168                 SDL_free(strLines);
2169                 SDL_stack_free(str);
2170                 return(NULL);
2171             }
2172             strLines = newLines;
2173             strLines[numLines++] = tok;
2174 
2175             /* Look for the end of the line */
2176             if ((spot = SDL_strchr(tok, '\r')) != NULL ||
2177                 (spot = SDL_strchr(tok, '\n')) != NULL) {
2178                 if (*spot == '\r') {
2179                     ++spot;
2180                 }
2181                 if (*spot == '\n') {
2182                     ++spot;
2183                 }
2184             } else {
2185                 spot = end;
2186             }
2187             next_tok = spot;
2188 
2189             /* Get the longest string that will fit in the desired space */
2190             for (; ;) {
2191                 /* Strip trailing whitespace */
2192                 while (spot > tok &&
2193                         CharacterIsDelimiter(spot[-1], wrapDelims)) {
2194                     --spot;
2195                 }
2196                 if (spot == tok) {
2197                     if (CharacterIsDelimiter(*spot, wrapDelims)) {
2198                         *spot = '\0';
2199                     }
2200                     break;
2201                 }
2202                 delim = *spot;
2203                 *spot = '\0';
2204 
2205                 TTF_SizeUTF8(font, tok, &w, &h);
2206                 if ((Uint32)w <= wrapLength) {
2207                     break;
2208                 } else {
2209                     /* Back up and try again... */
2210                     *spot = delim;
2211                 }
2212 
2213                 while (spot > tok &&
2214                         !CharacterIsDelimiter(spot[-1], wrapDelims)) {
2215                     --spot;
2216                 }
2217                 if (spot > tok) {
2218                     next_tok = spot;
2219                 }
2220             }
2221             tok = next_tok;
2222         } while (tok < end);
2223     }
2224 
2225     /* Create the target surface */
2226     textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE,
2227             (numLines > 1) ? wrapLength : width,
2228 #ifdef TTF_USE_LINESKIP
2229             numLines * TTF_FontLineSkip(font),
2230 #else
2231             height * numLines + (lineSpace * (numLines - 1)),
2232 #endif
2233             32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
2234     if (textbuf == NULL) {
2235         if (strLines) {
2236             SDL_free(strLines);
2237             SDL_stack_free(str);
2238         }
2239         raqm_destroy(rq);
2240         return(NULL);
2241     }
2242 
2243 #ifdef TTF_USE_LINESKIP
2244     rowSize = textbuf->pitch/4 * TTF_FontLineSkip(font);
2245 #else
2246     rowSize = textbuf->pitch/4 * height;
2247 #endif
2248 
2249     /* Adding bound checking to avoid all kinds of memory corruption errors
2250      that may occur. */
2251     dst_check = (Uint32*)textbuf->pixels + textbuf->pitch/4 * textbuf->h;
2252 
2253     /* Support alpha blending */
2254     if (!fg.a) {
2255         fg.a = SDL_ALPHA_OPAQUE;
2256     }
2257     if (fg.a == SDL_ALPHA_OPAQUE) {
2258         for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
2259             alpha_table[i] = (Uint8)i;
2260         }
2261     } else {
2262         for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
2263             alpha_table[i] = (Uint8)(i * fg.a / 255);
2264         }
2265         SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
2266     }
2267 
2268     /* Load and render each glyph */
2269     pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
2270     SDL_FillRect(textbuf, NULL, pixel); /* Initialize with fg and 0 alpha */
2271 
2272     for (line = 0; line < numLines; line++) {
2273         if (strLines) {
2274             text = strLines[line];
2275         }
2276         first = SDL_TRUE;
2277         xstart = 0;
2278         for (i = 0; i < glyph_count; i++) {
2279             int y_offset;
2280             error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS|CACHED_PIXMAP);
2281             if (error) {
2282                 TTF_SetFTError("Couldn't find glyph", error);
2283                 SDL_FreeSurface(textbuf);
2284                 if (strLines) {
2285                     SDL_free(strLines);
2286                     SDL_stack_free(str);
2287                 }
2288                 return NULL;
2289             }
2290             glyph = font->current;
2291             y_offset = glyph->yoffset - FT_FLOOR(g_info[i].y_offset);
2292             /* Ensure the width of the pixmap is correct. On some cases,
2293              * freetype may report a larger pixmap than possible.*/
2294             width = glyph->pixmap.width;
2295             if (font->outline <= 0 && width > glyph->maxx - glyph->minx) {
2296                 width = glyph->maxx - glyph->minx;
2297             }
2298             /* Compensate for the wrap around bug with negative minx's */
2299             if (first && (glyph->minx < 0)) {
2300                 xstart -= glyph->minx;
2301             }
2302             first = SDL_FALSE;
2303 
2304             for (row = 0; row < glyph->pixmap.rows; ++row) {
2305                 /* Make sure we don't go either over, or under the
2306                  * limit */
2307                 if ( row+y_offset < 0 ) {
2308                     continue;
2309                 }
2310                 if ( row+y_offset >= textbuf->h ) {
2311                     continue;
2312                 }
2313                 dst =  ((Uint32*)textbuf->pixels + rowSize * line) +
2314                 (row+y_offset) * textbuf->pitch/4 +
2315                 xstart + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
2316 
2317                 /* Added code to adjust src pointer for pixmaps to
2318                  * account for pitch.
2319                  * */
2320                 src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row);
2321                 for (col = width; col>0 && dst < dst_check; --col) {
2322                     alpha = *src++;
2323                     *dst++ |= pixel | ((Uint32)alpha_table[alpha] << 24);
2324                 }
2325             }
2326 
2327             xstart += FT_FLOOR(g_info[i].x_advance);
2328             if (TTF_HANDLE_STYLE_BOLD(font)) {
2329                 xstart += font->glyph_overhang;
2330             }
2331             prev_index = g_info[i].index;
2332         }
2333 
2334         /* Handle the underline style *
2335         if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
2336             row = TTF_underline_top_row(font);
2337             TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
2338         }
2339         */
2340 
2341         /* Handle the strikethrough style *
2342         if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
2343             row = TTF_strikethrough_top_row(font);
2344             TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
2345         }
2346         */
2347     }
2348 
2349     if (strLines) {
2350         SDL_free(strLines);
2351         SDL_stack_free(str);
2352     }
2353 
2354     raqm_destroy(rq);
2355     return(textbuf);
2356 }
2357 
TTF_RenderUNICODE_Blended_Wrapped(TTF_Font * font,const Uint16 * text,SDL_Color fg,Uint32 wrapLength)2358 SDL_Surface *TTF_RenderUNICODE_Blended_Wrapped(TTF_Font *font, const Uint16* text,
2359                                                SDL_Color fg, Uint32 wrapLength)
2360 {
2361     SDL_Surface *surface = NULL;
2362     Uint8 *utf8;
2363 
2364     TTF_CHECKPOINTER(text, NULL);
2365 
2366     utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
2367     if (utf8) {
2368         UCS2_to_UTF8(text, utf8);
2369         surface = TTF_RenderUTF8_Blended_Wrapped(font, (char *)utf8, fg, wrapLength);
2370         SDL_stack_free(utf8);
2371     } else {
2372         SDL_OutOfMemory();
2373     }
2374     return surface;
2375 }
2376 
TTF_RenderGlyph_Blended(TTF_Font * font,Uint16 ch,SDL_Color fg)2377 SDL_Surface *TTF_RenderGlyph_Blended(TTF_Font *font, Uint16 ch, SDL_Color fg)
2378 {
2379     Uint16 ucs2[2];
2380     Uint8 utf8[4];
2381 
2382     ucs2[0] = ch;
2383     ucs2[1] = 0;
2384     UCS2_to_UTF8(ucs2, utf8);
2385     return TTF_RenderUTF8_Blended(font, (char *)utf8, fg);
2386 }
2387 
TTF_SetFontStyle(TTF_Font * font,int style)2388 void TTF_SetFontStyle(TTF_Font* font, int style)
2389 {
2390     int prev_style = font->style;
2391     font->style = style | font->face_style;
2392 
2393     /* Flush the cache if the style has changed.
2394      * Ignore UNDERLINE which does not impact glyph drawning.
2395      * */
2396     if ((font->style | TTF_STYLE_NO_GLYPH_CHANGE) != (prev_style | TTF_STYLE_NO_GLYPH_CHANGE)) {
2397         Flush_Cache(font);
2398     }
2399 }
2400 
TTF_GetFontStyle(const TTF_Font * font)2401 int TTF_GetFontStyle(const TTF_Font* font)
2402 {
2403     return font->style;
2404 }
2405 
TTF_SetFontOutline(TTF_Font * font,int outline)2406 void TTF_SetFontOutline(TTF_Font* font, int outline)
2407 {
2408     font->outline = outline;
2409     Flush_Cache(font);
2410 }
2411 
TTF_GetFontOutline(const TTF_Font * font)2412 int TTF_GetFontOutline(const TTF_Font* font)
2413 {
2414     return font->outline;
2415 }
2416 
TTF_SetFontHinting(TTF_Font * font,int hinting)2417 void TTF_SetFontHinting(TTF_Font* font, int hinting)
2418 {
2419     if (hinting == TTF_HINTING_LIGHT)
2420         font->hinting = FT_LOAD_TARGET_LIGHT;
2421     else if (hinting == TTF_HINTING_MONO)
2422         font->hinting = FT_LOAD_TARGET_MONO;
2423     else if (hinting == TTF_HINTING_NONE)
2424         font->hinting = FT_LOAD_NO_HINTING;
2425     else
2426         font->hinting = 0;
2427 
2428     Flush_Cache(font);
2429 }
2430 
TTF_GetFontHinting(const TTF_Font * font)2431 int TTF_GetFontHinting(const TTF_Font* font)
2432 {
2433     if (font->hinting == FT_LOAD_TARGET_LIGHT)
2434         return TTF_HINTING_LIGHT;
2435     else if (font->hinting == FT_LOAD_TARGET_MONO)
2436         return TTF_HINTING_MONO;
2437     else if (font->hinting == FT_LOAD_NO_HINTING)
2438         return TTF_HINTING_NONE;
2439     return 0;
2440 }
2441 
TTF_Quit(void)2442 void TTF_Quit(void)
2443 {
2444     if (TTF_initialized) {
2445         if (--TTF_initialized == 0) {
2446             FT_Done_FreeType(library);
2447         }
2448     }
2449 }
2450 
TTF_WasInit(void)2451 int TTF_WasInit(void)
2452 {
2453     return TTF_initialized;
2454 }
2455 
2456 /* don't use this function. It's just here for binary compatibility. */
TTF_GetFontKerningSize(TTF_Font * font,int prev_index,int index)2457 int TTF_GetFontKerningSize(TTF_Font* font, int prev_index, int index)
2458 {
2459     FT_Vector delta;
2460     FT_Get_Kerning(font->face, prev_index, index, ft_kerning_default, &delta);
2461     return (delta.x >> 6);
2462 }
2463 
TTF_GetFontKerningSizeGlyphs(TTF_Font * font,Uint16 previous_ch,Uint16 ch)2464 int TTF_GetFontKerningSizeGlyphs(TTF_Font *font, Uint16 previous_ch, Uint16 ch)
2465 {
2466     int error;
2467     int glyph_index, prev_index;
2468     FT_Vector delta;
2469 
2470     if (ch == UNICODE_BOM_NATIVE || ch == UNICODE_BOM_SWAPPED) {
2471         return 0;
2472     }
2473 
2474     if (previous_ch == UNICODE_BOM_NATIVE || previous_ch == UNICODE_BOM_SWAPPED) {
2475         return 0;
2476     }
2477 
2478     error = Find_Glyph(font, ch, CACHED_METRICS);
2479     if (error) {
2480         TTF_SetFTError("Couldn't find glyph", error);
2481         return -1;
2482     }
2483     glyph_index = font->current->index;
2484 
2485     error = Find_Glyph(font, previous_ch, CACHED_METRICS);
2486     if (error) {
2487         TTF_SetFTError("Couldn't find glyph", error);
2488         return -1;
2489     }
2490     prev_index = font->current->index;
2491 
2492     error = FT_Get_Kerning(font->face, prev_index, glyph_index, ft_kerning_default, &delta);
2493     if (error) {
2494         TTF_SetFTError("Couldn't get glyph kerning", error);
2495         return -1;
2496     }
2497     return (delta.x >> 6);
2498 }
2499 
2500 /* vi: set ts=4 sw=4 expandtab: */
2501