123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644 |
- /*
- 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.3 2004/07/20 17:01:14 paigoddess Exp $ */
- // @@@ MODIFIED 1/30/2004 GJ (search for similar markers) @@@ //
- #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
- // @@@ MODIFIED 7/20/2004 changed #includes @@@ //
- //#include <freetype/freetype.h>
- //#include <freetype/ftoutln.h>
- //#include <freetype/ttnameid.h>
- //#include <freetype/internal/ftobjs.h>
- #include <ft2build.h>
- #include FT_FREETYPE_H
- #include FT_OUTLINE_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;
- }
- // @@@ MODIFIED 1/30/2004 GJ (added this error check) @@@ //
- /* Check to make sure stream was opened successfully */
- if ( src == NULL ) {
- TTF_SetError( "Error opening stream or file" );
- 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 = NULL;
- 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 = (unsigned char*)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;
- }
|