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