SDL_ttf.c 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644
  1. /*
  2. SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
  3. Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with this library; if not, write to the Free
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. Sam Lantinga
  16. slouken@libsdl.org
  17. */
  18. /* $Id: SDL_ttf.c,v 1.3 2004/07/20 17:01:14 paigoddess Exp $ */
  19. // @@@ MODIFIED 1/30/2004 GJ (search for similar markers) @@@ //
  20. #include <math.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #ifdef HAVE_ALLOCA_H
  25. #include <alloca.h>
  26. #endif
  27. #ifdef HAVE_ALLOCA
  28. #define ALLOCA(n) ((void*)alloca(n))
  29. #define FREEA(p)
  30. #else
  31. #define ALLOCA(n) malloc(n)
  32. #define FREEA(p) free(p)
  33. #endif
  34. // @@@ MODIFIED 7/20/2004 changed #includes @@@ //
  35. //#include <freetype/freetype.h>
  36. //#include <freetype/ftoutln.h>
  37. //#include <freetype/ttnameid.h>
  38. //#include <freetype/internal/ftobjs.h>
  39. #include <ft2build.h>
  40. #include FT_FREETYPE_H
  41. #include FT_OUTLINE_H
  42. //#include FT_INTERNAL_OBJECTS_H
  43. #include "SDL.h"
  44. #include "SDL_endian.h"
  45. #include "SDL_ttf.h"
  46. /* FIXME: Right now we assume the gray-scale renderer Freetype is using
  47. supports 256 shades of gray, but we should instead key off of num_grays
  48. in the result FT_Bitmap after the FT_Render_Glyph() call. */
  49. #define NUM_GRAYS 256
  50. /* Handy routines for converting from fixed point */
  51. #define FT_FLOOR(X) ((X & -64) / 64)
  52. #define FT_CEIL(X) (((X + 63) & -64) / 64)
  53. #define CACHED_METRICS 0x10
  54. #define CACHED_BITMAP 0x01
  55. #define CACHED_PIXMAP 0x02
  56. /* Cached glyph information */
  57. typedef struct cached_glyph {
  58. int stored;
  59. FT_UInt index;
  60. FT_Bitmap bitmap;
  61. FT_Bitmap pixmap;
  62. int minx;
  63. int maxx;
  64. int miny;
  65. int maxy;
  66. int yoffset;
  67. int advance;
  68. Uint16 cached;
  69. } c_glyph;
  70. /* The structure used to hold internal font information */
  71. struct _TTF_Font {
  72. /* Freetype2 maintains all sorts of useful info itself */
  73. FT_Face face;
  74. /* We'll cache these ourselves */
  75. int height;
  76. int ascent;
  77. int descent;
  78. int lineskip;
  79. /* The font style */
  80. int style;
  81. /* Extra width in glyph bounds for text styles */
  82. int glyph_overhang;
  83. float glyph_italics;
  84. /* Information in the font for underlining */
  85. int underline_offset;
  86. int underline_height;
  87. /* Cache for style-transformed glyphs */
  88. c_glyph *current;
  89. c_glyph cache[256];
  90. c_glyph scratch;
  91. /* We are responsible for closing the font stream */
  92. SDL_RWops *src;
  93. int freesrc;
  94. FT_Open_Args args;
  95. /* For non-scalable formats, we must remember which font index size */
  96. int font_size_family;
  97. };
  98. /* The FreeType font engine/library */
  99. static FT_Library library;
  100. static int TTF_initialized = 0;
  101. static int TTF_byteswapped = 0;
  102. /* UNICODE string utilities */
  103. static __inline__ int UNICODE_strlen(const Uint16 *text)
  104. {
  105. int size = 0;
  106. while ( *text++ ) {
  107. ++size;
  108. }
  109. return size;
  110. }
  111. static __inline__ void UNICODE_strcpy(Uint16 *dst, const Uint16 *src, int swap)
  112. {
  113. if ( swap ) {
  114. while ( *src ) {
  115. *dst = SDL_Swap16(*src);
  116. ++src;
  117. ++dst;
  118. }
  119. *dst = '\0';
  120. } else {
  121. while ( *src ) {
  122. *dst = *src;
  123. ++src;
  124. ++dst;
  125. }
  126. *dst = '\0';
  127. }
  128. }
  129. /* rcg06192001 get linked library's version. */
  130. const SDL_version *TTF_Linked_Version(void)
  131. {
  132. static SDL_version linked_version;
  133. TTF_VERSION(&linked_version);
  134. return(&linked_version);
  135. }
  136. /* This function tells the library whether UNICODE text is generally
  137. byteswapped. A UNICODE BOM character at the beginning of a string
  138. will override this setting for that string.
  139. */
  140. void TTF_ByteSwappedUNICODE(int swapped)
  141. {
  142. TTF_byteswapped = swapped;
  143. }
  144. static void TTF_SetFTError(const char *msg, FT_Error error)
  145. {
  146. #ifdef USE_FREETYPE_ERRORS
  147. #undef FTERRORS_H
  148. #define FT_ERRORDEF( e, v, s ) { e, s },
  149. static const struct
  150. {
  151. int err_code;
  152. const char* err_msg;
  153. } ft_errors[] = {
  154. #include <freetype/fterrors.h>
  155. };
  156. int i;
  157. const char *err_msg;
  158. char buffer[1024];
  159. err_msg = NULL;
  160. for ( i=0; i<((sizeof ft_errors)/(sizeof ft_errors[0])); ++i ) {
  161. if ( error == ft_errors[i].err_code ) {
  162. err_msg = ft_errors[i].err_msg;
  163. break;
  164. }
  165. }
  166. if ( ! err_msg ) {
  167. err_msg = "unknown FreeType error";
  168. }
  169. sprintf(buffer, "%s: %s", msg, err_msg);
  170. TTF_SetError(buffer);
  171. #else
  172. TTF_SetError(msg);
  173. #endif /* USE_FREETYPE_ERRORS */
  174. }
  175. int TTF_Init( void )
  176. {
  177. int status = 0;
  178. if ( ! TTF_initialized ) {
  179. FT_Error error = FT_Init_FreeType( &library );
  180. if ( error ) {
  181. TTF_SetFTError("Couldn't init FreeType engine", error);
  182. status = -1;
  183. }
  184. }
  185. if ( status == 0 ) {
  186. ++TTF_initialized;
  187. }
  188. return status;
  189. }
  190. static unsigned long RWread(
  191. FT_Stream stream,
  192. unsigned long offset,
  193. unsigned char* buffer,
  194. unsigned long count
  195. )
  196. {
  197. SDL_RWops *src;
  198. src = (SDL_RWops *)stream->descriptor.pointer;
  199. SDL_RWseek( src, (int)offset, SEEK_SET );
  200. return SDL_RWread( src, buffer, 1, (int)count );
  201. }
  202. TTF_Font* TTF_OpenFontIndexRW( SDL_RWops *src, int freesrc, int ptsize, long index )
  203. {
  204. TTF_Font* font;
  205. FT_Error error;
  206. FT_Face face;
  207. FT_Fixed scale;
  208. FT_Stream stream;
  209. int position;
  210. if ( ! TTF_initialized ) {
  211. TTF_SetError( "Library not initialized" );
  212. return NULL;
  213. }
  214. // @@@ MODIFIED 1/30/2004 GJ (added this error check) @@@ //
  215. /* Check to make sure stream was opened successfully */
  216. if ( src == NULL ) {
  217. TTF_SetError( "Error opening stream or file" );
  218. return NULL;
  219. }
  220. /* Check to make sure we can seek in this stream */
  221. position = SDL_RWtell(src);
  222. if ( position < 0 ) {
  223. TTF_SetError( "Can't seek in stream" );
  224. return NULL;
  225. }
  226. font = (TTF_Font*) malloc(sizeof *font);
  227. if ( font == NULL ) {
  228. TTF_SetError( "Out of memory" );
  229. return NULL;
  230. }
  231. memset(font, 0, sizeof(*font));
  232. font->src = src;
  233. font->freesrc = freesrc;
  234. stream = (FT_Stream)malloc(sizeof(*stream));
  235. if ( stream == NULL ) {
  236. TTF_SetError( "Out of memory" );
  237. TTF_CloseFont( font );
  238. return NULL;
  239. }
  240. memset(stream, 0, sizeof(*stream));
  241. stream->memory = NULL;
  242. stream->read = RWread;
  243. stream->descriptor.pointer = src;
  244. stream->pos = (unsigned long)position;
  245. SDL_RWseek(src, 0, SEEK_END);
  246. stream->size = (unsigned long)(SDL_RWtell(src) - position);
  247. SDL_RWseek(src, position, SEEK_SET);
  248. font->args.flags = ft_open_stream;
  249. font->args.stream = stream;
  250. error = FT_Open_Face( library, &font->args, index, &font->face );
  251. if( error ) {
  252. TTF_SetFTError( "Couldn't load font file", error );
  253. TTF_CloseFont( font );
  254. return NULL;
  255. }
  256. face = font->face;
  257. /* Make sure that our font face is scalable (global metrics) */
  258. if ( FT_IS_SCALABLE(face) ) {
  259. /* Set the character size and use default DPI (72) */
  260. error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 0, 0 );
  261. if( error ) {
  262. TTF_SetFTError( "Couldn't set font size", error );
  263. TTF_CloseFont( font );
  264. return NULL;
  265. }
  266. /* Get the scalable font metrics for this font */
  267. scale = face->size->metrics.y_scale;
  268. font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
  269. font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
  270. font->height = font->ascent - font->descent + /* baseline */ 1;
  271. font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
  272. font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
  273. font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
  274. } else {
  275. /* Non-scalable font case. ptsize determines which family
  276. * or series of fonts to grab from the non-scalable format.
  277. * It is not the point size of the font.
  278. * */
  279. if ( ptsize >= font->face->num_fixed_sizes )
  280. ptsize = font->face->num_fixed_sizes - 1;
  281. font->font_size_family = ptsize;
  282. error = FT_Set_Pixel_Sizes( face,
  283. face->available_sizes[ptsize].height,
  284. face->available_sizes[ptsize].width );
  285. /* With non-scalale fonts, Freetype2 likes to fill many of the
  286. * font metrics with the value of 0. The size of the
  287. * non-scalable fonts must be determined differently
  288. * or sometimes cannot be determined.
  289. * */
  290. font->ascent = face->available_sizes[ptsize].height;
  291. font->descent = 0;
  292. font->height = face->available_sizes[ptsize].height;
  293. font->lineskip = FT_CEIL(font->ascent);
  294. font->underline_offset = FT_FLOOR(face->underline_position);
  295. font->underline_height = FT_FLOOR(face->underline_thickness);
  296. }
  297. if ( font->underline_height < 1 ) {
  298. font->underline_height = 1;
  299. }
  300. #ifdef DEBUG_FONTS
  301. printf("Font metrics:\n");
  302. printf("\tascent = %d, descent = %d\n",
  303. font->ascent, font->descent);
  304. printf("\theight = %d, lineskip = %d\n",
  305. font->height, font->lineskip);
  306. printf("\tunderline_offset = %d, underline_height = %d\n",
  307. font->underline_offset, font->underline_height);
  308. #endif
  309. /* Set the default font style */
  310. font->style = TTF_STYLE_NORMAL;
  311. font->glyph_overhang = face->size->metrics.y_ppem / 10;
  312. /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
  313. font->glyph_italics = 0.207f;
  314. font->glyph_italics *= font->height;
  315. return font;
  316. }
  317. TTF_Font* TTF_OpenFontRW( SDL_RWops *src, int freesrc, int ptsize )
  318. {
  319. return TTF_OpenFontIndexRW(src, freesrc, ptsize, 0);
  320. }
  321. TTF_Font* TTF_OpenFontIndex( const char *file, int ptsize, long index )
  322. {
  323. return TTF_OpenFontIndexRW(SDL_RWFromFile(file, "rb"), 1, ptsize, index);
  324. }
  325. TTF_Font* TTF_OpenFont( const char *file, int ptsize )
  326. {
  327. return TTF_OpenFontIndex(file, ptsize, 0);
  328. }
  329. static void Flush_Glyph( c_glyph* glyph )
  330. {
  331. glyph->stored = 0;
  332. glyph->index = 0;
  333. if( glyph->bitmap.buffer ) {
  334. free( glyph->bitmap.buffer );
  335. glyph->bitmap.buffer = 0;
  336. }
  337. if( glyph->pixmap.buffer ) {
  338. free( glyph->pixmap.buffer );
  339. glyph->pixmap.buffer = 0;
  340. }
  341. glyph->cached = 0;
  342. }
  343. static void Flush_Cache( TTF_Font* font )
  344. {
  345. int i;
  346. int size = sizeof( font->cache ) / sizeof( font->cache[0] );
  347. for( i = 0; i < size; ++i ) {
  348. if( font->cache[i].cached ) {
  349. Flush_Glyph( &font->cache[i] );
  350. }
  351. }
  352. if( font->scratch.cached ) {
  353. Flush_Glyph( &font->scratch );
  354. }
  355. }
  356. static FT_Error Load_Glyph( TTF_Font* font, Uint16 ch, c_glyph* cached, int want )
  357. {
  358. FT_Face face;
  359. FT_Error error;
  360. FT_GlyphSlot glyph;
  361. FT_Glyph_Metrics* metrics;
  362. FT_Outline* outline;
  363. if ( !font || !font->face ) {
  364. return FT_Err_Invalid_Handle;
  365. }
  366. face = font->face;
  367. /* Load the glyph */
  368. if ( ! cached->index ) {
  369. cached->index = FT_Get_Char_Index( face, ch );
  370. }
  371. error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT );
  372. if( error ) {
  373. return error;
  374. }
  375. /* Get our glyph shortcuts */
  376. glyph = face->glyph;
  377. metrics = &glyph->metrics;
  378. outline = &glyph->outline;
  379. /* Get the glyph metrics if desired */
  380. if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) {
  381. if ( FT_IS_SCALABLE( face ) ) {
  382. /* Get the bounding box */
  383. cached->minx = FT_FLOOR(metrics->horiBearingX);
  384. cached->maxx = cached->minx + FT_CEIL(metrics->width);
  385. cached->maxy = FT_FLOOR(metrics->horiBearingY);
  386. cached->miny = cached->maxy - FT_CEIL(metrics->height);
  387. cached->yoffset = font->ascent - cached->maxy;
  388. cached->advance = FT_CEIL(metrics->horiAdvance);
  389. } else {
  390. /* Get the bounding box for non-scalable format.
  391. * Again, freetype2 fills in many of the font metrics
  392. * with the value of 0, so some of the values we
  393. * need must be calculated differently with certain
  394. * assumptions about non-scalable formats.
  395. * */
  396. cached->minx = FT_FLOOR(metrics->horiBearingX);
  397. cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance);
  398. cached->maxy = FT_FLOOR(metrics->horiBearingY);
  399. cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height);
  400. cached->yoffset = 0;
  401. cached->advance = FT_CEIL(metrics->horiAdvance);
  402. }
  403. /* Adjust for bold and italic text */
  404. if( font->style & TTF_STYLE_BOLD ) {
  405. cached->maxx += font->glyph_overhang;
  406. }
  407. if( font->style & TTF_STYLE_ITALIC ) {
  408. cached->maxx += (int)ceil(font->glyph_italics);
  409. }
  410. cached->stored |= CACHED_METRICS;
  411. }
  412. if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
  413. ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) {
  414. int mono = (want & CACHED_BITMAP);
  415. int i;
  416. FT_Bitmap* src;
  417. FT_Bitmap* dst;
  418. /* Handle the italic style */
  419. if( font->style & TTF_STYLE_ITALIC ) {
  420. FT_Matrix shear;
  421. shear.xx = 1 << 16;
  422. shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height;
  423. shear.yx = 0;
  424. shear.yy = 1 << 16;
  425. FT_Outline_Transform( outline, &shear );
  426. }
  427. /* Render the glyph */
  428. if ( mono ) {
  429. error = FT_Render_Glyph( glyph, ft_render_mode_mono );
  430. } else {
  431. error = FT_Render_Glyph( glyph, ft_render_mode_normal );
  432. }
  433. if( error ) {
  434. return error;
  435. }
  436. /* Copy over information to cache */
  437. src = &glyph->bitmap;
  438. if ( mono ) {
  439. dst = &cached->bitmap;
  440. } else {
  441. dst = &cached->pixmap;
  442. }
  443. memcpy( dst, src, sizeof( *dst ) );
  444. /* FT_Render_Glyph() and .fon fonts always generate a
  445. * two-color (black and white) glyphslot surface, even
  446. * when rendered in ft_render_mode_normal. This is probably
  447. * a freetype2 bug because it is inconsistent with the
  448. * freetype2 documentation under FT_Render_Mode section.
  449. * */
  450. if ( mono || !FT_IS_SCALABLE(face) ) {
  451. dst->pitch *= 8;
  452. }
  453. /* Adjust for bold and italic text */
  454. if( font->style & TTF_STYLE_BOLD ) {
  455. int bump = font->glyph_overhang;
  456. dst->pitch += bump;
  457. dst->width += bump;
  458. }
  459. if( font->style & TTF_STYLE_ITALIC ) {
  460. int bump = (int)ceil(font->glyph_italics);
  461. dst->pitch += bump;
  462. dst->width += bump;
  463. }
  464. if (dst->rows != 0) {
  465. dst->buffer = (unsigned char*)malloc( dst->pitch * dst->rows );
  466. if( !dst->buffer ) {
  467. return FT_Err_Out_Of_Memory;
  468. }
  469. memset( dst->buffer, 0, dst->pitch * dst->rows );
  470. for( i = 0; i < src->rows; i++ ) {
  471. int soffset = i * src->pitch;
  472. int doffset = i * dst->pitch;
  473. if ( mono ) {
  474. unsigned char *srcp = src->buffer + soffset;
  475. unsigned char *dstp = dst->buffer + doffset;
  476. int j;
  477. for ( j = 0; j < src->width; j += 8 ) {
  478. unsigned char ch = *srcp++;
  479. *dstp++ = (ch&0x80) >> 7;
  480. ch <<= 1;
  481. *dstp++ = (ch&0x80) >> 7;
  482. ch <<= 1;
  483. *dstp++ = (ch&0x80) >> 7;
  484. ch <<= 1;
  485. *dstp++ = (ch&0x80) >> 7;
  486. ch <<= 1;
  487. *dstp++ = (ch&0x80) >> 7;
  488. ch <<= 1;
  489. *dstp++ = (ch&0x80) >> 7;
  490. ch <<= 1;
  491. *dstp++ = (ch&0x80) >> 7;
  492. ch <<= 1;
  493. *dstp++ = (ch&0x80) >> 7;
  494. }
  495. } else if ( !FT_IS_SCALABLE(face) ) {
  496. /* This special case wouldn't
  497. * be here if the FT_Render_Glyph()
  498. * function wasn't buggy when it tried
  499. * to render a .fon font with 256
  500. * shades of gray. Instead, it
  501. * returns a black and white surface
  502. * and we have to translate it back
  503. * to a 256 gray shaded surface.
  504. * */
  505. unsigned char *srcp = src->buffer + soffset;
  506. unsigned char *dstp = dst->buffer + doffset;
  507. unsigned char ch;
  508. int j, k;
  509. for ( j = 0; j < src->width; j += 8) {
  510. ch = *srcp++;
  511. for (k = 0; k < 8; ++k) {
  512. if ((ch&0x80) >> 7) {
  513. *dstp++ = NUM_GRAYS - 1;
  514. } else {
  515. *dstp++ = 0x00;
  516. }
  517. ch <<= 1;
  518. }
  519. }
  520. } else {
  521. memcpy(dst->buffer+doffset,
  522. src->buffer+soffset, src->pitch);
  523. }
  524. }
  525. }
  526. /* Handle the bold style */
  527. if ( font->style & TTF_STYLE_BOLD ) {
  528. int row;
  529. int col;
  530. int offset;
  531. int pixel;
  532. Uint8* pixmap;
  533. /* The pixmap is a little hard, we have to add and clamp */
  534. for( row = dst->rows - 1; row >= 0; --row ) {
  535. pixmap = (Uint8*) dst->buffer + row * dst->pitch;
  536. for( offset=1; offset <= font->glyph_overhang; ++offset ) {
  537. for( col = dst->width - 1; col > 0; --col ) {
  538. pixel = (pixmap[col] + pixmap[col-1]);
  539. if( pixel > NUM_GRAYS - 1 ) {
  540. pixel = NUM_GRAYS - 1;
  541. }
  542. pixmap[col] = (Uint8) pixel;
  543. }
  544. }
  545. }
  546. }
  547. /* Mark that we rendered this format */
  548. if ( mono ) {
  549. cached->stored |= CACHED_BITMAP;
  550. } else {
  551. cached->stored |= CACHED_PIXMAP;
  552. }
  553. }
  554. /* We're done, mark this glyph cached */
  555. cached->cached = ch;
  556. return 0;
  557. }
  558. static FT_Error Find_Glyph( TTF_Font* font, Uint16 ch, int want )
  559. {
  560. int retval = 0;
  561. if( ch < 256 ) {
  562. font->current = &font->cache[ch];
  563. } else {
  564. if ( font->scratch.cached != ch ) {
  565. Flush_Glyph( &font->scratch );
  566. }
  567. font->current = &font->scratch;
  568. }
  569. if ( (font->current->stored & want) != want ) {
  570. retval = Load_Glyph( font, ch, font->current, want );
  571. }
  572. return retval;
  573. }
  574. void TTF_CloseFont( TTF_Font* font )
  575. {
  576. Flush_Cache( font );
  577. if ( font->face ) {
  578. FT_Done_Face( font->face );
  579. }
  580. if ( font->args.stream ) {
  581. free( font->args.stream );
  582. }
  583. if ( font->freesrc ) {
  584. SDL_RWclose( font->src );
  585. }
  586. free( font );
  587. }
  588. static Uint16 *LATIN1_to_UNICODE(Uint16 *unicode, const char *text, int len)
  589. {
  590. int i;
  591. for ( i=0; i < len; ++i ) {
  592. unicode[i] = ((const unsigned char *)text)[i];
  593. }
  594. unicode[i] = 0;
  595. return unicode;
  596. }
  597. static Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len)
  598. {
  599. int i, j;
  600. Uint16 ch;
  601. for ( i=0, j=0; i < len; ++i, ++j ) {
  602. ch = ((const unsigned char *)utf8)[i];
  603. if ( ch >= 0xF0 ) {
  604. ch = (Uint16)(utf8[i]&0x07) << 18;
  605. ch |= (Uint16)(utf8[++i]&0x3F) << 12;
  606. ch |= (Uint16)(utf8[++i]&0x3F) << 6;
  607. ch |= (Uint16)(utf8[++i]&0x3F);
  608. } else
  609. if ( ch >= 0xE0 ) {
  610. ch = (Uint16)(utf8[i]&0x3F) << 12;
  611. ch |= (Uint16)(utf8[++i]&0x3F) << 6;
  612. ch |= (Uint16)(utf8[++i]&0x3F);
  613. } else
  614. if ( ch >= 0xC0 ) {
  615. ch = (Uint16)(utf8[i]&0x3F) << 6;
  616. ch |= (Uint16)(utf8[++i]&0x3F);
  617. }
  618. unicode[j] = ch;
  619. }
  620. unicode[j] = 0;
  621. return unicode;
  622. }
  623. int TTF_FontHeight(TTF_Font *font)
  624. {
  625. return(font->height);
  626. }
  627. int TTF_FontAscent(TTF_Font *font)
  628. {
  629. return(font->ascent);
  630. }
  631. int TTF_FontDescent(TTF_Font *font)
  632. {
  633. return(font->descent);
  634. }
  635. int TTF_FontLineSkip(TTF_Font *font)
  636. {
  637. return(font->lineskip);
  638. }
  639. long TTF_FontFaces(TTF_Font *font)
  640. {
  641. return(font->face->num_faces);
  642. }
  643. int TTF_FontFaceIsFixedWidth(TTF_Font *font)
  644. {
  645. return(FT_IS_FIXED_WIDTH(font->face));
  646. }
  647. char *TTF_FontFaceFamilyName(TTF_Font *font)
  648. {
  649. return(font->face->family_name);
  650. }
  651. char *TTF_FontFaceStyleName(TTF_Font *font)
  652. {
  653. return(font->face->style_name);
  654. }
  655. int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch,
  656. int* minx, int* maxx, int* miny, int* maxy, int* advance)
  657. {
  658. FT_Error error;
  659. error = Find_Glyph(font, ch, CACHED_METRICS);
  660. if ( error ) {
  661. TTF_SetFTError("Couldn't find glyph", error);
  662. return -1;
  663. }
  664. if ( minx ) {
  665. *minx = font->current->minx;
  666. }
  667. if ( maxx ) {
  668. *maxx = font->current->maxx;
  669. }
  670. if ( miny ) {
  671. *miny = font->current->miny;
  672. }
  673. if ( maxy ) {
  674. *maxy = font->current->maxy;
  675. }
  676. if ( advance ) {
  677. *advance = font->current->advance;
  678. }
  679. return 0;
  680. }
  681. int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h)
  682. {
  683. Uint16 *unicode_text;
  684. int unicode_len;
  685. int status;
  686. /* Copy the Latin-1 text to a UNICODE text buffer */
  687. unicode_len = strlen(text);
  688. unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
  689. if ( unicode_text == NULL ) {
  690. TTF_SetError("Out of memory");
  691. return -1;
  692. }
  693. *unicode_text = UNICODE_BOM_NATIVE;
  694. LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);
  695. /* Render the new text */
  696. status = TTF_SizeUNICODE(font, unicode_text, w, h);
  697. /* Free the text buffer and return */
  698. FREEA(unicode_text);
  699. return status;
  700. }
  701. int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h)
  702. {
  703. Uint16 *unicode_text;
  704. int unicode_len;
  705. int status;
  706. /* Copy the UTF-8 text to a UNICODE text buffer */
  707. unicode_len = strlen(text);
  708. unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
  709. if ( unicode_text == NULL ) {
  710. TTF_SetError("Out of memory");
  711. return -1;
  712. }
  713. *unicode_text = UNICODE_BOM_NATIVE;
  714. UTF8_to_UNICODE(unicode_text+1, text, unicode_len);
  715. /* Render the new text */
  716. status = TTF_SizeUNICODE(font, unicode_text, w, h);
  717. /* Free the text buffer and return */
  718. FREEA(unicode_text);
  719. return status;
  720. }
  721. int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h)
  722. {
  723. int status;
  724. const Uint16 *ch;
  725. int swapped;
  726. int x, z;
  727. int minx, maxx;
  728. int miny, maxy;
  729. c_glyph *glyph;
  730. FT_Error error;
  731. /* Initialize everything to 0 */
  732. if ( ! TTF_initialized ) {
  733. TTF_SetError( "Library not initialized" );
  734. return -1;
  735. }
  736. status = 0;
  737. minx = maxx = 0;
  738. miny = maxy = 0;
  739. swapped = TTF_byteswapped;
  740. /* Load each character and sum it's bounding box */
  741. x= 0;
  742. for ( ch=text; *ch; ++ch ) {
  743. Uint16 c = *ch;
  744. if ( c == UNICODE_BOM_NATIVE ) {
  745. swapped = 0;
  746. if ( text == ch ) {
  747. ++text;
  748. }
  749. continue;
  750. }
  751. if ( c == UNICODE_BOM_SWAPPED ) {
  752. swapped = 1;
  753. if ( text == ch ) {
  754. ++text;
  755. }
  756. continue;
  757. }
  758. if ( swapped ) {
  759. c = SDL_Swap16(c);
  760. }
  761. error = Find_Glyph(font, c, CACHED_METRICS);
  762. if ( error ) {
  763. return -1;
  764. }
  765. glyph = font->current;
  766. if ( (ch == text) && (glyph->minx < 0) ) {
  767. /* Fixes the texture wrapping bug when the first letter
  768. * has a negative minx value or horibearing value. The entire
  769. * bounding box must be adjusted to be bigger so the entire
  770. * letter can fit without any texture corruption or wrapping.
  771. *
  772. * Effects: First enlarges bounding box.
  773. * Second, xstart has to start ahead of its normal spot in the
  774. * negative direction of the negative minx value.
  775. * (pushes everything to the right).
  776. *
  777. * This will make the memory copy of the glyph bitmap data
  778. * work out correctly.
  779. * */
  780. z -= glyph->minx;
  781. }
  782. z = x + glyph->minx;
  783. if ( minx > z ) {
  784. minx = z;
  785. }
  786. if ( font->style & TTF_STYLE_BOLD ) {
  787. x += font->glyph_overhang;
  788. }
  789. if ( glyph->advance > glyph->maxx ) {
  790. z = x + glyph->advance;
  791. } else {
  792. z = x + glyph->maxx;
  793. }
  794. if ( maxx < z ) {
  795. maxx = z;
  796. }
  797. x += glyph->advance;
  798. if ( glyph->miny < miny ) {
  799. miny = glyph->miny;
  800. }
  801. if ( glyph->maxy > maxy ) {
  802. maxy = glyph->maxy;
  803. }
  804. }
  805. /* Fill the bounds rectangle */
  806. if ( w ) {
  807. *w = (maxx - minx);
  808. }
  809. if ( h ) {
  810. #if 0 /* This is correct, but breaks many applications */
  811. *h = (maxy - miny);
  812. #else
  813. *h = font->height;
  814. #endif
  815. }
  816. return status;
  817. }
  818. /* Convert the Latin-1 text to UNICODE and render it
  819. */
  820. SDL_Surface *TTF_RenderText_Solid(TTF_Font *font,
  821. const char *text, SDL_Color fg)
  822. {
  823. SDL_Surface *textbuf;
  824. Uint16 *unicode_text;
  825. int unicode_len;
  826. /* Copy the Latin-1 text to a UNICODE text buffer */
  827. unicode_len = strlen(text);
  828. unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
  829. if ( unicode_text == NULL ) {
  830. TTF_SetError("Out of memory");
  831. return(NULL);
  832. }
  833. *unicode_text = UNICODE_BOM_NATIVE;
  834. LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);
  835. /* Render the new text */
  836. textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg);
  837. /* Free the text buffer and return */
  838. FREEA(unicode_text);
  839. return(textbuf);
  840. }
  841. /* Convert the UTF-8 text to UNICODE and render it
  842. */
  843. SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font,
  844. const char *text, SDL_Color fg)
  845. {
  846. SDL_Surface *textbuf;
  847. Uint16 *unicode_text;
  848. int unicode_len;
  849. /* Copy the UTF-8 text to a UNICODE text buffer */
  850. unicode_len = strlen(text);
  851. unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
  852. if ( unicode_text == NULL ) {
  853. TTF_SetError("Out of memory");
  854. return(NULL);
  855. }
  856. *unicode_text = UNICODE_BOM_NATIVE;
  857. UTF8_to_UNICODE(unicode_text, text, unicode_len);
  858. /* Render the new text */
  859. textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg);
  860. /* Free the text buffer and return */
  861. FREEA(unicode_text);
  862. return(textbuf);
  863. }
  864. SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font,
  865. const Uint16 *text, SDL_Color fg)
  866. {
  867. int xstart;
  868. int width;
  869. int height;
  870. SDL_Surface* textbuf;
  871. SDL_Palette* palette;
  872. const Uint16* ch;
  873. Uint8* src;
  874. Uint8* dst;
  875. int swapped;
  876. int row, col;
  877. c_glyph *glyph;
  878. FT_Bitmap *current;
  879. FT_Error error;
  880. /* Get the dimensions of the text surface */
  881. if( ( TTF_SizeUNICODE(font, text, &width, NULL) < 0 ) || !width ) {
  882. TTF_SetError( "Text has zero width" );
  883. return NULL;
  884. }
  885. height = font->height;
  886. /* Create the target surface */
  887. textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
  888. if( textbuf == NULL ) {
  889. return NULL;
  890. }
  891. /* Fill the palette with the foreground color */
  892. palette = textbuf->format->palette;
  893. palette->colors[0].r = 255 - fg.r;
  894. palette->colors[0].g = 255 - fg.g;
  895. palette->colors[0].b = 255 - fg.b;
  896. palette->colors[1].r = fg.r;
  897. palette->colors[1].g = fg.g;
  898. palette->colors[1].b = fg.b;
  899. SDL_SetColorKey( textbuf, SDL_SRCCOLORKEY, 0 );
  900. /* Load and render each character */
  901. xstart = 0;
  902. swapped = TTF_byteswapped;
  903. for( ch=text; *ch; ++ch ) {
  904. Uint16 c = *ch;
  905. if ( c == UNICODE_BOM_NATIVE ) {
  906. swapped = 0;
  907. if ( text == ch ) {
  908. ++text;
  909. }
  910. continue;
  911. }
  912. if ( c == UNICODE_BOM_SWAPPED ) {
  913. swapped = 1;
  914. if ( text == ch ) {
  915. ++text;
  916. }
  917. continue;
  918. }
  919. if ( swapped ) {
  920. c = SDL_Swap16(c);
  921. }
  922. error = Find_Glyph(font, c, CACHED_METRICS|CACHED_BITMAP);
  923. if( error ) {
  924. SDL_FreeSurface( textbuf );
  925. return NULL;
  926. }
  927. glyph = font->current;
  928. current = &glyph->bitmap;
  929. /* Compensate for wrap around bug with negative minx's */
  930. if ( (ch == text) && (glyph->minx < 0) ) {
  931. xstart -= glyph->minx;
  932. }
  933. for( row = 0; row < current->rows; ++row ) {
  934. /* Make sure we don't go over the limit */
  935. if ( row+glyph->yoffset >= textbuf->h ) {
  936. continue;
  937. }
  938. dst = (Uint8*) textbuf->pixels +
  939. (row+glyph->yoffset) * textbuf->pitch +
  940. xstart + glyph->minx;
  941. src = current->buffer + row * current->pitch;
  942. for ( col=current->width; col>0; --col ) {
  943. *dst++ |= *src++;
  944. }
  945. }
  946. xstart += glyph->advance;
  947. if ( font->style & TTF_STYLE_BOLD ) {
  948. xstart += font->glyph_overhang;
  949. }
  950. }
  951. /* Handle the underline style */
  952. if( font->style & TTF_STYLE_UNDERLINE ) {
  953. row = font->ascent - font->underline_offset - 1;
  954. if ( row >= textbuf->h) {
  955. row = (textbuf->h-1) - font->underline_height;
  956. }
  957. dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
  958. for ( row=font->underline_height; row>0; --row ) {
  959. /* 1 because 0 is the bg color */
  960. memset( dst, 1, textbuf->w );
  961. dst += textbuf->pitch;
  962. }
  963. }
  964. return textbuf;
  965. }
  966. SDL_Surface *TTF_RenderGlyph_Solid(TTF_Font *font, Uint16 ch, SDL_Color fg)
  967. {
  968. SDL_Surface *textbuf;
  969. SDL_Palette *palette;
  970. Uint8 *src, *dst;
  971. int row;
  972. FT_Error error;
  973. c_glyph *glyph;
  974. /* Get the glyph itself */
  975. error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_BITMAP);
  976. if ( error ) {
  977. return(NULL);
  978. }
  979. glyph = font->current;
  980. /* Create the target surface */
  981. textbuf = SDL_CreateRGBSurface( SDL_SWSURFACE,
  982. glyph->bitmap.pitch,
  983. glyph->bitmap.rows,
  984. 8, 0, 0, 0, 0 );
  985. if ( ! textbuf ) {
  986. return(NULL);
  987. }
  988. /* Fill the palette with the foreground color */
  989. palette = textbuf->format->palette;
  990. palette->colors[0].r = 255-fg.r;
  991. palette->colors[0].g = 255-fg.g;
  992. palette->colors[0].b = 255-fg.b;
  993. palette->colors[1].r = fg.r;
  994. palette->colors[1].g = fg.g;
  995. palette->colors[1].b = fg.b;
  996. SDL_SetColorKey(textbuf, SDL_SRCCOLORKEY, 0);
  997. /* Copy the character from the pixmap */
  998. src = glyph->bitmap.buffer;
  999. dst = (Uint8*) textbuf->pixels;
  1000. for ( row = 0; row < textbuf->h; ++row ) {
  1001. memcpy( dst, src, glyph->bitmap.pitch );
  1002. src += glyph->bitmap.pitch;
  1003. dst += textbuf->pitch;
  1004. }
  1005. /* Handle the underline style */
  1006. if( font->style & TTF_STYLE_UNDERLINE ) {
  1007. row = font->ascent - font->underline_offset - 1;
  1008. if ( row >= textbuf->h) {
  1009. row = (textbuf->h-1) - font->underline_height;
  1010. }
  1011. dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
  1012. for ( row=font->underline_height; row>0; --row ) {
  1013. /* 1 because 0 is the bg color */
  1014. memset( dst, 1, textbuf->w );
  1015. dst += textbuf->pitch;
  1016. }
  1017. }
  1018. return(textbuf);
  1019. }
  1020. /* Convert the Latin-1 text to UNICODE and render it
  1021. */
  1022. SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font,
  1023. const char *text, SDL_Color fg, SDL_Color bg)
  1024. {
  1025. SDL_Surface *textbuf;
  1026. Uint16 *unicode_text;
  1027. int unicode_len;
  1028. /* Copy the Latin-1 text to a UNICODE text buffer */
  1029. unicode_len = strlen(text);
  1030. unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
  1031. if ( unicode_text == NULL ) {
  1032. TTF_SetError("Out of memory");
  1033. return(NULL);
  1034. }
  1035. *unicode_text = UNICODE_BOM_NATIVE;
  1036. LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);
  1037. /* Render the new text */
  1038. textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg);
  1039. /* Free the text buffer and return */
  1040. FREEA(unicode_text);
  1041. return(textbuf);
  1042. }
  1043. /* Convert the UTF-8 text to UNICODE and render it
  1044. */
  1045. SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font,
  1046. const char *text, SDL_Color fg, SDL_Color bg)
  1047. {
  1048. SDL_Surface *textbuf;
  1049. Uint16 *unicode_text;
  1050. int unicode_len;
  1051. /* Copy the UTF-8 text to a UNICODE text buffer */
  1052. unicode_len = strlen(text);
  1053. unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
  1054. if ( unicode_text == NULL ) {
  1055. TTF_SetError("Out of memory");
  1056. return(NULL);
  1057. }
  1058. *unicode_text = UNICODE_BOM_NATIVE;
  1059. UTF8_to_UNICODE(unicode_text+1, text, unicode_len);
  1060. /* Render the new text */
  1061. textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg);
  1062. /* Free the text buffer and return */
  1063. FREEA(unicode_text);
  1064. return(textbuf);
  1065. }
  1066. SDL_Surface* TTF_RenderUNICODE_Shaded( TTF_Font* font,
  1067. const Uint16* text,
  1068. SDL_Color fg,
  1069. SDL_Color bg )
  1070. {
  1071. int xstart;
  1072. int width;
  1073. int height;
  1074. SDL_Surface* textbuf;
  1075. SDL_Palette* palette;
  1076. int index;
  1077. int rdiff;
  1078. int gdiff;
  1079. int bdiff;
  1080. const Uint16* ch;
  1081. Uint8* src;
  1082. Uint8* dst;
  1083. int swapped;
  1084. int row, col;
  1085. FT_Bitmap* current;
  1086. c_glyph *glyph;
  1087. FT_Error error;
  1088. /* Get the dimensions of the text surface */
  1089. if( ( TTF_SizeUNICODE(font, text, &width, NULL) < 0 ) || !width ) {
  1090. TTF_SetError("Text has zero width");
  1091. return NULL;
  1092. }
  1093. height = font->height;
  1094. /* Create the target surface */
  1095. textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
  1096. if( textbuf == NULL ) {
  1097. return NULL;
  1098. }
  1099. /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
  1100. palette = textbuf->format->palette;
  1101. rdiff = fg.r - bg.r;
  1102. gdiff = fg.g - bg.g;
  1103. bdiff = fg.b - bg.b;
  1104. for( index = 0; index < NUM_GRAYS; ++index ) {
  1105. palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1);
  1106. palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1);
  1107. palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1);
  1108. }
  1109. /* Load and render each character */
  1110. xstart = 0;
  1111. swapped = TTF_byteswapped;
  1112. for( ch = text; *ch; ++ch ) {
  1113. Uint16 c = *ch;
  1114. if ( c == UNICODE_BOM_NATIVE ) {
  1115. swapped = 0;
  1116. if ( text == ch ) {
  1117. ++text;
  1118. }
  1119. continue;
  1120. }
  1121. if ( c == UNICODE_BOM_SWAPPED ) {
  1122. swapped = 1;
  1123. if ( text == ch ) {
  1124. ++text;
  1125. }
  1126. continue;
  1127. }
  1128. if ( swapped ) {
  1129. c = SDL_Swap16(c);
  1130. }
  1131. error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP);
  1132. if( error ) {
  1133. SDL_FreeSurface( textbuf );
  1134. return NULL;
  1135. }
  1136. glyph = font->current;
  1137. /* Compensate for the wrap around with negative minx's */
  1138. if ( (ch == text) && (glyph->minx < 0) ) {
  1139. xstart -= glyph->minx;
  1140. }
  1141. current = &glyph->pixmap;
  1142. for( row = 0; row < current->rows; ++row ) {
  1143. /* Make sure we don't go over the limit */
  1144. if ( row+glyph->yoffset >= textbuf->h ) {
  1145. continue;
  1146. }
  1147. dst = (Uint8*) textbuf->pixels +
  1148. (row+glyph->yoffset) * textbuf->pitch +
  1149. xstart + glyph->minx;
  1150. src = current->buffer + row * current->pitch;
  1151. for ( col=current->width; col>0; --col ) {
  1152. *dst++ |= *src++;
  1153. }
  1154. }
  1155. xstart += glyph->advance;
  1156. if( font->style & TTF_STYLE_BOLD ) {
  1157. xstart += font->glyph_overhang;
  1158. }
  1159. }
  1160. /* Handle the underline style */
  1161. if( font->style & TTF_STYLE_UNDERLINE ) {
  1162. row = font->ascent - font->underline_offset - 1;
  1163. if ( row >= textbuf->h) {
  1164. row = (textbuf->h-1) - font->underline_height;
  1165. }
  1166. dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
  1167. for ( row=font->underline_height; row>0; --row ) {
  1168. memset( dst, NUM_GRAYS - 1, textbuf->w );
  1169. dst += textbuf->pitch;
  1170. }
  1171. }
  1172. return textbuf;
  1173. }
  1174. SDL_Surface* TTF_RenderGlyph_Shaded( TTF_Font* font,
  1175. Uint16 ch,
  1176. SDL_Color fg,
  1177. SDL_Color bg )
  1178. {
  1179. SDL_Surface* textbuf;
  1180. SDL_Palette* palette;
  1181. int index;
  1182. int rdiff;
  1183. int gdiff;
  1184. int bdiff;
  1185. Uint8* src;
  1186. Uint8* dst;
  1187. int row;
  1188. FT_Error error;
  1189. c_glyph* glyph;
  1190. /* Get the glyph itself */
  1191. error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_PIXMAP);
  1192. if( error ) {
  1193. return NULL;
  1194. }
  1195. glyph = font->current;
  1196. /* Create the target surface */
  1197. textbuf = SDL_CreateRGBSurface( SDL_SWSURFACE,
  1198. glyph->pixmap.width,
  1199. glyph->pixmap.rows,
  1200. 8, 0, 0, 0, 0 );
  1201. if( !textbuf ) {
  1202. return NULL;
  1203. }
  1204. /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
  1205. palette = textbuf->format->palette;
  1206. rdiff = fg.r - bg.r;
  1207. gdiff = fg.g - bg.g;
  1208. bdiff = fg.b - bg.b;
  1209. for( index = 0; index < NUM_GRAYS; ++index ) {
  1210. palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1);
  1211. palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1);
  1212. palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1);
  1213. }
  1214. /* Copy the character from the pixmap */
  1215. src = glyph->pixmap.buffer;
  1216. dst = (Uint8*) textbuf->pixels;
  1217. for ( row = 0; row < textbuf->h; ++row ) {
  1218. memcpy( dst, src, glyph->pixmap.pitch );
  1219. src += glyph->pixmap.pitch;
  1220. dst += textbuf->pitch;
  1221. }
  1222. /* Handle the underline style */
  1223. if( font->style & TTF_STYLE_UNDERLINE ) {
  1224. row = font->ascent - font->underline_offset - 1;
  1225. if ( row >= textbuf->h) {
  1226. row = (textbuf->h-1) - font->underline_height;
  1227. }
  1228. dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
  1229. for ( row=font->underline_height; row>0; --row ) {
  1230. memset( dst, NUM_GRAYS - 1, textbuf->w );
  1231. dst += textbuf->pitch;
  1232. }
  1233. }
  1234. return textbuf;
  1235. }
  1236. /* Convert the Latin-1 text to UNICODE and render it
  1237. */
  1238. SDL_Surface *TTF_RenderText_Blended(TTF_Font *font,
  1239. const char *text, SDL_Color fg)
  1240. {
  1241. SDL_Surface *textbuf;
  1242. Uint16 *unicode_text;
  1243. int unicode_len;
  1244. /* Copy the Latin-1 text to a UNICODE text buffer */
  1245. unicode_len = strlen(text);
  1246. unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
  1247. if ( unicode_text == NULL ) {
  1248. TTF_SetError("Out of memory");
  1249. return(NULL);
  1250. }
  1251. *unicode_text = UNICODE_BOM_NATIVE;
  1252. LATIN1_to_UNICODE(unicode_text+1, text, unicode_len);
  1253. /* Render the new text */
  1254. textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg);
  1255. /* Free the text buffer and return */
  1256. FREEA(unicode_text);
  1257. return(textbuf);
  1258. }
  1259. /* Convert the UTF-8 text to UNICODE and render it
  1260. */
  1261. SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
  1262. const char *text, SDL_Color fg)
  1263. {
  1264. SDL_Surface *textbuf;
  1265. Uint16 *unicode_text;
  1266. int unicode_len;
  1267. /* Copy the UTF-8 text to a UNICODE text buffer */
  1268. unicode_len = strlen(text);
  1269. unicode_text = (Uint16 *)ALLOCA((1+unicode_len+1)*(sizeof *unicode_text));
  1270. if ( unicode_text == NULL ) {
  1271. TTF_SetError("Out of memory");
  1272. return(NULL);
  1273. }
  1274. *unicode_text = UNICODE_BOM_NATIVE;
  1275. UTF8_to_UNICODE(unicode_text+1, text, unicode_len);
  1276. /* Render the new text */
  1277. textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg);
  1278. /* Free the text buffer and return */
  1279. FREEA(unicode_text);
  1280. return(textbuf);
  1281. }
  1282. SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font,
  1283. const Uint16 *text, SDL_Color fg)
  1284. {
  1285. int xstart;
  1286. int width, height;
  1287. SDL_Surface *textbuf;
  1288. Uint32 alpha;
  1289. Uint32 pixel;
  1290. const Uint16 *ch;
  1291. Uint8 *src;
  1292. Uint32 *dst;
  1293. int swapped;
  1294. int row, col;
  1295. c_glyph *glyph;
  1296. FT_Error error;
  1297. /* Get the dimensions of the text surface */
  1298. if ( (TTF_SizeUNICODE(font, text, &width, NULL) < 0) || !width ) {
  1299. TTF_SetError("Text has zero width");
  1300. return(NULL);
  1301. }
  1302. height = font->height;
  1303. textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 32,
  1304. 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
  1305. if ( textbuf == NULL ) {
  1306. return(NULL);
  1307. }
  1308. /* Load and render each character */
  1309. xstart = 0;
  1310. swapped = TTF_byteswapped;
  1311. pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
  1312. for ( ch=text; *ch; ++ch ) {
  1313. Uint16 c = *ch;
  1314. if ( c == UNICODE_BOM_NATIVE ) {
  1315. swapped = 0;
  1316. if ( text == ch ) {
  1317. ++text;
  1318. }
  1319. continue;
  1320. }
  1321. if ( c == UNICODE_BOM_SWAPPED ) {
  1322. swapped = 1;
  1323. if ( text == ch ) {
  1324. ++text;
  1325. }
  1326. continue;
  1327. }
  1328. if ( swapped ) {
  1329. c = SDL_Swap16(c);
  1330. }
  1331. error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP);
  1332. if( error ) {
  1333. SDL_FreeSurface( textbuf );
  1334. return NULL;
  1335. }
  1336. glyph = font->current;
  1337. width = glyph->pixmap.width;
  1338. /* Compensate for the wrap around bug with negative minx's */
  1339. if ( (ch == text) && (glyph->minx < 0) ) {
  1340. xstart -= glyph->minx;
  1341. }
  1342. for ( row = 0; row < glyph->pixmap.rows; ++row ) {
  1343. /* Make sure we don't go over the limit */
  1344. if ( row+glyph->yoffset >= textbuf->h ) {
  1345. continue;
  1346. }
  1347. dst = (Uint32*) textbuf->pixels +
  1348. (row+glyph->yoffset) * textbuf->pitch/4 +
  1349. xstart + glyph->minx;
  1350. /* Added code to adjust src pointer for pixmaps to
  1351. * account for pitch.
  1352. * */
  1353. src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row);
  1354. for ( col = width; col>0; --col) {
  1355. alpha = *src++;
  1356. *dst++ |= pixel | (alpha << 24);
  1357. }
  1358. }
  1359. xstart += glyph->advance;
  1360. if ( font->style & TTF_STYLE_BOLD ) {
  1361. xstart += font->glyph_overhang;
  1362. }
  1363. }
  1364. /* Handle the underline style */
  1365. if( font->style & TTF_STYLE_UNDERLINE ) {
  1366. row = font->ascent - font->underline_offset - 1;
  1367. if ( row >= textbuf->h) {
  1368. row = (textbuf->h-1) - font->underline_height;
  1369. }
  1370. dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
  1371. pixel |= 0xFF000000; /* Amask */
  1372. for ( row=font->underline_height; row>0; --row ) {
  1373. for ( col=0; col < textbuf->w; ++col ) {
  1374. dst[col] = pixel;
  1375. }
  1376. dst += textbuf->pitch/4;
  1377. }
  1378. }
  1379. return(textbuf);
  1380. }
  1381. SDL_Surface *TTF_RenderGlyph_Blended(TTF_Font *font, Uint16 ch, SDL_Color fg)
  1382. {
  1383. SDL_Surface *textbuf;
  1384. Uint32 alpha;
  1385. Uint32 pixel;
  1386. Uint8 *src;
  1387. Uint32 *dst;
  1388. int row, col;
  1389. FT_Error error;
  1390. c_glyph *glyph;
  1391. /* Get the glyph itself */
  1392. error = Find_Glyph(font, ch, CACHED_METRICS|CACHED_PIXMAP);
  1393. if ( error ) {
  1394. return(NULL);
  1395. }
  1396. glyph = font->current;
  1397. textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE,
  1398. glyph->pixmap.width, glyph->pixmap.rows, 32,
  1399. 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
  1400. if ( ! textbuf ) {
  1401. return(NULL);
  1402. }
  1403. /* Copy the character from the pixmap */
  1404. pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
  1405. for ( row=0; row<textbuf->h; ++row ) {
  1406. /* Changed src to take pitch into account, not just width */
  1407. src = glyph->pixmap.buffer + row * glyph->pixmap.pitch;
  1408. dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
  1409. for ( col=0; col<glyph->pixmap.width; ++col ) {
  1410. alpha = *src++;
  1411. *dst++ = pixel | (alpha << 24);
  1412. }
  1413. }
  1414. /* Handle the underline style */
  1415. if( font->style & TTF_STYLE_UNDERLINE ) {
  1416. row = font->ascent - font->underline_offset - 1;
  1417. if ( row >= textbuf->h) {
  1418. row = (textbuf->h-1) - font->underline_height;
  1419. }
  1420. dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
  1421. pixel |= 0xFF000000; /* Amask */
  1422. for ( row=font->underline_height; row>0; --row ) {
  1423. for ( col=0; col < textbuf->w; ++col ) {
  1424. dst[col] = pixel;
  1425. }
  1426. dst += textbuf->pitch/4;
  1427. }
  1428. }
  1429. return(textbuf);
  1430. }
  1431. void TTF_SetFontStyle( TTF_Font* font, int style )
  1432. {
  1433. font->style = style;
  1434. Flush_Cache( font );
  1435. }
  1436. int TTF_GetFontStyle( TTF_Font* font )
  1437. {
  1438. return font->style;
  1439. }
  1440. void TTF_Quit( void )
  1441. {
  1442. if ( TTF_initialized ) {
  1443. if ( --TTF_initialized == 0 ) {
  1444. FT_Done_FreeType( library );
  1445. }
  1446. }
  1447. }
  1448. int TTF_WasInit( void )
  1449. {
  1450. return TTF_initialized;
  1451. }