Logo Search packages:      
Sourcecode: adonthell version File versions  Download package

SDL_ttf.c

/*
    SDL_ttf:  A companion library to SDL for working with TrueType (tm) fonts
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Sam Lantinga
    slouken@libsdl.org
*/

/* $Id: SDL_ttf.c,v 1.2 2004/11/26 11:57:53 ksterker Exp $ */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif

#ifdef HAVE_ALLOCA
#define ALLOCA(n) ((void*)alloca(n))
#define FREEA(p)
#else
#define ALLOCA(n) malloc(n)
#define FREEA(p) free(p)
#endif

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#include FT_TRUETYPE_IDS_H
#include FT_INTERNAL_OBJECTS_H

#include "SDL.h"
#include "SDL_endian.h"
#include "SDL_ttf.h"

/* FIXME: Right now we assume the gray-scale renderer Freetype is using
   supports 256 shades of gray, but we should instead key off of num_grays
   in the result FT_Bitmap after the FT_Render_Glyph() call. */
#define NUM_GRAYS       256

/* Handy routines for converting from fixed point */
#define FT_FLOOR(X)     ((X & -64) / 64)
#define FT_CEIL(X)      (((X + 63) & -64) / 64)

#define CACHED_METRICS  0x10
#define CACHED_BITMAP   0x01
#define CACHED_PIXMAP   0x02

/* Cached glyph information */
typedef struct cached_glyph {
      int stored;
      FT_UInt index;
      FT_Bitmap bitmap;
      FT_Bitmap pixmap;
      int minx;
      int maxx;
      int miny;
      int maxy;
      int yoffset;
      int advance;
      Uint16 cached;
} c_glyph;

/* The structure used to hold internal font information */
struct _TTF_Font {
      /* Freetype2 maintains all sorts of useful info itself */
      FT_Face face;

      /* We'll cache these ourselves */
      int height;
      int ascent;
      int descent;
      int lineskip;

      /* The font style */
      int style;

      /* Extra width in glyph bounds for text styles */
      int glyph_overhang;
      float glyph_italics;

      /* Information in the font for underlining */
      int underline_offset;
      int underline_height;

      /* Cache for style-transformed glyphs */
      c_glyph *current;
      c_glyph cache[256];
      c_glyph scratch;

      /* We are responsible for closing the font stream */
      SDL_RWops *src;
      int freesrc;
      FT_Open_Args args;

      /* For non-scalable formats, we must remember which font index size */
      int font_size_family;
};

/* The FreeType font engine/library */
static FT_Library library;
static int TTF_initialized = 0;
static int TTF_byteswapped = 0;

/* UNICODE string utilities */
static __inline__ int UNICODE_strlen(const Uint16 *text)
{
      int size = 0;
      while ( *text++ ) {
            ++size;
      }
      return size;
}
static __inline__ void UNICODE_strcpy(Uint16 *dst, const Uint16 *src, int swap)
{
      if ( swap ) {
            while ( *src ) {
                  *dst = SDL_Swap16(*src);
                  ++src;
                  ++dst;
            }
            *dst = '\0';
      } else {
            while ( *src ) {
                  *dst = *src;
                  ++src;
                  ++dst;
            }
            *dst = '\0';
      }
}

/* rcg06192001 get linked library's version. */
const SDL_version *TTF_Linked_Version(void)
{
      static SDL_version linked_version;
      TTF_VERSION(&linked_version);
      return(&linked_version);
}

/* This function tells the library whether UNICODE text is generally
   byteswapped.  A UNICODE BOM character at the beginning of a string
   will override this setting for that string.
 */
void TTF_ByteSwappedUNICODE(int swapped)
{
      TTF_byteswapped = swapped;
}

static void TTF_SetFTError(const char *msg, FT_Error error)
{
#ifdef USE_FREETYPE_ERRORS
#undef FTERRORS_H
#define FT_ERRORDEF( e, v, s )  { e, s },
      static const struct
      {
        int          err_code;
        const char*  err_msg;
      } ft_errors[] = {
#include <freetype/fterrors.h>
      };
      int i;
      const char *err_msg;
      char buffer[1024];

      err_msg = NULL;
      for ( i=0; i<((sizeof ft_errors)/(sizeof ft_errors[0])); ++i ) {
            if ( error == ft_errors[i].err_code ) {
                  err_msg = ft_errors[i].err_msg;
                  break;
            }
      }
      if ( ! err_msg ) {
            err_msg = "unknown FreeType error";
      }
      sprintf(buffer, "%s: %s", msg, err_msg);
      TTF_SetError(buffer);
#else
      TTF_SetError(msg);
#endif /* USE_FREETYPE_ERRORS */
}

int TTF_Init( void )
{
      int status = 0;

      if ( ! TTF_initialized ) {
            FT_Error error = FT_Init_FreeType( &library );
            if ( error ) {
                  TTF_SetFTError("Couldn't init FreeType engine", error);
                  status = -1;
            }
      }
      if ( status == 0 ) {
            ++TTF_initialized;
      }
      return status;
}

static unsigned long RWread(
      FT_Stream stream,
      unsigned long offset,
      unsigned char* buffer,
      unsigned long count
)
{
      SDL_RWops *src;

      src = (SDL_RWops *)stream->descriptor.pointer;
      SDL_RWseek( src, (int)offset, SEEK_SET );
      return SDL_RWread( src, buffer, 1, (int)count );
}

