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