/*
SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
Copyright (C) 1997-2004 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 2304 2006-05-01 09:26:07Z slouken $ */
#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 <freetype/freetype.h>
#include <freetype/ftoutln.h>
#include <freetype/ttnameid.h>
*/
#include <freetype/internal/ftobjs.h>
#ifndef FT_OPEN_STREAM
#define FT_OPEN_STREAM ft_open_stream
#endif
#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;
SDL_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 );
if ( count == 0 ) {
return 0;
}
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;
}
/* 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->ascender, scale));
font->descent = FT_CEIL(FT_MulFix(face->descender, 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[pt
评论1