TTF_Font* TTF_OpenFontIndexRW( SDL_RWops *src, int freesrc, int ptsize, long index )
{
      TTF_Font* font;
      FT_Error error;
      FT_Face face;
      FT_Fixed scale;
      FT_Stream stream;
      int position;

      if ( ! TTF_initialized ) {
            TTF_SetError( "Library not initialized" );
            return NULL;
      }

    if (src == NULL) {
        return NULL;
    }

      /* Check to make sure we can seek in this stream */
      position = SDL_RWtell(src);
      if ( position < 0 ) {
            TTF_SetError( "Can't seek in stream" );
            return NULL;
      }

      font = (TTF_Font*) malloc(sizeof *font);
      if ( font == NULL ) {
            TTF_SetError( "Out of memory" );
            return NULL;
      }
      memset(font, 0, sizeof(*font));

      font->src = src;
      font->freesrc = freesrc;

      stream = (FT_Stream)malloc(sizeof(*stream));
      if ( stream == NULL ) {
            TTF_SetError( "Out of memory" );
            TTF_CloseFont( font );
            return NULL;
      }
      memset(stream, 0, sizeof(*stream));

      stream->memory = library->memory;
      stream->read = RWread;
      stream->descriptor.pointer = src;
      stream->pos = (unsigned long)position;
      SDL_RWseek(src, 0, SEEK_END);
      stream->size = (unsigned long)(SDL_RWtell(src) - position);
      SDL_RWseek(src, position, SEEK_SET);

      font->args.flags = ft_open_stream;
      font->args.stream = stream;

      error = FT_Open_Face( library, &font->args, index, &font->face );
      if( error ) {
            TTF_SetFTError( "Couldn't load font file", error );
            TTF_CloseFont( font );
            return NULL;
      }
      face = font->face;

      /* Make sure that our font face is scalable (global metrics) */
      if ( FT_IS_SCALABLE(face) ) {

            /* Set the character size and use default DPI (72) */
            error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 0, 0 );
                  if( error ) {
            TTF_SetFTError( "Couldn't set font size", error );
            TTF_CloseFont( font );
            return NULL;
        }

        /* Get the scalable font metrics for this font */
        scale = face->size->metrics.y_scale;
        font->ascent  = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
        font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
        font->height  = font->ascent - font->descent + /* baseline */ 1;
        font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
        font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
        font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));

      } else {
            /* Non-scalable font case.  ptsize determines which family
             * or series of fonts to grab from the non-scalable format.
             * It is not the point size of the font.
             * */
            if ( ptsize >= font->face->num_fixed_sizes )
                  ptsize = font->face->num_fixed_sizes - 1;
            font->font_size_family = ptsize;
            error = FT_Set_Pixel_Sizes( face,
                        face->available_sizes[ptsize].height,
                        face->available_sizes[ptsize].width );
            /* With non-scalale fonts, Freetype2 likes to fill many of the
             * font metrics with the value of 0.  The size of the
             * non-scalable fonts must be determined differently
             * or sometimes cannot be determined.
             * */
            font->ascent = face->available_sizes[ptsize].height;
            font->descent = 0;
            font->height = face->available_sizes[ptsize].height;
            font->lineskip = FT_CEIL(font->ascent);
            font->underline_offset = FT_FLOOR(face->underline_position);
            font->underline_height = FT_FLOOR(face->underline_thickness);
      }

      if ( font->underline_height < 1 ) {
            font->underline_height = 1;
      }

#ifdef DEBUG_FONTS
      printf("Font metrics:\n");
      printf("\tascent = %d, descent = %d\n",
            font->ascent, font->descent);
      printf("\theight = %d, lineskip = %d\n",
            font->height, font->lineskip);
      printf("\tunderline_offset = %d, underline_height = %d\n",
            font->underline_offset, font->underline_height);
#endif

      /* Set the default font style */
      font->style = TTF_STYLE_NORMAL;
      font->glyph_overhang = face->size->metrics.y_ppem / 10;
      /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
      font->glyph_italics = 0.207f;
      font->glyph_italics *= font->height;

      return font;
}

TTF_Font* TTF_OpenFontRW( SDL_RWops *src, int freesrc, int ptsize )
{
      return TTF_OpenFontIndexRW(src, freesrc, ptsize, 0);
}

TTF_Font* TTF_OpenFontIndex( const char *file, int ptsize, long index )
{
      return TTF_OpenFontIndexRW(SDL_RWFromFile(file, "rb"), 1, ptsize, index);
}

TTF_Font* TTF_OpenFont( const char *file, int ptsize )
{
      return TTF_OpenFontIndex(file, ptsize, 0);
}

static void Flush_Glyph( c_glyph* glyph )
{
      glyph->stored = 0;
      glyph->index = 0;
      if( glyph->bitmap.buffer ) {
            free( glyph->bitmap.buffer );
            glyph->bitmap.buffer = 0;
      }
      if( glyph->pixmap.buffer ) {
            free( glyph->pixmap.buffer );
            glyph->pixmap.buffer = 0;
      }
      glyph->cached = 0;
}

static void Flush_Cache( TTF_Font* font )
{
      int i;
      int size = sizeof( font->cache ) / sizeof( font->cache[0] );

      for( i = 0; i < size; ++i ) {
            if( font->cache[i].cached ) {
                  Flush_Glyph( &font->cache[i] );
            }

      }
      if( font->scratch.cached ) {
            Flush_Glyph( &font->scratch );
      }

}

