SDL_ttf.c
author David Ludwig <dludwig@pobox.com>
Sun, 11 May 2014 11:20:09 -0400
changeset 267 997babb2f547
parent 258 a46e12bd4976
child 268 73118378dae8
permissions -rw-r--r--
Made Win[Phone] 8.1 project file names more consistent with 8.0 counterparts

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