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