static FT_Error Load_Glyph( TTF_Font* font, Uint16 ch, c_glyph* cached, int want )
{
      FT_Face face;
      FT_Error error;
      FT_GlyphSlot glyph;
      FT_Glyph_Metrics* metrics;
      FT_Outline* outline;

      if ( !font || !font->face ) {
            return FT_Err_Invalid_Handle;
      }

      face = font->face;

      /* Load the glyph */
      if ( ! cached->index ) {
            cached->index = FT_Get_Char_Index( face, ch );
      }
      error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT );
      if( error ) {
            return error;
      }

      /* Get our glyph shortcuts */
      glyph = face->glyph;
      metrics = &glyph->metrics;
      outline = &glyph->outline;

      /* Get the glyph metrics if desired */
      if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) {
            if ( FT_IS_SCALABLE( face ) ) {
                  /* Get the bounding box */
                  cached->minx = FT_FLOOR(metrics->horiBearingX);
                  cached->maxx = cached->minx + FT_CEIL(metrics->width);
                  cached->maxy = FT_FLOOR(metrics->horiBearingY);
                  cached->miny = cached->maxy - FT_CEIL(metrics->height);
                  cached->yoffset = font->ascent - cached->maxy;
                  cached->advance = FT_CEIL(metrics->horiAdvance);
            } else {
                  /* Get the bounding box for non-scalable format.
                   * Again, freetype2 fills in many of the font metrics
                   * with the value of 0, so some of the values we
                   * need must be calculated differently with certain
                   * assumptions about non-scalable formats.
                   * */
                  cached->minx = FT_FLOOR(metrics->horiBearingX);
                  cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance);
                  cached->maxy = FT_FLOOR(metrics->horiBearingY);
                  cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height);
                  cached->yoffset = 0;
                  cached->advance = FT_CEIL(metrics->horiAdvance);
            }

            /* Adjust for bold and italic text */
            if( font->style & TTF_STYLE_BOLD ) {
                  cached->maxx += font->glyph_overhang;
            }
            if( font->style & TTF_STYLE_ITALIC ) {
                  cached->maxx += (int)ceil(font->glyph_italics);
            }
            cached->stored |= CACHED_METRICS;
      }

      if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
           ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) {
            int mono = (want & CACHED_BITMAP);
            int i;
            FT_Bitmap* src;
            FT_Bitmap* dst;

            /* Handle the italic style */
            if( font->style & TTF_STYLE_ITALIC ) {
                  FT_Matrix shear;

                  shear.xx = 1 << 16;
                  shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height;
                  shear.yx = 0;
                  shear.yy = 1 << 16;

                  FT_Outline_Transform( outline, &shear );
            }

            /* Render the glyph */
            if ( mono ) {
                  error = FT_Render_Glyph( glyph, ft_render_mode_mono );
            } else {
                  error = FT_Render_Glyph( glyph, ft_render_mode_normal );
            }
            if( error ) {
                  return error;
            }

            /* Copy over information to cache */
            src = &glyph->bitmap;
            if ( mono ) {
                  dst = &cached->bitmap;
            } else {
                  dst = &cached->pixmap;
            }
            memcpy( dst, src, sizeof( *dst ) );

            /* FT_Render_Glyph() and .fon fonts always generate a
             * two-color (black and white) glyphslot surface, even
             * when rendered in ft_render_mode_normal.  This is probably
             * a freetype2 bug because it is inconsistent with the
             * freetype2 documentation under FT_Render_Mode section.
             * */
            if ( mono || !FT_IS_SCALABLE(face) ) {
                  dst->pitch *= 8;
            }

            /* Adjust for bold and italic text */
            if( font->style & TTF_STYLE_BOLD ) {
                  int bump = font->glyph_overhang;
                  dst->pitch += bump;
                  dst->width += bump;
            }
            if( font->style & TTF_STYLE_ITALIC ) {
                  int bump = (int)ceil(font->glyph_italics);
                  dst->pitch += bump;
                  dst->width += bump;
            }

            if (dst->rows != 0) {
                  dst->buffer = malloc( dst->pitch * dst->rows );
                  if( !dst->buffer ) {
                        return FT_Err_Out_Of_Memory;
                  }
                  memset( dst->buffer, 0, dst->pitch * dst->rows );

                  for( i = 0; i < src->rows; i++ ) {
                        int soffset = i * src->pitch;
                        int doffset = i * dst->pitch;
                        if ( mono ) {
                              unsigned char *srcp = src->buffer + soffset;
                              unsigned char *dstp = dst->buffer + doffset;
                              int j;
                              for ( j = 0; j < src->width; j += 8 ) {
                                    unsigned char ch = *srcp++;
                                    *dstp++ = (ch&0x80) >> 7;
                                    ch <<= 1;
                                    *dstp++ = (ch&0x80) >> 7;
                                    ch <<= 1;
                                    *dstp++ = (ch&0x80) >> 7;
                                    ch <<= 1;
                                    *dstp++ = (ch&0x80) >> 7;
                                    ch <<= 1;
                                    *dstp++ = (ch&0x80) >> 7;
                                    ch <<= 1;
                                    *dstp++ = (ch&0x80) >> 7;
                                    ch <<= 1;
                                    *dstp++ = (ch&0x80) >> 7;
                                    ch <<= 1;
                                    *dstp++ = (ch&0x80) >> 7;
                              }
                        } else if ( !FT_IS_SCALABLE(face) ) {
                              /* This special case wouldn't
                               * be here if the FT_Render_Glyph()
                               * function wasn't buggy when it tried
                               * to render a .fon font with 256
                               * shades of gray.  Instead, it
                               * returns a black and white surface
                               * and we have to translate it back
                               * to a 256 gray shaded surface.
                               * */
                              unsigned char *srcp = src->buffer + soffset;
                              unsigned char *dstp = dst->buffer + doffset;
                              unsigned char ch;
                              int j, k;
                              for ( j = 0; j < src->width; j += 8) {
                                    ch = *srcp++;
                                    for (k = 0; k < 8; ++k) {
                                          if ((ch&0x80) >> 7) {
                                                *dstp++ = NUM_GRAYS - 1;
                                          } else {
                                                *dstp++ = 0x00;
                                          }
                                          ch <<= 1;
                                    }
                              }
                        } else {
                              memcpy(dst->buffer+doffset,
                                     src->buffer+soffset, src->pitch);
                        }
                  }
            }

            /* Handle the bold style */
            if ( font->style & TTF_STYLE_BOLD ) {
                  int row;
                  int col;
                  int offset;
                  int pixel;
                  Uint8* pixmap;

                  /* The pixmap is a little hard, we have to add and clamp */
                  for( row = dst->rows - 1; row >= 0; --row ) {
                        pixmap = (Uint8*) dst->buffer + row * dst->pitch;
                        for( offset=1; offset <= font->glyph_overhang; ++offset ) {
                              for( col = dst->width - 1; col > 0; --col ) {
                                    pixel = (pixmap[col] + pixmap[col-1]);
                                    if( pixel > NUM_GRAYS - 1 ) {
                                          pixel = NUM_GRAYS - 1;
                                    }
                                    pixmap[col] = (Uint8) pixel;
                              }
                        }
                  }
            }

            /* Mark that we rendered this format */
            if ( mono ) {
                  cached->stored |= CACHED_BITMAP;
            } else {
                  cached->stored |= CACHED_PIXMAP;
            }
      }

      /* We're done, mark this glyph cached */
      cached->cached = ch;

      return 0;
}

