Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1.  
  2. #include <math.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <assert.h>
  7.  
  8. #include <freetype/freetype.h>
  9.  
  10. #include "SDL.h"
  11. #include "SDL_ttf.h"
  12.  
  13. /* Macro to convert a character to a Unicode value -- assume already Unicode */
  14. #define UNICODE(c)      c
  15.  
  16. /* Round a float up to the nearest integeter and return that integer */
  17. static int round(float x)
  18. {
  19.         int value;
  20.  
  21.         value = (int)x;
  22.         if ( x > value ) {
  23.                 value = value + 1;
  24.         } else
  25.         if ( x < value ) {
  26.                 value = value - 1;
  27.         }
  28.         return value;
  29. }
  30.  
  31. /* The structure used to hold glyph information (cached) */
  32. struct glyph {
  33.         int cached;
  34.         TT_Raster_Map bitmap;
  35.         TT_Raster_Map pixmap;
  36.         int minx;
  37.         int maxx;
  38.         int miny;
  39.         int maxy;
  40.         int advance;
  41. };
  42.  
  43. /* The structure used to hold internal font information */
  44. struct _TTF_Font {
  45.         TT_Face face;
  46.         TT_Instance inst;
  47.         TT_Glyph glyph;
  48.         TT_CharMap map;
  49.  
  50.         /* Font metrics */
  51.         int pointsize;
  52.         int height;  /* ascent - descent */
  53.         float ascent;
  54.         float descent;
  55.         float lineskip;
  56.  
  57.         /* The font style */
  58.         int style;
  59.  
  60.         /* Extra width in glyph bounds for text styles */
  61.         int glyph_overhang;
  62.         float glyph_italics;
  63.  
  64.         /* For now, support Latin-1 character set caching */
  65.         struct glyph *current;
  66.         struct glyph cache[256];
  67.         struct glyph scratch;
  68. };
  69.  
  70. /* The FreeType font engine */
  71. static TT_Engine engine;
  72.  
  73. int TTF_Init(void)
  74. {
  75.         int error;
  76.  
  77.         error = TT_Init_FreeType(&engine);
  78.         if ( error ) {
  79.                 SDL_SetError("Couldn't init FreeType engine");
  80.                 return(-1);
  81.         }
  82.         return(0);
  83. }
  84.  
  85. TTF_Font *TTF_OpenFont(const char *file, int ptsize)
  86. {
  87.         TTF_Font *font;
  88.         TT_Face_Properties properties;
  89.         TT_Instance_Metrics imetrics;
  90.         int i, n;
  91.         TT_UShort platform, encoding;
  92.         TT_Error error;
  93.  
  94.         font = (TTF_Font *)malloc(sizeof(*font));
  95.         if ( font == NULL ) {
  96.                 SDL_SetError("Out of memory");
  97.                 return(NULL);
  98.         }
  99.         memset(font, 0, sizeof(*font));
  100.  
  101.         /* Open the font and create ancillary data */
  102.         error = TT_Open_Face(engine, file, &font->face);
  103.         if ( error ) {
  104.                 SDL_SetError("Couldn't load font file");
  105.                 free(font);
  106.                 return(NULL);
  107.         }
  108.         error = TT_New_Glyph(font->face, &font->glyph);
  109.         if ( error ) {
  110.                 SDL_SetError("Couldn't create glyph container");
  111.                 TTF_CloseFont(font);
  112.                 return(NULL);
  113.         }
  114.         error = TT_New_Instance(font->face, &font->inst);
  115.         if ( error ) {
  116.                 SDL_SetError("Couldn't create font instance");
  117.                 TTF_CloseFont(font);
  118.                 return(NULL);
  119.         }
  120.  
  121.         /* Set the display resolution */
  122.         error = TT_Set_Instance_Resolutions(font->inst, 72, 72);
  123.         if ( error ) {
  124.                 SDL_SetError("Couldn't set font resolution");
  125.                 TTF_CloseFont(font);
  126.                 return(NULL);
  127.         }
  128.         error = TT_Set_Instance_CharSize(font->inst, ptsize*64);
  129.         if ( error ) {
  130.                 SDL_SetError("Couldn't set font size");
  131.                 TTF_CloseFont(font);
  132.                 return(NULL);
  133.         }
  134.  
  135.         /* Get a Unicode mapping for this font */
  136.         n = TT_Get_CharMap_Count(font->face);
  137.         for ( i=0; i<n; ++i ) {
  138.                 TT_Get_CharMap_ID(font->face, i, &platform, &encoding);
  139.                 if ( ((platform == TT_PLATFORM_MICROSOFT) &&
  140.                                   (encoding == TT_MS_ID_UNICODE_CS)) ||
  141.                      ((platform == TT_PLATFORM_APPLE_UNICODE) &&
  142.                                   (encoding == TT_APPLE_ID_DEFAULT)) ) {
  143.                         TT_Get_CharMap(font->face, i, &font->map);
  144.                         break;
  145.                 }
  146.         }
  147.         if ( i == n ) {
  148.                 SDL_SetError("Font doesn't have a Unicode mapping");
  149.                 TTF_CloseFont(font);
  150.                 return(NULL);
  151.         }
  152.  
  153.         /* Get the font metrics for this font */
  154.         TT_Get_Face_Properties(font->face, &properties );
  155.         TT_Get_Instance_Metrics(font->inst, &imetrics);
  156.         font->pointsize = imetrics.y_ppem;
  157.         font->ascent = (float)properties.horizontal->Ascender /
  158.                         properties.header->Units_Per_EM;
  159.         font->ascent *= font->pointsize;
  160.         font->descent = (float)properties.horizontal->Descender /
  161.                          properties.header->Units_Per_EM;
  162.         font->descent *= font->pointsize;
  163.         font->lineskip = (float)properties.horizontal->Line_Gap /
  164.                           properties.header->Units_Per_EM;
  165.         font->lineskip *= font->pointsize;
  166.         font->height = round(font->ascent - font->descent);
  167.  
  168.         /* Set the default font style */
  169.         font->style = TTF_STYLE_NORMAL;
  170.         font->glyph_overhang = font->pointsize/10;
  171.         /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
  172.         font->glyph_italics = 0.207;
  173.         font->glyph_italics *= font->height;
  174.  
  175.         return(font);
  176. }
  177.  
  178. static void Flush_Glyph(struct glyph *glyph)
  179. {
  180.         if ( glyph->bitmap.bitmap ) {
  181.                 free(glyph->bitmap.bitmap);
  182.                 glyph->bitmap.bitmap = 0;
  183.         }
  184.         if ( glyph->pixmap.bitmap ) {
  185.                 free(glyph->pixmap.bitmap);
  186.                 glyph->pixmap.bitmap = 0;
  187.         }
  188.         glyph->cached = 0;
  189. }
  190.        
  191. static void Flush_Cache(TTF_Font *font)
  192. {
  193.         int i;
  194.  
  195.         for ( i=0; i<(sizeof font->cache)/(sizeof font->cache[0]); ++i ) {
  196.                 if ( font->cache[i].cached ) {
  197.                         Flush_Glyph(&font->cache[i]);
  198.                 }
  199.         }
  200.         if ( font->scratch.cached ) {
  201.                 Flush_Glyph(&font->scratch);
  202.         }
  203. }
  204.  
  205. static TT_Error Load_Glyph(TTF_Font *font, Uint16 ch, struct glyph *glyph)
  206. {
  207.         TT_UShort index;
  208.         TT_Glyph_Metrics metrics;
  209.         TT_Outline outline;
  210.         int x_offset;
  211.         int y_offset;
  212.         TT_Error error;
  213.  
  214.         /* Load the glyph */
  215.         index = TT_Char_Index(font->map, UNICODE(ch));
  216.         error = TT_Load_Glyph(font->inst, font->glyph, index, TTLOAD_DEFAULT);
  217.         if ( error ) return error;
  218.  
  219.         /* Get the bounding box */
  220.         TT_Get_Glyph_Metrics(font->glyph, &metrics);
  221.         glyph->minx = (metrics.bbox.xMin & -64) / 64;
  222.         glyph->maxx = ((metrics.bbox.xMax + 63) & -64) / 64;
  223.         glyph->miny = (metrics.bbox.yMin & -64) / 64;
  224.         glyph->maxy = ((metrics.bbox.yMax + 63) & -64) / 64;
  225.         glyph->advance = (metrics.advance & -64) / 64;
  226.  
  227.         /* Adjust for bold and italic text */
  228.         if ( font->style & TTF_STYLE_BOLD ) {
  229.                 glyph->maxx += font->glyph_overhang;
  230.         }
  231.         if ( font->style & TTF_STYLE_ITALIC ) {
  232.                 glyph->maxx += round(font->glyph_italics);
  233.         }
  234.  
  235.         /* Get the bitmap memory */
  236.         glyph->bitmap.width = ((glyph->maxx - glyph->minx) + 7) & ~7;
  237.         glyph->bitmap.rows = font->height;
  238.         glyph->bitmap.cols = glyph->bitmap.width/8;
  239.         glyph->bitmap.flow = TT_Flow_Down;
  240.         glyph->bitmap.size = (glyph->bitmap.rows * glyph->bitmap.cols);
  241.         if ( glyph->bitmap.size ) {
  242.                 glyph->bitmap.bitmap = malloc(glyph->bitmap.size);
  243.                 if ( ! glyph->bitmap.bitmap ) {
  244.                         error = TT_Err_Out_Of_Memory;
  245.                         goto was_error;
  246.                 }
  247.                 memset(glyph->bitmap.bitmap, 0, glyph->bitmap.size);
  248.         } else {
  249.                 glyph->bitmap.bitmap = 0;
  250.         }
  251.  
  252.         /* Get the pixmap memory */
  253.         glyph->pixmap.width = ((glyph->maxx - glyph->minx) + 3) & ~3;
  254.         glyph->pixmap.rows = font->height;
  255.         glyph->pixmap.cols = glyph->pixmap.width;
  256.         glyph->pixmap.flow = TT_Flow_Down;
  257.         glyph->pixmap.size = (glyph->pixmap.rows * glyph->pixmap.cols);
  258.         if ( glyph->pixmap.size ) {
  259.                 glyph->pixmap.bitmap = malloc(glyph->pixmap.size);
  260.                 if ( ! glyph->pixmap.bitmap ) {
  261.                         error = TT_Err_Out_Of_Memory;
  262.                         goto was_error;
  263.                 }
  264.                 memset(glyph->pixmap.bitmap, 0, glyph->pixmap.size);
  265.         } else {
  266.                 glyph->pixmap.bitmap = 0;
  267.         }
  268.  
  269.         /* Render the glyph into the bitmap and pixmap */
  270.         error = TT_Get_Glyph_Outline(font->glyph, &outline);
  271.         /* Handle the italic style */
  272.         if ( font->style & TTF_STYLE_ITALIC ) {
  273.                 TT_Matrix shear;
  274.  
  275.                 shear.xx = 1<<16;
  276.                 shear.xy = (int)(font->glyph_italics*(1<<16))/font->height;
  277.                 shear.yx = 0;
  278.                 shear.yy = 1<<16;
  279.                 TT_Transform_Outline(&outline, &shear);
  280.         }
  281.         x_offset = -glyph->minx * 64;
  282.         y_offset = -round(font->descent) * 64;
  283.         TT_Translate_Outline(&outline, x_offset, y_offset);
  284.         error += TT_Get_Outline_Bitmap(engine, &outline, &glyph->bitmap);
  285.         error += TT_Get_Outline_Pixmap(engine, &outline, &glyph->pixmap);
  286.         /* Handle the bold style */
  287.         if ( font->style & TTF_STYLE_BOLD ) {
  288.                 int row, col;
  289.                 int offset;
  290.                 int pixel;
  291.                 Uint8 *pixmap;
  292.  
  293.                 /* The bitmap is easy, just render another copy */
  294.                 for ( offset=0; offset < font->glyph_overhang; ++offset ) {
  295.                         TT_Translate_Outline(&outline, 64, 0);
  296.                         error += TT_Get_Outline_Bitmap(engine,
  297.                                                        &outline,&glyph->bitmap);
  298.                 }
  299.                 x_offset += font->glyph_overhang*64;
  300.  
  301.                 /* The pixmap is a little harder, we have to add and clamp */
  302.                 for ( row=glyph->pixmap.rows-1; row >= 0; --row ) {
  303.                         pixmap = (Uint8 *)glyph->pixmap.bitmap +
  304.                                           row*glyph->pixmap.cols;
  305.                         for (offset=1; offset<=font->glyph_overhang; ++offset) {
  306.                                 for (col=glyph->pixmap.cols-1; col > 0; --col) {
  307.                                         pixel=(pixmap[col]+pixmap[col-1]);
  308.                                         if ( pixel > 4 ) {
  309.                                                 pixel = 4;
  310.                                         }
  311.                                         pixmap[col] = (Uint8)pixel;
  312.                                 }
  313.                         }
  314.                 }
  315.         }
  316.         TT_Translate_Outline(&outline, -x_offset, -y_offset);
  317. was_error:
  318.         if ( error ) {
  319.                 if ( glyph->bitmap.bitmap ) {
  320.                         free(glyph->bitmap.bitmap);
  321.                         glyph->bitmap.bitmap = 0;
  322.                 }
  323.                 if ( glyph->pixmap.bitmap ) {
  324.                         free(glyph->pixmap.bitmap);
  325.                         glyph->pixmap.bitmap = 0;
  326.                 }
  327.                 return error;
  328.         }
  329.  
  330.         /* We're done, mark this glyph cached */
  331.         glyph->cached = ch;
  332.         return TT_Err_Ok;
  333. }
  334.  
  335. static TT_Error Find_Glyph(TTF_Font *font, Uint16 ch)
  336. {
  337.         int retval;
  338.  
  339.         retval = 0;
  340.         if ( ch < 256 ) {
  341.                 font->current = &font->cache[ch];
  342.         } else {
  343.                 if ( font->scratch.cached != ch ) {
  344.                         Flush_Glyph(&font->scratch);
  345.                 }
  346.                 font->current = &font->scratch;
  347.         }
  348.         if ( ! font->current->cached ) {
  349.                 retval = Load_Glyph(font, ch, font->current);
  350.         }
  351.         return retval;
  352. }
  353.  
  354. void TTF_CloseFont(TTF_Font *font)
  355. {
  356.         Flush_Cache(font);
  357.         TT_Close_Face(font->face);
  358.         free(font);
  359. }
  360.  
  361. static Uint16 *ASCII_to_UNICODE(Uint16 *unicode, const char *text, int len)
  362. {
  363.         int i;
  364.  
  365.         for ( i=0; i < len; ++i ) {
  366.                 unicode[i] = ((const unsigned char *)text)[i];
  367.         }
  368.         unicode[i] = 0;
  369.  
  370.         return unicode;
  371. }
  372.  
  373. static Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len)
  374. {
  375.         int i, j;
  376.         Uint16 ch;
  377.  
  378.         for ( i=0, j=0; i < len; ++i, ++j ) {
  379.                 ch = ((const unsigned char *)utf8)[i];
  380.                 if ( ch >= 0xF0 ) {
  381.                         ch  =  (Uint16)(utf8[i]&0x07) << 18;
  382.                         ch |=  (Uint16)(utf8[++i]&0x3F) << 12;
  383.                         ch |=  (Uint16)(utf8[++i]&0x3F) << 6;
  384.                         ch |=  (Uint16)(utf8[++i]&0x3F);
  385.                 } else
  386.                 if ( ch >= 0xE0 ) {
  387.                         ch  =  (Uint16)(utf8[i]&0x3F) << 12;
  388.                         ch |=  (Uint16)(utf8[++i]&0x3F) << 6;
  389.                         ch |=  (Uint16)(utf8[++i]&0x3F);
  390.                 } else
  391.                 if ( ch >= 0xC0 ) {
  392.                         ch  =  (Uint16)(utf8[i]&0x3F) << 6;
  393.                         ch |=  (Uint16)(utf8[++i]&0x3F);
  394.                 }
  395.                 unicode[j] = ch;
  396.         }
  397.         unicode[j] = 0;
  398.  
  399.         return unicode;
  400. }
  401.  
  402. int TTF_FontHeight(TTF_Font *font)
  403. {
  404.         return(font->height);
  405. }
  406.  
  407. int TTF_FontAscent(TTF_Font *font)
  408. {
  409.        return(round(font->ascent));
  410. }
  411.  
  412. int TTF_FontDescent(TTF_Font *font)
  413. {
  414.         return(round(font->descent));
  415. }
  416.  
  417. int TTF_FontLineSkip(TTF_Font *font)
  418. {
  419.         return(round(font->lineskip));
  420. }
  421.  
  422. int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch,
  423.                      int* minx, int* maxx, int* miny, int* maxy, int* advance)
  424. {
  425.         TT_Error error;
  426.  
  427.         error = Find_Glyph(font, ch);
  428.  
  429.         if ( error ) {
  430.                 return -1;
  431.         }
  432.  
  433.         if ( minx ) {
  434.                 *minx = font->current->minx;
  435.         }
  436.         if ( maxx ) {
  437.                 *maxx = font->current->maxx;
  438.         }
  439.         if ( miny ) {
  440.                 *miny = font->current->miny;
  441.         }
  442.         if ( maxy ) {
  443.                 *maxy = font->current->maxy;
  444.         }
  445.         if ( advance ) {
  446.                 *advance = font->current->advance;
  447.         }
  448.         return 0;
  449. }
  450.  
  451. int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h)
  452. {
  453.         Uint16 *unicode_text;
  454.         int unicode_len;
  455.         int status;
  456.  
  457.         /* Copy the Latin-1 text to a UNICODE text buffer */
  458.         unicode_len = strlen(text);
  459.         unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
  460.         if ( unicode_text == NULL ) {
  461.                 SDL_SetError("Out of memory");
  462.                 return -1;
  463.         }
  464.         ASCII_to_UNICODE(unicode_text, text, unicode_len);
  465.  
  466.         /* Render the new text */
  467.         status = TTF_SizeUNICODE(font, unicode_text, w, h);
  468.  
  469.         /* Free the text buffer and return */
  470.         free(unicode_text);
  471.         return status;
  472. }
  473.  
  474. int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h)
  475. {
  476.         Uint16 *unicode_text;
  477.         int unicode_len;
  478.         int status;
  479.  
  480.         /* Copy the UTF-8 text to a UNICODE text buffer */
  481.         unicode_len = strlen(text);
  482.         unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
  483.         if ( unicode_text == NULL ) {
  484.                 SDL_SetError("Out of memory");
  485.                 return -1;
  486.         }
  487.         UTF8_to_UNICODE(unicode_text, text, unicode_len);
  488.  
  489.         /* Render the new text */
  490.         status = TTF_SizeUNICODE(font, unicode_text, w, h);
  491.  
  492.         /* Free the text buffer and return */
  493.         free(unicode_text);
  494.         return status;
  495. }
  496.  
  497. int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h)
  498. {
  499.         int status;
  500.         const Uint16 *ch;
  501.         int x, z, minx, maxx;
  502.         TT_Error error;
  503.  
  504.         /* Initialize everything to 0 */
  505.         status = 0;
  506.         minx = maxx = 0;
  507.  
  508.         /* Load each character and sum it's bounding box */
  509.         x= 0;
  510.         for ( ch=text; *ch; ++ch ) {
  511.                 error = Find_Glyph(font, *ch);
  512.                 if ( ! error ) {
  513.                         z = x + font->current->minx;
  514.                         if ( minx > z ) {
  515.                                 minx = z;
  516.                         }
  517.                         if ( font->style & TTF_STYLE_BOLD ) {
  518.                                 x += font->glyph_overhang;
  519.                         }
  520.                         if ( font->current->advance > font->current->maxx ) {
  521.                                 z = x + font->current->advance;
  522.                         } else {
  523.                                 z = x + font->current->maxx;
  524.                         }
  525.                         if ( maxx < z ) {
  526.                                 maxx = z;
  527.                         }
  528.                         x += font->current->advance;
  529.                 }
  530.         }
  531.  
  532.         /* Fill the bounds rectangle */
  533.         if ( w ) {
  534.                 *w = (maxx - minx);
  535.         }
  536.         if ( h ) {
  537.                 *h = font->height;
  538.         }
  539.         return status;
  540. }
  541.  
  542. /* Convert the Latin-1 text to UNICODE and render it
  543. */
  544. SDL_Surface *TTF_RenderText_Solid(TTF_Font *font,
  545.                                 const char *text, SDL_Color fg)
  546. {
  547.         SDL_Surface *textbuf;
  548.         Uint16 *unicode_text;
  549.         int unicode_len;
  550.  
  551.         /* Copy the Latin-1 text to a UNICODE text buffer */
  552.         unicode_len = strlen(text);
  553.         unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
  554.         if ( unicode_text == NULL ) {
  555.                 SDL_SetError("Out of memory");
  556.                 return(NULL);
  557.         }
  558.         ASCII_to_UNICODE(unicode_text, text, unicode_len);
  559.  
  560.         /* Render the new text */
  561.         textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg);
  562.  
  563.         /* Free the text buffer and return */
  564.         free(unicode_text);
  565.         return(textbuf);
  566. }
  567.  
  568. /* Convert the UTF-8 text to UNICODE and render it
  569. */
  570. SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font,
  571.                                 const char *text, SDL_Color fg)
  572. {
  573.         SDL_Surface *textbuf;
  574.         Uint16 *unicode_text;
  575.         int unicode_len;
  576.  
  577.         /* Copy the UTF-8 text to a UNICODE text buffer */
  578.         unicode_len = strlen(text);
  579.         unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
  580.         if ( unicode_text == NULL ) {
  581.                 SDL_SetError("Out of memory");
  582.                 return(NULL);
  583.         }
  584.         UTF8_to_UNICODE(unicode_text, text, unicode_len);
  585.  
  586.         /* Render the new text */
  587.         textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg);
  588.  
  589.         /* Free the text buffer and return */
  590.         free(unicode_text);
  591.         return(textbuf);
  592. }
  593.  
  594. SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font,
  595.                                 const Uint16 *text, SDL_Color fg)
  596. {
  597.         int xstart, width;
  598.         int w, h;
  599.         SDL_Surface *textbuf;
  600.         SDL_Palette *palette;
  601.         const Uint16 *ch;
  602.         Uint8 *src, *dst;
  603.         int row, col;
  604.         TT_Error error;
  605.  
  606.         /* Get the dimensions of the text surface */
  607.         if ( (TTF_SizeUNICODE(font, text, &w, &h) < 0) || !w ) {
  608.                 TTF_SetError("Text has zero width");
  609.                 return(NULL);
  610.         }
  611.  
  612.         /* Create the target surface */
  613.         width = w;
  614.         w = (w+7)&~7;
  615.         textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
  616.         if ( textbuf == NULL ) {
  617.                 return(NULL);
  618.         }
  619.  
  620.         /* Fill the palette with the foreground color */
  621.         palette = textbuf->format->palette;
  622.         palette->colors[0].r = 255-fg.r;
  623.         palette->colors[0].g = 255-fg.g;
  624.         palette->colors[0].b = 255-fg.b;
  625.         palette->colors[1].r = fg.r;
  626.         palette->colors[1].g = fg.g;
  627.         palette->colors[1].b = fg.b;
  628.         SDL_SetColorKey(textbuf, SDL_SRCCOLORKEY, 0);
  629.  
  630.         /* Load and render each character */
  631.         xstart = 0;
  632.         for ( ch=text; *ch; ++ch ) {
  633.                 error = Find_Glyph(font, *ch);
  634.                 if ( ! error ) {
  635.                         w = font->current->bitmap.width;
  636.                         src = (Uint8 *)font->current->bitmap.bitmap;
  637.                         for ( row = 0; row < h; ++row ) {
  638.                                 dst = (Uint8 *)textbuf->pixels +
  639.                                                row * textbuf->pitch +
  640.                                                xstart + font->current->minx;
  641.                                 for ( col = 0; col < w; col += 8 ) {
  642.                                         Uint8 c = *src++;
  643.                                         *dst++ |= (c&0x80)>>7;
  644.                                         c <<= 1;
  645.                                         *dst++ |= (c&0x80)>>7;
  646.                                         c <<= 1;
  647.                                         *dst++ |= (c&0x80)>>7;
  648.                                         c <<= 1;
  649.                                         *dst++ |= (c&0x80)>>7;
  650.                                         c <<= 1;
  651.                                         *dst++ |= (c&0x80)>>7;
  652.                                         c <<= 1;
  653.                                         *dst++ |= (c&0x80)>>7;
  654.                                         c <<= 1;
  655.                                         *dst++ |= (c&0x80)>>7;
  656.                                         c <<= 1;
  657.                                         *dst++ |= (c&0x80)>>7;
  658.                                 }
  659.                         }
  660.                         xstart += font->current->advance;
  661.                         if ( font->style & TTF_STYLE_BOLD ) {
  662.                                 xstart += font->glyph_overhang;
  663.                         }
  664.                 }
  665.         }
  666.         /* Handle the underline style */
  667.         if ( font->style & TTF_STYLE_UNDERLINE ) {
  668.                 int row_offset;
  669.  
  670.                 row_offset = round(font->ascent) + 1;
  671.                 if ( row_offset > font->height ) {
  672.                         row_offset = font->height-1;
  673.                 }
  674.                 memset((Uint8 *)textbuf->pixels+row_offset*textbuf->pitch,
  675.                                                                 1, width);
  676.         }
  677.         return(textbuf);
  678. }
  679.  
  680. SDL_Surface *TTF_RenderGlyph_Solid(TTF_Font *font, Uint16 ch, SDL_Color fg)
  681. {
  682.         SDL_Surface *textbuf;
  683.         SDL_Palette *palette;
  684.         Uint8 *src, *dst;
  685.         int row, col;
  686.         TT_Error error;
  687.         struct glyph *glyph;
  688.  
  689.         /* Get the glyph itself */
  690.         error = Find_Glyph(font, ch);
  691.         if ( error ) {
  692.                 return(NULL);
  693.         }
  694.         glyph = font->current;
  695.  
  696.         /* Create the target surface */
  697.         textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE,
  698.                       glyph->bitmap.width, glyph->bitmap.rows, 8, 0, 0, 0, 0);
  699.         if ( ! textbuf ) {
  700.                 return(NULL);
  701.         }
  702.  
  703.         /* Fill the palette with the foreground color */
  704.         palette = textbuf->format->palette;
  705.         palette->colors[0].r = 255-fg.r;
  706.         palette->colors[0].g = 255-fg.g;
  707.         palette->colors[0].b = 255-fg.b;
  708.         palette->colors[1].r = fg.r;
  709.         palette->colors[1].g = fg.g;
  710.         palette->colors[1].b = fg.b;
  711.         SDL_SetColorKey(textbuf, SDL_SRCCOLORKEY, 0);
  712.  
  713.         /* Load and render each character */
  714.         src = (Uint8 *)font->current->bitmap.bitmap;
  715.         for ( row = 0; row < textbuf->h; ++row ) {
  716.                 dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
  717.                 for ( col = 0; col < textbuf->w; col += 8 ) {
  718.                         Uint8 c = *src++;
  719.                         *dst++ |= (c&0x80)>>7;
  720.                         c <<= 1;
  721.                         *dst++ |= (c&0x80)>>7;
  722.                         c <<= 1;
  723.                         *dst++ |= (c&0x80)>>7;
  724.                         c <<= 1;
  725.                         *dst++ |= (c&0x80)>>7;
  726.                         c <<= 1;
  727.                         *dst++ |= (c&0x80)>>7;
  728.                         c <<= 1;
  729.                         *dst++ |= (c&0x80)>>7;
  730.                         c <<= 1;
  731.                         *dst++ |= (c&0x80)>>7;
  732.                         c <<= 1;
  733.                         *dst++ |= (c&0x80)>>7;
  734.                 }
  735.         }
  736.  
  737.         /* Handle the underline style */
  738.         if ( font->style & TTF_STYLE_UNDERLINE ) {
  739.                 int row_offset;
  740.  
  741.                 row_offset = round(font->ascent) + 1;
  742.                 if ( row_offset > font->height ) {
  743.                         row_offset = font->height-1;
  744.                 }
  745.                 memset((Uint8 *)textbuf->pixels+row_offset*textbuf->pitch,
  746.                                                         1, textbuf->w);
  747.         }
  748.         return(textbuf);
  749. }
  750.  
  751.  
  752. /* Convert the Latin-1 text to UNICODE and render it
  753. */
  754. SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font,
  755.                                 const char *text, SDL_Color fg, SDL_Color bg)
  756. {
  757.         SDL_Surface *textbuf;
  758.         Uint16 *unicode_text;
  759.         int unicode_len;
  760.  
  761.         /* Copy the Latin-1 text to a UNICODE text buffer */
  762.         unicode_len = strlen(text);
  763.         unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
  764.         if ( unicode_text == NULL ) {
  765.                 SDL_SetError("Out of memory");
  766.                 return(NULL);
  767.         }
  768.         ASCII_to_UNICODE(unicode_text, text, unicode_len);
  769.  
  770.         /* Render the new text */
  771.         textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg);
  772.  
  773.         /* Free the text buffer and return */
  774.         free(unicode_text);
  775.         return(textbuf);
  776. }
  777.  
  778. /* Convert the UTF-8 text to UNICODE and render it
  779. */
  780. SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font,
  781.                                 const char *text, SDL_Color fg, SDL_Color bg)
  782. {
  783.         SDL_Surface *textbuf;
  784.         Uint16 *unicode_text;
  785.         int unicode_len;
  786.  
  787.         /* Copy the UTF-8 text to a UNICODE text buffer */
  788.         unicode_len = strlen(text);
  789.         unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
  790.         if ( unicode_text == NULL ) {
  791.                 SDL_SetError("Out of memory");
  792.                 return(NULL);
  793.         }
  794.         UTF8_to_UNICODE(unicode_text, text, unicode_len);
  795.  
  796.         /* Render the new text */
  797.         textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg);
  798.  
  799.         /* Free the text buffer and return */
  800.         free(unicode_text);
  801.         return(textbuf);
  802. }
  803.  
  804. SDL_Surface *TTF_RenderUNICODE_Shaded(TTF_Font *font,
  805.                                 const Uint16 *text, SDL_Color fg, SDL_Color bg)
  806. {
  807.         int xstart, width;
  808.         int w, h;
  809.         SDL_Surface *textbuf;
  810.         SDL_Palette *palette;
  811.         int index;
  812.         int rdiff, gdiff, bdiff;
  813.         const Uint16 *ch;
  814.         Uint8 *src, *dst;
  815.         int row, col;
  816.         TT_Error error;
  817.  
  818.         /* Get the dimensions of the text surface */
  819.         if ( (TTF_SizeUNICODE(font, text, &w, &h) < 0) || !w ) {
  820.                 TTF_SetError("Text has zero width");
  821.                 return(NULL);
  822.         }
  823.  
  824.         /* Create the target surface */
  825.         width = w;
  826.         w = (w+3)&~3;
  827.         textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
  828.         if ( textbuf == NULL ) {
  829.                 return(NULL);
  830.         }
  831.  
  832.         /* Fill the palette with 5 levels of shading from bg to fg */
  833.         palette = textbuf->format->palette;
  834.         rdiff = fg.r - bg.r;
  835.         gdiff = fg.g - bg.g;
  836.         bdiff = fg.b - bg.b;
  837.         for ( index=0; index<5; ++index ) {
  838.                 palette->colors[index].r = bg.r + (index*rdiff)/4;
  839.                 palette->colors[index].g = bg.g + (index*gdiff)/4;
  840.                 palette->colors[index].b = bg.b + (index*bdiff)/4;
  841.         }
  842.         /* The other 3 levels are used as overflow when ORing pixels */
  843.         for ( ; index<8; ++index ) {
  844.                 palette->colors[index] = palette->colors[4];
  845.         }
  846.  
  847.         /* Load and render each character */
  848.         xstart = 0;
  849.         for ( ch=text; *ch; ++ch ) {
  850.                 error = Find_Glyph(font, *ch);
  851.                 if ( ! error ) {
  852.                         w = font->current->pixmap.width;
  853.                         src = (Uint8 *)font->current->pixmap.bitmap;
  854.                         for ( row = 0; row < h; ++row ) {
  855.                                 dst = (Uint8 *)textbuf->pixels +
  856.                                                row * textbuf->pitch +
  857.                                                xstart + font->current->minx;
  858.                                 for ( col=w; col>0; col -= 4 ) {
  859.                                         *dst++ |= *src++;
  860.                                         *dst++ |= *src++;
  861.                                         *dst++ |= *src++;
  862.                                         *dst++ |= *src++;
  863.                                 }
  864.                         }
  865.                         xstart += font->current->advance;
  866.                         if ( font->style & TTF_STYLE_BOLD ) {
  867.                                 xstart += font->glyph_overhang;
  868.                         }
  869.                 }
  870.         }
  871.         /* Handle the underline style */
  872.         if ( font->style & TTF_STYLE_UNDERLINE ) {
  873.                 int row_offset;
  874.  
  875.                 row_offset = round(font->ascent) + 1;
  876.                 if ( row_offset > font->height ) {
  877.                         row_offset = font->height-1;
  878.                 }
  879.                 memset((Uint8 *)textbuf->pixels+row_offset*textbuf->pitch,
  880.                                                                 4, width);
  881.         }
  882.         return(textbuf);
  883. }
  884.  
  885. SDL_Surface *TTF_RenderGlyph_Shaded(TTF_Font *font,
  886.                                 Uint16 ch, SDL_Color fg, SDL_Color bg)
  887. {
  888.         SDL_Surface *textbuf;
  889.         SDL_Palette *palette;
  890.         int index;
  891.         int rdiff, gdiff, bdiff;
  892.         Uint8 *src, *dst;
  893.         int row, col;
  894.         TT_Error error;
  895.         struct glyph *glyph;
  896.  
  897.         /* Get the glyph itself */
  898.         error = Find_Glyph(font, ch);
  899.         if ( error ) {
  900.                 return(NULL);
  901.         }
  902.         glyph = font->current;
  903.  
  904.         /* Create the target surface */
  905.         textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE,
  906.                       glyph->pixmap.width, glyph->pixmap.rows, 8, 0, 0, 0, 0);
  907.         if ( ! textbuf ) {
  908.                 return(NULL);
  909.         }
  910.  
  911.         /* Fill the palette with 5 levels of shading from bg to fg */
  912.         palette = textbuf->format->palette;
  913.         rdiff = fg.r - bg.r;
  914.         gdiff = fg.g - bg.g;
  915.         bdiff = fg.b - bg.b;
  916.         for ( index=0; index<5; ++index ) {
  917.                 palette->colors[index].r = bg.r + (index*rdiff)/4;
  918.                 palette->colors[index].g = bg.g + (index*gdiff)/4;
  919.                 palette->colors[index].b = bg.b + (index*bdiff)/4;
  920.         }
  921.  
  922.         /* Copy the character from the pixmap */
  923.         for ( row=0; row<textbuf->h; ++row ) {
  924.                 src = glyph->pixmap.bitmap + row * glyph->pixmap.cols;
  925.                 dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
  926.                 memcpy(dst, src, glyph->pixmap.cols);
  927.         }
  928.  
  929.         /* Handle the underline style */
  930.         if ( font->style & TTF_STYLE_UNDERLINE ) {
  931.                 int row_offset;
  932.  
  933.                 row_offset = round(font->ascent) + 1;
  934.                 if ( row_offset > font->height ) {
  935.                         row_offset = font->height-1;
  936.                 }
  937.                 memset((Uint8 *)textbuf->pixels+row_offset*textbuf->pitch,
  938.                                                         4, glyph->pixmap.cols);
  939.         }
  940.         return(textbuf);
  941. }
  942.  
  943. /* Convert the Latin-1 text to UNICODE and render it
  944. */
  945. SDL_Surface *TTF_RenderText_Blended(TTF_Font *font,
  946.                                 const char *text, SDL_Color fg)
  947. {
  948.         SDL_Surface *textbuf;
  949.         Uint16 *unicode_text;
  950.         int unicode_len;
  951.  
  952.         /* Copy the Latin-1 text to a UNICODE text buffer */
  953.         unicode_len = strlen(text);
  954.         unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
  955.         if ( unicode_text == NULL ) {
  956.                 SDL_SetError("Out of memory");
  957.                 return(NULL);
  958.         }
  959.         ASCII_to_UNICODE(unicode_text, text, unicode_len);
  960.  
  961.         /* Render the new text */
  962.         textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg);
  963.  
  964.         /* Free the text buffer and return */
  965.         free(unicode_text);
  966.         return(textbuf);
  967. }
  968.  
  969. /* Convert the UTF-8 text to UNICODE and render it
  970. */
  971. SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
  972.                                 const char *text, SDL_Color fg)
  973. {
  974.         SDL_Surface *textbuf;
  975.         Uint16 *unicode_text;
  976.         int unicode_len;
  977.  
  978.         /* Copy the UTF-8 text to a UNICODE text buffer */
  979.         unicode_len = strlen(text);
  980.         unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
  981.         if ( unicode_text == NULL ) {
  982.                 SDL_SetError("Out of memory");
  983.                 return(NULL);
  984.         }
  985.         UTF8_to_UNICODE(unicode_text, text, unicode_len);
  986.  
  987.         /* Render the new text */
  988.         textbuf = TTF_RenderUNICODE_Blended(font, unicode_text, fg);
  989.  
  990.         /* Free the text buffer and return */
  991.         free(unicode_text);
  992.         return(textbuf);
  993. }
  994.  
  995. SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font,
  996.                                 const Uint16 *text, SDL_Color fg)
  997. {
  998.         int xstart, width;
  999.         int w, h;
  1000.         SDL_Surface *textbuf;
  1001. #if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) >= \
  1002.     SDL_VERSIONNUM(1, 1, 5)                     /* The great alpha flip */
  1003.         Uint32 alpha_table[] = {
  1004.                 (0)<<24,      (255-128)<<24, (255-64)<<24, (255-32)<<24,
  1005.                 (255)<<24,    (255)<<24,     (255)<<24,    (255)<<24
  1006.         };
  1007. #else
  1008.         Uint32 alpha_table[] = {
  1009.                 (255<<24), (128<<24), (64<<24), (32<<24), 0, 0, 0, 0
  1010.         };
  1011. #endif
  1012.         Uint32 pixel;
  1013.         const Uint16 *ch;
  1014.         Uint8 *src;
  1015.         Uint32 *dst;
  1016.         int row, col;
  1017.         TT_Error error;
  1018.  
  1019.         /* Get the dimensions of the text surface */
  1020.         if ( (TTF_SizeUNICODE(font, text, &w, &h) < 0) || !w ) {
  1021.                 TTF_SetError("Text has zero width");
  1022.                 return(NULL);
  1023.         }
  1024.  
  1025.         /* Create the target surface, 32-bit ARGB format */
  1026.         width = w;
  1027.         w = (w+3)&~3;
  1028.         textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 32,
  1029.                                    0x00FF0000, 0x0000FF00, 0x000000FF,
  1030.                                    0xFF000000);
  1031.         if ( textbuf == NULL ) {
  1032.                 return(NULL);
  1033.         }
  1034.  
  1035.         /* Load and render each character */
  1036.         xstart = 0;
  1037.         for ( ch=text; *ch; ++ch ) {
  1038.                 error = Find_Glyph(font, *ch);
  1039.                 if ( ! error ) {
  1040.                         w = font->current->pixmap.width;
  1041.                         src = (Uint8 *)font->current->pixmap.bitmap;
  1042.                         for ( row = 0; row < h; ++row ) {
  1043.                                 dst = (Uint32 *)textbuf->pixels +
  1044.                                                row * textbuf->pitch/4 +
  1045.                                                xstart + font->current->minx;
  1046.                                 for ( col=w; col>0; col -= 4 ) {
  1047.                                         *dst++ |= *src++;
  1048.                                         *dst++ |= *src++;
  1049.                                         *dst++ |= *src++;
  1050.                                         *dst++ |= *src++;
  1051.                                 }
  1052.                         }
  1053.                         xstart += font->current->advance;
  1054.                         if ( font->style & TTF_STYLE_BOLD ) {
  1055.                                 xstart += font->glyph_overhang;
  1056.                         }
  1057.                 }
  1058.         }
  1059.  
  1060.         /* Handle the underline style */
  1061.         if ( font->style & TTF_STYLE_UNDERLINE ) {
  1062.                 int row_offset;
  1063.  
  1064.                 row_offset = round(font->ascent) + 1;
  1065.                 if ( row_offset > font->height ) {
  1066.                         row_offset = font->height-1;
  1067.                 }
  1068.                 dst = (Uint32 *)textbuf->pixels+row_offset*textbuf->pitch/4;
  1069.                 for ( col=width; col > 0; ++col ) {
  1070.                         *dst++ = 4;
  1071.                 }
  1072.         }
  1073.  
  1074.         /* Build the alpha table */
  1075.         pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
  1076.         for ( xstart = 0; xstart < 8; ++xstart ) {
  1077.                 alpha_table[xstart] |= pixel;
  1078.         }
  1079.  
  1080.         /* Transform the alpha values */
  1081.         for ( row = 0; row < textbuf->h; ++row ) {
  1082.                 dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
  1083.                 for ( col=textbuf->w; col>0; col -= 4 ) {
  1084.                         *dst = alpha_table[*dst];
  1085.                         ++dst;
  1086.                         *dst = alpha_table[*dst];
  1087.                         ++dst;
  1088.                         *dst = alpha_table[*dst];
  1089.                         ++dst;
  1090.                         *dst = alpha_table[*dst];
  1091.                         ++dst;
  1092.                 }
  1093.         }
  1094.         return(textbuf);
  1095. }
  1096.  
  1097. SDL_Surface *TTF_RenderGlyph_Blended(TTF_Font *font, Uint16 ch, SDL_Color fg)
  1098. {
  1099.         SDL_Surface *textbuf;
  1100. #if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) >= \
  1101.     SDL_VERSIONNUM(1, 1, 5)                     /* The great alpha flip */
  1102.         Uint32 alpha_table[] = {
  1103.                 (0)<<24,      (255-128)<<24, (255-64)<<24, (255-32)<<24,
  1104.                 (255)<<24,    (255)<<24,     (255)<<24,    (255)<<24
  1105.         };
  1106. #else
  1107.         Uint32 alpha_table[] = {
  1108.                 (255<<24), (128<<24), (64<<24), (32<<24), 0, 0, 0, 0
  1109.         };
  1110. #endif
  1111.         Uint32 pixel;
  1112.         Uint8 *src;
  1113.         Uint32 *dst;
  1114.         int row, col;
  1115.         TT_Error error;
  1116.         struct glyph *glyph;
  1117.  
  1118.         /* Get the glyph itself */
  1119.         error = Find_Glyph(font, ch);
  1120.         if ( error ) {
  1121.                 return(NULL);
  1122.         }
  1123.         glyph = font->current;
  1124.  
  1125.         /* Create the target surface, 32-bit ARGB format */
  1126.         textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE,
  1127.                       glyph->pixmap.width, glyph->pixmap.rows, 32,
  1128.                       0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
  1129.         if ( ! textbuf ) {
  1130.                 return(NULL);
  1131.         }
  1132.  
  1133.         /* Copy the character from the pixmap */
  1134.         for ( row=0; row<textbuf->h; ++row ) {
  1135.                 src = glyph->pixmap.bitmap + row * glyph->pixmap.cols;
  1136.                 dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
  1137.                 for ( col=0; col<glyph->pixmap.cols; ++col ) {
  1138.                         *dst++ = *src++;
  1139.                 }
  1140.         }
  1141.  
  1142.         /* Handle the underline style */
  1143.         if ( font->style & TTF_STYLE_UNDERLINE ) {
  1144.                 int row_offset;
  1145.  
  1146.                 row_offset = round(font->ascent) + 1;
  1147.                 if ( row_offset > font->height ) {
  1148.                         row_offset = font->height-1;
  1149.                 }
  1150.                 dst = (Uint32 *)textbuf->pixels+row_offset*textbuf->pitch/4;
  1151.                 for ( col=glyph->pixmap.cols; col > 0; ++col ) {
  1152.                         *dst++ = 4;
  1153.                 }
  1154.         }
  1155.  
  1156.         /* Build the alpha table */
  1157.         pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
  1158.         for ( col = 0; col < 8; ++col ) {
  1159.                 alpha_table[col] |= pixel;
  1160.         }
  1161.  
  1162.         /* Transform the alpha values */
  1163.         for ( row = 0; row < textbuf->h; ++row ) {
  1164.                 dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
  1165.                 for ( col=textbuf->w; col>0; col -= 4 ) {
  1166.                         *dst = alpha_table[*dst];
  1167.                         ++dst;
  1168.                         *dst = alpha_table[*dst];
  1169.                         ++dst;
  1170.                         *dst = alpha_table[*dst];
  1171.                         ++dst;
  1172.                         *dst = alpha_table[*dst];
  1173.                         ++dst;
  1174.                 }
  1175.         }
  1176.         return(textbuf);
  1177. }
  1178.  
  1179. void TTF_SetFontStyle(TTF_Font *font, int style)
  1180. {
  1181.         font->style = style;
  1182.         Flush_Cache(font);
  1183. }
  1184.  
  1185. int TTF_GetFontStyle(TTF_Font *font)
  1186. {
  1187.         return(font->style);
  1188. }
  1189.  
  1190. void TTF_Quit(void)
  1191. {
  1192.         TT_Done_FreeType(engine);
  1193. }
  1194.