1 diff -durN SDL_ttf-2.0.6.orig/SDL_ttf.c SDL_ttf-2.0.6/SDL_ttf.c
2 --- SDL_ttf-2.0.6.orig/SDL_ttf.c 2003-02-21 17:38:15.000000000 +0000
3 +++ SDL_ttf-2.0.6/SDL_ttf.c 2004-12-29 11:18:02.473824704 +0000
5 #define FREEA(p) free(p)
9 #include <freetype/freetype.h>
10 #include <freetype/ftoutln.h>
11 #include <freetype/ttnameid.h>
12 diff -durN SDL_ttf-2.0.6.orig/SDL_ttf.c~ SDL_ttf-2.0.6/SDL_ttf.c~
13 --- SDL_ttf-2.0.6.orig/SDL_ttf.c~ 1970-01-01 00:00:00.000000000 +0000
14 +++ SDL_ttf-2.0.6/SDL_ttf.c~ 2003-02-21 17:38:15.000000000 +0000
17 + SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
18 + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
20 + This library is free software; you can redistribute it and/or
21 + modify it under the terms of the GNU Library General Public
22 + License as published by the Free Software Foundation; either
23 + version 2 of the License, or (at your option) any later version.
25 + This library is distributed in the hope that it will be useful,
26 + but WITHOUT ANY WARRANTY; without even the implied warranty of
27 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 + Library General Public License for more details.
30 + You should have received a copy of the GNU Library General Public
31 + License along with this library; if not, write to the Free
32 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
50 +#define ALLOCA(n) ((void*)alloca(n))
53 +#define ALLOCA(n) malloc(n)
54 +#define FREEA(p) free(p)
57 +#include <freetype/freetype.h>
58 +#include <freetype/ftoutln.h>
59 +#include <freetype/ttnameid.h>
60 +#include <freetype/internal/ftobjs.h>
63 +#include "SDL_endian.h"
66 +/* FIXME: Right now we assume the gray-scale renderer Freetype is using
67 + supports 256 shades of gray, but we should instead key off of num_grays
68 + in the result FT_Bitmap after the FT_Render_Glyph() call. */
69 +#define NUM_GRAYS 256
71 +/* Handy routines for converting from fixed point */
72 +#define FT_FLOOR(X) ((X & -64) / 64)
73 +#define FT_CEIL(X) (((X + 63) & -64) / 64)
75 +#define CACHED_METRICS 0x10
76 +#define CACHED_BITMAP 0x01
77 +#define CACHED_PIXMAP 0x02
79 +/* Cached glyph information */
80 +typedef struct cached_glyph {
94 +/* The structure used to hold internal font information */
96 + /* Freetype2 maintains all sorts of useful info itself */
99 + /* We'll cache these ourselves */
105 + /* The font style */
108 + /* Extra width in glyph bounds for text styles */
109 + int glyph_overhang;
110 + float glyph_italics;
112 + /* Information in the font for underlining */
113 + int underline_offset;
114 + int underline_height;
116 + /* Cache for style-transformed glyphs */
118 + c_glyph cache[256];
121 + /* We are responsible for closing the font stream */
126 + /* For non-scalable formats, we must remember which font index size */
127 + int font_size_family;
130 +/* The FreeType font engine/library */
131 +static FT_Library library;
132 +static int TTF_initialized = 0;
133 +static int TTF_byteswapped = 0;
135 +/* UNICODE string utilities */
136 +static __inline__ int UNICODE_strlen(const Uint16 *text)
139 + while ( *text++ ) {
144 +static __inline__ void UNICODE_strcpy(Uint16 *dst, const Uint16 *src, int swap)
148 + *dst = SDL_Swap16(*src);
163 +/* rcg06192001 get linked library's version. */
164 +const SDL_version *TTF_Linked_Version(void)
166 + static SDL_version linked_version;
167 + TTF_VERSION(&linked_version);
168 + return(&linked_version);
171 +/* This function tells the library whether UNICODE text is generally
172 + byteswapped. A UNICODE BOM character at the beginning of a string
173 + will override this setting for that string.
175 +void TTF_ByteSwappedUNICODE(int swapped)
177 + TTF_byteswapped = swapped;
180 +static void TTF_SetFTError(const char *msg, FT_Error error)
182 +#ifdef USE_FREETYPE_ERRORS
184 +#define FT_ERRORDEF( e, v, s ) { e, s },
185 + static const struct
188 + const char* err_msg;
190 +#include <freetype/fterrors.h>
193 + const char *err_msg;
197 + for ( i=0; i<((sizeof ft_errors)/(sizeof ft_errors[0])); ++i ) {
198 + if ( error == ft_errors[i].err_code ) {
199 + err_msg = ft_errors[i].err_msg;
204 + err_msg = "unknown FreeType error";
206 + sprintf(buffer, "%s: %s", msg, err_msg);
207 + TTF_SetError(buffer);
210 +#endif /* USE_FREETYPE_ERRORS */
213 +int TTF_Init( void )
217 + if ( ! TTF_initialized ) {
218 + FT_Error error = FT_Init_FreeType( &library );
220 + TTF_SetFTError("Couldn't init FreeType engine", error);
224 + if ( status == 0 ) {
230 +static unsigned long RWread(
232 + unsigned long offset,
233 + unsigned char* buffer,
234 + unsigned long count
239 + src = (SDL_RWops *)stream->descriptor.pointer;
240 + SDL_RWseek( src, (int)offset, SEEK_SET );
241 + return SDL_RWread( src, buffer, 1, (int)count );
244 +TTF_Font* TTF_OpenFontIndexRW( SDL_RWops *src, int freesrc, int ptsize, long index )
253 + if ( ! TTF_initialized ) {
254 + TTF_SetError( "Library not initialized" );
258 + /* Check to make sure we can seek in this stream */
259 + position = SDL_RWtell(src);
260 + if ( position < 0 ) {
261 + TTF_SetError( "Can't seek in stream" );
265 + font = (TTF_Font*) malloc(sizeof *font);
266 + if ( font == NULL ) {
267 + TTF_SetError( "Out of memory" );
270 + memset(font, 0, sizeof(*font));
273 + font->freesrc = freesrc;
275 + stream = (FT_Stream)malloc(sizeof(*stream));
276 + if ( stream == NULL ) {
277 + TTF_SetError( "Out of memory" );
278 + TTF_CloseFont( font );
281 + memset(stream, 0, sizeof(*stream));
283 + stream->memory = library->memory;
284 + stream->read = RWread;
285 + stream->descriptor.pointer = src;
286 + stream->pos = (unsigned long)position;
287 + SDL_RWseek(src, 0, SEEK_END);
288 + stream->size = (unsigned long)(SDL_RWtell(src) - position);
289 + SDL_RWseek(src, position, SEEK_SET);
291 + font->args.flags = ft_open_stream;
292 + font->args.stream = stream;
294 + error = FT_Open_Face( library, &font->args, index, &font->face );
296 + TTF_SetFTError( "Couldn't load font file", error );
297 + TTF_CloseFont( font );
302 + /* Make sure that our font face is scalable (global metrics) */
303 + if ( FT_IS_SCALABLE(face) ) {
305 + /* Set the character size and use default DPI (72) */
306 + error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 0, 0 );
308 + TTF_SetFTError( "Couldn't set font size", error );
309 + TTF_CloseFont( font );
313 + /* Get the scalable font metrics for this font */
314 + scale = face->size->metrics.y_scale;
315 + font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
316 + font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
317 + font->height = font->ascent - font->descent + /* baseline */ 1;
318 + font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
319 + font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
320 + font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
323 + /* Non-scalable font case. ptsize determines which family
324 + * or series of fonts to grab from the non-scalable format.
325 + * It is not the point size of the font.
327 + if ( ptsize >= font->face->num_fixed_sizes )
328 + ptsize = font->face->num_fixed_sizes - 1;
329 + font->font_size_family = ptsize;
330 + error = FT_Set_Pixel_Sizes( face,
331 + face->available_sizes[ptsize].height,
332 + face->available_sizes[ptsize].width );
333 + /* With non-scalale fonts, Freetype2 likes to fill many of the
334 + * font metrics with the value of 0. The size of the
335 + * non-scalable fonts must be determined differently
336 + * or sometimes cannot be determined.
338 + font->ascent = face->available_sizes[ptsize].height;
340 + font->height = face->available_sizes[ptsize].height;
341 + font->lineskip = FT_CEIL(font->ascent);
342 + font->underline_offset = FT_FLOOR(face->underline_position);
343 + font->underline_height = FT_FLOOR(face->underline_thickness);
346 + if ( font->underline_height < 1 ) {
347 + font->underline_height = 1;
351 + printf("Font metrics:\n");
352 + printf("\tascent = %d, descent = %d\n",
353 + font->ascent, font->descent);
354 + printf("\theight = %d, lineskip = %d\n",
355 + font->height, font->lineskip);
356 + printf("\tunderline_offset = %d, underline_height = %d\n",
357 + font->underline_offset, font->underline_height);
360 + /* Set the default font style */
361 + font->style = TTF_STYLE_NORMAL;
362 + font->glyph_overhang = face->size->metrics.y_ppem / 10;
363 + /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
364 + font->glyph_italics = 0.207f;
365 + font->glyph_italics *= font->height;
370 +TTF_Font* TTF_OpenFontRW( SDL_RWops *src, int freesrc, int ptsize )
372 + return TTF_OpenFontIndexRW(src, freesrc, ptsize, 0);
375 +TTF_Font* TTF_OpenFontIndex( const char *file, int ptsize, long index )
377 + return TTF_OpenFontIndexRW(SDL_RWFromFile(file, "rb"), 1, ptsize, index);
380 +TTF_Font* TTF_OpenFont( const char *file, int ptsize )
382 + return TTF_OpenFontIndex(file, ptsize, 0);
385 +static void Flush_Glyph( c_glyph* glyph )
389 + if( glyph->bitmap.buffer ) {
390 + free( glyph->bitmap.buffer );
391 + glyph->bitmap.buffer = 0;
393 + if( glyph->pixmap.buffer ) {
394 + free( glyph->pixmap.buffer );
395 + glyph->pixmap.buffer = 0;
400 +static void Flush_Cache( TTF_Font* font )
403 + int size = sizeof( font->cache ) / sizeof( font->cache[0] );
405 + for( i = 0; i < size; ++i ) {
406 + if( font->cache[i].cached ) {
407 + Flush_Glyph( &font->cache[i] );
411 + if( font->scratch.cached ) {
412 + Flush_Glyph( &font->scratch );
417 +static FT_Error Load_Glyph( TTF_Font* font, Uint16 ch, c_glyph* cached, int want )
421 + FT_GlyphSlot glyph;
422 + FT_Glyph_Metrics* metrics;
423 + FT_Outline* outline;
425 + if ( !font || !font->face ) {
426 + return FT_Err_Invalid_Handle;
431 + /* Load the glyph */
432 + if ( ! cached->index ) {
433 + cached->index = FT_Get_Char_Index( face, ch );
435 + error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT );
440 + /* Get our glyph shortcuts */
441 + glyph = face->glyph;
442 + metrics = &glyph->metrics;
443 + outline = &glyph->outline;
445 + /* Get the glyph metrics if desired */
446 + if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) {
447 + if ( FT_IS_SCALABLE( face ) ) {
448 + /* Get the bounding box */
449 + cached->minx = FT_FLOOR(metrics->horiBearingX);
450 + cached->maxx = cached->minx + FT_CEIL(metrics->width);
451 + cached->maxy = FT_FLOOR(metrics->horiBearingY);
452 + cached->miny = cached->maxy - FT_CEIL(metrics->height);
453 + cached->yoffset = font->ascent - cached->maxy;
454 + cached->advance = FT_CEIL(metrics->horiAdvance);
456 + /* Get the bounding box for non-scalable format.
457 + * Again, freetype2 fills in many of the font metrics
458 + * with the value of 0, so some of the values we
459 + * need must be calculated differently with certain
460 + * assumptions about non-scalable formats.
462 + cached->minx = FT_FLOOR(metrics->horiBearingX);
463 + cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance);
464 + cached->maxy = FT_FLOOR(metrics->horiBearingY);
465 + cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height);
466 + cached->yoffset = 0;
467 + cached->advance = FT_CEIL(metrics->horiAdvance);
470 + /* Adjust for bold and italic text */
471 + if( font->style & TTF_STYLE_BOLD ) {
472 + cached->maxx += font->glyph_overhang;
474 + if( font->style & TTF_STYLE_ITALIC ) {
475 + cached->maxx += (int)ceil(font->glyph_italics);
477 + cached->stored |= CACHED_METRICS;
480 + if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
481 + ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) {
482 + int mono = (want & CACHED_BITMAP);
487 + /* Handle the italic style */
488 + if( font->style & TTF_STYLE_ITALIC ) {
491 + shear.xx = 1 << 16;
492 + shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height;
494 + shear.yy = 1 << 16;
496 + FT_Outline_Transform( outline, &shear );
499 + /* Render the glyph */
501 + error = FT_Render_Glyph( glyph, ft_render_mode_mono );
503 + error = FT_Render_Glyph( glyph, ft_render_mode_normal );
509 + /* Copy over information to cache */
510 + src = &glyph->bitmap;
512 + dst = &cached->bitmap;
514 + dst = &cached->pixmap;
516 + memcpy( dst, src, sizeof( *dst ) );
518 + /* FT_Render_Glyph() and .fon fonts always generate a
519 + * two-color (black and white) glyphslot surface, even
520 + * when rendered in ft_render_mode_normal. This is probably
521 + * a freetype2 bug because it is inconsistent with the
522 + * freetype2 documentation under FT_Render_Mode section.
524 + if ( mono || !FT_IS_SCALABLE(face) ) {
528 + /* Adjust for bold and italic text */
529 + if( font->style & TTF_STYLE_BOLD ) {
530 + int bump = font->glyph_overhang;
531 + dst->pitch += bump;
532 + dst->width += bump;
534 + if( font->style & TTF_STYLE_ITALIC ) {
535 + int bump = (int)ceil(font->glyph_italics);
536 + dst->pitch += bump;
537 + dst->width += bump;
540 + if (dst->rows != 0) {
541 + dst->buffer = malloc( dst->pitch * dst->rows );
542 + if( !dst->buffer ) {
543 + return FT_Err_Out_Of_Memory;
545 + memset( dst->buffer, 0, dst->pitch * dst->rows );
547 + for( i = 0; i < src->rows; i++ ) {
548 + int soffset = i * src->pitch;
549 + int doffset = i * dst->pitch;
551 + unsigned char *srcp = src->buffer + soffset;
552 + unsigned char *dstp = dst->buffer + doffset;
554 + for ( j = 0; j < src->width; j += 8 ) {
555 + unsigned char ch = *srcp++;
556 + *dstp++ = (ch&0x80) >> 7;
558 + *dstp++ = (ch&0x80) >> 7;
560 + *dstp++ = (ch&0x80) >> 7;
562 + *dstp++ = (ch&0x80) >> 7;
564 + *dstp++ = (ch&0x80) >> 7;
566 + *dstp++ = (ch&0x80) >> 7;
568 + *dstp++ = (ch&0x80) >> 7;
570 + *dstp++ = (ch&0x80) >> 7;
572 + } else if ( !FT_IS_SCALABLE(face) ) {
573 + /* This special case wouldn't
574 + * be here if the FT_Render_Glyph()
575 + * function wasn't buggy when it tried
576 + * to render a .fon font with 256
577 + * shades of gray. Instead, it
578 + * returns a black and white surface
579 + * and we have to translate it back
580 + * to a 256 gray shaded surface.
582 + unsigned char *srcp = src->buffer + soffset;
583 + unsigned char *dstp = dst->buffer + doffset;
586 + for ( j = 0; j < src->width; j += 8) {
588 + for (k = 0; k < 8; ++k) {
589 + if ((ch&0x80) >> 7) {
590 + *dstp++ = NUM_GRAYS - 1;
598 + memcpy(dst->buffer+doffset,
599 + src->buffer+soffset, src->pitch);
604 + /* Handle the bold style */
605 + if ( font->style & TTF_STYLE_BOLD ) {
612 + /* The pixmap is a little hard, we have to add and clamp */
613 + for( row = dst->rows - 1; row >= 0; --row ) {
614 + pixmap = (Uint8*) dst->buffer + row * dst->pitch;
615 + for( offset=1; offset <= font->glyph_overhang; ++offset ) {
616 + for( col = dst->width - 1; col > 0; --col ) {
617 + pixel = (pixmap[col] + pixmap[col-1]);
618 + if( pixel > NUM_GRAYS - 1 ) {
619 + pixel = NUM_GRAYS - 1;
621 + pixmap[col] = (Uint8) pixel;
627 + /* Mark that we rendered this format */
629 + cached->stored |= CACHED_BITMAP;
631 + cached->stored |= CACHED_PIXMAP;
635 + /* We're done, mark this glyph cached */
636 + cached->cached = ch;
641 +static FT_Error Find_Glyph( TTF_Font* font, Uint16 ch, int want )
646 + font->current = &font->cache[ch];
648 + if ( font->scratch.cached != ch ) {
649 + Flush_Glyph( &font->scratch );
651 + font->current = &font->scratch;
653 + if ( (font->current->stored & want) != want ) {
654 + retval = Load_Glyph( font, ch, font->current, want );
659 +void TTF_CloseFont( TTF_Font* font )
661 + Flush_Cache( font );
662 + if ( font->face ) {
663 + FT_Done_Face( font->face );
665 + if ( font->args.stream ) {
666 + free( font->args.stream );
668 + if ( font->freesrc ) {
669 + SDL_RWclose( font->src );
674 +static Uint16 *LATIN1_to_UNICODE(Uint16 *unicode, const char *text, int len)
678 + for ( i=0; i < len; ++i ) {
679 + unicode[i] = ((const unsigned char *)text)[i];
686 +static Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len)
691 + for ( i=0, j=0; i < len; ++i, ++j ) {
692 + ch = ((const unsigned char *)utf8)[i];
693 + if ( ch >= 0xF0 ) {
694 + ch = (Uint16)(utf8[i]&0x07) << 18;
695 + ch |= (Uint16)(utf8[++i]&0x3F) << 12;
696 + ch |= (Uint16)(utf8[++i]&0x3F) << 6;
697 + ch |= (Uint16)(utf8[++i]&0x3F);
699 + if ( ch >= 0xE0 ) {
700 + ch = (Uint16)(utf8[i]&0x3F) << 12;
701 + ch |= (Uint16)(utf8[++i]&0x3F) << 6;
702 + ch |= (Uint16)(utf8[++i]&0x3F);
704 + if ( ch >= 0xC0 ) {
705 + ch = (Uint16)(utf8[i]&0x3F) << 6;
706 + ch |= (Uint16)(utf8[++i]&0x3F);
715 +int TTF_FontHeight(TTF_Font *font)
717 + return(font->height);
720 +int TTF_FontAscent(TTF_Font *font)
722 + return(font->ascent);
725 +int TTF_FontDescent(TTF_Font *font)
727 + return(font->descent);
730 +int TTF_FontLineSkip(TTF_Font *font)
732 + return(font->lineskip);
735 +long TTF_FontFaces(TTF_Font *font)
737 + return(font->face->num_faces);
740 +int TTF_FontFaceIsFixedWidth(TTF_Font *font)
742 + return(FT_IS_FIXED_WIDTH(font->face));
745 +char *TTF_FontFaceFamilyName(TTF_Font *font)
747 + return(font->face->family_name);
750 +char *TTF_FontFaceStyleName(TTF_Font *font)
752 + return(font->face->style_name);
755 +int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch,
756 + int* minx, int* maxx, int* miny, int* maxy, int* advance)
760 + error = Find_Glyph(font, ch, CACHED_METRICS);
762 + TTF_SetFTError("Couldn't find glyph", error);
767 + *minx = font->current->minx;
770 + *maxx = font->current->maxx;
773 + *miny = font->current->miny;
776 + *maxy = font->current->maxy;
779 + *advance = font->current->advance;
784 +int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h)
786 + Uint16 *unicode_text;
790 + /* Copy the Latin-1 text to a UNICODE text buffer */
791 + unicode_len = strlen(text);
792 + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
793 + if ( unicode_text == NULL ) {
794 + TTF_SetError("Out of memory");
797 + *unicode_text = UNICODE_BOM_NATIVE;
798 + LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);
800 + /* Render the new text */
801 + status = TTF_SizeUNICODE(font, unicode_text, w, h);
803 + /* Free the text buffer and return */
804 + FREEA(unicode_text);
808 +int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h)
810 + Uint16 *unicode_text;
814 + /* Copy the UTF-8 text to a UNICODE text buffer */
815 + unicode_len = strlen(text);
816 + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
817 + if ( unicode_text == NULL ) {
818 + TTF_SetError("Out of memory");
821 + *unicode_text = UNICODE_BOM_NATIVE;
822 + UTF8_to_UNICODE(unicode_text+1, text, unicode_len);
824 + /* Render the new text */
825 + status = TTF_SizeUNICODE(font, unicode_text, w, h);
827 + /* Free the text buffer and return */
828 + FREEA(unicode_text);
832 +int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h)
843 + /* Initialize everything to 0 */
844 + if ( ! TTF_initialized ) {
845 + TTF_SetError( "Library not initialized" );
851 + swapped = TTF_byteswapped;
853 + /* Load each character and sum it's bounding box */
855 + for ( ch=text; *ch; ++ch ) {
857 + if ( c == UNICODE_BOM_NATIVE ) {
859 + if ( text == ch ) {
864 + if ( c == UNICODE_BOM_SWAPPED ) {
866 + if ( text == ch ) {
875 + error = Find_Glyph(font, c, CACHED_METRICS);
879 + glyph = font->current;
881 + if ( (ch == text) && (glyph->minx < 0) ) {
882 + /* Fixes the texture wrapping bug when the first letter
883 + * has a negative minx value or horibearing value. The entire
884 + * bounding box must be adjusted to be bigger so the entire
885 + * letter can fit without any texture corruption or wrapping.
887 + * Effects: First enlarges bounding box.
888 + * Second, xstart has to start ahead of its normal spot in the
889 + * negative direction of the negative minx value.
890 + * (pushes everything to the right).
892 + * This will make the memory copy of the glyph bitmap data
893 + * work out correctly.
899 + z = x + glyph->minx;
903 + if ( font->style & TTF_STYLE_BOLD ) {
904 + x += font->glyph_overhang;
906 + if ( glyph->advance > glyph->maxx ) {
907 + z = x + glyph->advance;
909 + z = x + glyph->maxx;
914 + x += glyph->advance;
916 + if ( glyph->miny < miny ) {
917 + miny = glyph->miny;
919 + if ( glyph->maxy > maxy ) {
920 + maxy = glyph->maxy;
924 + /* Fill the bounds rectangle */
926 + *w = (maxx - minx);
929 +#if 0 /* This is correct, but breaks many applications */
930 + *h = (maxy - miny);
938 +/* Convert the Latin-1 text to UNICODE and render it
940 +SDL_Surface *TTF_RenderText_Solid(TTF_Font *font,
941 + const char *text, SDL_Color fg)
943 + SDL_Surface *textbuf;
944 + Uint16 *unicode_text;
947 + /* Copy the Latin-1 text to a UNICODE text buffer */
948 + unicode_len = strlen(text);
949 + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
950 + if ( unicode_text == NULL ) {
951 + TTF_SetError("Out of memory");
954 + *unicode_text = UNICODE_BOM_NATIVE;
955 + LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);
957 + /* Render the new text */
958 + textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg);
960 + /* Free the text buffer and return */
961 + FREEA(unicode_text);
965 +/* Convert the UTF-8 text to UNICODE and render it
967 +SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font,
968 + const char *text, SDL_Color fg)
970 + SDL_Surface *textbuf;
971 + Uint16 *unicode_text;
974 + /* Copy the UTF-8 text to a UNICODE text buffer */
975 + unicode_len = strlen(text);
976 + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
977 + if ( unicode_text == NULL ) {
978 + TTF_SetError("Out of memory");
981 + *unicode_text = UNICODE_BOM_NATIVE;
982 + UTF8_to_UNICODE(unicode_text, text, unicode_len);
984 + /* Render the new text */
985 + textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg);
987 + /* Free the text buffer and return */
988 + FREEA(unicode_text);
992 +SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font,
993 + const Uint16 *text, SDL_Color fg)
998 + SDL_Surface* textbuf;
999 + SDL_Palette* palette;
1006 + FT_Bitmap *current;
1009 + /* Get the dimensions of the text surface */
1010 + if( ( TTF_SizeUNICODE(font, text, &width, NULL) < 0 ) || !width ) {
1011 + TTF_SetError( "Text has zero width" );
1014 + height = font->height;
1016 + /* Create the target surface */
1017 + textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
1018 + if( textbuf == NULL ) {
1022 + /* Fill the palette with the foreground color */
1023 + palette = textbuf->format->palette;
1024 + palette->colors[0].r = 255 - fg.r;
1025 + palette->colors[0].g = 255 - fg.g;
1026 + palette->colors[0].b = 255 - fg.b;
1027 + palette->colors[1].r = fg.r;
1028 + palette->colors[1].g = fg.g;
1029 + palette->colors[1].b = fg.b;
1030 + SDL_SetColorKey( textbuf, SDL_SRCCOLORKEY, 0 );
1032 + /* Load and render each character */
1034 + swapped = TTF_byteswapped;
1035 + for( ch=text; *ch; ++ch ) {
1037 + if ( c == UNICODE_BOM_NATIVE ) {
1039 + if ( text == ch ) {
1044 + if ( c == UNICODE_BOM_SWAPPED ) {
1046 + if ( text == ch ) {
1052 + c = SDL_Swap16(c);
1055 + error = Find_Glyph(font, c, CACHED_METRICS|CACHED_BITMAP);
1057 + SDL_FreeSurface( textbuf );
1060 + glyph = font->current;
1061 + current = &glyph->bitmap;
1062 + /* Compensate for wrap around bug with negative minx's */
1063 + if ( (ch == text) && (glyph->minx < 0) ) {
1064 + xstart -= glyph->minx;
1067 + for( row = 0; row < current->rows; ++row ) {
1068 + /* Make sure we don't go over the limit */
1069 + if ( row+glyph->yoffset >= textbuf->h ) {
1072 + dst = (Uint8*) textbuf->pixels +
1073 + (row+glyph->yoffset) * textbuf->pitch +
1074 + xstart + glyph->minx;
1075 + src = current->buffer + row * current->pitch;
1077 + for ( col=current->width; col>0; --col ) {
1082 + xstart += glyph->advance;
1083 + if ( font->style & TTF_STYLE_BOLD ) {
1084 + xstart += font->glyph_overhang;
1088 + /* Handle the underline style */
1089 + if( font->style & TTF_STYLE_UNDERLINE ) {
1090 + row = font->ascent - font->underline_offset - 1;
1091 + if ( row >= textbuf->h) {
1092 + row = (textbuf->h-1) - font->underline_height;
1094 + dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
1095 + for ( row=font->underline_height; row>0; --row ) {
1096 + /* 1 because 0 is the bg color */
1097 + memset( dst, 1, textbuf->w );
1098 + dst += textbuf->pitch;
1104 +SDL_Surface *TTF_RenderGlyph_Solid(TTF_Font *font, Uint16 ch, SDL_Color fg)
1106 + SDL_Surface *textbuf;
1107 + SDL_Palette *palette;
1113 + /* Get the glyph itself */
1114 + error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_BITMAP);
1118 + glyph = font->current;
1120 + /* Create the target surface */
1121 + textbuf = SDL_CreateRGBSurface( SDL_SWSURFACE,
1122 + glyph->bitmap.pitch,
1123 + glyph->bitmap.rows,
1125 + if ( ! textbuf ) {
1129 + /* Fill the palette with the foreground color */
1130 + palette = textbuf->format->palette;
1131 + palette->colors[0].r = 255-fg.r;
1132 + palette->colors[0].g = 255-fg.g;
1133 + palette->colors[0].b = 255-fg.b;
1134 + palette->colors[1].r = fg.r;
1135 + palette->colors[1].g = fg.g;
1136 + palette->colors[1].b = fg.b;
1137 + SDL_SetColorKey(textbuf, SDL_SRCCOLORKEY, 0);
1139 + /* Copy the character from the pixmap */
1140 + src = glyph->bitmap.buffer;
1141 + dst = (Uint8*) textbuf->pixels;
1142 + for ( row = 0; row < textbuf->h; ++row ) {
1143 + memcpy( dst, src, glyph->bitmap.pitch );
1144 + src += glyph->bitmap.pitch;
1145 + dst += textbuf->pitch;
1148 + /* Handle the underline style */
1149 + if( font->style & TTF_STYLE_UNDERLINE ) {
1150 + row = font->ascent - font->underline_offset - 1;
1151 + if ( row >= textbuf->h) {
1152 + row = (textbuf->h-1) - font->underline_height;
1154 + dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
1155 + for ( row=font->underline_height; row>0; --row ) {
1156 + /* 1 because 0 is the bg color */
1157 + memset( dst, 1, textbuf->w );
1158 + dst += textbuf->pitch;
1165 +/* Convert the Latin-1 text to UNICODE and render it
1167 +SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font,
1168 + const char *text, SDL_Color fg, SDL_Color bg)
1170 + SDL_Surface *textbuf;
1171 + Uint16 *unicode_text;
1174 + /* Copy the Latin-1 text to a UNICODE text buffer */
1175 + unicode_len = strlen(text);
1176 + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
1177 + if ( unicode_text == NULL ) {
1178 + TTF_SetError("Out of memory");
1181 + *unicode_text = UNICODE_BOM_NATIVE;
1182 + LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);
1184 + /* Render the new text */
1185 + textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg);
1187 + /* Free the text buffer and return */
1188 + FREEA(unicode_text);
1192 +/* Convert the UTF-8 text to UNICODE and render it
1194 +SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font,
1195 + const char *text, SDL_Color fg, SDL_Color bg)
1197 + SDL_Surface *textbuf;
1198 + Uint16 *unicode_text;
1201 + /* Copy the UTF-8 text to a UNICODE text buffer */
1202 + unicode_len = strlen(text);
1203 + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
1204 + if ( unicode_text == NULL ) {
1205 + TTF_SetError("Out of memory");
1208 + *unicode_text = UNICODE_BOM_NATIVE;
1209 + UTF8_to_UNICODE(unicode_text+1, text, unicode_len);
1211 + /* Render the new text */
1212 + textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg);
1214 + /* Free the text buffer and return */
1215 + FREEA(unicode_text);
1219 +SDL_Surface* TTF_RenderUNICODE_Shaded( TTF_Font* font,
1220 + const Uint16* text,
1227 + SDL_Surface* textbuf;
1228 + SDL_Palette* palette;
1238 + FT_Bitmap* current;
1242 + /* Get the dimensions of the text surface */
1243 + if( ( TTF_SizeUNICODE(font, text, &width, NULL) < 0 ) || !width ) {
1244 + TTF_SetError("Text has zero width");
1247 + height = font->height;
1249 + /* Create the target surface */
1250 + textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
1251 + if( textbuf == NULL ) {
1255 + /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
1256 + palette = textbuf->format->palette;
1257 + rdiff = fg.r - bg.r;
1258 + gdiff = fg.g - bg.g;
1259 + bdiff = fg.b - bg.b;
1261 + for( index = 0; index < NUM_GRAYS; ++index ) {
1262 + palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1);
1263 + palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1);
1264 + palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1);
1267 + /* Load and render each character */
1269 + swapped = TTF_byteswapped;
1270 + for( ch = text; *ch; ++ch ) {
1272 + if ( c == UNICODE_BOM_NATIVE ) {
1274 + if ( text == ch ) {
1279 + if ( c == UNICODE_BOM_SWAPPED ) {
1281 + if ( text == ch ) {
1287 + c = SDL_Swap16(c);
1290 + error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP);
1292 + SDL_FreeSurface( textbuf );
1295 + glyph = font->current;
1296 + /* Compensate for the wrap around with negative minx's */
1297 + if ( (ch == text) && (glyph->minx < 0) ) {
1298 + xstart -= glyph->minx;
1301 + current = &glyph->pixmap;
1302 + for( row = 0; row < current->rows; ++row ) {
1303 + /* Make sure we don't go over the limit */
1304 + if ( row+glyph->yoffset >= textbuf->h ) {
1307 + dst = (Uint8*) textbuf->pixels +
1308 + (row+glyph->yoffset) * textbuf->pitch +
1309 + xstart + glyph->minx;
1310 + src = current->buffer + row * current->pitch;
1311 + for ( col=current->width; col>0; --col ) {
1316 + xstart += glyph->advance;
1317 + if( font->style & TTF_STYLE_BOLD ) {
1318 + xstart += font->glyph_overhang;
1322 + /* Handle the underline style */
1323 + if( font->style & TTF_STYLE_UNDERLINE ) {
1324 + row = font->ascent - font->underline_offset - 1;
1325 + if ( row >= textbuf->h) {
1326 + row = (textbuf->h-1) - font->underline_height;
1328 + dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
1329 + for ( row=font->underline_height; row>0; --row ) {
1330 + memset( dst, NUM_GRAYS - 1, textbuf->w );
1331 + dst += textbuf->pitch;
1337 +SDL_Surface* TTF_RenderGlyph_Shaded( TTF_Font* font,
1342 + SDL_Surface* textbuf;
1343 + SDL_Palette* palette;
1354 + /* Get the glyph itself */
1355 + error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_PIXMAP);
1359 + glyph = font->current;
1361 + /* Create the target surface */
1362 + textbuf = SDL_CreateRGBSurface( SDL_SWSURFACE,
1363 + glyph->pixmap.width,
1364 + glyph->pixmap.rows,
1370 + /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
1371 + palette = textbuf->format->palette;
1372 + rdiff = fg.r - bg.r;
1373 + gdiff = fg.g - bg.g;
1374 + bdiff = fg.b - bg.b;
1375 + for( index = 0; index < NUM_GRAYS; ++index ) {
1376 + palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1);
1377 + palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1);
1378 + palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1);
1381 + /* Copy the character from the pixmap */
1382 + src = glyph->pixmap.buffer;
1383 + dst = (Uint8*) textbuf->pixels;
1384 + for ( row = 0; row < textbuf->h; ++row ) {
1385 + memcpy( dst, src, glyph->pixmap.pitch );
1386 + src += glyph->pixmap.pitch;
1387 + dst += textbuf->pitch;
1390 + /* Handle the underline style */
1391 + if( font->style & TTF_STYLE_UNDERLINE ) {
1392 + row = font->ascent - font->underline_offset - 1;
1393 + if ( row >= textbuf->h) {
1394 + row = (textbuf->h-1) - font->underline_height;
1396 + dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
1397 + for ( row=font->underline_height; row>0; --row ) {
1398 + memset( dst, NUM_GRAYS - 1, textbuf->w );
1399 + dst += textbuf->pitch;
1405 +/* Convert the Latin-1 text to UNICODE and render it
1407 +SDL_Surface *TTF_RenderText_Blended(TTF_Font *font,
1408 + const char *text, SDL_Color fg)
1410 + SDL_Surface *textbuf;
1411 + Uint16 *unicode_text;
1414 + /* Copy the Latin-1 text to a UNICODE text buffer */
1415 + unicode_len = strlen(text);
1416 + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
1417 + if ( unicode_text == NULL ) {
1418 + TTF_SetError("Out of memory");
1421 + *unicode_text = UNICODE_BOM_NATIVE;
1422 + LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);
1424 + /* Render the new text */
1425 + textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg);
1427 + /* Free the text buffer and return */
1428 + FREEA(unicode_text);
1432 +/* Convert the UTF-8 text to UNICODE and render it
1434 +SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
1435 + const char *text, SDL_Color fg)
1437 + SDL_Surface *textbuf;
1438 + Uint16 *unicode_text;
1441 + /* Copy the UTF-8 text to a UNICODE text buffer */
1442 + unicode_len = strlen(text);
1443 + unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
1444 + if ( unicode_text == NULL ) {
1445 + TTF_SetError("Out of memory");
1448 + *unicode_text = UNICODE_BOM_NATIVE;
1449 + UTF8_to_UNICODE(unicode_text+1, text, unicode_len);
1451 + /* Render the new text */
1452 + textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg);
1454 + /* Free the text buffer and return */
1455 + FREEA(unicode_text);
1459 +SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font,
1460 + const Uint16 *text, SDL_Color fg)
1463 + int width, height;
1464 + SDL_Surface *textbuf;
1475 + /* Get the dimensions of the text surface */
1476 + if ( (TTF_SizeUNICODE(font, text, &width, NULL) < 0) || !width ) {
1477 + TTF_SetError("Text has zero width");
1480 + height = font->height;
1482 + textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 32,
1483 + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
1484 + if ( textbuf == NULL ) {
1488 + /* Load and render each character */
1490 + swapped = TTF_byteswapped;
1491 + pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
1492 + for ( ch=text; *ch; ++ch ) {
1494 + if ( c == UNICODE_BOM_NATIVE ) {
1496 + if ( text == ch ) {
1501 + if ( c == UNICODE_BOM_SWAPPED ) {
1503 + if ( text == ch ) {
1509 + c = SDL_Swap16(c);
1511 + error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP);
1513 + SDL_FreeSurface( textbuf );
1516 + glyph = font->current;
1517 + width = glyph->pixmap.width;
1518 + /* Compensate for the wrap around bug with negative minx's */
1519 + if ( (ch == text) && (glyph->minx < 0) ) {
1520 + xstart -= glyph->minx;
1523 + for ( row = 0; row < glyph->pixmap.rows; ++row ) {
1524 + /* Make sure we don't go over the limit */
1525 + if ( row+glyph->yoffset >= textbuf->h ) {
1528 + dst = (Uint32*) textbuf->pixels +
1529 + (row+glyph->yoffset) * textbuf->pitch/4 +
1530 + xstart + glyph->minx;
1531 + /* Added code to adjust src pointer for pixmaps to
1532 + * account for pitch.
1534 + src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row);
1535 + for ( col = width; col>0; --col) {
1537 + *dst++ |= pixel | (alpha << 24);
1541 + xstart += glyph->advance;
1542 + if ( font->style & TTF_STYLE_BOLD ) {
1543 + xstart += font->glyph_overhang;
1547 + /* Handle the underline style */
1548 + if( font->style & TTF_STYLE_UNDERLINE ) {
1549 + row = font->ascent - font->underline_offset - 1;
1550 + if ( row >= textbuf->h) {
1551 + row = (textbuf->h-1) - font->underline_height;
1553 + dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
1554 + pixel |= 0xFF000000; /* Amask */
1555 + for ( row=font->underline_height; row>0; --row ) {
1556 + for ( col=0; col < textbuf->w; ++col ) {
1559 + dst += textbuf->pitch/4;
1565 +SDL_Surface *TTF_RenderGlyph_Blended(TTF_Font *font, Uint16 ch, SDL_Color fg)
1567 + SDL_Surface *textbuf;
1576 + /* Get the glyph itself */
1577 + error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_PIXMAP);
1581 + glyph = font->current;
1583 + textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE,
1584 + glyph->pixmap.width, glyph->pixmap.rows, 32,
1585 + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
1586 + if ( ! textbuf ) {
1590 + /* Copy the character from the pixmap */
1591 + pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
1592 + for ( row=0; row<textbuf->h; ++row ) {
1593 + /* Changed src to take pitch into account, not just width */
1594 + src = glyph->pixmap.buffer + row * glyph->pixmap.pitch;
1595 + dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
1596 + for ( col=0; col<glyph->pixmap.width; ++col ) {
1598 + *dst++ = pixel | (alpha << 24);
1602 + /* Handle the underline style */
1603 + if( font->style & TTF_STYLE_UNDERLINE ) {
1604 + row = font->ascent - font->underline_offset - 1;
1605 + if ( row >= textbuf->h) {
1606 + row = (textbuf->h-1) - font->underline_height;
1608 + dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
1609 + pixel |= 0xFF000000; /* Amask */
1610 + for ( row=font->underline_height; row>0; --row ) {
1611 + for ( col=0; col < textbuf->w; ++col ) {
1614 + dst += textbuf->pitch/4;
1620 +void TTF_SetFontStyle( TTF_Font* font, int style )
1622 + font->style = style;
1623 + Flush_Cache( font );
1626 +int TTF_GetFontStyle( TTF_Font* font )
1628 + return font->style;
1631 +void TTF_Quit( void )
1633 + if ( TTF_initialized ) {
1634 + if ( --TTF_initialized == 0 ) {
1635 + FT_Done_FreeType( library );
1640 +int TTF_WasInit( void )
1642 + return TTF_initialized;