static FT_Error Find_Glyph( TTF_Font* font, Uint16 ch, int want )
{
      int retval = 0;

      if( ch < 256 ) {
            font->current = &font->cache[ch];
      } else {
            if ( font->scratch.cached != ch ) {
                  Flush_Glyph( &font->scratch );
            }
            font->current = &font->scratch;
      }
      if ( (font->current->stored & want) != want ) {
            retval = Load_Glyph( font, ch, font->current, want );
      }
      return retval;
}

void TTF_CloseFont( TTF_Font* font )
{
      Flush_Cache( font );
      if ( font->face ) {
            FT_Done_Face( font->face );
      }
      if ( font->args.stream ) {
            free( font->args.stream );
      }
      if ( font->freesrc ) {
            SDL_RWclose( font->src );
      }
      free( font );
}

static Uint16 *LATIN1_to_UNICODE(Uint16 *unicode, const char *text, int len)
{
      int i;

      for ( i=0; i < len; ++i ) {
            unicode[i] = ((const unsigned char *)text)[i];
      }
      unicode[i] = 0;

      return unicode;
}

static Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len)
{
      int i, j;
      Uint16 ch;

      for ( i=0, j=0; i < len; ++i, ++j ) {
            ch = ((const unsigned char *)utf8)[i];
            if ( ch >= 0xF0 ) {
                  ch  =  (Uint16)(utf8[i]&0x07) << 18;
                  ch |=  (Uint16)(utf8[++i]&0x3F) << 12;
                  ch |=  (Uint16)(utf8[++i]&0x3F) << 6;
                  ch |=  (Uint16)(utf8[++i]&0x3F);
            } else
            if ( ch >= 0xE0 ) {
                  ch  =  (Uint16)(utf8[i]&0x3F) << 12;
                  ch |=  (Uint16)(utf8[++i]&0x3F) << 6;
                  ch |=  (Uint16)(utf8[++i]&0x3F);
            } else
            if ( ch >= 0xC0 ) {
                  ch  =  (Uint16)(utf8[i]&0x3F) << 6;
                  ch |=  (Uint16)(utf8[++i]&0x3F);
            }
            unicode[j] = ch;
      }
      unicode[j] = 0;

      return unicode;
}

int TTF_FontHeight(TTF_Font *font)
{
      return(font->height);
}

int TTF_FontAscent(TTF_Font *font)
{
       return(font->ascent);
}

int TTF_FontDescent(TTF_Font *font)
{
      return(font->descent);
}

int TTF_FontLineSkip(TTF_Font *font)
{
      return(font->lineskip);
}

long TTF_FontFaces(TTF_Font *font)
{
      return(font->face->num_faces);
}

int TTF_FontFaceIsFixedWidth(TTF_Font *font)
{
      return(FT_IS_FIXED_WIDTH(font->face));
}

char *TTF_FontFaceFamilyName(TTF_Font *font)
{
      return(font->face->family_name);
}

char *TTF_FontFaceStyleName(TTF_Font *font)
{
      return(font->face->style_name);
}

int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch,
                     int* minx, int* maxx, int* miny, int* maxy, int* advance)
{
      FT_Error error;

      error = Find_Glyph(font, ch, CACHED_METRICS);
      if ( error ) {
            TTF_SetFTError("Couldn't find glyph", error);
            return -1;
      }

      if ( minx ) {
            *minx = font->current->minx;
      }
      if ( maxx ) {
            *maxx = font->current->maxx;
      }
      if ( miny ) {
            *miny = font->current->miny;
      }
      if ( maxy ) {
            *maxy = font->current->maxy;
      }
      if ( advance ) {
            *advance = font->current->advance;
      }
      return 0;
}

int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h)
{
      Uint16 *unicode_text;
      int unicode_len;
      int status;

      /* Copy the Latin-1 text to a UNICODE text buffer */
      unicode_len = strlen(text);
      unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
      if ( unicode_text == NULL ) {
            TTF_SetError("Out of memory");
            return -1;
      }
      *unicode_text = UNICODE_BOM_NATIVE;
      LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);

      /* Render the new text */
      status = TTF_SizeUNICODE(font, unicode_text, w, h);

      /* Free the text buffer and return */
      FREEA(unicode_text);
      return status;
}

int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h)
{
      Uint16 *unicode_text;
      int unicode_len;
      int status;

      /* Copy the UTF-8 text to a UNICODE text buffer */
      unicode_len = strlen(text);
      unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
      if ( unicode_text == NULL ) {
            TTF_SetError("Out of memory");
            return -1;
      }
      *unicode_text = UNICODE_BOM_NATIVE;
      UTF8_to_UNICODE(unicode_text+1, text, unicode_len);

      /* Render the new text */
      status = TTF_SizeUNICODE(font, unicode_text, w, h);

      /* Free the text buffer and return */
      FREEA(unicode_text);
      return status;
}

