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 */ }
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 *)malloc((unicode_len+1)*(sizeof *unicode_text)); if ( unicode_text == NULL ) { TTF_SetError("Out of memory"); return(NULL); } ASCII_to_UNICODE(unicode_text, text, unicode_len); RenderUnicode(font, unicode_text, fg); /* Render the new text */ textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg); /* Free the text buffer and return */ free(unicode_text); return(textbuf); }
TTF_Font* TTF_OpenFontIndex( const char *file, int ptsize, long index ) { SDL_RWops *rw = SDL_RWFromFile(file, "rb"); if ( rw == NULL ) { TTF_SetError(SDL_GetError()); return NULL; } return TTF_OpenFontIndexRW(rw, 1, ptsize, index); }
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)); /* 090303 Chase - Newer FT2 version sets this internally so we don't have to. (Can't anyway, Don't have a definition for FT_Library) */ // 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; }
SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font, const Uint16 *text, SDL_Color fg) { int xstart, width; int w, h; SDL_Surface *textbuf; SDL_Palette *palette; const Uint16 *ch; Uint8 *src, *dst; int row, col; TT_Error error; /* Get the dimensions of the text surface */ if ( (TTF_SizeUNICODE(font, text, &w, &h) < 0) || !w ) { TTF_SetError("Text has zero width"); return(NULL); } /* Create the target surface */ width = w; w = (w+7)&~7; textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 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; for ( ch=text; *ch; ++ch ) { error = Find_Glyph(font, *ch); if ( ! error ) { w = font->current->bitmap.width; src = (Uint8 *)font->current->bitmap.bitmap; for ( row = 0; row < h; ++row ) { dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch + xstart + font->current->minx; for ( col = 0; col < w; col += 8 ) { Uint8 c = *src++; *dst++ |= (c&0x80)>>7; c <<= 1; *dst++ |= (c&0x80)>>7; c <<= 1; *dst++ |= (c&0x80)>>7; c <<= 1; *dst++ |= (c&0x80)>>7; c <<= 1; *dst++ |= (c&0x80)>>7; c <<= 1; *dst++ |= (c&0x80)>>7; c <<= 1; *dst++ |= (c&0x80)>>7; c <<= 1; *dst++ |= (c&0x80)>>7; } } xstart += font->current->advance; if ( font->style & TTF_STYLE_BOLD ) { xstart += font->glyph_overhang; } } }
TTF_Font* TTF_OpenFontIndexRW( FILE* src, int freesrc, int ptsize, long index ) { TTF_Font* font; FT_Error error; FT_Face face; FT_Fixed scale; FT_Stream stream; FT_CharMap found; int position, i; if ( ! TTF_initialized ) { TTF_SetError( "Library not initialized" ); return NULL; } /* Check to make sure we can seek in this stream */ position = ftell(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->read = ft_read; stream->descriptor.pointer = src; stream->pos = (unsigned long)position; fseek(src, 0, SEEK_END); stream->size = (unsigned long)(ftell(src) - position); fseek(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; /* Set charmap for loaded font */ found = 0; for (i = 0; i < face->num_charmaps; i++) { FT_CharMap charmap = face->charmaps[i]; /* Windows Unicode */ if ((charmap->platform_id == 3 && charmap->encoding_id == 1) /* Windows Symbol */ || (charmap->platform_id == 3 && charmap->encoding_id == 0) /* ISO Unicode */ || (charmap->platform_id == 2 && charmap->encoding_id == 1) /* Apple Unicode */ || (charmap->platform_id == 0)) { found = charmap; break; } } if ( found ) { /* If this fails, continue using the default charmap */ FT_Set_Charmap(face, found); } /* 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[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); printf("\tunderline_top_row = %d, strikethrough_top_row = %d\n", TTF_underline_top_row(font), TTF_strikethrough_top_row(font)); #endif /* Initialize the font face style */ font->face_style = TTF_STYLE_NORMAL; if ( font->face->style_flags & FT_STYLE_FLAG_BOLD ) { font->face_style |= TTF_STYLE_BOLD; } if ( font->face->style_flags & FT_STYLE_FLAG_ITALIC ) { font->face_style |= TTF_STYLE_ITALIC; } /* Set the default font style */ font->style = font->face_style; font->outline = 0; font->kerning = 1; 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; }