int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h)
{
      int status;
      const Uint16 *ch;
      int swapped;
      int x, z;
      int minx, maxx;
      int miny, maxy;
      c_glyph *glyph;
      FT_Error error;

      /* Initialize everything to 0 */
      if ( ! TTF_initialized ) {
            TTF_SetError( "Library not initialized" );
            return -1;
      }
      status = 0;
      minx = maxx = 0;
      miny = maxy = 0;
      swapped = TTF_byteswapped;

      /* Load each character and sum it's bounding box */
      x= 0;
      for ( ch=text; *ch; ++ch ) {
            Uint16 c = *ch;
            if ( c == UNICODE_BOM_NATIVE ) {
                  swapped = 0;
                  if ( text == ch ) {
                        ++text;
                  }
                  continue;
            }
            if ( c == UNICODE_BOM_SWAPPED ) {
                  swapped = 1;
                  if ( text == ch ) {
                        ++text;
                  }
                  continue;
            }
            if ( swapped ) {
                  c = SDL_Swap16(c);
            }

            error = Find_Glyph(font, c, CACHED_METRICS);
            if ( error ) {
                  return -1;
            }
            glyph = font->current;

            if ( (ch == text) && (glyph->minx < 0) ) {
            /* Fixes the texture wrapping bug when the first letter
             * has a negative minx value or horibearing value.  The entire
             * bounding box must be adjusted to be bigger so the entire
             * letter can fit without any texture corruption or wrapping.
             *
             * Effects: First enlarges bounding box.
             * Second, xstart has to start ahead of its normal spot in the
             * negative direction of the negative minx value.
             * (pushes everything to the right).
             *
             * This will make the memory copy of the glyph bitmap data
             * work out correctly.
             * */
                  z -= glyph->minx;

            }

            z = x + glyph->minx;
            if ( minx > z ) {
                  minx = z;
            }
            if ( font->style & TTF_STYLE_BOLD ) {
                  x += font->glyph_overhang;
            }
            if ( glyph->advance > glyph->maxx ) {
                  z = x + glyph->advance;
            } else {
                  z = x + glyph->maxx;
            }
            if ( maxx < z ) {
                  maxx = z;
            }
            x += glyph->advance;

            if ( glyph->miny < miny ) {
                  miny = glyph->miny;
            }
            if ( glyph->maxy > maxy ) {
                  maxy = glyph->maxy;
            }
      }

      /* Fill the bounds rectangle */
      if ( w ) {
            *w = (maxx - minx);
      }
      if ( h ) {
#if 0 /* This is correct, but breaks many applications */
            *h = (maxy - miny);
#else
            *h = font->height;
#endif
      }
      return status;
}

/* Convert the Latin-1 text to UNICODE and render it
*/
SDL_Surface *TTF_RenderText_Solid(TTF_Font *font,
                        const char *text, SDL_Color fg)
{
      SDL_Surface *textbuf;
      Uint16 *unicode_text;
      int unicode_len;

      /* Copy the Latin-1 text to a UNICODE text buffer */
      unicode_len = strlen(text);
      unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
      if ( unicode_text == NULL ) {
            TTF_SetError("Out of memory");
            return(NULL);
      }
      *unicode_text = UNICODE_BOM_NATIVE;
      LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);

      /* Render the new text */
      textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg);

      /* Free the text buffer and return */
      FREEA(unicode_text);
      return(textbuf);
}

/* Convert the UTF-8 text to UNICODE and render it
*/
SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font,
                        const char *text, SDL_Color fg)
{
      SDL_Surface *textbuf;
      Uint16 *unicode_text;
      int unicode_len;

      /* Copy the UTF-8 text to a UNICODE text buffer */
      unicode_len = strlen(text);
      unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
      if ( unicode_text == NULL ) {
            TTF_SetError("Out of memory");
            return(NULL);
      }
      *unicode_text = UNICODE_BOM_NATIVE;
      UTF8_to_UNICODE(unicode_text, text, unicode_len);

      /* Render the new text */
      textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg);

      /* Free the text buffer and return */
      FREEA(unicode_text);
      return(textbuf);
}

SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font,
                        const Uint16 *text, SDL_Color fg)
{
      int xstart;
      int width;
      int height;
      SDL_Surface* textbuf;
      SDL_Palette* palette;
      const Uint16* ch;
      Uint8* src;
      Uint8* dst;
      int swapped;
      int row, col;
      c_glyph *glyph;
      FT_Bitmap *current;
      FT_Error error;

      /* Get the dimensions of the text surface */
      if( ( TTF_SizeUNICODE(font, text, &width, NULL) < 0 ) || !width ) {
            TTF_SetError( "Text has zero width" );
            return NULL;
      }
      height = font->height;

      /* Create the target surface */
      textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
      if( textbuf == NULL ) {
            return NULL;
      }

      /* Fill the palette with the foreground color */
      palette = textbuf->format->palette;
      palette->colors[0].r = 255 - fg.r;
      palette->colors[0].g = 255 - fg.g;
      palette->colors[0].b = 255 - fg.b;
      palette->colors[1].r = fg.r;
      palette->colors[1].g = fg.g;
      palette->colors[1].b = fg.b;
      SDL_SetColorKey( textbuf, SDL_SRCCOLORKEY, 0 );

      /* Load and render each character */
      xstart = 0;
      swapped = TTF_byteswapped;
      for( ch=text; *ch; ++ch ) {
            Uint16 c = *ch;
            if ( c == UNICODE_BOM_NATIVE ) {
                  swapped = 0;
                  if ( text == ch ) {
                        ++text;
                  }
                  continue;
            }
            if ( c == UNICODE_BOM_SWAPPED ) {
                  swapped = 1;
                  if ( text == ch ) {
                        ++text;
                  }
                  continue;
            }
            if ( swapped ) {
                  c = SDL_Swap16(c);
            }

            error = Find_Glyph(font, c, CACHED_METRICS|CACHED_BITMAP);
            if( error ) {
                  SDL_FreeSurface( textbuf );
                  return NULL;
            }
            glyph = font->current;
            current = &glyph->bitmap;
            /* Compensate for wrap around bug with negative minx's */
            if ( (ch == text) && (glyph->minx < 0) ) {
                  xstart -= glyph->minx;
            }

            for( row = 0; row < current->rows; ++row ) {
                  /* Make sure we don't go over the limit */
                  if ( row+glyph->yoffset >= textbuf->h ) {
                        continue;
                  }
                  dst = (Uint8*) textbuf->pixels +
                        (row+glyph->yoffset) * textbuf->pitch +
                        xstart + glyph->minx;
                  src = current->buffer + row * current->pitch;

                  for ( col=current->width; col>0; --col ) {
                        *dst++ |= *src++;
                  }
            }

            xstart += glyph->advance;
            if ( font->style & TTF_STYLE_BOLD ) {
                  xstart += font->glyph_overhang;
            }
      }

      /* Handle the underline style */
      if( font->style & TTF_STYLE_UNDERLINE ) {
            row = font->ascent - font->underline_offset - 1;
            if ( row >= textbuf->h) {
                  row = (textbuf->h-1) - font->underline_height;
            }
            dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
            for ( row=font->underline_height; row>0; --row ) {
                  /* 1 because 0 is the bg color */
                  memset( dst, 1, textbuf->w );
                  dst += textbuf->pitch;
            }
      }
      return textbuf;
}

SDL_Surface *TTF_RenderGlyph_Solid(TTF_Font *font, Uint16 ch, SDL_Color fg)
{
      SDL_Surface *textbuf;
      SDL_Palette *palette;
      Uint8 *src, *dst;
      int row;
      FT_Error error;
      c_glyph *glyph;

      /* Get the glyph itself */
      error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_BITMAP);
      if ( error ) {
            return(NULL);
      }
      glyph = font->current;

      /* Create the target surface */
      textbuf = SDL_CreateRGBSurface( SDL_SWSURFACE,
                              glyph->bitmap.pitch,
                              glyph->bitmap.rows,
                              8, 0, 0, 0, 0 );
      if ( ! textbuf ) {
            return(NULL);
      }

      /* Fill the palette with the foreground color */
      palette = textbuf->format->palette;
      palette->colors[0].r = 255-fg.r;
      palette->colors[0].g = 255-fg.g;
      palette->colors[0].b = 255-fg.b;
      palette->colors[1].r = fg.r;
      palette->colors[1].g = fg.g;
      palette->colors[1].b = fg.b;
      SDL_SetColorKey(textbuf, SDL_SRCCOLORKEY, 0);

      /* Copy the character from the pixmap */
      src = glyph->bitmap.buffer;
      dst = (Uint8*) textbuf->pixels;
      for ( row = 0; row < textbuf->h; ++row ) {
            memcpy( dst, src, glyph->bitmap.pitch );
            src += glyph->bitmap.pitch;
            dst += textbuf->pitch;
      }

      /* Handle the underline style */
      if( font->style & TTF_STYLE_UNDERLINE ) {
            row = font->ascent - font->underline_offset - 1;
            if ( row >= textbuf->h) {
                  row = (textbuf->h-1) - font->underline_height;
            }
            dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
            for ( row=font->underline_height; row>0; --row ) {
                  /* 1 because 0 is the bg color */
                  memset( dst, 1, textbuf->w );
                  dst += textbuf->pitch;
            }
      }
      return(textbuf);
}


/* Convert the Latin-1 text to UNICODE and render it
*/
SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font,
                        const char *text, SDL_Color fg, SDL_Color bg)
{
      SDL_Surface *textbuf;
      Uint16 *unicode_text;
      int unicode_len;

      /* Copy the Latin-1 text to a UNICODE text buffer */
      unicode_len = strlen(text);
      unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
      if ( unicode_text == NULL ) {
            TTF_SetError("Out of memory");
            return(NULL);
      }
      *unicode_text = UNICODE_BOM_NATIVE;
      LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);

      /* Render the new text */
      textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg);

      /* Free the text buffer and return */
      FREEA(unicode_text);
      return(textbuf);
}

/* Convert the UTF-8 text to UNICODE and render it
*/
SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font,
                        const char *text, SDL_Color fg, SDL_Color bg)
{
      SDL_Surface *textbuf;
      Uint16 *unicode_text;
      int unicode_len;

      /* Copy the UTF-8 text to a UNICODE text buffer */
      unicode_len = strlen(text);
      unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
      if ( unicode_text == NULL ) {
            TTF_SetError("Out of memory");
            return(NULL);
      }
      *unicode_text = UNICODE_BOM_NATIVE;
      UTF8_to_UNICODE(unicode_text+1, text, unicode_len);

      /* Render the new text */
      textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg);

      /* Free the text buffer and return */
      FREEA(unicode_text);
      return(textbuf);
}

SDL_Surface* TTF_RenderUNICODE_Shaded( TTF_Font* font,
                               const Uint16* text,
                               SDL_Color fg,
                               SDL_Color bg )
{
      int xstart;
      int width;
      int height;
      SDL_Surface* textbuf;
      SDL_Palette* palette;
      int index;
      int rdiff;
      int gdiff;
      int bdiff;
      const Uint16* ch;
      Uint8* src;
      Uint8* dst;
      int swapped;
      int row, col;
      FT_Bitmap* current;
      c_glyph *glyph;
      FT_Error error;

      /* Get the dimensions of the text surface */
      if( ( TTF_SizeUNICODE(font, text, &width, NULL) < 0 ) || !width ) {
            TTF_SetError("Text has zero width");
            return NULL;
      }
      height = font->height;

      /* Create the target surface */
      textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
      if( textbuf == NULL ) {
            return NULL;
      }

      /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
      palette = textbuf->format->palette;
      rdiff = fg.r - bg.r;
      gdiff = fg.g - bg.g;
      bdiff = fg.b - bg.b;

      for( index = 0; index < NUM_GRAYS; ++index ) {
            palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1);
            palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1);
            palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1);
      }

      /* Load and render each character */
      xstart = 0;
      swapped = TTF_byteswapped;
      for( ch = text; *ch; ++ch ) {
            Uint16 c = *ch;
            if ( c == UNICODE_BOM_NATIVE ) {
                  swapped = 0;
                  if ( text == ch ) {
                        ++text;
                  }
                  continue;
            }
            if ( c == UNICODE_BOM_SWAPPED ) {
                  swapped = 1;
                  if ( text == ch ) {
                        ++text;
                  }
                  continue;
            }
            if ( swapped ) {
                  c = SDL_Swap16(c);
            }

            error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP);
            if( error ) {
                  SDL_FreeSurface( textbuf );
                  return NULL;
            }
            glyph = font->current;
            /* Compensate for the wrap around with negative minx's */
            if ( (ch == text) && (glyph->minx < 0) ) {
                  xstart -= glyph->minx;
            }

            current = &glyph->pixmap;
            for( row = 0; row < current->rows; ++row ) {
                  /* Make sure we don't go over the limit */
                  if ( row+glyph->yoffset >= textbuf->h ) {
                        continue;
                  }
                  dst = (Uint8*) textbuf->pixels +
                        (row+glyph->yoffset) * textbuf->pitch +
                        xstart + glyph->minx;
                  src = current->buffer + row * current->pitch;
                  for ( col=current->width; col>0; --col ) {
                        *dst++ |= *src++;
                  }
            }

            xstart += glyph->advance;
            if( font->style & TTF_STYLE_BOLD ) {
                  xstart += font->glyph_overhang;
            }
      }

      /* Handle the underline style */
      if( font->style & TTF_STYLE_UNDERLINE ) {
            row = font->ascent - font->underline_offset - 1;
            if ( row >= textbuf->h) {
                  row = (textbuf->h-1) - font->underline_height;
            }
            dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
            for ( row=font->underline_height; row>0; --row ) {
                  memset( dst, NUM_GRAYS - 1, textbuf->w );
                  dst += textbuf->pitch;
            }
      }
      return textbuf;
}

SDL_Surface* TTF_RenderGlyph_Shaded( TTF_Font* font,
                             Uint16 ch,
                             SDL_Color fg,
                             SDL_Color bg )
{
      SDL_Surface* textbuf;
      SDL_Palette* palette;
      int index;
      int rdiff;
      int gdiff;
      int bdiff;
      Uint8* src;
      Uint8* dst;
      int row;
      FT_Error error;
      c_glyph* glyph;

      /* Get the glyph itself */
      error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_PIXMAP);
      if( error ) {
            return NULL;
      }
      glyph = font->current;

      /* Create the target surface */
      textbuf = SDL_CreateRGBSurface( SDL_SWSURFACE,
                              glyph->pixmap.width,
                              glyph->pixmap.rows,
                              8, 0, 0, 0, 0 );
      if( !textbuf ) {
            return NULL;
      }

      /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
      palette = textbuf->format->palette;
      rdiff = fg.r - bg.r;
      gdiff = fg.g - bg.g;
      bdiff = fg.b - bg.b;
      for( index = 0; index < NUM_GRAYS; ++index ) {
            palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1);
            palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1);
            palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1);
      }

      /* Copy the character from the pixmap */
      src = glyph->pixmap.buffer;
      dst = (Uint8*) textbuf->pixels;
      for ( row = 0; row < textbuf->h; ++row ) {
            memcpy( dst, src, glyph->pixmap.pitch );
            src += glyph->pixmap.pitch;
            dst += textbuf->pitch;
      }

      /* Handle the underline style */
      if( font->style & TTF_STYLE_UNDERLINE ) {
            row = font->ascent - font->underline_offset - 1;
            if ( row >= textbuf->h) {
                  row = (textbuf->h-1) - font->underline_height;
            }
            dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
            for ( row=font->underline_height; row>0; --row ) {
                  memset( dst, NUM_GRAYS - 1, textbuf->w );
                  dst += textbuf->pitch;
            }
      }
      return textbuf;
}

/* Convert the Latin-1 text to UNICODE and render it
*/
SDL_Surface *TTF_RenderText_Blended(TTF_Font *font,
                        const char *text, SDL_Color fg)
{
      SDL_Surface *textbuf;
      Uint16 *unicode_text;
      int unicode_len;

      /* Copy the Latin-1 text to a UNICODE text buffer */
      unicode_len = strlen(text);
      unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
      if ( unicode_text == NULL ) {
            TTF_SetError("Out of memory");
            return(NULL);
      }
      *unicode_text = UNICODE_BOM_NATIVE;
      LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);

      /* Render the new text */
      textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg);

      /* Free the text buffer and return */
      FREEA(unicode_text);
      return(textbuf);
}

/* Convert the UTF-8 text to UNICODE and render it
*/
SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
                        const char *text, SDL_Color fg)
{
      SDL_Surface *textbuf;
      Uint16 *unicode_text;
      int unicode_len;

      /* Copy the UTF-8 text to a UNICODE text buffer */
      unicode_len = strlen(text);
      unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
      if ( unicode_text == NULL ) {
            TTF_SetError("Out of memory");
            return(NULL);
      }
      *unicode_text = UNICODE_BOM_NATIVE;
      UTF8_to_UNICODE(unicode_text+1, text, unicode_len);

      /* Render the new text */
      textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg);

      /* Free the text buffer and return */
      FREEA(unicode_text);
      return(textbuf);
}

SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font,
                        const Uint16 *text, SDL_Color fg)
{
      int xstart;
      int width, height;
      SDL_Surface *textbuf;
      Uint32 alpha;
      Uint32 pixel;
      const Uint16 *ch;
      Uint8 *src;
      Uint32 *dst;
      int swapped;
      int row, col;
      c_glyph *glyph;
      FT_Error error;

      /* Get the dimensions of the text surface */
      if ( (TTF_SizeUNICODE(font, text, &width, NULL) < 0) || !width ) {
            TTF_SetError("Text has zero width");
            return(NULL);
      }
      height = font->height;

      textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 32,
                  0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
      if ( textbuf == NULL ) {
            return(NULL);
      }

      /* Load and render each character */
      xstart = 0;
      swapped = TTF_byteswapped;
      pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
      for ( ch=text; *ch; ++ch ) {
            Uint16 c = *ch;
            if ( c == UNICODE_BOM_NATIVE ) {
                  swapped = 0;
                  if ( text == ch ) {
                        ++text;
                  }
                  continue;
            }
            if ( c == UNICODE_BOM_SWAPPED ) {
                  swapped = 1;
                  if ( text == ch ) {
                        ++text;
                  }
                  continue;
            }
            if ( swapped ) {
                  c = SDL_Swap16(c);
            }
            error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP);
            if( error ) {
                  SDL_FreeSurface( textbuf );
                  return NULL;
            }
            glyph = font->current;
            width = glyph->pixmap.width;
            /* Compensate for the wrap around bug with negative minx's */
            if ( (ch == text) && (glyph->minx < 0) ) {
                  xstart -= glyph->minx;
            }

            for ( row = 0; row < glyph->pixmap.rows; ++row ) {
                  /* Make sure we don't go over the limit */
                  if ( row+glyph->yoffset >= textbuf->h ) {
                        continue;
                  }
                  dst = (Uint32*) textbuf->pixels +
                        (row+glyph->yoffset) * textbuf->pitch/4 +
                        xstart + glyph->minx;
                  /* Added code to adjust src pointer for pixmaps to
                   * account for pitch.
                   * */
                  src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row);
                  for ( col = width; col>0; --col) {
                        alpha = *src++;
                        *dst++ |= pixel | (alpha << 24);
                  }
            }

            xstart += glyph->advance;
            if ( font->style & TTF_STYLE_BOLD ) {
                  xstart += font->glyph_overhang;
            }
      }

      /* Handle the underline style */
      if( font->style & TTF_STYLE_UNDERLINE ) {
            row = font->ascent - font->underline_offset - 1;
            if ( row >= textbuf->h) {
                  row = (textbuf->h-1) - font->underline_height;
            }
            dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
            pixel |= 0xFF000000; /* Amask */
            for ( row=font->underline_height; row>0; --row ) {
                  for ( col=0; col < textbuf->w; ++col ) {
                        dst[col] = pixel;
                  }
                  dst += textbuf->pitch/4;
            }
      }
      return(textbuf);
}

SDL_Surface *TTF_RenderGlyph_Blended(TTF_Font *font, Uint16 ch, SDL_Color fg)
{
      SDL_Surface *textbuf;
      Uint32 alpha;
      Uint32 pixel;
      Uint8 *src;
      Uint32 *dst;
      int row, col;
      FT_Error error;
      c_glyph *glyph;

      /* Get the glyph itself */
      error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_PIXMAP);
      if ( error ) {
            return(NULL);
      }
      glyph = font->current;

      textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE,
                    glyph->pixmap.width, glyph->pixmap.rows, 32,
                  0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
      if ( ! textbuf ) {
            return(NULL);
      }

      /* Copy the character from the pixmap */
      pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
      for ( row=0; row<textbuf->h; ++row ) {
            /* Changed src to take pitch into account, not just width */
            src = glyph->pixmap.buffer + row * glyph->pixmap.pitch;
            dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
            for ( col=0; col<glyph->pixmap.width; ++col ) {
                  alpha = *src++;
                  *dst++ = pixel | (alpha << 24);
            }
      }

      /* Handle the underline style */
      if( font->style & TTF_STYLE_UNDERLINE ) {
            row = font->ascent - font->underline_offset - 1;
            if ( row >= textbuf->h) {
                  row = (textbuf->h-1) - font->underline_height;
            }
            dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
            pixel |= 0xFF000000; /* Amask */
            for ( row=font->underline_height; row>0; --row ) {
                  for ( col=0; col < textbuf->w; ++col ) {
                        dst[col] = pixel;
                  }
                  dst += textbuf->pitch/4;
            }
      }
      return(textbuf);
}

void TTF_SetFontStyle( TTF_Font* font, int style )
{
      font->style = style;
      Flush_Cache( font );
}

int TTF_GetFontStyle( TTF_Font* font )
{
      return font->style;
}

void TTF_Quit( void )
{
      if ( TTF_initialized ) {
            if ( --TTF_initialized == 0 ) {
                  FT_Done_FreeType( library );
            }
      }
}

int TTF_WasInit( void )
{
      return TTF_initialized;
}

Generated by  Doxygen 1.6.0   Back to index